1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
3 
4 #include "prestera.h"
5 #include "prestera_acl.h"
6 #include "prestera_flow.h"
7 #include "prestera_flower.h"
8 
9 struct prestera_flower_template {
10 	struct prestera_acl_ruleset *ruleset;
11 	struct list_head list;
12 	u32 chain_index;
13 };
14 
15 static void
16 prestera_flower_template_free(struct prestera_flower_template *template)
17 {
18 	prestera_acl_ruleset_put(template->ruleset);
19 	list_del(&template->list);
20 	kfree(template);
21 }
22 
23 void prestera_flower_template_cleanup(struct prestera_flow_block *block)
24 {
25 	struct prestera_flower_template *template, *tmp;
26 
27 	/* put the reference to all rulesets kept in tmpl create */
28 	list_for_each_entry_safe(template, tmp, &block->template_list, list)
29 		prestera_flower_template_free(template);
30 }
31 
32 static int
33 prestera_flower_parse_goto_action(struct prestera_flow_block *block,
34 				  struct prestera_acl_rule *rule,
35 				  u32 chain_index,
36 				  const struct flow_action_entry *act)
37 {
38 	struct prestera_acl_ruleset *ruleset;
39 
40 	if (act->chain_index <= chain_index)
41 		/* we can jump only forward */
42 		return -EINVAL;
43 
44 	if (rule->re_arg.jump.valid)
45 		return -EEXIST;
46 
47 	ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
48 					   act->chain_index);
49 	if (IS_ERR(ruleset))
50 		return PTR_ERR(ruleset);
51 
52 	rule->re_arg.jump.valid = 1;
53 	rule->re_arg.jump.i.index = prestera_acl_ruleset_index_get(ruleset);
54 
55 	rule->jump_ruleset = ruleset;
56 
57 	return 0;
58 }
59 
60 static int prestera_flower_parse_actions(struct prestera_flow_block *block,
61 					 struct prestera_acl_rule *rule,
62 					 struct flow_action *flow_action,
63 					 u32 chain_index,
64 					 struct netlink_ext_ack *extack)
65 {
66 	const struct flow_action_entry *act;
67 	int err, i;
68 
69 	/* whole struct (rule->re_arg) must be initialized with 0 */
70 	if (!flow_action_has_entries(flow_action))
71 		return 0;
72 
73 	if (!flow_action_mixed_hw_stats_check(flow_action, extack))
74 		return -EOPNOTSUPP;
75 
76 	act = flow_action_first_entry_get(flow_action);
77 	if (act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED) {
78 		/* Nothing to do */
79 	} else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
80 		/* setup counter first */
81 		rule->re_arg.count.valid = true;
82 		err = prestera_acl_chain_to_client(chain_index, block->ingress,
83 						   &rule->re_arg.count.client);
84 		if (err)
85 			return err;
86 	} else {
87 		NL_SET_ERR_MSG_MOD(extack, "Unsupported action HW stats type");
88 		return -EOPNOTSUPP;
89 	}
90 
91 	flow_action_for_each(i, act, flow_action) {
92 		switch (act->id) {
93 		case FLOW_ACTION_ACCEPT:
94 			if (rule->re_arg.accept.valid)
95 				return -EEXIST;
96 
97 			rule->re_arg.accept.valid = 1;
98 			break;
99 		case FLOW_ACTION_DROP:
100 			if (rule->re_arg.drop.valid)
101 				return -EEXIST;
102 
103 			rule->re_arg.drop.valid = 1;
104 			break;
105 		case FLOW_ACTION_TRAP:
106 			if (rule->re_arg.trap.valid)
107 				return -EEXIST;
108 
109 			rule->re_arg.trap.valid = 1;
110 			break;
111 		case FLOW_ACTION_POLICE:
112 			if (rule->re_arg.police.valid)
113 				return -EEXIST;
114 
115 			rule->re_arg.police.valid = 1;
116 			rule->re_arg.police.rate =
117 				act->police.rate_bytes_ps;
118 			rule->re_arg.police.burst = act->police.burst;
119 			rule->re_arg.police.ingress = block->ingress;
120 			break;
121 		case FLOW_ACTION_GOTO:
122 			err = prestera_flower_parse_goto_action(block, rule,
123 								chain_index,
124 								act);
125 			if (err)
126 				return err;
127 			break;
128 		default:
129 			NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
130 			pr_err("Unsupported action\n");
131 			return -EOPNOTSUPP;
132 		}
133 	}
134 
135 	return 0;
136 }
137 
138 static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
139 				      struct flow_cls_offload *f,
140 				      struct prestera_flow_block *block)
141 {
142 	struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
143 	struct prestera_acl_match *r_match = &rule->re_key.match;
144 	struct prestera_port *port;
145 	struct net_device *ingress_dev;
146 	struct flow_match_meta match;
147 	__be16 key, mask;
148 
149 	flow_rule_match_meta(f_rule, &match);
150 	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
151 		NL_SET_ERR_MSG_MOD(f->common.extack,
152 				   "Unsupported ingress ifindex mask");
153 		return -EINVAL;
154 	}
155 
156 	ingress_dev = __dev_get_by_index(block->net,
157 					 match.key->ingress_ifindex);
158 	if (!ingress_dev) {
159 		NL_SET_ERR_MSG_MOD(f->common.extack,
160 				   "Can't find specified ingress port to match on");
161 		return -EINVAL;
162 	}
163 
164 	if (!prestera_netdev_check(ingress_dev)) {
165 		NL_SET_ERR_MSG_MOD(f->common.extack,
166 				   "Can't match on switchdev ingress port");
167 		return -EINVAL;
168 	}
169 	port = netdev_priv(ingress_dev);
170 
171 	mask = htons(0x1FFF << 3);
172 	key = htons(port->hw_id << 3);
173 	rule_match_set(r_match->key, SYS_PORT, key);
174 	rule_match_set(r_match->mask, SYS_PORT, mask);
175 
176 	mask = htons(0x3FF);
177 	key = htons(port->dev_id);
178 	rule_match_set(r_match->key, SYS_DEV, key);
179 	rule_match_set(r_match->mask, SYS_DEV, mask);
180 
181 	return 0;
182 }
183 
184 static int prestera_flower_parse(struct prestera_flow_block *block,
185 				 struct prestera_acl_rule *rule,
186 				 struct flow_cls_offload *f)
187 {
188 	struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
189 	struct flow_dissector *dissector = f_rule->match.dissector;
190 	struct prestera_acl_match *r_match = &rule->re_key.match;
191 	__be16 n_proto_mask = 0;
192 	__be16 n_proto_key = 0;
193 	u16 addr_type = 0;
194 	u8 ip_proto = 0;
195 	int err;
196 
197 	if (dissector->used_keys &
198 	    ~(BIT(FLOW_DISSECTOR_KEY_META) |
199 	      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
200 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
201 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
202 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
203 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
204 	      BIT(FLOW_DISSECTOR_KEY_ICMP) |
205 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
206 	      BIT(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
207 	      BIT(FLOW_DISSECTOR_KEY_VLAN))) {
208 		NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
209 		return -EOPNOTSUPP;
210 	}
211 
212 	prestera_acl_rule_priority_set(rule, f->common.prio);
213 
214 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
215 		err = prestera_flower_parse_meta(rule, f, block);
216 		if (err)
217 			return err;
218 	}
219 
220 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
221 		struct flow_match_control match;
222 
223 		flow_rule_match_control(f_rule, &match);
224 		addr_type = match.key->addr_type;
225 	}
226 
227 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
228 		struct flow_match_basic match;
229 
230 		flow_rule_match_basic(f_rule, &match);
231 		n_proto_key = match.key->n_proto;
232 		n_proto_mask = match.mask->n_proto;
233 
234 		if (ntohs(match.key->n_proto) == ETH_P_ALL) {
235 			n_proto_key = 0;
236 			n_proto_mask = 0;
237 		}
238 
239 		rule_match_set(r_match->key, ETH_TYPE, n_proto_key);
240 		rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask);
241 
242 		rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto);
243 		rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto);
244 		ip_proto = match.key->ip_proto;
245 	}
246 
247 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
248 		struct flow_match_eth_addrs match;
249 
250 		flow_rule_match_eth_addrs(f_rule, &match);
251 
252 		/* DA key, mask */
253 		rule_match_set_n(r_match->key,
254 				 ETH_DMAC_0, &match.key->dst[0], 4);
255 		rule_match_set_n(r_match->key,
256 				 ETH_DMAC_1, &match.key->dst[4], 2);
257 
258 		rule_match_set_n(r_match->mask,
259 				 ETH_DMAC_0, &match.mask->dst[0], 4);
260 		rule_match_set_n(r_match->mask,
261 				 ETH_DMAC_1, &match.mask->dst[4], 2);
262 
263 		/* SA key, mask */
264 		rule_match_set_n(r_match->key,
265 				 ETH_SMAC_0, &match.key->src[0], 4);
266 		rule_match_set_n(r_match->key,
267 				 ETH_SMAC_1, &match.key->src[4], 2);
268 
269 		rule_match_set_n(r_match->mask,
270 				 ETH_SMAC_0, &match.mask->src[0], 4);
271 		rule_match_set_n(r_match->mask,
272 				 ETH_SMAC_1, &match.mask->src[4], 2);
273 	}
274 
275 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
276 		struct flow_match_ipv4_addrs match;
277 
278 		flow_rule_match_ipv4_addrs(f_rule, &match);
279 
280 		rule_match_set(r_match->key, IP_SRC, match.key->src);
281 		rule_match_set(r_match->mask, IP_SRC, match.mask->src);
282 
283 		rule_match_set(r_match->key, IP_DST, match.key->dst);
284 		rule_match_set(r_match->mask, IP_DST, match.mask->dst);
285 	}
286 
287 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
288 		struct flow_match_ports match;
289 
290 		if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
291 			NL_SET_ERR_MSG_MOD
292 			    (f->common.extack,
293 			     "Only UDP and TCP keys are supported");
294 			return -EINVAL;
295 		}
296 
297 		flow_rule_match_ports(f_rule, &match);
298 
299 		rule_match_set(r_match->key, L4_PORT_SRC, match.key->src);
300 		rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src);
301 
302 		rule_match_set(r_match->key, L4_PORT_DST, match.key->dst);
303 		rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst);
304 	}
305 
306 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS_RANGE)) {
307 		struct flow_match_ports_range match;
308 		__be32 tp_key, tp_mask;
309 
310 		flow_rule_match_ports_range(f_rule, &match);
311 
312 		/* src port range (min, max) */
313 		tp_key = htonl(ntohs(match.key->tp_min.src) |
314 			       (ntohs(match.key->tp_max.src) << 16));
315 		tp_mask = htonl(ntohs(match.mask->tp_min.src) |
316 				(ntohs(match.mask->tp_max.src) << 16));
317 		rule_match_set(r_match->key, L4_PORT_RANGE_SRC, tp_key);
318 		rule_match_set(r_match->mask, L4_PORT_RANGE_SRC, tp_mask);
319 
320 		/* dst port range (min, max) */
321 		tp_key = htonl(ntohs(match.key->tp_min.dst) |
322 			       (ntohs(match.key->tp_max.dst) << 16));
323 		tp_mask = htonl(ntohs(match.mask->tp_min.dst) |
324 				(ntohs(match.mask->tp_max.dst) << 16));
325 		rule_match_set(r_match->key, L4_PORT_RANGE_DST, tp_key);
326 		rule_match_set(r_match->mask, L4_PORT_RANGE_DST, tp_mask);
327 	}
328 
329 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
330 		struct flow_match_vlan match;
331 
332 		flow_rule_match_vlan(f_rule, &match);
333 
334 		if (match.mask->vlan_id != 0) {
335 			__be16 key = cpu_to_be16(match.key->vlan_id);
336 			__be16 mask = cpu_to_be16(match.mask->vlan_id);
337 
338 			rule_match_set(r_match->key, VLAN_ID, key);
339 			rule_match_set(r_match->mask, VLAN_ID, mask);
340 		}
341 
342 		rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid);
343 		rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid);
344 	}
345 
346 	if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
347 		struct flow_match_icmp match;
348 
349 		flow_rule_match_icmp(f_rule, &match);
350 
351 		rule_match_set(r_match->key, ICMP_TYPE, match.key->type);
352 		rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type);
353 
354 		rule_match_set(r_match->key, ICMP_CODE, match.key->code);
355 		rule_match_set(r_match->mask, ICMP_CODE, match.mask->code);
356 	}
357 
358 	return prestera_flower_parse_actions(block, rule, &f->rule->action,
359 					     f->common.chain_index,
360 					     f->common.extack);
361 }
362 
363 int prestera_flower_replace(struct prestera_flow_block *block,
364 			    struct flow_cls_offload *f)
365 {
366 	struct prestera_acl_ruleset *ruleset;
367 	struct prestera_acl *acl = block->sw->acl;
368 	struct prestera_acl_rule *rule;
369 	int err;
370 
371 	ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index);
372 	if (IS_ERR(ruleset))
373 		return PTR_ERR(ruleset);
374 
375 	/* increments the ruleset reference */
376 	rule = prestera_acl_rule_create(ruleset, f->cookie,
377 					f->common.chain_index);
378 	if (IS_ERR(rule)) {
379 		err = PTR_ERR(rule);
380 		goto err_rule_create;
381 	}
382 
383 	err = prestera_flower_parse(block, rule, f);
384 	if (err)
385 		goto err_rule_add;
386 
387 	if (!prestera_acl_ruleset_is_offload(ruleset)) {
388 		err = prestera_acl_ruleset_offload(ruleset);
389 		if (err)
390 			goto err_ruleset_offload;
391 	}
392 
393 	err = prestera_acl_rule_add(block->sw, rule);
394 	if (err)
395 		goto err_rule_add;
396 
397 	prestera_acl_ruleset_put(ruleset);
398 	return 0;
399 
400 err_ruleset_offload:
401 err_rule_add:
402 	prestera_acl_rule_destroy(rule);
403 err_rule_create:
404 	prestera_acl_ruleset_put(ruleset);
405 	return err;
406 }
407 
408 void prestera_flower_destroy(struct prestera_flow_block *block,
409 			     struct flow_cls_offload *f)
410 {
411 	struct prestera_acl_ruleset *ruleset;
412 	struct prestera_acl_rule *rule;
413 
414 	ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
415 					      f->common.chain_index);
416 	if (IS_ERR(ruleset))
417 		return;
418 
419 	rule = prestera_acl_rule_lookup(ruleset, f->cookie);
420 	if (rule) {
421 		prestera_acl_rule_del(block->sw, rule);
422 		prestera_acl_rule_destroy(rule);
423 	}
424 	prestera_acl_ruleset_put(ruleset);
425 }
426 
427 int prestera_flower_tmplt_create(struct prestera_flow_block *block,
428 				 struct flow_cls_offload *f)
429 {
430 	struct prestera_flower_template *template;
431 	struct prestera_acl_ruleset *ruleset;
432 	struct prestera_acl_rule rule;
433 	int err;
434 
435 	memset(&rule, 0, sizeof(rule));
436 	err = prestera_flower_parse(block, &rule, f);
437 	if (err)
438 		return err;
439 
440 	template = kmalloc(sizeof(*template), GFP_KERNEL);
441 	if (!template) {
442 		err = -ENOMEM;
443 		goto err_malloc;
444 	}
445 
446 	prestera_acl_rule_keymask_pcl_id_set(&rule, 0);
447 	ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
448 					   f->common.chain_index);
449 	if (IS_ERR_OR_NULL(ruleset)) {
450 		err = -EINVAL;
451 		goto err_ruleset_get;
452 	}
453 
454 	/* preserve keymask/template to this ruleset */
455 	prestera_acl_ruleset_keymask_set(ruleset, rule.re_key.match.mask);
456 
457 	/* skip error, as it is not possible to reject template operation,
458 	 * so, keep the reference to the ruleset for rules to be added
459 	 * to that ruleset later. In case of offload fail, the ruleset
460 	 * will be offloaded again during adding a new rule. Also,
461 	 * unlikly possble that ruleset is already offloaded at this staage.
462 	 */
463 	prestera_acl_ruleset_offload(ruleset);
464 
465 	/* keep the reference to the ruleset */
466 	template->ruleset = ruleset;
467 	template->chain_index = f->common.chain_index;
468 	list_add_rcu(&template->list, &block->template_list);
469 	return 0;
470 
471 err_ruleset_get:
472 	kfree(template);
473 err_malloc:
474 	NL_SET_ERR_MSG_MOD(f->common.extack, "Create chain template failed");
475 	return err;
476 }
477 
478 void prestera_flower_tmplt_destroy(struct prestera_flow_block *block,
479 				   struct flow_cls_offload *f)
480 {
481 	struct prestera_flower_template *template, *tmp;
482 
483 	list_for_each_entry_safe(template, tmp, &block->template_list, list)
484 		if (template->chain_index == f->common.chain_index) {
485 			/* put the reference to the ruleset kept in create */
486 			prestera_flower_template_free(template);
487 			return;
488 		}
489 }
490 
491 int prestera_flower_stats(struct prestera_flow_block *block,
492 			  struct flow_cls_offload *f)
493 {
494 	struct prestera_acl_ruleset *ruleset;
495 	struct prestera_acl_rule *rule;
496 	u64 packets;
497 	u64 lastuse;
498 	u64 bytes;
499 	int err;
500 
501 	ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
502 					      f->common.chain_index);
503 	if (IS_ERR(ruleset))
504 		return PTR_ERR(ruleset);
505 
506 	rule = prestera_acl_rule_lookup(ruleset, f->cookie);
507 	if (!rule) {
508 		err = -EINVAL;
509 		goto err_rule_get_stats;
510 	}
511 
512 	err = prestera_acl_rule_get_stats(block->sw->acl, rule, &packets,
513 					  &bytes, &lastuse);
514 	if (err)
515 		goto err_rule_get_stats;
516 
517 	flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
518 			  FLOW_ACTION_HW_STATS_DELAYED);
519 
520 err_rule_get_stats:
521 	prestera_acl_ruleset_put(ruleset);
522 	return err;
523 }
524