1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
3  */
4 
5 #include <errno.h>
6 #include <stdbool.h>
7 
8 #include <rte_malloc.h>
9 
10 #include "ionic_lif.h"
11 #include "ionic_rx_filter.h"
12 
13 void
ionic_rx_filter_free(struct ionic_rx_filter * f)14 ionic_rx_filter_free(struct ionic_rx_filter *f)
15 {
16 	LIST_REMOVE(f, by_id);
17 	LIST_REMOVE(f, by_hash);
18 	rte_free(f);
19 }
20 
21 int
ionic_rx_filter_del(struct ionic_lif * lif,struct ionic_rx_filter * f)22 ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f)
23 {
24 	struct ionic_admin_ctx ctx = {
25 		.pending_work = true,
26 		.cmd.rx_filter_del = {
27 			.opcode = IONIC_CMD_RX_FILTER_DEL,
28 			.filter_id = f->filter_id,
29 		},
30 	};
31 
32 	return ionic_adminq_post(lif, &ctx);
33 }
34 
35 int
ionic_rx_filters_init(struct ionic_lif * lif)36 ionic_rx_filters_init(struct ionic_lif *lif)
37 {
38 	uint32_t i;
39 
40 	rte_spinlock_init(&lif->rx_filters.lock);
41 
42 	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
43 		LIST_INIT(&lif->rx_filters.by_hash[i]);
44 		LIST_INIT(&lif->rx_filters.by_id[i]);
45 	}
46 
47 	return 0;
48 }
49 
50 void
ionic_rx_filters_deinit(struct ionic_lif * lif)51 ionic_rx_filters_deinit(struct ionic_lif *lif)
52 {
53 	struct ionic_rx_filter *f;
54 	uint32_t i;
55 
56 	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
57 		while (!LIST_EMPTY(&lif->rx_filters.by_id[i])) {
58 			f = LIST_FIRST(&lif->rx_filters.by_id[i]);
59 			ionic_rx_filter_free(f);
60 		}
61 	}
62 }
63 
64 int
ionic_rx_filter_save(struct ionic_lif * lif,uint32_t flow_id,uint16_t rxq_index,struct ionic_admin_ctx * ctx)65 ionic_rx_filter_save(struct ionic_lif *lif, uint32_t flow_id,
66 		uint16_t rxq_index, struct ionic_admin_ctx *ctx)
67 {
68 	struct ionic_rx_filter *f;
69 	uint32_t key;
70 
71 	f = rte_zmalloc("ionic", sizeof(*f), 0);
72 
73 	if (!f)
74 		return -ENOMEM;
75 
76 	f->flow_id = flow_id;
77 	f->filter_id = ctx->comp.rx_filter_add.filter_id;
78 	f->rxq_index = rxq_index;
79 	memcpy(&f->cmd, &ctx->cmd, sizeof(f->cmd));
80 
81 	switch (f->cmd.match) {
82 	case IONIC_RX_FILTER_MATCH_VLAN:
83 		key = f->cmd.vlan.vlan & IONIC_RX_FILTER_HLISTS_MASK;
84 		break;
85 	case IONIC_RX_FILTER_MATCH_MAC:
86 		memcpy(&key, f->cmd.mac.addr, sizeof(key));
87 		key &= IONIC_RX_FILTER_HLISTS_MASK;
88 		break;
89 	case IONIC_RX_FILTER_MATCH_MAC_VLAN:
90 		key = f->cmd.mac_vlan.vlan & IONIC_RX_FILTER_HLISTS_MASK;
91 		break;
92 	default:
93 		return -EINVAL;
94 	}
95 
96 	rte_spinlock_lock(&lif->rx_filters.lock);
97 
98 	LIST_INSERT_HEAD(&lif->rx_filters.by_hash[key], f, by_hash);
99 
100 	key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK;
101 
102 	LIST_INSERT_HEAD(&lif->rx_filters.by_id[key], f, by_id);
103 
104 	rte_spinlock_unlock(&lif->rx_filters.lock);
105 
106 	return 0;
107 }
108 
109 struct ionic_rx_filter *
ionic_rx_filter_by_vlan(struct ionic_lif * lif,uint16_t vid)110 ionic_rx_filter_by_vlan(struct ionic_lif *lif, uint16_t vid)
111 {
112 	uint32_t key = vid & IONIC_RX_FILTER_HLISTS_MASK;
113 	struct ionic_rx_filter *f;
114 
115 	LIST_FOREACH(f, &lif->rx_filters.by_hash[key], by_hash) {
116 		if (f->cmd.match != IONIC_RX_FILTER_MATCH_VLAN)
117 			continue;
118 		if (f->cmd.vlan.vlan == vid)
119 			return f;
120 	}
121 
122 	return NULL;
123 }
124 
125 struct ionic_rx_filter *
ionic_rx_filter_by_addr(struct ionic_lif * lif,const uint8_t * addr)126 ionic_rx_filter_by_addr(struct ionic_lif *lif, const uint8_t *addr)
127 {
128 	const uint32_t key = *(const uint32_t *)addr &
129 		IONIC_RX_FILTER_HLISTS_MASK;
130 	struct ionic_rx_filter *f;
131 
132 	LIST_FOREACH(f, &lif->rx_filters.by_hash[key], by_hash) {
133 		if (f->cmd.match != IONIC_RX_FILTER_MATCH_MAC)
134 			continue;
135 		if (memcmp(addr, f->cmd.mac.addr, RTE_ETHER_ADDR_LEN) == 0)
136 			return f;
137 	}
138 
139 	return NULL;
140 }
141