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 
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  */
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  */
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 
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 *
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 
145 static int
146 ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
147 					struct ocelot_vcap_filter *filter,
148 					const struct flow_action_entry *a,
149 					struct netlink_ext_ack *extack)
150 {
151 	struct ocelot_port *ocelot_port = ocelot->ports[port];
152 
153 	if (filter->goto_target != -1) {
154 		NL_SET_ERR_MSG_MOD(extack,
155 				   "Last action must be GOTO");
156 		return -EOPNOTSUPP;
157 	}
158 
159 	if (!ocelot_port->vlan_aware) {
160 		NL_SET_ERR_MSG_MOD(extack,
161 				   "Can only modify VLAN under VLAN aware bridge");
162 		return -EOPNOTSUPP;
163 	}
164 
165 	filter->action.vid_replace_ena = true;
166 	filter->action.pcp_dei_ena = true;
167 	filter->action.vid = a->vlan.vid;
168 	filter->action.pcp = a->vlan.prio;
169 	filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
170 
171 	return 0;
172 }
173 
174 static int
175 ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
176 				       const struct flow_action_entry *a,
177 				       struct netlink_ext_ack *extack)
178 {
179 	enum ocelot_tag_tpid_sel tpid;
180 
181 	switch (ntohs(a->vlan.proto)) {
182 	case ETH_P_8021Q:
183 		tpid = OCELOT_TAG_TPID_SEL_8021Q;
184 		break;
185 	case ETH_P_8021AD:
186 		tpid = OCELOT_TAG_TPID_SEL_8021AD;
187 		break;
188 	default:
189 		NL_SET_ERR_MSG_MOD(extack,
190 				   "Cannot modify custom TPID");
191 		return -EOPNOTSUPP;
192 	}
193 
194 	filter->action.tag_a_tpid_sel = tpid;
195 	filter->action.push_outer_tag = OCELOT_ES0_TAG;
196 	filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
197 	filter->action.vid_a_val = a->vlan.vid;
198 	filter->action.pcp_a_val = a->vlan.prio;
199 	filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
200 	filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
201 
202 	return 0;
203 }
204 
205 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
206 				      bool ingress, struct flow_cls_offload *f,
207 				      struct ocelot_vcap_filter *filter)
208 {
209 	struct netlink_ext_ack *extack = f->common.extack;
210 	bool allow_missing_goto_target = false;
211 	const struct flow_action_entry *a;
212 	enum ocelot_tag_tpid_sel tpid;
213 	int i, chain, egress_port;
214 	u64 rate;
215 	int err;
216 
217 	if (!flow_action_basic_hw_stats_check(&f->rule->action,
218 					      f->common.extack))
219 		return -EOPNOTSUPP;
220 
221 	chain = f->common.chain_index;
222 	filter->block_id = ocelot_chain_to_block(chain, ingress);
223 	if (filter->block_id < 0) {
224 		NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
225 		return -EOPNOTSUPP;
226 	}
227 	if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
228 		filter->lookup = ocelot_chain_to_lookup(chain);
229 	if (filter->block_id == VCAP_IS2)
230 		filter->pag = ocelot_chain_to_pag(chain);
231 
232 	filter->goto_target = -1;
233 	filter->type = OCELOT_VCAP_FILTER_DUMMY;
234 
235 	flow_action_for_each(i, a, &f->rule->action) {
236 		switch (a->id) {
237 		case FLOW_ACTION_DROP:
238 			if (filter->block_id != VCAP_IS2) {
239 				NL_SET_ERR_MSG_MOD(extack,
240 						   "Drop action can only be offloaded to VCAP IS2");
241 				return -EOPNOTSUPP;
242 			}
243 			if (filter->goto_target != -1) {
244 				NL_SET_ERR_MSG_MOD(extack,
245 						   "Last action must be GOTO");
246 				return -EOPNOTSUPP;
247 			}
248 			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
249 			filter->action.port_mask = 0;
250 			filter->action.police_ena = true;
251 			filter->action.pol_ix = OCELOT_POLICER_DISCARD;
252 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
253 			break;
254 		case FLOW_ACTION_TRAP:
255 			if (filter->block_id != VCAP_IS2) {
256 				NL_SET_ERR_MSG_MOD(extack,
257 						   "Trap action can only be offloaded to VCAP IS2");
258 				return -EOPNOTSUPP;
259 			}
260 			if (filter->goto_target != -1) {
261 				NL_SET_ERR_MSG_MOD(extack,
262 						   "Last action must be GOTO");
263 				return -EOPNOTSUPP;
264 			}
265 			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
266 			filter->action.port_mask = 0;
267 			filter->action.cpu_copy_ena = true;
268 			filter->action.cpu_qu_num = 0;
269 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
270 			break;
271 		case FLOW_ACTION_POLICE:
272 			if (filter->block_id != VCAP_IS2 ||
273 			    filter->lookup != 0) {
274 				NL_SET_ERR_MSG_MOD(extack,
275 						   "Police action can only be offloaded to VCAP IS2 lookup 0");
276 				return -EOPNOTSUPP;
277 			}
278 			if (filter->goto_target != -1) {
279 				NL_SET_ERR_MSG_MOD(extack,
280 						   "Last action must be GOTO");
281 				return -EOPNOTSUPP;
282 			}
283 			if (a->police.rate_pkt_ps) {
284 				NL_SET_ERR_MSG_MOD(extack,
285 						   "QoS offload not support packets per second");
286 				return -EOPNOTSUPP;
287 			}
288 			filter->action.police_ena = true;
289 			rate = a->police.rate_bytes_ps;
290 			filter->action.pol.rate = div_u64(rate, 1000) * 8;
291 			filter->action.pol.burst = a->police.burst;
292 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
293 			break;
294 		case FLOW_ACTION_REDIRECT:
295 			if (filter->block_id != VCAP_IS2) {
296 				NL_SET_ERR_MSG_MOD(extack,
297 						   "Redirect action can only be offloaded to VCAP IS2");
298 				return -EOPNOTSUPP;
299 			}
300 			if (filter->goto_target != -1) {
301 				NL_SET_ERR_MSG_MOD(extack,
302 						   "Last action must be GOTO");
303 				return -EOPNOTSUPP;
304 			}
305 			egress_port = ocelot->ops->netdev_to_port(a->dev);
306 			if (egress_port < 0) {
307 				NL_SET_ERR_MSG_MOD(extack,
308 						   "Destination not an ocelot port");
309 				return -EOPNOTSUPP;
310 			}
311 			filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
312 			filter->action.port_mask = BIT(egress_port);
313 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
314 			break;
315 		case FLOW_ACTION_VLAN_POP:
316 			if (filter->block_id != VCAP_IS1) {
317 				NL_SET_ERR_MSG_MOD(extack,
318 						   "VLAN pop action can only be offloaded to VCAP IS1");
319 				return -EOPNOTSUPP;
320 			}
321 			if (filter->goto_target != -1) {
322 				NL_SET_ERR_MSG_MOD(extack,
323 						   "Last action must be GOTO");
324 				return -EOPNOTSUPP;
325 			}
326 			filter->action.vlan_pop_cnt_ena = true;
327 			filter->action.vlan_pop_cnt++;
328 			if (filter->action.vlan_pop_cnt > 2) {
329 				NL_SET_ERR_MSG_MOD(extack,
330 						   "Cannot pop more than 2 VLAN headers");
331 				return -EOPNOTSUPP;
332 			}
333 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
334 			break;
335 		case FLOW_ACTION_VLAN_MANGLE:
336 			if (filter->block_id == VCAP_IS1) {
337 				err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
338 									      filter, a,
339 									      extack);
340 			} else if (filter->block_id == VCAP_ES0) {
341 				err = ocelot_flower_parse_egress_vlan_modify(filter, a,
342 									     extack);
343 			} else {
344 				NL_SET_ERR_MSG_MOD(extack,
345 						   "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
346 				err = -EOPNOTSUPP;
347 			}
348 			if (err)
349 				return err;
350 			break;
351 		case FLOW_ACTION_PRIORITY:
352 			if (filter->block_id != VCAP_IS1) {
353 				NL_SET_ERR_MSG_MOD(extack,
354 						   "Priority action can only be offloaded to VCAP IS1");
355 				return -EOPNOTSUPP;
356 			}
357 			if (filter->goto_target != -1) {
358 				NL_SET_ERR_MSG_MOD(extack,
359 						   "Last action must be GOTO");
360 				return -EOPNOTSUPP;
361 			}
362 			filter->action.qos_ena = true;
363 			filter->action.qos_val = a->priority;
364 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
365 			break;
366 		case FLOW_ACTION_GOTO:
367 			filter->goto_target = a->chain_index;
368 
369 			if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
370 				int pag = ocelot_chain_to_pag(filter->goto_target);
371 
372 				filter->action.pag_override_mask = 0xff;
373 				filter->action.pag_val = pag;
374 				filter->type = OCELOT_VCAP_FILTER_PAG;
375 			}
376 			break;
377 		case FLOW_ACTION_VLAN_PUSH:
378 			if (filter->block_id != VCAP_ES0) {
379 				NL_SET_ERR_MSG_MOD(extack,
380 						   "VLAN push action can only be offloaded to VCAP ES0");
381 				return -EOPNOTSUPP;
382 			}
383 			switch (ntohs(a->vlan.proto)) {
384 			case ETH_P_8021Q:
385 				tpid = OCELOT_TAG_TPID_SEL_8021Q;
386 				break;
387 			case ETH_P_8021AD:
388 				tpid = OCELOT_TAG_TPID_SEL_8021AD;
389 				break;
390 			default:
391 				NL_SET_ERR_MSG_MOD(extack,
392 						   "Cannot push custom TPID");
393 				return -EOPNOTSUPP;
394 			}
395 			filter->action.tag_a_tpid_sel = tpid;
396 			filter->action.push_outer_tag = OCELOT_ES0_TAG;
397 			filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
398 			filter->action.vid_a_val = a->vlan.vid;
399 			filter->action.pcp_a_val = a->vlan.prio;
400 			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
401 			break;
402 		default:
403 			NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
404 			return -EOPNOTSUPP;
405 		}
406 	}
407 
408 	if (filter->goto_target == -1) {
409 		if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
410 		    chain == 0) {
411 			allow_missing_goto_target = true;
412 		} else {
413 			NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
414 			return -EOPNOTSUPP;
415 		}
416 	}
417 
418 	if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
419 	    !allow_missing_goto_target) {
420 		NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
421 		return -EOPNOTSUPP;
422 	}
423 
424 	return 0;
425 }
426 
427 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
428 				     struct flow_cls_offload *f,
429 				     struct ocelot_vcap_filter *filter)
430 {
431 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
432 	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
433 	int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
434 	struct netlink_ext_ack *extack = f->common.extack;
435 	struct net_device *dev, *indev;
436 	struct flow_match_meta match;
437 	int ingress_port;
438 
439 	flow_rule_match_meta(rule, &match);
440 
441 	if (!match.mask->ingress_ifindex)
442 		return 0;
443 
444 	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
445 		NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
446 		return -EOPNOTSUPP;
447 	}
448 
449 	dev = ocelot->ops->port_to_netdev(ocelot, port);
450 	if (!dev)
451 		return -EINVAL;
452 
453 	indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
454 	if (!indev) {
455 		NL_SET_ERR_MSG_MOD(extack,
456 				   "Can't find the ingress port to match on");
457 		return -ENOENT;
458 	}
459 
460 	ingress_port = ocelot->ops->netdev_to_port(indev);
461 	if (ingress_port < 0) {
462 		NL_SET_ERR_MSG_MOD(extack,
463 				   "Can only offload an ocelot ingress port");
464 		return -EOPNOTSUPP;
465 	}
466 	if (ingress_port == port) {
467 		NL_SET_ERR_MSG_MOD(extack,
468 				   "Ingress port is equal to the egress port");
469 		return -EINVAL;
470 	}
471 
472 	filter->ingress_port.value = ingress_port;
473 	filter->ingress_port.mask = GENMASK(key_length - 1, 0);
474 
475 	return 0;
476 }
477 
478 static int
479 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
480 			struct flow_cls_offload *f,
481 			struct ocelot_vcap_filter *filter)
482 {
483 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
484 	struct flow_dissector *dissector = rule->match.dissector;
485 	struct netlink_ext_ack *extack = f->common.extack;
486 	u16 proto = ntohs(f->common.protocol);
487 	bool match_protocol = true;
488 	int ret;
489 
490 	if (dissector->used_keys &
491 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
492 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
493 	      BIT(FLOW_DISSECTOR_KEY_META) |
494 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
495 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
496 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
497 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
498 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
499 		return -EOPNOTSUPP;
500 	}
501 
502 	/* For VCAP ES0 (egress rewriter) we can match on the ingress port */
503 	if (!ingress) {
504 		ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
505 		if (ret)
506 			return ret;
507 	}
508 
509 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
510 		struct flow_match_control match;
511 
512 		flow_rule_match_control(rule, &match);
513 	}
514 
515 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
516 		struct flow_match_eth_addrs match;
517 
518 		if (filter->block_id == VCAP_ES0) {
519 			NL_SET_ERR_MSG_MOD(extack,
520 					   "VCAP ES0 cannot match on MAC address");
521 			return -EOPNOTSUPP;
522 		}
523 
524 		if (filter->block_id == VCAP_IS1 &&
525 		    !is_zero_ether_addr(match.mask->dst)) {
526 			NL_SET_ERR_MSG_MOD(extack,
527 					   "Key type S1_NORMAL cannot match on destination MAC");
528 			return -EOPNOTSUPP;
529 		}
530 
531 		/* The hw support mac matches only for MAC_ETYPE key,
532 		 * therefore if other matches(port, tcp flags, etc) are added
533 		 * then just bail out
534 		 */
535 		if ((dissector->used_keys &
536 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
537 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
538 		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
539 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
540 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
541 		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
542 			return -EOPNOTSUPP;
543 
544 		flow_rule_match_eth_addrs(rule, &match);
545 		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
546 		ether_addr_copy(filter->key.etype.dmac.value,
547 				match.key->dst);
548 		ether_addr_copy(filter->key.etype.smac.value,
549 				match.key->src);
550 		ether_addr_copy(filter->key.etype.dmac.mask,
551 				match.mask->dst);
552 		ether_addr_copy(filter->key.etype.smac.mask,
553 				match.mask->src);
554 		goto finished_key_parsing;
555 	}
556 
557 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
558 		struct flow_match_basic match;
559 
560 		flow_rule_match_basic(rule, &match);
561 		if (ntohs(match.key->n_proto) == ETH_P_IP) {
562 			if (filter->block_id == VCAP_ES0) {
563 				NL_SET_ERR_MSG_MOD(extack,
564 						   "VCAP ES0 cannot match on IP protocol");
565 				return -EOPNOTSUPP;
566 			}
567 
568 			filter->key_type = OCELOT_VCAP_KEY_IPV4;
569 			filter->key.ipv4.proto.value[0] =
570 				match.key->ip_proto;
571 			filter->key.ipv4.proto.mask[0] =
572 				match.mask->ip_proto;
573 			match_protocol = false;
574 		}
575 		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
576 			if (filter->block_id == VCAP_ES0) {
577 				NL_SET_ERR_MSG_MOD(extack,
578 						   "VCAP ES0 cannot match on IP protocol");
579 				return -EOPNOTSUPP;
580 			}
581 
582 			filter->key_type = OCELOT_VCAP_KEY_IPV6;
583 			filter->key.ipv6.proto.value[0] =
584 				match.key->ip_proto;
585 			filter->key.ipv6.proto.mask[0] =
586 				match.mask->ip_proto;
587 			match_protocol = false;
588 		}
589 	}
590 
591 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
592 	    proto == ETH_P_IP) {
593 		struct flow_match_ipv4_addrs match;
594 		u8 *tmp;
595 
596 		if (filter->block_id == VCAP_ES0) {
597 			NL_SET_ERR_MSG_MOD(extack,
598 					   "VCAP ES0 cannot match on IP address");
599 			return -EOPNOTSUPP;
600 		}
601 
602 		flow_rule_match_ipv4_addrs(rule, &match);
603 
604 		if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
605 			NL_SET_ERR_MSG_MOD(extack,
606 					   "Key type S1_NORMAL cannot match on destination IP");
607 			return -EOPNOTSUPP;
608 		}
609 
610 		tmp = &filter->key.ipv4.sip.value.addr[0];
611 		memcpy(tmp, &match.key->src, 4);
612 
613 		tmp = &filter->key.ipv4.sip.mask.addr[0];
614 		memcpy(tmp, &match.mask->src, 4);
615 
616 		tmp = &filter->key.ipv4.dip.value.addr[0];
617 		memcpy(tmp, &match.key->dst, 4);
618 
619 		tmp = &filter->key.ipv4.dip.mask.addr[0];
620 		memcpy(tmp, &match.mask->dst, 4);
621 		match_protocol = false;
622 	}
623 
624 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
625 	    proto == ETH_P_IPV6) {
626 		return -EOPNOTSUPP;
627 	}
628 
629 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
630 		struct flow_match_ports match;
631 
632 		if (filter->block_id == VCAP_ES0) {
633 			NL_SET_ERR_MSG_MOD(extack,
634 					   "VCAP ES0 cannot match on L4 ports");
635 			return -EOPNOTSUPP;
636 		}
637 
638 		flow_rule_match_ports(rule, &match);
639 		filter->key.ipv4.sport.value = ntohs(match.key->src);
640 		filter->key.ipv4.sport.mask = ntohs(match.mask->src);
641 		filter->key.ipv4.dport.value = ntohs(match.key->dst);
642 		filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
643 		match_protocol = false;
644 	}
645 
646 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
647 		struct flow_match_vlan match;
648 
649 		flow_rule_match_vlan(rule, &match);
650 		filter->key_type = OCELOT_VCAP_KEY_ANY;
651 		filter->vlan.vid.value = match.key->vlan_id;
652 		filter->vlan.vid.mask = match.mask->vlan_id;
653 		filter->vlan.pcp.value[0] = match.key->vlan_priority;
654 		filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
655 		match_protocol = false;
656 	}
657 
658 finished_key_parsing:
659 	if (match_protocol && proto != ETH_P_ALL) {
660 		if (filter->block_id == VCAP_ES0) {
661 			NL_SET_ERR_MSG_MOD(extack,
662 					   "VCAP ES0 cannot match on L2 proto");
663 			return -EOPNOTSUPP;
664 		}
665 
666 		/* TODO: support SNAP, LLC etc */
667 		if (proto < ETH_P_802_3_MIN)
668 			return -EOPNOTSUPP;
669 		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
670 		*(__be16 *)filter->key.etype.etype.value = htons(proto);
671 		*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
672 	}
673 	/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
674 
675 	return 0;
676 }
677 
678 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
679 			       struct flow_cls_offload *f,
680 			       struct ocelot_vcap_filter *filter)
681 {
682 	int ret;
683 
684 	filter->prio = f->common.prio;
685 	filter->id.cookie = f->cookie;
686 	filter->id.tc_offload = true;
687 
688 	ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
689 	if (ret)
690 		return ret;
691 
692 	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
693 }
694 
695 static struct ocelot_vcap_filter
696 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
697 			   struct flow_cls_offload *f)
698 {
699 	struct ocelot_vcap_filter *filter;
700 
701 	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
702 	if (!filter)
703 		return NULL;
704 
705 	if (ingress) {
706 		filter->ingress_port_mask = BIT(port);
707 	} else {
708 		const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
709 		int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
710 
711 		filter->egress_port.value = port;
712 		filter->egress_port.mask = GENMASK(key_length - 1, 0);
713 	}
714 
715 	return filter;
716 }
717 
718 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
719 					struct ocelot_vcap_filter *filter)
720 {
721 	list_add(&filter->list, &ocelot->dummy_rules);
722 
723 	return 0;
724 }
725 
726 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
727 					struct ocelot_vcap_filter *filter)
728 {
729 	list_del(&filter->list);
730 	kfree(filter);
731 
732 	return 0;
733 }
734 
735 /* If we have an egress VLAN modification rule, we need to actually write the
736  * delta between the input VLAN (from the key) and the output VLAN (from the
737  * action), but the action was parsed first. So we need to patch the delta into
738  * the action here.
739  */
740 static int
741 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
742 				    struct netlink_ext_ack *extack)
743 {
744 	if (filter->block_id != VCAP_ES0 ||
745 	    filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
746 		return 0;
747 
748 	if (filter->vlan.vid.mask != VLAN_VID_MASK) {
749 		NL_SET_ERR_MSG_MOD(extack,
750 				   "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
751 		return -EOPNOTSUPP;
752 	}
753 
754 	filter->action.vid_a_val -= filter->vlan.vid.value;
755 	filter->action.vid_a_val &= VLAN_VID_MASK;
756 
757 	return 0;
758 }
759 
760 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
761 			      struct flow_cls_offload *f, bool ingress)
762 {
763 	struct netlink_ext_ack *extack = f->common.extack;
764 	struct ocelot_vcap_filter *filter;
765 	int chain = f->common.chain_index;
766 	int ret;
767 
768 	if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
769 		NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
770 		return -EOPNOTSUPP;
771 	}
772 
773 	filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
774 	if (!filter)
775 		return -ENOMEM;
776 
777 	ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
778 	if (ret) {
779 		kfree(filter);
780 		return ret;
781 	}
782 
783 	ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
784 	if (ret) {
785 		kfree(filter);
786 		return ret;
787 	}
788 
789 	/* The non-optional GOTOs for the TCAM skeleton don't need
790 	 * to be actually offloaded.
791 	 */
792 	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
793 		return ocelot_vcap_dummy_filter_add(ocelot, filter);
794 
795 	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
796 }
797 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
798 
799 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
800 			      struct flow_cls_offload *f, bool ingress)
801 {
802 	struct ocelot_vcap_filter *filter;
803 	struct ocelot_vcap_block *block;
804 	int block_id;
805 
806 	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
807 	if (block_id < 0)
808 		return 0;
809 
810 	block = &ocelot->block[block_id];
811 
812 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
813 	if (!filter)
814 		return 0;
815 
816 	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
817 		return ocelot_vcap_dummy_filter_del(ocelot, filter);
818 
819 	return ocelot_vcap_filter_del(ocelot, filter);
820 }
821 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
822 
823 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
824 			    struct flow_cls_offload *f, bool ingress)
825 {
826 	struct ocelot_vcap_filter *filter;
827 	struct ocelot_vcap_block *block;
828 	int block_id, ret;
829 
830 	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
831 	if (block_id < 0)
832 		return 0;
833 
834 	block = &ocelot->block[block_id];
835 
836 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
837 	if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
838 		return 0;
839 
840 	ret = ocelot_vcap_filter_stats_update(ocelot, filter);
841 	if (ret)
842 		return ret;
843 
844 	flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
845 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
846 	return 0;
847 }
848 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
849