1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3  * Copyright (c) 2019 Microsemi Corporation
4  */
5 
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8 
9 #include "ocelot_ace.h"
10 
11 struct ocelot_port_block {
12 	struct ocelot_acl_block *block;
13 	struct ocelot_port_private *priv;
14 };
15 
16 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
17 				      struct ocelot_ace_rule *rule)
18 {
19 	const struct flow_action_entry *a;
20 	int i;
21 
22 	if (f->rule->action.num_entries != 1)
23 		return -EOPNOTSUPP;
24 
25 	flow_action_for_each(i, a, &f->rule->action) {
26 		switch (a->id) {
27 		case FLOW_ACTION_DROP:
28 			rule->action = OCELOT_ACL_ACTION_DROP;
29 			break;
30 		case FLOW_ACTION_TRAP:
31 			rule->action = OCELOT_ACL_ACTION_TRAP;
32 			break;
33 		default:
34 			return -EOPNOTSUPP;
35 		}
36 	}
37 
38 	return 0;
39 }
40 
41 static int ocelot_flower_parse(struct flow_cls_offload *f,
42 			       struct ocelot_ace_rule *ocelot_rule)
43 {
44 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
45 	struct flow_dissector *dissector = rule->match.dissector;
46 
47 	if (dissector->used_keys &
48 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
49 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
50 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
51 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
52 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
53 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
54 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
55 		return -EOPNOTSUPP;
56 	}
57 
58 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
59 		struct flow_match_control match;
60 
61 		flow_rule_match_control(rule, &match);
62 	}
63 
64 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
65 		struct flow_match_eth_addrs match;
66 		u16 proto = ntohs(f->common.protocol);
67 
68 		/* The hw support mac matches only for MAC_ETYPE key,
69 		 * therefore if other matches(port, tcp flags, etc) are added
70 		 * then just bail out
71 		 */
72 		if ((dissector->used_keys &
73 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
74 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
75 		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
76 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
77 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
78 		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
79 			return -EOPNOTSUPP;
80 
81 		if (proto == ETH_P_IP ||
82 		    proto == ETH_P_IPV6 ||
83 		    proto == ETH_P_ARP)
84 			return -EOPNOTSUPP;
85 
86 		flow_rule_match_eth_addrs(rule, &match);
87 		ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
88 		ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
89 				match.key->dst);
90 		ether_addr_copy(ocelot_rule->frame.etype.smac.value,
91 				match.key->src);
92 		ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
93 				match.mask->dst);
94 		ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
95 				match.mask->src);
96 		goto finished_key_parsing;
97 	}
98 
99 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
100 		struct flow_match_basic match;
101 
102 		flow_rule_match_basic(rule, &match);
103 		if (ntohs(match.key->n_proto) == ETH_P_IP) {
104 			ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
105 			ocelot_rule->frame.ipv4.proto.value[0] =
106 				match.key->ip_proto;
107 			ocelot_rule->frame.ipv4.proto.mask[0] =
108 				match.mask->ip_proto;
109 		}
110 		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
111 			ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
112 			ocelot_rule->frame.ipv6.proto.value[0] =
113 				match.key->ip_proto;
114 			ocelot_rule->frame.ipv6.proto.mask[0] =
115 				match.mask->ip_proto;
116 		}
117 	}
118 
119 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
120 	    ntohs(f->common.protocol) == ETH_P_IP) {
121 		struct flow_match_ipv4_addrs match;
122 		u8 *tmp;
123 
124 		flow_rule_match_ipv4_addrs(rule, &match);
125 		tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
126 		memcpy(tmp, &match.key->src, 4);
127 
128 		tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
129 		memcpy(tmp, &match.mask->src, 4);
130 
131 		tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
132 		memcpy(tmp, &match.key->dst, 4);
133 
134 		tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
135 		memcpy(tmp, &match.mask->dst, 4);
136 	}
137 
138 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
139 	    ntohs(f->common.protocol) == ETH_P_IPV6) {
140 		return -EOPNOTSUPP;
141 	}
142 
143 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
144 		struct flow_match_ports match;
145 
146 		flow_rule_match_ports(rule, &match);
147 		ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
148 		ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
149 		ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
150 		ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
151 	}
152 
153 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
154 		struct flow_match_vlan match;
155 
156 		flow_rule_match_vlan(rule, &match);
157 		ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
158 		ocelot_rule->vlan.vid.value = match.key->vlan_id;
159 		ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
160 		ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
161 		ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
162 	}
163 
164 finished_key_parsing:
165 	ocelot_rule->prio = f->common.prio;
166 	ocelot_rule->id = f->cookie;
167 	return ocelot_flower_parse_action(f, ocelot_rule);
168 }
169 
170 static
171 struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
172 					       struct ocelot_port_block *block)
173 {
174 	struct ocelot_ace_rule *rule;
175 
176 	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
177 	if (!rule)
178 		return NULL;
179 
180 	rule->port = &block->priv->port;
181 	rule->chip_port = block->priv->chip_port;
182 	return rule;
183 }
184 
185 static int ocelot_flower_replace(struct flow_cls_offload *f,
186 				 struct ocelot_port_block *port_block)
187 {
188 	struct ocelot_ace_rule *rule;
189 	int ret;
190 
191 	rule = ocelot_ace_rule_create(f, port_block);
192 	if (!rule)
193 		return -ENOMEM;
194 
195 	ret = ocelot_flower_parse(f, rule);
196 	if (ret) {
197 		kfree(rule);
198 		return ret;
199 	}
200 
201 	ret = ocelot_ace_rule_offload_add(rule);
202 	if (ret)
203 		return ret;
204 
205 	port_block->priv->tc.offload_cnt++;
206 	return 0;
207 }
208 
209 static int ocelot_flower_destroy(struct flow_cls_offload *f,
210 				 struct ocelot_port_block *port_block)
211 {
212 	struct ocelot_ace_rule rule;
213 	int ret;
214 
215 	rule.prio = f->common.prio;
216 	rule.port = &port_block->priv->port;
217 	rule.id = f->cookie;
218 
219 	ret = ocelot_ace_rule_offload_del(&rule);
220 	if (ret)
221 		return ret;
222 
223 	port_block->priv->tc.offload_cnt--;
224 	return 0;
225 }
226 
227 static int ocelot_flower_stats_update(struct flow_cls_offload *f,
228 				      struct ocelot_port_block *port_block)
229 {
230 	struct ocelot_ace_rule rule;
231 	int ret;
232 
233 	rule.prio = f->common.prio;
234 	rule.port = &port_block->priv->port;
235 	rule.id = f->cookie;
236 	ret = ocelot_ace_rule_stats_update(&rule);
237 	if (ret)
238 		return ret;
239 
240 	flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
241 	return 0;
242 }
243 
244 static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
245 				      struct ocelot_port_block *port_block)
246 {
247 	switch (f->command) {
248 	case FLOW_CLS_REPLACE:
249 		return ocelot_flower_replace(f, port_block);
250 	case FLOW_CLS_DESTROY:
251 		return ocelot_flower_destroy(f, port_block);
252 	case FLOW_CLS_STATS:
253 		return ocelot_flower_stats_update(f, port_block);
254 	default:
255 		return -EOPNOTSUPP;
256 	}
257 }
258 
259 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
260 					   void *type_data, void *cb_priv)
261 {
262 	struct ocelot_port_block *port_block = cb_priv;
263 
264 	if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data))
265 		return -EOPNOTSUPP;
266 
267 	switch (type) {
268 	case TC_SETUP_CLSFLOWER:
269 		return ocelot_setup_tc_cls_flower(type_data, cb_priv);
270 	case TC_SETUP_CLSMATCHALL:
271 		return 0;
272 	default:
273 		return -EOPNOTSUPP;
274 	}
275 }
276 
277 static struct ocelot_port_block*
278 ocelot_port_block_create(struct ocelot_port_private *priv)
279 {
280 	struct ocelot_port_block *port_block;
281 
282 	port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
283 	if (!port_block)
284 		return NULL;
285 
286 	port_block->priv = priv;
287 
288 	return port_block;
289 }
290 
291 static void ocelot_port_block_destroy(struct ocelot_port_block *block)
292 {
293 	kfree(block);
294 }
295 
296 static void ocelot_tc_block_unbind(void *cb_priv)
297 {
298 	struct ocelot_port_block *port_block = cb_priv;
299 
300 	ocelot_port_block_destroy(port_block);
301 }
302 
303 int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
304 				      struct flow_block_offload *f)
305 {
306 	struct ocelot_port_block *port_block;
307 	struct flow_block_cb *block_cb;
308 	int ret;
309 
310 	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
311 		return -EOPNOTSUPP;
312 
313 	block_cb = flow_block_cb_lookup(f->block,
314 					ocelot_setup_tc_block_cb_flower, priv);
315 	if (!block_cb) {
316 		port_block = ocelot_port_block_create(priv);
317 		if (!port_block)
318 			return -ENOMEM;
319 
320 		block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
321 					       priv, port_block,
322 					       ocelot_tc_block_unbind);
323 		if (IS_ERR(block_cb)) {
324 			ret = PTR_ERR(block_cb);
325 			goto err_cb_register;
326 		}
327 		flow_block_cb_add(block_cb, f);
328 		list_add_tail(&block_cb->driver_list, f->driver_block_list);
329 	} else {
330 		port_block = flow_block_cb_priv(block_cb);
331 	}
332 
333 	flow_block_cb_incref(block_cb);
334 	return 0;
335 
336 err_cb_register:
337 	ocelot_port_block_destroy(port_block);
338 
339 	return ret;
340 }
341 
342 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
343 					 struct flow_block_offload *f)
344 {
345 	struct flow_block_cb *block_cb;
346 
347 	block_cb = flow_block_cb_lookup(f->block,
348 					ocelot_setup_tc_block_cb_flower, priv);
349 	if (!block_cb)
350 		return;
351 
352 	if (!flow_block_cb_decref(block_cb)) {
353 		flow_block_cb_remove(block_cb, f);
354 		list_del(&block_cb->driver_list);
355 	}
356 }
357