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 #include <soc/mscc/ocelot_vcap.h>
9 #include "ocelot_vcap.h"
10 
11 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
12  * into the chain number. This is UAPI.
13  */
14 #define VCAP_BLOCK			10000
15 #define VCAP_LOOKUP			1000
16 #define VCAP_IS1_NUM_LOOKUPS		3
17 #define VCAP_IS2_NUM_LOOKUPS		2
18 #define VCAP_IS2_NUM_PAG		256
19 #define VCAP_IS1_CHAIN(lookup)		\
20 	(1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
21 #define VCAP_IS2_CHAIN(lookup, pag)	\
22 	(2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
23 
ocelot_chain_to_block(int chain,bool ingress)24 static int ocelot_chain_to_block(int chain, bool ingress)
25 {
26 	int lookup, pag;
27 
28 	if (!ingress) {
29 		if (chain == 0)
30 			return VCAP_ES0;
31 		return -EOPNOTSUPP;
32 	}
33 
34 	/* Backwards compatibility with older, single-chain tc-flower
35 	 * offload support in Ocelot
36 	 */
37 	if (chain == 0)
38 		return VCAP_IS2;
39 
40 	for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
41 		if (chain == VCAP_IS1_CHAIN(lookup))
42 			return VCAP_IS1;
43 
44 	for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
45 		for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
46 			if (chain == VCAP_IS2_CHAIN(lookup, pag))
47 				return VCAP_IS2;
48 
49 	return -EOPNOTSUPP;
50 }
51 
52 /* Caller must ensure this is a valid IS1 or IS2 chain first,
53  * by calling ocelot_chain_to_block.
54  */
ocelot_chain_to_lookup(int chain)55 static int ocelot_chain_to_lookup(int chain)
56 {
57 	return (chain / VCAP_LOOKUP) % 10;
58 }
59 
60 /* Caller must ensure this is a valid IS2 chain first,
61  * by calling ocelot_chain_to_block.
62  */
ocelot_chain_to_pag(int chain)63 static int ocelot_chain_to_pag(int chain)
64 {
65 	int lookup = ocelot_chain_to_lookup(chain);
66 
67 	/* calculate PAG value as chain index relative to the first PAG */
68 	return chain - VCAP_IS2_CHAIN(lookup, 0);
69 }
70 
ocelot_is_goto_target_valid(int goto_target,int chain,bool ingress)71 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
72 					bool ingress)
73 {
74 	int pag;
75 
76 	/* Can't offload GOTO in VCAP ES0 */
77 	if (!ingress)
78 		return (goto_target < 0);
79 
80 	/* Non-optional GOTOs */
81 	if (chain == 0)
82 		/* VCAP IS1 can be skipped, either partially or completely */
83 		return (goto_target == VCAP_IS1_CHAIN(0) ||
84 			goto_target == VCAP_IS1_CHAIN(1) ||
85 			goto_target == VCAP_IS1_CHAIN(2) ||
86 			goto_target == VCAP_IS2_CHAIN(0, 0) ||
87 			goto_target == VCAP_IS2_CHAIN(1, 0));
88 
89 	if (chain == VCAP_IS1_CHAIN(0))
90 		return (goto_target == VCAP_IS1_CHAIN(1));
91 
92 	if (chain == VCAP_IS1_CHAIN(1))
93 		return (goto_target == VCAP_IS1_CHAIN(2));
94 
95 	/* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
96 	 * using a Policy Association Group (PAG) value, which is an 8-bit
97 	 * value encoding a VCAP IS2 target chain.
98 	 */
99 	if (chain == VCAP_IS1_CHAIN(2)) {
100 		for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
101 			if (goto_target == VCAP_IS2_CHAIN(0, pag))
102 				return true;
103 
104 		return false;
105 	}
106 
107 	/* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
108 	 * We cannot change the PAG at this point.
109 	 */
110 	for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
111 		if (chain == VCAP_IS2_CHAIN(0, pag))
112 			return (goto_target == VCAP_IS2_CHAIN(1, pag));
113 
114 	/* VCAP IS2 lookup 1 cannot jump anywhere */
115 	return false;
116 }
117 
118 static struct ocelot_vcap_filter *
ocelot_find_vcap_filter_that_points_at(struct ocelot * ocelot,int chain)119 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
120 {
121 	struct ocelot_vcap_filter *filter;
122 	struct ocelot_vcap_block *block;
123 	int block_id;
124 
125 	block_id = ocelot_chain_to_block(chain, true);
126 	if (block_id < 0)
127 		return NULL;
128 
129 	if (block_id == VCAP_IS2) {
130 		block = &ocelot->block[VCAP_IS1];
131 
132 		list_for_each_entry(filter, &block->rules, list)
133 			if (filter->type == OCELOT_VCAP_FILTER_PAG &&
134 			    filter->goto_target == chain)
135 				return filter;
136 	}
137 
138 	list_for_each_entry(filter, &ocelot->dummy_rules, list)
139 		if (filter->goto_target == chain)
140 			return filter;
141 
142 	return NULL;
143 }
144 
ocelot_flower_parse_action(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)145 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
146 				      bool ingress, struct flow_cls_offload *f,
147 				      struct ocelot_vcap_filter *filter)
148 {
149 	struct ocelot_port *ocelot_port = ocelot->ports[port];
150 	struct netlink_ext_ack *extack = f->common.extack;
151 	bool allow_missing_goto_target = false;
152 	const struct flow_action_entry *a;
153 	enum ocelot_tag_tpid_sel tpid;
154 	int i, chain, egress_port;
155 	u64 rate;
156 
157 	if (!flow_action_basic_hw_stats_check(&f->rule->action,
158 					      f->common.extack))
159 		return -EOPNOTSUPP;
160 
161 	chain = f->common.chain_index;
162 	filter->block_id = ocelot_chain_to_block(chain, ingress);
163 	if (filter->block_id < 0) {
164 		NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
165 		return -EOPNOTSUPP;
166 	}
167 	if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
168 		filter->lookup = ocelot_chain_to_lookup(chain);
169 	if (filter->block_id == VCAP_IS2)
170 		filter->pag = ocelot_chain_to_pag(chain);
171 
172 	filter->goto_target = -1;
173 	filter->type = OCELOT_VCAP_FILTER_DUMMY;
174 
175 	flow_action_for_each(i, a, &f->rule->action) {
176 		switch (a->id) {
177 		case FLOW_ACTION_DROP:
178 			if (filter->block_id != VCAP_IS2) {
179 				NL_SET_ERR_MSG_MOD(extack,
180 						   "Drop action can only be offloaded to VCAP IS2");
181 				return -EOPNOTSUPP;
182 			}
183 			if (filter->goto_target != -1) {
184 				NL_SET_ERR_MSG_MOD(extack,
185 						   "Last action must be GOTO");
186 				return -EOPNOTSUPP;
187 			}
188 			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
189 			filter->action.port_mask = 0;
190 			filter->action.police_ena = true;
191 			filter->action.pol_ix = OCELOT_POLICER_DISCARD;
192 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
193 			break;
194 		case FLOW_ACTION_TRAP:
195 			if (filter->block_id != VCAP_IS2) {
196 				NL_SET_ERR_MSG_MOD(extack,
197 						   "Trap action can only be offloaded to VCAP IS2");
198 				return -EOPNOTSUPP;
199 			}
200 			if (filter->goto_target != -1) {
201 				NL_SET_ERR_MSG_MOD(extack,
202 						   "Last action must be GOTO");
203 				return -EOPNOTSUPP;
204 			}
205 			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
206 			filter->action.port_mask = 0;
207 			filter->action.cpu_copy_ena = true;
208 			filter->action.cpu_qu_num = 0;
209 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
210 			break;
211 		case FLOW_ACTION_POLICE:
212 			if (filter->block_id != VCAP_IS2 ||
213 			    filter->lookup != 0) {
214 				NL_SET_ERR_MSG_MOD(extack,
215 						   "Police action can only be offloaded to VCAP IS2 lookup 0");
216 				return -EOPNOTSUPP;
217 			}
218 			if (filter->goto_target != -1) {
219 				NL_SET_ERR_MSG_MOD(extack,
220 						   "Last action must be GOTO");
221 				return -EOPNOTSUPP;
222 			}
223 			if (a->police.rate_pkt_ps) {
224 				NL_SET_ERR_MSG_MOD(extack,
225 						   "QoS offload not support packets per second");
226 				return -EOPNOTSUPP;
227 			}
228 			filter->action.police_ena = true;
229 			rate = a->police.rate_bytes_ps;
230 			filter->action.pol.rate = div_u64(rate, 1000) * 8;
231 			filter->action.pol.burst = a->police.burst;
232 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
233 			break;
234 		case FLOW_ACTION_REDIRECT:
235 			if (filter->block_id != VCAP_IS2) {
236 				NL_SET_ERR_MSG_MOD(extack,
237 						   "Redirect action can only be offloaded to VCAP IS2");
238 				return -EOPNOTSUPP;
239 			}
240 			if (filter->goto_target != -1) {
241 				NL_SET_ERR_MSG_MOD(extack,
242 						   "Last action must be GOTO");
243 				return -EOPNOTSUPP;
244 			}
245 			egress_port = ocelot->ops->netdev_to_port(a->dev);
246 			if (egress_port < 0) {
247 				NL_SET_ERR_MSG_MOD(extack,
248 						   "Destination not an ocelot port");
249 				return -EOPNOTSUPP;
250 			}
251 			filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
252 			filter->action.port_mask = BIT(egress_port);
253 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
254 			break;
255 		case FLOW_ACTION_VLAN_POP:
256 			if (filter->block_id != VCAP_IS1) {
257 				NL_SET_ERR_MSG_MOD(extack,
258 						   "VLAN pop action can only be offloaded to VCAP IS1");
259 				return -EOPNOTSUPP;
260 			}
261 			if (filter->goto_target != -1) {
262 				NL_SET_ERR_MSG_MOD(extack,
263 						   "Last action must be GOTO");
264 				return -EOPNOTSUPP;
265 			}
266 			filter->action.vlan_pop_cnt_ena = true;
267 			filter->action.vlan_pop_cnt++;
268 			if (filter->action.vlan_pop_cnt > 2) {
269 				NL_SET_ERR_MSG_MOD(extack,
270 						   "Cannot pop more than 2 VLAN headers");
271 				return -EOPNOTSUPP;
272 			}
273 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
274 			break;
275 		case FLOW_ACTION_VLAN_MANGLE:
276 			if (filter->block_id != VCAP_IS1) {
277 				NL_SET_ERR_MSG_MOD(extack,
278 						   "VLAN modify action can only be offloaded to VCAP IS1");
279 				return -EOPNOTSUPP;
280 			}
281 			if (filter->goto_target != -1) {
282 				NL_SET_ERR_MSG_MOD(extack,
283 						   "Last action must be GOTO");
284 				return -EOPNOTSUPP;
285 			}
286 			if (!ocelot_port->vlan_aware) {
287 				NL_SET_ERR_MSG_MOD(extack,
288 						   "Can only modify VLAN under VLAN aware bridge");
289 				return -EOPNOTSUPP;
290 			}
291 			filter->action.vid_replace_ena = true;
292 			filter->action.pcp_dei_ena = true;
293 			filter->action.vid = a->vlan.vid;
294 			filter->action.pcp = a->vlan.prio;
295 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
296 			break;
297 		case FLOW_ACTION_PRIORITY:
298 			if (filter->block_id != VCAP_IS1) {
299 				NL_SET_ERR_MSG_MOD(extack,
300 						   "Priority action can only be offloaded to VCAP IS1");
301 				return -EOPNOTSUPP;
302 			}
303 			if (filter->goto_target != -1) {
304 				NL_SET_ERR_MSG_MOD(extack,
305 						   "Last action must be GOTO");
306 				return -EOPNOTSUPP;
307 			}
308 			filter->action.qos_ena = true;
309 			filter->action.qos_val = a->priority;
310 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
311 			break;
312 		case FLOW_ACTION_GOTO:
313 			filter->goto_target = a->chain_index;
314 
315 			if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
316 				int pag = ocelot_chain_to_pag(filter->goto_target);
317 
318 				filter->action.pag_override_mask = 0xff;
319 				filter->action.pag_val = pag;
320 				filter->type = OCELOT_VCAP_FILTER_PAG;
321 			}
322 			break;
323 		case FLOW_ACTION_VLAN_PUSH:
324 			if (filter->block_id != VCAP_ES0) {
325 				NL_SET_ERR_MSG_MOD(extack,
326 						   "VLAN push action can only be offloaded to VCAP ES0");
327 				return -EOPNOTSUPP;
328 			}
329 			switch (ntohs(a->vlan.proto)) {
330 			case ETH_P_8021Q:
331 				tpid = OCELOT_TAG_TPID_SEL_8021Q;
332 				break;
333 			case ETH_P_8021AD:
334 				tpid = OCELOT_TAG_TPID_SEL_8021AD;
335 				break;
336 			default:
337 				NL_SET_ERR_MSG_MOD(extack,
338 						   "Cannot push custom TPID");
339 				return -EOPNOTSUPP;
340 			}
341 			filter->action.tag_a_tpid_sel = tpid;
342 			filter->action.push_outer_tag = OCELOT_ES0_TAG;
343 			filter->action.tag_a_vid_sel = 1;
344 			filter->action.vid_a_val = a->vlan.vid;
345 			filter->action.pcp_a_val = a->vlan.prio;
346 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
347 			break;
348 		default:
349 			NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
350 			return -EOPNOTSUPP;
351 		}
352 	}
353 
354 	if (filter->goto_target == -1) {
355 		if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
356 		    chain == 0) {
357 			allow_missing_goto_target = true;
358 		} else {
359 			NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
360 			return -EOPNOTSUPP;
361 		}
362 	}
363 
364 	if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
365 	    !allow_missing_goto_target) {
366 		NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
367 		return -EOPNOTSUPP;
368 	}
369 
370 	return 0;
371 }
372 
ocelot_flower_parse_indev(struct ocelot * ocelot,int port,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)373 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
374 				     struct flow_cls_offload *f,
375 				     struct ocelot_vcap_filter *filter)
376 {
377 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
378 	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
379 	int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
380 	struct netlink_ext_ack *extack = f->common.extack;
381 	struct net_device *dev, *indev;
382 	struct flow_match_meta match;
383 	int ingress_port;
384 
385 	flow_rule_match_meta(rule, &match);
386 
387 	if (!match.mask->ingress_ifindex)
388 		return 0;
389 
390 	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
391 		NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
392 		return -EOPNOTSUPP;
393 	}
394 
395 	dev = ocelot->ops->port_to_netdev(ocelot, port);
396 	if (!dev)
397 		return -EINVAL;
398 
399 	indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
400 	if (!indev) {
401 		NL_SET_ERR_MSG_MOD(extack,
402 				   "Can't find the ingress port to match on");
403 		return -ENOENT;
404 	}
405 
406 	ingress_port = ocelot->ops->netdev_to_port(indev);
407 	if (ingress_port < 0) {
408 		NL_SET_ERR_MSG_MOD(extack,
409 				   "Can only offload an ocelot ingress port");
410 		return -EOPNOTSUPP;
411 	}
412 	if (ingress_port == port) {
413 		NL_SET_ERR_MSG_MOD(extack,
414 				   "Ingress port is equal to the egress port");
415 		return -EINVAL;
416 	}
417 
418 	filter->ingress_port.value = ingress_port;
419 	filter->ingress_port.mask = GENMASK(key_length - 1, 0);
420 
421 	return 0;
422 }
423 
424 static int
ocelot_flower_parse_key(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)425 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
426 			struct flow_cls_offload *f,
427 			struct ocelot_vcap_filter *filter)
428 {
429 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
430 	struct flow_dissector *dissector = rule->match.dissector;
431 	struct netlink_ext_ack *extack = f->common.extack;
432 	u16 proto = ntohs(f->common.protocol);
433 	bool match_protocol = true;
434 	int ret;
435 
436 	if (dissector->used_keys &
437 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
438 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
439 	      BIT(FLOW_DISSECTOR_KEY_META) |
440 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
441 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
442 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
443 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
444 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
445 		return -EOPNOTSUPP;
446 	}
447 
448 	/* For VCAP ES0 (egress rewriter) we can match on the ingress port */
449 	if (!ingress) {
450 		ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
451 		if (ret)
452 			return ret;
453 	}
454 
455 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
456 		struct flow_match_control match;
457 
458 		flow_rule_match_control(rule, &match);
459 	}
460 
461 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
462 		struct flow_match_eth_addrs match;
463 
464 		if (filter->block_id == VCAP_ES0) {
465 			NL_SET_ERR_MSG_MOD(extack,
466 					   "VCAP ES0 cannot match on MAC address");
467 			return -EOPNOTSUPP;
468 		}
469 
470 		if (filter->block_id == VCAP_IS1 &&
471 		    !is_zero_ether_addr(match.mask->dst)) {
472 			NL_SET_ERR_MSG_MOD(extack,
473 					   "Key type S1_NORMAL cannot match on destination MAC");
474 			return -EOPNOTSUPP;
475 		}
476 
477 		/* The hw support mac matches only for MAC_ETYPE key,
478 		 * therefore if other matches(port, tcp flags, etc) are added
479 		 * then just bail out
480 		 */
481 		if ((dissector->used_keys &
482 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
483 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
484 		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
485 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
486 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
487 		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
488 			return -EOPNOTSUPP;
489 
490 		flow_rule_match_eth_addrs(rule, &match);
491 		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
492 		ether_addr_copy(filter->key.etype.dmac.value,
493 				match.key->dst);
494 		ether_addr_copy(filter->key.etype.smac.value,
495 				match.key->src);
496 		ether_addr_copy(filter->key.etype.dmac.mask,
497 				match.mask->dst);
498 		ether_addr_copy(filter->key.etype.smac.mask,
499 				match.mask->src);
500 		goto finished_key_parsing;
501 	}
502 
503 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
504 		struct flow_match_basic match;
505 
506 		flow_rule_match_basic(rule, &match);
507 		if (ntohs(match.key->n_proto) == ETH_P_IP) {
508 			if (filter->block_id == VCAP_ES0) {
509 				NL_SET_ERR_MSG_MOD(extack,
510 						   "VCAP ES0 cannot match on IP protocol");
511 				return -EOPNOTSUPP;
512 			}
513 
514 			filter->key_type = OCELOT_VCAP_KEY_IPV4;
515 			filter->key.ipv4.proto.value[0] =
516 				match.key->ip_proto;
517 			filter->key.ipv4.proto.mask[0] =
518 				match.mask->ip_proto;
519 			match_protocol = false;
520 		}
521 		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
522 			if (filter->block_id == VCAP_ES0) {
523 				NL_SET_ERR_MSG_MOD(extack,
524 						   "VCAP ES0 cannot match on IP protocol");
525 				return -EOPNOTSUPP;
526 			}
527 
528 			filter->key_type = OCELOT_VCAP_KEY_IPV6;
529 			filter->key.ipv6.proto.value[0] =
530 				match.key->ip_proto;
531 			filter->key.ipv6.proto.mask[0] =
532 				match.mask->ip_proto;
533 			match_protocol = false;
534 		}
535 	}
536 
537 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
538 	    proto == ETH_P_IP) {
539 		struct flow_match_ipv4_addrs match;
540 		u8 *tmp;
541 
542 		if (filter->block_id == VCAP_ES0) {
543 			NL_SET_ERR_MSG_MOD(extack,
544 					   "VCAP ES0 cannot match on IP address");
545 			return -EOPNOTSUPP;
546 		}
547 
548 		flow_rule_match_ipv4_addrs(rule, &match);
549 
550 		if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
551 			NL_SET_ERR_MSG_MOD(extack,
552 					   "Key type S1_NORMAL cannot match on destination IP");
553 			return -EOPNOTSUPP;
554 		}
555 
556 		tmp = &filter->key.ipv4.sip.value.addr[0];
557 		memcpy(tmp, &match.key->src, 4);
558 
559 		tmp = &filter->key.ipv4.sip.mask.addr[0];
560 		memcpy(tmp, &match.mask->src, 4);
561 
562 		tmp = &filter->key.ipv4.dip.value.addr[0];
563 		memcpy(tmp, &match.key->dst, 4);
564 
565 		tmp = &filter->key.ipv4.dip.mask.addr[0];
566 		memcpy(tmp, &match.mask->dst, 4);
567 		match_protocol = false;
568 	}
569 
570 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
571 	    proto == ETH_P_IPV6) {
572 		return -EOPNOTSUPP;
573 	}
574 
575 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
576 		struct flow_match_ports match;
577 
578 		if (filter->block_id == VCAP_ES0) {
579 			NL_SET_ERR_MSG_MOD(extack,
580 					   "VCAP ES0 cannot match on L4 ports");
581 			return -EOPNOTSUPP;
582 		}
583 
584 		flow_rule_match_ports(rule, &match);
585 		filter->key.ipv4.sport.value = ntohs(match.key->src);
586 		filter->key.ipv4.sport.mask = ntohs(match.mask->src);
587 		filter->key.ipv4.dport.value = ntohs(match.key->dst);
588 		filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
589 		match_protocol = false;
590 	}
591 
592 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
593 		struct flow_match_vlan match;
594 
595 		flow_rule_match_vlan(rule, &match);
596 		filter->key_type = OCELOT_VCAP_KEY_ANY;
597 		filter->vlan.vid.value = match.key->vlan_id;
598 		filter->vlan.vid.mask = match.mask->vlan_id;
599 		filter->vlan.pcp.value[0] = match.key->vlan_priority;
600 		filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
601 		match_protocol = false;
602 	}
603 
604 finished_key_parsing:
605 	if (match_protocol && proto != ETH_P_ALL) {
606 		if (filter->block_id == VCAP_ES0) {
607 			NL_SET_ERR_MSG_MOD(extack,
608 					   "VCAP ES0 cannot match on L2 proto");
609 			return -EOPNOTSUPP;
610 		}
611 
612 		/* TODO: support SNAP, LLC etc */
613 		if (proto < ETH_P_802_3_MIN)
614 			return -EOPNOTSUPP;
615 		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
616 		*(__be16 *)filter->key.etype.etype.value = htons(proto);
617 		*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
618 	}
619 	/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
620 
621 	return 0;
622 }
623 
ocelot_flower_parse(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f,struct ocelot_vcap_filter * filter)624 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
625 			       struct flow_cls_offload *f,
626 			       struct ocelot_vcap_filter *filter)
627 {
628 	int ret;
629 
630 	filter->prio = f->common.prio;
631 	filter->id.cookie = f->cookie;
632 	filter->id.tc_offload = true;
633 
634 	ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
635 	if (ret)
636 		return ret;
637 
638 	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
639 }
640 
641 static struct ocelot_vcap_filter
ocelot_vcap_filter_create(struct ocelot * ocelot,int port,bool ingress,struct flow_cls_offload * f)642 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
643 			   struct flow_cls_offload *f)
644 {
645 	struct ocelot_vcap_filter *filter;
646 
647 	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
648 	if (!filter)
649 		return NULL;
650 
651 	if (ingress) {
652 		filter->ingress_port_mask = BIT(port);
653 	} else {
654 		const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
655 		int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
656 
657 		filter->egress_port.value = port;
658 		filter->egress_port.mask = GENMASK(key_length - 1, 0);
659 	}
660 
661 	return filter;
662 }
663 
ocelot_vcap_dummy_filter_add(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)664 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
665 					struct ocelot_vcap_filter *filter)
666 {
667 	list_add(&filter->list, &ocelot->dummy_rules);
668 
669 	return 0;
670 }
671 
ocelot_vcap_dummy_filter_del(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)672 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
673 					struct ocelot_vcap_filter *filter)
674 {
675 	list_del(&filter->list);
676 	kfree(filter);
677 
678 	return 0;
679 }
680 
ocelot_cls_flower_replace(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)681 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
682 			      struct flow_cls_offload *f, bool ingress)
683 {
684 	struct netlink_ext_ack *extack = f->common.extack;
685 	struct ocelot_vcap_filter *filter;
686 	int chain = f->common.chain_index;
687 	int ret;
688 
689 	if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
690 		NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
691 		return -EOPNOTSUPP;
692 	}
693 
694 	filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
695 	if (!filter)
696 		return -ENOMEM;
697 
698 	ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
699 	if (ret) {
700 		kfree(filter);
701 		return ret;
702 	}
703 
704 	/* The non-optional GOTOs for the TCAM skeleton don't need
705 	 * to be actually offloaded.
706 	 */
707 	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
708 		return ocelot_vcap_dummy_filter_add(ocelot, filter);
709 
710 	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
711 }
712 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
713 
ocelot_cls_flower_destroy(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)714 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
715 			      struct flow_cls_offload *f, bool ingress)
716 {
717 	struct ocelot_vcap_filter *filter;
718 	struct ocelot_vcap_block *block;
719 	int block_id;
720 
721 	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
722 	if (block_id < 0)
723 		return 0;
724 
725 	block = &ocelot->block[block_id];
726 
727 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
728 	if (!filter)
729 		return 0;
730 
731 	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
732 		return ocelot_vcap_dummy_filter_del(ocelot, filter);
733 
734 	return ocelot_vcap_filter_del(ocelot, filter);
735 }
736 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
737 
ocelot_cls_flower_stats(struct ocelot * ocelot,int port,struct flow_cls_offload * f,bool ingress)738 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
739 			    struct flow_cls_offload *f, bool ingress)
740 {
741 	struct ocelot_vcap_filter *filter;
742 	struct ocelot_vcap_block *block;
743 	int block_id, ret;
744 
745 	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
746 	if (block_id < 0)
747 		return 0;
748 
749 	block = &ocelot->block[block_id];
750 
751 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
752 	if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
753 		return 0;
754 
755 	ret = ocelot_vcap_filter_stats_update(ocelot, filter);
756 	if (ret)
757 		return ret;
758 
759 	flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
760 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
761 	return 0;
762 }
763 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
764