Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
0003 
0004 #include "prestera.h"
0005 #include "prestera_acl.h"
0006 #include "prestera_flow.h"
0007 #include "prestera_flower.h"
0008 
0009 struct prestera_flower_template {
0010     struct prestera_acl_ruleset *ruleset;
0011     struct list_head list;
0012     u32 chain_index;
0013 };
0014 
0015 static void
0016 prestera_flower_template_free(struct prestera_flower_template *template)
0017 {
0018     prestera_acl_ruleset_put(template->ruleset);
0019     list_del(&template->list);
0020     kfree(template);
0021 }
0022 
0023 void prestera_flower_template_cleanup(struct prestera_flow_block *block)
0024 {
0025     struct prestera_flower_template *template, *tmp;
0026 
0027     /* put the reference to all rulesets kept in tmpl create */
0028     list_for_each_entry_safe(template, tmp, &block->template_list, list)
0029         prestera_flower_template_free(template);
0030 }
0031 
0032 static int
0033 prestera_flower_parse_goto_action(struct prestera_flow_block *block,
0034                   struct prestera_acl_rule *rule,
0035                   u32 chain_index,
0036                   const struct flow_action_entry *act)
0037 {
0038     struct prestera_acl_ruleset *ruleset;
0039 
0040     if (act->chain_index <= chain_index)
0041         /* we can jump only forward */
0042         return -EINVAL;
0043 
0044     if (rule->re_arg.jump.valid)
0045         return -EEXIST;
0046 
0047     ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
0048                        act->chain_index);
0049     if (IS_ERR(ruleset))
0050         return PTR_ERR(ruleset);
0051 
0052     rule->re_arg.jump.valid = 1;
0053     rule->re_arg.jump.i.index = prestera_acl_ruleset_index_get(ruleset);
0054 
0055     rule->jump_ruleset = ruleset;
0056 
0057     return 0;
0058 }
0059 
0060 static int prestera_flower_parse_actions(struct prestera_flow_block *block,
0061                      struct prestera_acl_rule *rule,
0062                      struct flow_action *flow_action,
0063                      u32 chain_index,
0064                      struct netlink_ext_ack *extack)
0065 {
0066     const struct flow_action_entry *act;
0067     int err, i;
0068 
0069     /* whole struct (rule->re_arg) must be initialized with 0 */
0070     if (!flow_action_has_entries(flow_action))
0071         return 0;
0072 
0073     if (!flow_action_mixed_hw_stats_check(flow_action, extack))
0074         return -EOPNOTSUPP;
0075 
0076     act = flow_action_first_entry_get(flow_action);
0077     if (act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED) {
0078         /* Nothing to do */
0079     } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
0080         /* setup counter first */
0081         rule->re_arg.count.valid = true;
0082         err = prestera_acl_chain_to_client(chain_index, block->ingress,
0083                            &rule->re_arg.count.client);
0084         if (err)
0085             return err;
0086     } else {
0087         NL_SET_ERR_MSG_MOD(extack, "Unsupported action HW stats type");
0088         return -EOPNOTSUPP;
0089     }
0090 
0091     flow_action_for_each(i, act, flow_action) {
0092         switch (act->id) {
0093         case FLOW_ACTION_ACCEPT:
0094             if (rule->re_arg.accept.valid)
0095                 return -EEXIST;
0096 
0097             rule->re_arg.accept.valid = 1;
0098             break;
0099         case FLOW_ACTION_DROP:
0100             if (rule->re_arg.drop.valid)
0101                 return -EEXIST;
0102 
0103             rule->re_arg.drop.valid = 1;
0104             break;
0105         case FLOW_ACTION_TRAP:
0106             if (rule->re_arg.trap.valid)
0107                 return -EEXIST;
0108 
0109             rule->re_arg.trap.valid = 1;
0110             break;
0111         case FLOW_ACTION_POLICE:
0112             if (rule->re_arg.police.valid)
0113                 return -EEXIST;
0114 
0115             rule->re_arg.police.valid = 1;
0116             rule->re_arg.police.rate =
0117                 act->police.rate_bytes_ps;
0118             rule->re_arg.police.burst = act->police.burst;
0119             rule->re_arg.police.ingress = block->ingress;
0120             break;
0121         case FLOW_ACTION_GOTO:
0122             err = prestera_flower_parse_goto_action(block, rule,
0123                                 chain_index,
0124                                 act);
0125             if (err)
0126                 return err;
0127             break;
0128         default:
0129             NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
0130             pr_err("Unsupported action\n");
0131             return -EOPNOTSUPP;
0132         }
0133     }
0134 
0135     return 0;
0136 }
0137 
0138 static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
0139                       struct flow_cls_offload *f,
0140                       struct prestera_flow_block *block)
0141 {
0142     struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
0143     struct prestera_acl_match *r_match = &rule->re_key.match;
0144     struct prestera_port *port;
0145     struct net_device *ingress_dev;
0146     struct flow_match_meta match;
0147     __be16 key, mask;
0148 
0149     flow_rule_match_meta(f_rule, &match);
0150     if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
0151         NL_SET_ERR_MSG_MOD(f->common.extack,
0152                    "Unsupported ingress ifindex mask");
0153         return -EINVAL;
0154     }
0155 
0156     ingress_dev = __dev_get_by_index(block->net,
0157                      match.key->ingress_ifindex);
0158     if (!ingress_dev) {
0159         NL_SET_ERR_MSG_MOD(f->common.extack,
0160                    "Can't find specified ingress port to match on");
0161         return -EINVAL;
0162     }
0163 
0164     if (!prestera_netdev_check(ingress_dev)) {
0165         NL_SET_ERR_MSG_MOD(f->common.extack,
0166                    "Can't match on switchdev ingress port");
0167         return -EINVAL;
0168     }
0169     port = netdev_priv(ingress_dev);
0170 
0171     mask = htons(0x1FFF << 3);
0172     key = htons(port->hw_id << 3);
0173     rule_match_set(r_match->key, SYS_PORT, key);
0174     rule_match_set(r_match->mask, SYS_PORT, mask);
0175 
0176     mask = htons(0x3FF);
0177     key = htons(port->dev_id);
0178     rule_match_set(r_match->key, SYS_DEV, key);
0179     rule_match_set(r_match->mask, SYS_DEV, mask);
0180 
0181     return 0;
0182 }
0183 
0184 static int prestera_flower_parse(struct prestera_flow_block *block,
0185                  struct prestera_acl_rule *rule,
0186                  struct flow_cls_offload *f)
0187 {
0188     struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
0189     struct flow_dissector *dissector = f_rule->match.dissector;
0190     struct prestera_acl_match *r_match = &rule->re_key.match;
0191     __be16 n_proto_mask = 0;
0192     __be16 n_proto_key = 0;
0193     u16 addr_type = 0;
0194     u8 ip_proto = 0;
0195     int err;
0196 
0197     if (dissector->used_keys &
0198         ~(BIT(FLOW_DISSECTOR_KEY_META) |
0199           BIT(FLOW_DISSECTOR_KEY_CONTROL) |
0200           BIT(FLOW_DISSECTOR_KEY_BASIC) |
0201           BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
0202           BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
0203           BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
0204           BIT(FLOW_DISSECTOR_KEY_ICMP) |
0205           BIT(FLOW_DISSECTOR_KEY_PORTS) |
0206           BIT(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
0207           BIT(FLOW_DISSECTOR_KEY_VLAN))) {
0208         NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
0209         return -EOPNOTSUPP;
0210     }
0211 
0212     prestera_acl_rule_priority_set(rule, f->common.prio);
0213 
0214     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
0215         err = prestera_flower_parse_meta(rule, f, block);
0216         if (err)
0217             return err;
0218     }
0219 
0220     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
0221         struct flow_match_control match;
0222 
0223         flow_rule_match_control(f_rule, &match);
0224         addr_type = match.key->addr_type;
0225     }
0226 
0227     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
0228         struct flow_match_basic match;
0229 
0230         flow_rule_match_basic(f_rule, &match);
0231         n_proto_key = match.key->n_proto;
0232         n_proto_mask = match.mask->n_proto;
0233 
0234         if (ntohs(match.key->n_proto) == ETH_P_ALL) {
0235             n_proto_key = 0;
0236             n_proto_mask = 0;
0237         }
0238 
0239         rule_match_set(r_match->key, ETH_TYPE, n_proto_key);
0240         rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask);
0241 
0242         rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto);
0243         rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto);
0244         ip_proto = match.key->ip_proto;
0245     }
0246 
0247     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
0248         struct flow_match_eth_addrs match;
0249 
0250         flow_rule_match_eth_addrs(f_rule, &match);
0251 
0252         /* DA key, mask */
0253         rule_match_set_n(r_match->key,
0254                  ETH_DMAC_0, &match.key->dst[0], 4);
0255         rule_match_set_n(r_match->key,
0256                  ETH_DMAC_1, &match.key->dst[4], 2);
0257 
0258         rule_match_set_n(r_match->mask,
0259                  ETH_DMAC_0, &match.mask->dst[0], 4);
0260         rule_match_set_n(r_match->mask,
0261                  ETH_DMAC_1, &match.mask->dst[4], 2);
0262 
0263         /* SA key, mask */
0264         rule_match_set_n(r_match->key,
0265                  ETH_SMAC_0, &match.key->src[0], 4);
0266         rule_match_set_n(r_match->key,
0267                  ETH_SMAC_1, &match.key->src[4], 2);
0268 
0269         rule_match_set_n(r_match->mask,
0270                  ETH_SMAC_0, &match.mask->src[0], 4);
0271         rule_match_set_n(r_match->mask,
0272                  ETH_SMAC_1, &match.mask->src[4], 2);
0273     }
0274 
0275     if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
0276         struct flow_match_ipv4_addrs match;
0277 
0278         flow_rule_match_ipv4_addrs(f_rule, &match);
0279 
0280         rule_match_set(r_match->key, IP_SRC, match.key->src);
0281         rule_match_set(r_match->mask, IP_SRC, match.mask->src);
0282 
0283         rule_match_set(r_match->key, IP_DST, match.key->dst);
0284         rule_match_set(r_match->mask, IP_DST, match.mask->dst);
0285     }
0286 
0287     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
0288         struct flow_match_ports match;
0289 
0290         if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
0291             NL_SET_ERR_MSG_MOD
0292                 (f->common.extack,
0293                  "Only UDP and TCP keys are supported");
0294             return -EINVAL;
0295         }
0296 
0297         flow_rule_match_ports(f_rule, &match);
0298 
0299         rule_match_set(r_match->key, L4_PORT_SRC, match.key->src);
0300         rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src);
0301 
0302         rule_match_set(r_match->key, L4_PORT_DST, match.key->dst);
0303         rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst);
0304     }
0305 
0306     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS_RANGE)) {
0307         struct flow_match_ports_range match;
0308         __be32 tp_key, tp_mask;
0309 
0310         flow_rule_match_ports_range(f_rule, &match);
0311 
0312         /* src port range (min, max) */
0313         tp_key = htonl(ntohs(match.key->tp_min.src) |
0314                    (ntohs(match.key->tp_max.src) << 16));
0315         tp_mask = htonl(ntohs(match.mask->tp_min.src) |
0316                 (ntohs(match.mask->tp_max.src) << 16));
0317         rule_match_set(r_match->key, L4_PORT_RANGE_SRC, tp_key);
0318         rule_match_set(r_match->mask, L4_PORT_RANGE_SRC, tp_mask);
0319 
0320         /* dst port range (min, max) */
0321         tp_key = htonl(ntohs(match.key->tp_min.dst) |
0322                    (ntohs(match.key->tp_max.dst) << 16));
0323         tp_mask = htonl(ntohs(match.mask->tp_min.dst) |
0324                 (ntohs(match.mask->tp_max.dst) << 16));
0325         rule_match_set(r_match->key, L4_PORT_RANGE_DST, tp_key);
0326         rule_match_set(r_match->mask, L4_PORT_RANGE_DST, tp_mask);
0327     }
0328 
0329     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
0330         struct flow_match_vlan match;
0331 
0332         flow_rule_match_vlan(f_rule, &match);
0333 
0334         if (match.mask->vlan_id != 0) {
0335             __be16 key = cpu_to_be16(match.key->vlan_id);
0336             __be16 mask = cpu_to_be16(match.mask->vlan_id);
0337 
0338             rule_match_set(r_match->key, VLAN_ID, key);
0339             rule_match_set(r_match->mask, VLAN_ID, mask);
0340         }
0341 
0342         rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid);
0343         rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid);
0344     }
0345 
0346     if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
0347         struct flow_match_icmp match;
0348 
0349         flow_rule_match_icmp(f_rule, &match);
0350 
0351         rule_match_set(r_match->key, ICMP_TYPE, match.key->type);
0352         rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type);
0353 
0354         rule_match_set(r_match->key, ICMP_CODE, match.key->code);
0355         rule_match_set(r_match->mask, ICMP_CODE, match.mask->code);
0356     }
0357 
0358     return prestera_flower_parse_actions(block, rule, &f->rule->action,
0359                          f->common.chain_index,
0360                          f->common.extack);
0361 }
0362 
0363 int prestera_flower_replace(struct prestera_flow_block *block,
0364                 struct flow_cls_offload *f)
0365 {
0366     struct prestera_acl_ruleset *ruleset;
0367     struct prestera_acl *acl = block->sw->acl;
0368     struct prestera_acl_rule *rule;
0369     int err;
0370 
0371     ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index);
0372     if (IS_ERR(ruleset))
0373         return PTR_ERR(ruleset);
0374 
0375     /* increments the ruleset reference */
0376     rule = prestera_acl_rule_create(ruleset, f->cookie,
0377                     f->common.chain_index);
0378     if (IS_ERR(rule)) {
0379         err = PTR_ERR(rule);
0380         goto err_rule_create;
0381     }
0382 
0383     err = prestera_flower_parse(block, rule, f);
0384     if (err)
0385         goto err_rule_add;
0386 
0387     if (!prestera_acl_ruleset_is_offload(ruleset)) {
0388         err = prestera_acl_ruleset_offload(ruleset);
0389         if (err)
0390             goto err_ruleset_offload;
0391     }
0392 
0393     err = prestera_acl_rule_add(block->sw, rule);
0394     if (err)
0395         goto err_rule_add;
0396 
0397     prestera_acl_ruleset_put(ruleset);
0398     return 0;
0399 
0400 err_ruleset_offload:
0401 err_rule_add:
0402     prestera_acl_rule_destroy(rule);
0403 err_rule_create:
0404     prestera_acl_ruleset_put(ruleset);
0405     return err;
0406 }
0407 
0408 void prestera_flower_destroy(struct prestera_flow_block *block,
0409                  struct flow_cls_offload *f)
0410 {
0411     struct prestera_acl_ruleset *ruleset;
0412     struct prestera_acl_rule *rule;
0413 
0414     ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
0415                           f->common.chain_index);
0416     if (IS_ERR(ruleset))
0417         return;
0418 
0419     rule = prestera_acl_rule_lookup(ruleset, f->cookie);
0420     if (rule) {
0421         prestera_acl_rule_del(block->sw, rule);
0422         prestera_acl_rule_destroy(rule);
0423     }
0424     prestera_acl_ruleset_put(ruleset);
0425 }
0426 
0427 int prestera_flower_tmplt_create(struct prestera_flow_block *block,
0428                  struct flow_cls_offload *f)
0429 {
0430     struct prestera_flower_template *template;
0431     struct prestera_acl_ruleset *ruleset;
0432     struct prestera_acl_rule rule;
0433     int err;
0434 
0435     memset(&rule, 0, sizeof(rule));
0436     err = prestera_flower_parse(block, &rule, f);
0437     if (err)
0438         return err;
0439 
0440     template = kmalloc(sizeof(*template), GFP_KERNEL);
0441     if (!template) {
0442         err = -ENOMEM;
0443         goto err_malloc;
0444     }
0445 
0446     prestera_acl_rule_keymask_pcl_id_set(&rule, 0);
0447     ruleset = prestera_acl_ruleset_get(block->sw->acl, block,
0448                        f->common.chain_index);
0449     if (IS_ERR_OR_NULL(ruleset)) {
0450         err = -EINVAL;
0451         goto err_ruleset_get;
0452     }
0453 
0454     /* preserve keymask/template to this ruleset */
0455     prestera_acl_ruleset_keymask_set(ruleset, rule.re_key.match.mask);
0456 
0457     /* skip error, as it is not possible to reject template operation,
0458      * so, keep the reference to the ruleset for rules to be added
0459      * to that ruleset later. In case of offload fail, the ruleset
0460      * will be offloaded again during adding a new rule. Also,
0461      * unlikly possble that ruleset is already offloaded at this staage.
0462      */
0463     prestera_acl_ruleset_offload(ruleset);
0464 
0465     /* keep the reference to the ruleset */
0466     template->ruleset = ruleset;
0467     template->chain_index = f->common.chain_index;
0468     list_add_rcu(&template->list, &block->template_list);
0469     return 0;
0470 
0471 err_ruleset_get:
0472     kfree(template);
0473 err_malloc:
0474     NL_SET_ERR_MSG_MOD(f->common.extack, "Create chain template failed");
0475     return err;
0476 }
0477 
0478 void prestera_flower_tmplt_destroy(struct prestera_flow_block *block,
0479                    struct flow_cls_offload *f)
0480 {
0481     struct prestera_flower_template *template, *tmp;
0482 
0483     list_for_each_entry_safe(template, tmp, &block->template_list, list)
0484         if (template->chain_index == f->common.chain_index) {
0485             /* put the reference to the ruleset kept in create */
0486             prestera_flower_template_free(template);
0487             return;
0488         }
0489 }
0490 
0491 int prestera_flower_stats(struct prestera_flow_block *block,
0492               struct flow_cls_offload *f)
0493 {
0494     struct prestera_acl_ruleset *ruleset;
0495     struct prestera_acl_rule *rule;
0496     u64 packets;
0497     u64 lastuse;
0498     u64 bytes;
0499     int err;
0500 
0501     ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block,
0502                           f->common.chain_index);
0503     if (IS_ERR(ruleset))
0504         return PTR_ERR(ruleset);
0505 
0506     rule = prestera_acl_rule_lookup(ruleset, f->cookie);
0507     if (!rule) {
0508         err = -EINVAL;
0509         goto err_rule_get_stats;
0510     }
0511 
0512     err = prestera_acl_rule_get_stats(block->sw->acl, rule, &packets,
0513                       &bytes, &lastuse);
0514     if (err)
0515         goto err_rule_get_stats;
0516 
0517     flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
0518               FLOW_ACTION_HW_STATS_DELAYED);
0519 
0520 err_rule_get_stats:
0521     prestera_acl_ruleset_put(ruleset);
0522     return err;
0523 }