linux/drivers/net/ethernet/marvell/prestera/prestera_flower.c
<<
>>
Prefs
   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_flower.h"
   7
   8static int prestera_flower_parse_actions(struct prestera_flow_block *block,
   9                                         struct prestera_acl_rule *rule,
  10                                         struct flow_action *flow_action,
  11                                         struct netlink_ext_ack *extack)
  12{
  13        struct prestera_acl_rule_action_entry a_entry;
  14        const struct flow_action_entry *act;
  15        int err, i;
  16
  17        if (!flow_action_has_entries(flow_action))
  18                return 0;
  19
  20        flow_action_for_each(i, act, flow_action) {
  21                memset(&a_entry, 0, sizeof(a_entry));
  22
  23                switch (act->id) {
  24                case FLOW_ACTION_ACCEPT:
  25                        a_entry.id = PRESTERA_ACL_RULE_ACTION_ACCEPT;
  26                        break;
  27                case FLOW_ACTION_DROP:
  28                        a_entry.id = PRESTERA_ACL_RULE_ACTION_DROP;
  29                        break;
  30                case FLOW_ACTION_TRAP:
  31                        a_entry.id = PRESTERA_ACL_RULE_ACTION_TRAP;
  32                        break;
  33                default:
  34                        NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
  35                        pr_err("Unsupported action\n");
  36                        return -EOPNOTSUPP;
  37                }
  38
  39                err = prestera_acl_rule_action_add(rule, &a_entry);
  40                if (err)
  41                        return err;
  42        }
  43
  44        return 0;
  45}
  46
  47static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
  48                                      struct flow_cls_offload *f,
  49                                      struct prestera_flow_block *block)
  50{
  51        struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
  52        struct prestera_acl_rule_match_entry m_entry = {0};
  53        struct net_device *ingress_dev;
  54        struct flow_match_meta match;
  55        struct prestera_port *port;
  56
  57        flow_rule_match_meta(f_rule, &match);
  58        if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
  59                NL_SET_ERR_MSG_MOD(f->common.extack,
  60                                   "Unsupported ingress ifindex mask");
  61                return -EINVAL;
  62        }
  63
  64        ingress_dev = __dev_get_by_index(prestera_acl_block_net(block),
  65                                         match.key->ingress_ifindex);
  66        if (!ingress_dev) {
  67                NL_SET_ERR_MSG_MOD(f->common.extack,
  68                                   "Can't find specified ingress port to match on");
  69                return -EINVAL;
  70        }
  71
  72        if (!prestera_netdev_check(ingress_dev)) {
  73                NL_SET_ERR_MSG_MOD(f->common.extack,
  74                                   "Can't match on switchdev ingress port");
  75                return -EINVAL;
  76        }
  77        port = netdev_priv(ingress_dev);
  78
  79        m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT;
  80        m_entry.keymask.u64.key = port->hw_id | ((u64)port->dev_id << 32);
  81        m_entry.keymask.u64.mask = ~(u64)0;
  82
  83        return prestera_acl_rule_match_add(rule, &m_entry);
  84}
  85
  86static int prestera_flower_parse(struct prestera_flow_block *block,
  87                                 struct prestera_acl_rule *rule,
  88                                 struct flow_cls_offload *f)
  89{
  90        struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
  91        struct flow_dissector *dissector = f_rule->match.dissector;
  92        struct prestera_acl_rule_match_entry m_entry;
  93        u16 n_proto_mask = 0;
  94        u16 n_proto_key = 0;
  95        u16 addr_type = 0;
  96        u8 ip_proto = 0;
  97        int err;
  98
  99        if (dissector->used_keys &
 100            ~(BIT(FLOW_DISSECTOR_KEY_META) |
 101              BIT(FLOW_DISSECTOR_KEY_CONTROL) |
 102              BIT(FLOW_DISSECTOR_KEY_BASIC) |
 103              BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 104              BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
 105              BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
 106              BIT(FLOW_DISSECTOR_KEY_ICMP) |
 107              BIT(FLOW_DISSECTOR_KEY_PORTS) |
 108              BIT(FLOW_DISSECTOR_KEY_VLAN))) {
 109                NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
 110                return -EOPNOTSUPP;
 111        }
 112
 113        prestera_acl_rule_priority_set(rule, f->common.prio);
 114
 115        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
 116                err = prestera_flower_parse_meta(rule, f, block);
 117                if (err)
 118                        return err;
 119        }
 120
 121        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
 122                struct flow_match_control match;
 123
 124                flow_rule_match_control(f_rule, &match);
 125                addr_type = match.key->addr_type;
 126        }
 127
 128        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
 129                struct flow_match_basic match;
 130
 131                flow_rule_match_basic(f_rule, &match);
 132                n_proto_key = ntohs(match.key->n_proto);
 133                n_proto_mask = ntohs(match.mask->n_proto);
 134
 135                if (n_proto_key == ETH_P_ALL) {
 136                        n_proto_key = 0;
 137                        n_proto_mask = 0;
 138                }
 139
 140                /* add eth type key,mask */
 141                memset(&m_entry, 0, sizeof(m_entry));
 142                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE;
 143                m_entry.keymask.u16.key = n_proto_key;
 144                m_entry.keymask.u16.mask = n_proto_mask;
 145                err = prestera_acl_rule_match_add(rule, &m_entry);
 146                if (err)
 147                        return err;
 148
 149                /* add ip proto key,mask */
 150                memset(&m_entry, 0, sizeof(m_entry));
 151                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO;
 152                m_entry.keymask.u8.key = match.key->ip_proto;
 153                m_entry.keymask.u8.mask = match.mask->ip_proto;
 154                err = prestera_acl_rule_match_add(rule, &m_entry);
 155                if (err)
 156                        return err;
 157
 158                ip_proto = match.key->ip_proto;
 159        }
 160
 161        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
 162                struct flow_match_eth_addrs match;
 163
 164                flow_rule_match_eth_addrs(f_rule, &match);
 165
 166                /* add ethernet dst key,mask */
 167                memset(&m_entry, 0, sizeof(m_entry));
 168                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC;
 169                memcpy(&m_entry.keymask.mac.key,
 170                       &match.key->dst, sizeof(match.key->dst));
 171                memcpy(&m_entry.keymask.mac.mask,
 172                       &match.mask->dst, sizeof(match.mask->dst));
 173                err = prestera_acl_rule_match_add(rule, &m_entry);
 174                if (err)
 175                        return err;
 176
 177                /* add ethernet src key,mask */
 178                memset(&m_entry, 0, sizeof(m_entry));
 179                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC;
 180                memcpy(&m_entry.keymask.mac.key,
 181                       &match.key->src, sizeof(match.key->src));
 182                memcpy(&m_entry.keymask.mac.mask,
 183                       &match.mask->src, sizeof(match.mask->src));
 184                err = prestera_acl_rule_match_add(rule, &m_entry);
 185                if (err)
 186                        return err;
 187        }
 188
 189        if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
 190                struct flow_match_ipv4_addrs match;
 191
 192                flow_rule_match_ipv4_addrs(f_rule, &match);
 193
 194                memset(&m_entry, 0, sizeof(m_entry));
 195                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC;
 196                memcpy(&m_entry.keymask.u32.key,
 197                       &match.key->src, sizeof(match.key->src));
 198                memcpy(&m_entry.keymask.u32.mask,
 199                       &match.mask->src, sizeof(match.mask->src));
 200                err = prestera_acl_rule_match_add(rule, &m_entry);
 201                if (err)
 202                        return err;
 203
 204                memset(&m_entry, 0, sizeof(m_entry));
 205                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST;
 206                memcpy(&m_entry.keymask.u32.key,
 207                       &match.key->dst, sizeof(match.key->dst));
 208                memcpy(&m_entry.keymask.u32.mask,
 209                       &match.mask->dst, sizeof(match.mask->dst));
 210                err = prestera_acl_rule_match_add(rule, &m_entry);
 211                if (err)
 212                        return err;
 213        }
 214
 215        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
 216                struct flow_match_ports match;
 217
 218                if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
 219                        NL_SET_ERR_MSG_MOD
 220                            (f->common.extack,
 221                             "Only UDP and TCP keys are supported");
 222                        return -EINVAL;
 223                }
 224
 225                flow_rule_match_ports(f_rule, &match);
 226
 227                memset(&m_entry, 0, sizeof(m_entry));
 228                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC;
 229                m_entry.keymask.u16.key = ntohs(match.key->src);
 230                m_entry.keymask.u16.mask = ntohs(match.mask->src);
 231                err = prestera_acl_rule_match_add(rule, &m_entry);
 232                if (err)
 233                        return err;
 234
 235                memset(&m_entry, 0, sizeof(m_entry));
 236                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST;
 237                m_entry.keymask.u16.key = ntohs(match.key->dst);
 238                m_entry.keymask.u16.mask = ntohs(match.mask->dst);
 239                err = prestera_acl_rule_match_add(rule, &m_entry);
 240                if (err)
 241                        return err;
 242        }
 243
 244        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
 245                struct flow_match_vlan match;
 246
 247                flow_rule_match_vlan(f_rule, &match);
 248
 249                if (match.mask->vlan_id != 0) {
 250                        memset(&m_entry, 0, sizeof(m_entry));
 251                        m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID;
 252                        m_entry.keymask.u16.key = match.key->vlan_id;
 253                        m_entry.keymask.u16.mask = match.mask->vlan_id;
 254                        err = prestera_acl_rule_match_add(rule, &m_entry);
 255                        if (err)
 256                                return err;
 257                }
 258
 259                memset(&m_entry, 0, sizeof(m_entry));
 260                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID;
 261                m_entry.keymask.u16.key = ntohs(match.key->vlan_tpid);
 262                m_entry.keymask.u16.mask = ntohs(match.mask->vlan_tpid);
 263                err = prestera_acl_rule_match_add(rule, &m_entry);
 264                if (err)
 265                        return err;
 266        }
 267
 268        if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
 269                struct flow_match_icmp match;
 270
 271                flow_rule_match_icmp(f_rule, &match);
 272
 273                memset(&m_entry, 0, sizeof(m_entry));
 274                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE;
 275                m_entry.keymask.u8.key = match.key->type;
 276                m_entry.keymask.u8.mask = match.mask->type;
 277                err = prestera_acl_rule_match_add(rule, &m_entry);
 278                if (err)
 279                        return err;
 280
 281                memset(&m_entry, 0, sizeof(m_entry));
 282                m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE;
 283                m_entry.keymask.u8.key = match.key->code;
 284                m_entry.keymask.u8.mask = match.mask->code;
 285                err = prestera_acl_rule_match_add(rule, &m_entry);
 286                if (err)
 287                        return err;
 288        }
 289
 290        return prestera_flower_parse_actions(block, rule,
 291                                             &f->rule->action,
 292                                             f->common.extack);
 293}
 294
 295int prestera_flower_replace(struct prestera_flow_block *block,
 296                            struct flow_cls_offload *f)
 297{
 298        struct prestera_switch *sw = prestera_acl_block_sw(block);
 299        struct prestera_acl_rule *rule;
 300        int err;
 301
 302        rule = prestera_acl_rule_create(block, f->cookie);
 303        if (IS_ERR(rule))
 304                return PTR_ERR(rule);
 305
 306        err = prestera_flower_parse(block, rule, f);
 307        if (err)
 308                goto err_flower_parse;
 309
 310        err = prestera_acl_rule_add(sw, rule);
 311        if (err)
 312                goto err_rule_add;
 313
 314        return 0;
 315
 316err_rule_add:
 317err_flower_parse:
 318        prestera_acl_rule_destroy(rule);
 319        return err;
 320}
 321
 322void prestera_flower_destroy(struct prestera_flow_block *block,
 323                             struct flow_cls_offload *f)
 324{
 325        struct prestera_acl_rule *rule;
 326        struct prestera_switch *sw;
 327
 328        rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
 329                                        f->cookie);
 330        if (rule) {
 331                sw = prestera_acl_block_sw(block);
 332                prestera_acl_rule_del(sw, rule);
 333                prestera_acl_rule_destroy(rule);
 334        }
 335}
 336
 337int prestera_flower_stats(struct prestera_flow_block *block,
 338                          struct flow_cls_offload *f)
 339{
 340        struct prestera_switch *sw = prestera_acl_block_sw(block);
 341        struct prestera_acl_rule *rule;
 342        u64 packets;
 343        u64 lastuse;
 344        u64 bytes;
 345        int err;
 346
 347        rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
 348                                        f->cookie);
 349        if (!rule)
 350                return -EINVAL;
 351
 352        err = prestera_acl_rule_get_stats(sw, rule, &packets, &bytes, &lastuse);
 353        if (err)
 354                return err;
 355
 356        flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
 357                          FLOW_ACTION_HW_STATS_IMMEDIATE);
 358        return 0;
 359}
 360