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
24static 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 */
55static 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 */
69static 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
85static 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
132static struct ocelot_vcap_filter *
133ocelot_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
159static 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			filter->action.police_ena = true;
239			rate = a->police.rate_bytes_ps;
240			filter->action.pol.rate = div_u64(rate, 1000) * 8;
241			filter->action.pol.burst = a->police.burst;
242			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
243			break;
244		case FLOW_ACTION_REDIRECT:
245			if (filter->block_id != VCAP_IS2) {
246				NL_SET_ERR_MSG_MOD(extack,
247						   "Redirect action can only be offloaded to VCAP IS2");
248				return -EOPNOTSUPP;
249			}
250			if (filter->goto_target != -1) {
251				NL_SET_ERR_MSG_MOD(extack,
252						   "Last action must be GOTO");
253				return -EOPNOTSUPP;
254			}
255			egress_port = ocelot->ops->netdev_to_port(a->dev);
256			if (egress_port < 0) {
257				NL_SET_ERR_MSG_MOD(extack,
258						   "Destination not an ocelot port");
259				return -EOPNOTSUPP;
260			}
261			filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
262			filter->action.port_mask = BIT(egress_port);
263			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
264			break;
265		case FLOW_ACTION_VLAN_POP:
266			if (filter->block_id != VCAP_IS1) {
267				NL_SET_ERR_MSG_MOD(extack,
268						   "VLAN pop action can only be offloaded to VCAP IS1");
269				return -EOPNOTSUPP;
270			}
271			if (filter->goto_target != -1) {
272				NL_SET_ERR_MSG_MOD(extack,
273						   "Last action must be GOTO");
274				return -EOPNOTSUPP;
275			}
276			filter->action.vlan_pop_cnt_ena = true;
277			filter->action.vlan_pop_cnt++;
278			if (filter->action.vlan_pop_cnt > 2) {
279				NL_SET_ERR_MSG_MOD(extack,
280						   "Cannot pop more than 2 VLAN headers");
281				return -EOPNOTSUPP;
282			}
283			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
284			break;
285		case FLOW_ACTION_VLAN_MANGLE:
286			if (filter->block_id != VCAP_IS1) {
287				NL_SET_ERR_MSG_MOD(extack,
288						   "VLAN modify action can only be offloaded to VCAP IS1");
289				return -EOPNOTSUPP;
290			}
291			if (filter->goto_target != -1) {
292				NL_SET_ERR_MSG_MOD(extack,
293						   "Last action must be GOTO");
294				return -EOPNOTSUPP;
295			}
296			if (!ocelot_port->vlan_aware) {
297				NL_SET_ERR_MSG_MOD(extack,
298						   "Can only modify VLAN under VLAN aware bridge");
299				return -EOPNOTSUPP;
300			}
301			filter->action.vid_replace_ena = true;
302			filter->action.pcp_dei_ena = true;
303			filter->action.vid = a->vlan.vid;
304			filter->action.pcp = a->vlan.prio;
305			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
306			break;
307		case FLOW_ACTION_PRIORITY:
308			if (filter->block_id != VCAP_IS1) {
309				NL_SET_ERR_MSG_MOD(extack,
310						   "Priority action can only be offloaded to VCAP IS1");
311				return -EOPNOTSUPP;
312			}
313			if (filter->goto_target != -1) {
314				NL_SET_ERR_MSG_MOD(extack,
315						   "Last action must be GOTO");
316				return -EOPNOTSUPP;
317			}
318			filter->action.qos_ena = true;
319			filter->action.qos_val = a->priority;
320			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
321			break;
322		case FLOW_ACTION_GOTO:
323			filter->goto_target = a->chain_index;
324
325			if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
326				int pag = ocelot_chain_to_pag(filter->goto_target);
327
328				filter->action.pag_override_mask = 0xff;
329				filter->action.pag_val = pag;
330				filter->type = OCELOT_VCAP_FILTER_PAG;
331			}
332			break;
333		case FLOW_ACTION_VLAN_PUSH:
334			if (filter->block_id != VCAP_ES0) {
335				NL_SET_ERR_MSG_MOD(extack,
336						   "VLAN push action can only be offloaded to VCAP ES0");
337				return -EOPNOTSUPP;
338			}
339			switch (ntohs(a->vlan.proto)) {
340			case ETH_P_8021Q:
341				tpid = OCELOT_TAG_TPID_SEL_8021Q;
342				break;
343			case ETH_P_8021AD:
344				tpid = OCELOT_TAG_TPID_SEL_8021AD;
345				break;
346			default:
347				NL_SET_ERR_MSG_MOD(extack,
348						   "Cannot push custom TPID");
349				return -EOPNOTSUPP;
350			}
351			filter->action.tag_a_tpid_sel = tpid;
352			filter->action.push_outer_tag = OCELOT_ES0_TAG;
353			filter->action.tag_a_vid_sel = 1;
354			filter->action.vid_a_val = a->vlan.vid;
355			filter->action.pcp_a_val = a->vlan.prio;
356			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
357			break;
358		default:
359			NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
360			return -EOPNOTSUPP;
361		}
362	}
363
364	if (filter->goto_target == -1) {
365		if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
366		    chain == 0) {
367			allow_missing_goto_target = true;
368		} else {
369			NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
370			return -EOPNOTSUPP;
371		}
372	}
373
374	if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
375	    !allow_missing_goto_target) {
376		NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
377		return -EOPNOTSUPP;
378	}
379
380	return 0;
381}
382
383static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
384				     struct flow_cls_offload *f,
385				     struct ocelot_vcap_filter *filter)
386{
387	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
388	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
389	int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
390	struct netlink_ext_ack *extack = f->common.extack;
391	struct net_device *dev, *indev;
392	struct flow_match_meta match;
393	int ingress_port;
394
395	flow_rule_match_meta(rule, &match);
396
397	if (!match.mask->ingress_ifindex)
398		return 0;
399
400	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
401		NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
402		return -EOPNOTSUPP;
403	}
404
405	dev = ocelot->ops->port_to_netdev(ocelot, port);
406	if (!dev)
407		return -EINVAL;
408
409	indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
410	if (!indev) {
411		NL_SET_ERR_MSG_MOD(extack,
412				   "Can't find the ingress port to match on");
413		return -ENOENT;
414	}
415
416	ingress_port = ocelot->ops->netdev_to_port(indev);
417	if (ingress_port < 0) {
418		NL_SET_ERR_MSG_MOD(extack,
419				   "Can only offload an ocelot ingress port");
420		return -EOPNOTSUPP;
421	}
422	if (ingress_port == port) {
423		NL_SET_ERR_MSG_MOD(extack,
424				   "Ingress port is equal to the egress port");
425		return -EINVAL;
426	}
427
428	filter->ingress_port.value = ingress_port;
429	filter->ingress_port.mask = GENMASK(key_length - 1, 0);
430
431	return 0;
432}
433
434static int
435ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
436			struct flow_cls_offload *f,
437			struct ocelot_vcap_filter *filter)
438{
439	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
440	struct flow_dissector *dissector = rule->match.dissector;
441	struct netlink_ext_ack *extack = f->common.extack;
442	u16 proto = ntohs(f->common.protocol);
443	bool match_protocol = true;
444	int ret;
445
446	if (dissector->used_keys &
447	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
448	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
449	      BIT(FLOW_DISSECTOR_KEY_META) |
450	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
451	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
452	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
453	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
454	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
455		return -EOPNOTSUPP;
456	}
457
458	/* For VCAP ES0 (egress rewriter) we can match on the ingress port */
459	if (!ingress) {
460		ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
461		if (ret)
462			return ret;
463	}
464
465	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
466		struct flow_match_control match;
467
468		flow_rule_match_control(rule, &match);
469	}
470
471	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
472		struct flow_match_vlan match;
473
474		flow_rule_match_vlan(rule, &match);
475		filter->key_type = OCELOT_VCAP_KEY_ANY;
476		filter->vlan.vid.value = match.key->vlan_id;
477		filter->vlan.vid.mask = match.mask->vlan_id;
478		filter->vlan.pcp.value[0] = match.key->vlan_priority;
479		filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
480		match_protocol = false;
481	}
482
483	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
484		struct flow_match_eth_addrs match;
485
486		if (filter->block_id == VCAP_ES0) {
487			NL_SET_ERR_MSG_MOD(extack,
488					   "VCAP ES0 cannot match on MAC address");
489			return -EOPNOTSUPP;
490		}
491
492		/* The hw support mac matches only for MAC_ETYPE key,
493		 * therefore if other matches(port, tcp flags, etc) are added
494		 * then just bail out
495		 */
496		if ((dissector->used_keys &
497		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
498		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
499		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
500		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
501		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
502		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
503			return -EOPNOTSUPP;
504
505		flow_rule_match_eth_addrs(rule, &match);
506
507		if (filter->block_id == VCAP_IS1 &&
508		    !is_zero_ether_addr(match.mask->dst)) {
509			NL_SET_ERR_MSG_MOD(extack,
510					   "Key type S1_NORMAL cannot match on destination MAC");
511			return -EOPNOTSUPP;
512		}
513
514		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
515		ether_addr_copy(filter->key.etype.dmac.value,
516				match.key->dst);
517		ether_addr_copy(filter->key.etype.smac.value,
518				match.key->src);
519		ether_addr_copy(filter->key.etype.dmac.mask,
520				match.mask->dst);
521		ether_addr_copy(filter->key.etype.smac.mask,
522				match.mask->src);
523		goto finished_key_parsing;
524	}
525
526	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
527		struct flow_match_basic match;
528
529		flow_rule_match_basic(rule, &match);
530		if (ntohs(match.key->n_proto) == ETH_P_IP) {
531			if (filter->block_id == VCAP_ES0) {
532				NL_SET_ERR_MSG_MOD(extack,
533						   "VCAP ES0 cannot match on IP protocol");
534				return -EOPNOTSUPP;
535			}
536
537			filter->key_type = OCELOT_VCAP_KEY_IPV4;
538			filter->key.ipv4.proto.value[0] =
539				match.key->ip_proto;
540			filter->key.ipv4.proto.mask[0] =
541				match.mask->ip_proto;
542			match_protocol = false;
543		}
544		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
545			if (filter->block_id == VCAP_ES0) {
546				NL_SET_ERR_MSG_MOD(extack,
547						   "VCAP ES0 cannot match on IP protocol");
548				return -EOPNOTSUPP;
549			}
550
551			filter->key_type = OCELOT_VCAP_KEY_IPV6;
552			filter->key.ipv6.proto.value[0] =
553				match.key->ip_proto;
554			filter->key.ipv6.proto.mask[0] =
555				match.mask->ip_proto;
556			match_protocol = false;
557		}
558	}
559
560	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
561	    proto == ETH_P_IP) {
562		struct flow_match_ipv4_addrs match;
563		u8 *tmp;
564
565		if (filter->block_id == VCAP_ES0) {
566			NL_SET_ERR_MSG_MOD(extack,
567					   "VCAP ES0 cannot match on IP address");
568			return -EOPNOTSUPP;
569		}
570
571		flow_rule_match_ipv4_addrs(rule, &match);
572
573		if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
574			NL_SET_ERR_MSG_MOD(extack,
575					   "Key type S1_NORMAL cannot match on destination IP");
576			return -EOPNOTSUPP;
577		}
578
579		tmp = &filter->key.ipv4.sip.value.addr[0];
580		memcpy(tmp, &match.key->src, 4);
581
582		tmp = &filter->key.ipv4.sip.mask.addr[0];
583		memcpy(tmp, &match.mask->src, 4);
584
585		tmp = &filter->key.ipv4.dip.value.addr[0];
586		memcpy(tmp, &match.key->dst, 4);
587
588		tmp = &filter->key.ipv4.dip.mask.addr[0];
589		memcpy(tmp, &match.mask->dst, 4);
590		match_protocol = false;
591	}
592
593	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
594	    proto == ETH_P_IPV6) {
595		return -EOPNOTSUPP;
596	}
597
598	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
599		struct flow_match_ports match;
600
601		if (filter->block_id == VCAP_ES0) {
602			NL_SET_ERR_MSG_MOD(extack,
603					   "VCAP ES0 cannot match on L4 ports");
604			return -EOPNOTSUPP;
605		}
606
607		flow_rule_match_ports(rule, &match);
608		filter->key.ipv4.sport.value = ntohs(match.key->src);
609		filter->key.ipv4.sport.mask = ntohs(match.mask->src);
610		filter->key.ipv4.dport.value = ntohs(match.key->dst);
611		filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
612		match_protocol = false;
613	}
614
615finished_key_parsing:
616	if (match_protocol && proto != ETH_P_ALL) {
617		if (filter->block_id == VCAP_ES0) {
618			NL_SET_ERR_MSG_MOD(extack,
619					   "VCAP ES0 cannot match on L2 proto");
620			return -EOPNOTSUPP;
621		}
622
623		/* TODO: support SNAP, LLC etc */
624		if (proto < ETH_P_802_3_MIN)
625			return -EOPNOTSUPP;
626		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
627		*(__be16 *)filter->key.etype.etype.value = htons(proto);
628		*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
629	}
630	/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
631
632	return 0;
633}
634
635static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
636			       struct flow_cls_offload *f,
637			       struct ocelot_vcap_filter *filter)
638{
639	int ret;
640
641	filter->prio = f->common.prio;
642	filter->id = f->cookie;
643
644	ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
645	if (ret)
646		return ret;
647
648	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
649}
650
651static struct ocelot_vcap_filter
652*ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
653			   struct flow_cls_offload *f)
654{
655	struct ocelot_vcap_filter *filter;
656
657	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
658	if (!filter)
659		return NULL;
660
661	if (ingress) {
662		filter->ingress_port_mask = BIT(port);
663	} else {
664		const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
665		int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
666
667		filter->egress_port.value = port;
668		filter->egress_port.mask = GENMASK(key_length - 1, 0);
669	}
670
671	return filter;
672}
673
674static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
675					struct ocelot_vcap_filter *filter)
676{
677	list_add(&filter->list, &ocelot->dummy_rules);
678
679	return 0;
680}
681
682static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
683					struct ocelot_vcap_filter *filter)
684{
685	list_del(&filter->list);
686	kfree(filter);
687
688	return 0;
689}
690
691int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
692			      struct flow_cls_offload *f, bool ingress)
693{
694	struct netlink_ext_ack *extack = f->common.extack;
695	struct ocelot_vcap_filter *filter;
696	int chain = f->common.chain_index;
697	int ret;
698
699	if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
700		NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
701		return -EOPNOTSUPP;
702	}
703
704	filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
705	if (!filter)
706		return -ENOMEM;
707
708	ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
709	if (ret) {
710		kfree(filter);
711		return ret;
712	}
713
714	/* The non-optional GOTOs for the TCAM skeleton don't need
715	 * to be actually offloaded.
716	 */
717	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
718		return ocelot_vcap_dummy_filter_add(ocelot, filter);
719
720	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
721}
722EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
723
724int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
725			      struct flow_cls_offload *f, bool ingress)
726{
727	struct ocelot_vcap_filter *filter;
728	struct ocelot_vcap_block *block;
729	int block_id;
730
731	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
732	if (block_id < 0)
733		return 0;
734
735	block = &ocelot->block[block_id];
736
737	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
738	if (!filter)
739		return 0;
740
741	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
742		return ocelot_vcap_dummy_filter_del(ocelot, filter);
743
744	return ocelot_vcap_filter_del(ocelot, filter);
745}
746EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
747
748int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
749			    struct flow_cls_offload *f, bool ingress)
750{
751	struct ocelot_vcap_filter *filter;
752	struct ocelot_vcap_block *block;
753	int block_id, ret;
754
755	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
756	if (block_id < 0)
757		return 0;
758
759	block = &ocelot->block[block_id];
760
761	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
762	if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
763		return 0;
764
765	ret = ocelot_vcap_filter_stats_update(ocelot, filter);
766	if (ret)
767		return ret;
768
769	flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
770			  FLOW_ACTION_HW_STATS_IMMEDIATE);
771	return 0;
772}
773EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
774