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