1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
5 #include "prestera_acl.h"
6 #include "prestera_flow.h"
7 #include "prestera_flower.h"
8 #include "prestera_matchall.h"
10 struct prestera_flower_template {
11 struct prestera_acl_ruleset *ruleset;
12 struct list_head list;
17 prestera_flower_template_free(struct prestera_flower_template *template)
19 prestera_acl_ruleset_put(template->ruleset);
20 list_del(&template->list);
24 void prestera_flower_template_cleanup(struct prestera_flow_block *block)
26 struct prestera_flower_template *template, *tmp;
28 /* put the reference to all rulesets kept in tmpl create */
29 list_for_each_entry_safe(template, tmp, &block->template_list, list)
30 prestera_flower_template_free(template);
34 prestera_flower_parse_goto_action(struct prestera_flow_block *block,
35 struct prestera_acl_rule *rule,
37 const struct flow_action_entry *act)
39 struct prestera_acl_ruleset *ruleset;
41 if (act->chain_index <= chain_index)
42 /* we can jump only forward */
45 if (rule->re_arg.jump.valid)
48 ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
51 return PTR_ERR(ruleset);
53 rule->re_arg.jump.valid = 1;
54 rule->re_arg.jump.i.index = prestera_acl_ruleset_index_get(ruleset);
56 rule->jump_ruleset = ruleset;
61 static int prestera_flower_parse_actions(struct prestera_flow_block *block,
62 struct prestera_acl_rule *rule,
63 struct flow_action *flow_action,
65 struct netlink_ext_ack *extack)
67 const struct flow_action_entry *act;
70 /* whole struct (rule->re_arg) must be initialized with 0 */
71 if (!flow_action_has_entries(flow_action))
74 if (!flow_action_mixed_hw_stats_check(flow_action, extack))
77 act = flow_action_first_entry_get(flow_action);
78 if (act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED) {
80 } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
81 /* setup counter first */
82 rule->re_arg.count.valid = true;
83 err = prestera_acl_chain_to_client(chain_index, block->ingress,
84 &rule->re_arg.count.client);
88 NL_SET_ERR_MSG_MOD(extack, "Unsupported action HW stats type");
92 flow_action_for_each(i, act, flow_action) {
94 case FLOW_ACTION_ACCEPT:
95 if (rule->re_arg.accept.valid)
98 rule->re_arg.accept.valid = 1;
100 case FLOW_ACTION_DROP:
101 if (rule->re_arg.drop.valid)
104 rule->re_arg.drop.valid = 1;
106 case FLOW_ACTION_TRAP:
107 if (rule->re_arg.trap.valid)
110 rule->re_arg.trap.valid = 1;
112 case FLOW_ACTION_POLICE:
113 if (rule->re_arg.police.valid)
116 rule->re_arg.police.valid = 1;
117 rule->re_arg.police.rate =
118 act->police.rate_bytes_ps;
119 rule->re_arg.police.burst = act->police.burst;
120 rule->re_arg.police.ingress = block->ingress;
122 case FLOW_ACTION_GOTO:
123 err = prestera_flower_parse_goto_action(block, rule,
130 NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
131 pr_err("Unsupported action\n");
139 static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
140 struct flow_cls_offload *f,
141 struct prestera_flow_block *block)
143 struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
144 struct prestera_acl_match *r_match = &rule->re_key.match;
145 struct prestera_port *port;
146 struct net_device *ingress_dev;
147 struct flow_match_meta match;
150 flow_rule_match_meta(f_rule, &match);
152 if (match.mask->l2_miss) {
153 NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\"");
157 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
158 NL_SET_ERR_MSG_MOD(f->common.extack,
159 "Unsupported ingress ifindex mask");
163 ingress_dev = __dev_get_by_index(block->net,
164 match.key->ingress_ifindex);
166 NL_SET_ERR_MSG_MOD(f->common.extack,
167 "Can't find specified ingress port to match on");
171 if (!prestera_netdev_check(ingress_dev)) {
172 NL_SET_ERR_MSG_MOD(f->common.extack,
173 "Can't match on switchdev ingress port");
176 port = netdev_priv(ingress_dev);
178 mask = htons(0x1FFF << 3);
179 key = htons(port->hw_id << 3);
180 rule_match_set(r_match->key, SYS_PORT, key);
181 rule_match_set(r_match->mask, SYS_PORT, mask);
184 key = htons(port->dev_id);
185 rule_match_set(r_match->key, SYS_DEV, key);
186 rule_match_set(r_match->mask, SYS_DEV, mask);
191 static int prestera_flower_parse(struct prestera_flow_block *block,
192 struct prestera_acl_rule *rule,
193 struct flow_cls_offload *f)
195 struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
196 struct flow_dissector *dissector = f_rule->match.dissector;
197 struct prestera_acl_match *r_match = &rule->re_key.match;
198 __be16 n_proto_mask = 0;
199 __be16 n_proto_key = 0;
204 if (dissector->used_keys &
205 ~(BIT_ULL(FLOW_DISSECTOR_KEY_META) |
206 BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
207 BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
208 BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
209 BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
210 BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
211 BIT_ULL(FLOW_DISSECTOR_KEY_ICMP) |
212 BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
213 BIT_ULL(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
214 BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {
215 NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
219 prestera_acl_rule_priority_set(rule, f->common.prio);
221 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
222 err = prestera_flower_parse_meta(rule, f, block);
227 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
228 struct flow_match_control match;
230 flow_rule_match_control(f_rule, &match);
231 addr_type = match.key->addr_type;
234 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
235 struct flow_match_basic match;
237 flow_rule_match_basic(f_rule, &match);
238 n_proto_key = match.key->n_proto;
239 n_proto_mask = match.mask->n_proto;
241 if (ntohs(match.key->n_proto) == ETH_P_ALL) {
246 rule_match_set(r_match->key, ETH_TYPE, n_proto_key);
247 rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask);
249 rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto);
250 rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto);
251 ip_proto = match.key->ip_proto;
254 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
255 struct flow_match_eth_addrs match;
257 flow_rule_match_eth_addrs(f_rule, &match);
260 rule_match_set_n(r_match->key,
261 ETH_DMAC_0, &match.key->dst[0], 4);
262 rule_match_set_n(r_match->key,
263 ETH_DMAC_1, &match.key->dst[4], 2);
265 rule_match_set_n(r_match->mask,
266 ETH_DMAC_0, &match.mask->dst[0], 4);
267 rule_match_set_n(r_match->mask,
268 ETH_DMAC_1, &match.mask->dst[4], 2);
271 rule_match_set_n(r_match->key,
272 ETH_SMAC_0, &match.key->src[0], 4);
273 rule_match_set_n(r_match->key,
274 ETH_SMAC_1, &match.key->src[4], 2);
276 rule_match_set_n(r_match->mask,
277 ETH_SMAC_0, &match.mask->src[0], 4);
278 rule_match_set_n(r_match->mask,
279 ETH_SMAC_1, &match.mask->src[4], 2);
282 if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
283 struct flow_match_ipv4_addrs match;
285 flow_rule_match_ipv4_addrs(f_rule, &match);
287 rule_match_set(r_match->key, IP_SRC, match.key->src);
288 rule_match_set(r_match->mask, IP_SRC, match.mask->src);
290 rule_match_set(r_match->key, IP_DST, match.key->dst);
291 rule_match_set(r_match->mask, IP_DST, match.mask->dst);
294 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
295 struct flow_match_ports match;
297 if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
300 "Only UDP and TCP keys are supported");
304 flow_rule_match_ports(f_rule, &match);
306 rule_match_set(r_match->key, L4_PORT_SRC, match.key->src);
307 rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src);
309 rule_match_set(r_match->key, L4_PORT_DST, match.key->dst);
310 rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst);
313 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS_RANGE)) {
314 struct flow_match_ports_range match;
315 __be32 tp_key, tp_mask;
317 flow_rule_match_ports_range(f_rule, &match);
319 /* src port range (min, max) */
320 tp_key = htonl(ntohs(match.key->tp_min.src) |
321 (ntohs(match.key->tp_max.src) << 16));
322 tp_mask = htonl(ntohs(match.mask->tp_min.src) |
323 (ntohs(match.mask->tp_max.src) << 16));
324 rule_match_set(r_match->key, L4_PORT_RANGE_SRC, tp_key);
325 rule_match_set(r_match->mask, L4_PORT_RANGE_SRC, tp_mask);
327 /* dst port range (min, max) */
328 tp_key = htonl(ntohs(match.key->tp_min.dst) |
329 (ntohs(match.key->tp_max.dst) << 16));
330 tp_mask = htonl(ntohs(match.mask->tp_min.dst) |
331 (ntohs(match.mask->tp_max.dst) << 16));
332 rule_match_set(r_match->key, L4_PORT_RANGE_DST, tp_key);
333 rule_match_set(r_match->mask, L4_PORT_RANGE_DST, tp_mask);
336 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
337 struct flow_match_vlan match;
339 flow_rule_match_vlan(f_rule, &match);
341 if (match.mask->vlan_id != 0) {
342 __be16 key = cpu_to_be16(match.key->vlan_id);
343 __be16 mask = cpu_to_be16(match.mask->vlan_id);
345 rule_match_set(r_match->key, VLAN_ID, key);
346 rule_match_set(r_match->mask, VLAN_ID, mask);
349 rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid);
350 rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid);
353 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
354 struct flow_match_icmp match;
356 flow_rule_match_icmp(f_rule, &match);
358 rule_match_set(r_match->key, ICMP_TYPE, match.key->type);
359 rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type);
361 rule_match_set(r_match->key, ICMP_CODE, match.key->code);
362 rule_match_set(r_match->mask, ICMP_CODE, match.mask->code);
365 return prestera_flower_parse_actions(block, rule, &f->rule->action,
366 f->common.chain_index,
370 static int prestera_flower_prio_check(struct prestera_flow_block *block,
371 struct flow_cls_offload *f)
377 err = prestera_mall_prio_get(block, &mall_prio_min, &mall_prio_max);
379 /* No matchall filters installed on this chain. */
383 NL_SET_ERR_MSG(f->common.extack, "Failed to get matchall priorities");
387 if (f->common.prio <= mall_prio_max && block->ingress) {
388 NL_SET_ERR_MSG(f->common.extack,
389 "Failed to add in front of existing matchall rules");
392 if (f->common.prio >= mall_prio_min && !block->ingress) {
393 NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing matchall rules");
400 int prestera_flower_prio_get(struct prestera_flow_block *block, u32 chain_index,
401 u32 *prio_min, u32 *prio_max)
403 struct prestera_acl_ruleset *ruleset;
405 ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block, chain_index);
407 return PTR_ERR(ruleset);
409 prestera_acl_ruleset_prio_get(ruleset, prio_min, prio_max);
413 int prestera_flower_replace(struct prestera_flow_block *block,
414 struct flow_cls_offload *f)
416 struct prestera_acl_ruleset *ruleset;
417 struct prestera_acl *acl = block->sw->acl;
418 struct prestera_acl_rule *rule;
421 err = prestera_flower_prio_check(block, f);
425 ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index);
427 return PTR_ERR(ruleset);
429 /* increments the ruleset reference */
430 rule = prestera_acl_rule_create(ruleset, f->cookie,
431 f->common.chain_index);
434 goto err_rule_create;
437 err = prestera_flower_parse(block, rule, f);
441 if (!prestera_acl_ruleset_is_offload(ruleset)) {
442 err = prestera_acl_ruleset_offload(ruleset);
444 goto err_ruleset_offload;
447 err = prestera_acl_rule_add(block->sw, rule);
451 prestera_acl_ruleset_put(ruleset);
456 prestera_acl_rule_destroy(rule);
458 prestera_acl_ruleset_put(ruleset);
462 void prestera_flower_destroy(struct prestera_flow_block *block,
463 struct flow_cls_offload *f)
465 struct prestera_acl_ruleset *ruleset;
466 struct prestera_acl_rule *rule;
468 ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
469 f->common.chain_index);
473 rule = prestera_acl_rule_lookup(ruleset, f->cookie);
475 prestera_acl_rule_del(block->sw, rule);
476 prestera_acl_rule_destroy(rule);
478 prestera_acl_ruleset_put(ruleset);
481 int prestera_flower_tmplt_create(struct prestera_flow_block *block,
482 struct flow_cls_offload *f)
484 struct prestera_flower_template *template;
485 struct prestera_acl_ruleset *ruleset;
486 struct prestera_acl_rule rule;
489 memset(&rule, 0, sizeof(rule));
490 err = prestera_flower_parse(block, &rule, f);
494 template = kmalloc(sizeof(*template), GFP_KERNEL);
500 prestera_acl_rule_keymask_pcl_id_set(&rule, 0);
501 ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
502 f->common.chain_index);
503 if (IS_ERR_OR_NULL(ruleset)) {
505 goto err_ruleset_get;
508 /* preserve keymask/template to this ruleset */
509 err = prestera_acl_ruleset_keymask_set(ruleset, rule.re_key.match.mask);
511 goto err_ruleset_keymask_set;
513 /* skip error, as it is not possible to reject template operation,
514 * so, keep the reference to the ruleset for rules to be added
515 * to that ruleset later. In case of offload fail, the ruleset
516 * will be offloaded again during adding a new rule. Also,
517 * unlikly possble that ruleset is already offloaded at this staage.
519 prestera_acl_ruleset_offload(ruleset);
521 /* keep the reference to the ruleset */
522 template->ruleset = ruleset;
523 template->chain_index = f->common.chain_index;
524 list_add_rcu(&template->list, &block->template_list);
527 err_ruleset_keymask_set:
528 prestera_acl_ruleset_put(ruleset);
532 NL_SET_ERR_MSG_MOD(f->common.extack, "Create chain template failed");
536 void prestera_flower_tmplt_destroy(struct prestera_flow_block *block,
537 struct flow_cls_offload *f)
539 struct prestera_flower_template *template, *tmp;
541 list_for_each_entry_safe(template, tmp, &block->template_list, list)
542 if (template->chain_index == f->common.chain_index) {
543 /* put the reference to the ruleset kept in create */
544 prestera_flower_template_free(template);
549 int prestera_flower_stats(struct prestera_flow_block *block,
550 struct flow_cls_offload *f)
552 struct prestera_acl_ruleset *ruleset;
553 struct prestera_acl_rule *rule;
559 ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
560 f->common.chain_index);
562 return PTR_ERR(ruleset);
564 rule = prestera_acl_rule_lookup(ruleset, f->cookie);
567 goto err_rule_get_stats;
570 err = prestera_acl_rule_get_stats(block->sw->acl, rule, &packets,
573 goto err_rule_get_stats;
575 flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
576 FLOW_ACTION_HW_STATS_DELAYED);
579 prestera_acl_ruleset_put(ruleset);