linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
<<
>>
Prefs
   1/*
   2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
   3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
   4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions are met:
   8 *
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. Neither the names of the copyright holders nor the names of its
  15 *    contributors may be used to endorse or promote products derived from
  16 *    this software without specific prior written permission.
  17 *
  18 * Alternatively, this software may be distributed under the terms of the
  19 * GNU General Public License ("GPL") version 2 as published by the Free
  20 * Software Foundation.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32 * POSSIBILITY OF SUCH DAMAGE.
  33 */
  34
  35#include <linux/kernel.h>
  36#include <linux/errno.h>
  37#include <linux/netdevice.h>
  38#include <net/flow_dissector.h>
  39#include <net/pkt_cls.h>
  40#include <net/tc_act/tc_gact.h>
  41#include <net/tc_act/tc_mirred.h>
  42
  43#include "spectrum.h"
  44#include "core_acl_flex_keys.h"
  45
  46static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
  47                                         struct net_device *dev,
  48                                         struct mlxsw_sp_acl_rule_info *rulei,
  49                                         struct tcf_exts *exts)
  50{
  51        const struct tc_action *a;
  52        LIST_HEAD(actions);
  53        int err;
  54
  55        if (tc_no_actions(exts))
  56                return 0;
  57
  58        tcf_exts_to_list(exts, &actions);
  59        list_for_each_entry(a, &actions, list) {
  60                if (is_tcf_gact_shot(a)) {
  61                        err = mlxsw_sp_acl_rulei_act_drop(rulei);
  62                        if (err)
  63                                return err;
  64                } else if (is_tcf_mirred_egress_redirect(a)) {
  65                        int ifindex = tcf_mirred_ifindex(a);
  66                        struct net_device *out_dev;
  67
  68                        out_dev = __dev_get_by_index(dev_net(dev), ifindex);
  69                        if (out_dev == dev)
  70                                out_dev = NULL;
  71
  72                        err = mlxsw_sp_acl_rulei_act_fwd(mlxsw_sp, rulei,
  73                                                         out_dev);
  74                        if (err)
  75                                return err;
  76                } else {
  77                        dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
  78                        return -EOPNOTSUPP;
  79                }
  80        }
  81        return 0;
  82}
  83
  84static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
  85                                       struct tc_cls_flower_offload *f)
  86{
  87        struct flow_dissector_key_ipv4_addrs *key =
  88                skb_flow_dissector_target(f->dissector,
  89                                          FLOW_DISSECTOR_KEY_IPV4_ADDRS,
  90                                          f->key);
  91        struct flow_dissector_key_ipv4_addrs *mask =
  92                skb_flow_dissector_target(f->dissector,
  93                                          FLOW_DISSECTOR_KEY_IPV4_ADDRS,
  94                                          f->mask);
  95
  96        mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_IP4,
  97                                       ntohl(key->src), ntohl(mask->src));
  98        mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_IP4,
  99                                       ntohl(key->dst), ntohl(mask->dst));
 100}
 101
 102static void mlxsw_sp_flower_parse_ipv6(struct mlxsw_sp_acl_rule_info *rulei,
 103                                       struct tc_cls_flower_offload *f)
 104{
 105        struct flow_dissector_key_ipv6_addrs *key =
 106                skb_flow_dissector_target(f->dissector,
 107                                          FLOW_DISSECTOR_KEY_IPV6_ADDRS,
 108                                          f->key);
 109        struct flow_dissector_key_ipv6_addrs *mask =
 110                skb_flow_dissector_target(f->dissector,
 111                                          FLOW_DISSECTOR_KEY_IPV6_ADDRS,
 112                                          f->mask);
 113        size_t addr_half_size = sizeof(key->src) / 2;
 114
 115        mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_HI,
 116                                       &key->src.s6_addr[0],
 117                                       &mask->src.s6_addr[0],
 118                                       addr_half_size);
 119        mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_LO,
 120                                       &key->src.s6_addr[addr_half_size],
 121                                       &mask->src.s6_addr[addr_half_size],
 122                                       addr_half_size);
 123        mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_HI,
 124                                       &key->dst.s6_addr[0],
 125                                       &mask->dst.s6_addr[0],
 126                                       addr_half_size);
 127        mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_LO,
 128                                       &key->dst.s6_addr[addr_half_size],
 129                                       &mask->dst.s6_addr[addr_half_size],
 130                                       addr_half_size);
 131}
 132
 133static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
 134                                       struct mlxsw_sp_acl_rule_info *rulei,
 135                                       struct tc_cls_flower_offload *f,
 136                                       u8 ip_proto)
 137{
 138        struct flow_dissector_key_ports *key, *mask;
 139
 140        if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS))
 141                return 0;
 142
 143        if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
 144                dev_err(mlxsw_sp->bus_info->dev, "Only UDP and TCP keys are supported\n");
 145                return -EINVAL;
 146        }
 147
 148        key = skb_flow_dissector_target(f->dissector,
 149                                        FLOW_DISSECTOR_KEY_PORTS,
 150                                        f->key);
 151        mask = skb_flow_dissector_target(f->dissector,
 152                                         FLOW_DISSECTOR_KEY_PORTS,
 153                                         f->mask);
 154        mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_L4_PORT,
 155                                       ntohs(key->dst), ntohs(mask->dst));
 156        mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_L4_PORT,
 157                                       ntohs(key->src), ntohs(mask->src));
 158        return 0;
 159}
 160
 161static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
 162                                 struct net_device *dev,
 163                                 struct mlxsw_sp_acl_rule_info *rulei,
 164                                 struct tc_cls_flower_offload *f)
 165{
 166        u16 addr_type = 0;
 167        u8 ip_proto = 0;
 168        int err;
 169
 170        if (f->dissector->used_keys &
 171            ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
 172              BIT(FLOW_DISSECTOR_KEY_BASIC) |
 173              BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 174              BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
 175              BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
 176              BIT(FLOW_DISSECTOR_KEY_PORTS))) {
 177                dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n");
 178                return -EOPNOTSUPP;
 179        }
 180
 181        mlxsw_sp_acl_rulei_priority(rulei, f->prio);
 182
 183        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
 184                struct flow_dissector_key_control *key =
 185                        skb_flow_dissector_target(f->dissector,
 186                                                  FLOW_DISSECTOR_KEY_CONTROL,
 187                                                  f->key);
 188                addr_type = key->addr_type;
 189        }
 190
 191        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
 192                struct flow_dissector_key_basic *key =
 193                        skb_flow_dissector_target(f->dissector,
 194                                                  FLOW_DISSECTOR_KEY_BASIC,
 195                                                  f->key);
 196                struct flow_dissector_key_basic *mask =
 197                        skb_flow_dissector_target(f->dissector,
 198                                                  FLOW_DISSECTOR_KEY_BASIC,
 199                                                  f->mask);
 200                u16 n_proto_key = ntohs(key->n_proto);
 201                u16 n_proto_mask = ntohs(mask->n_proto);
 202
 203                if (n_proto_key == ETH_P_ALL) {
 204                        n_proto_key = 0;
 205                        n_proto_mask = 0;
 206                }
 207                mlxsw_sp_acl_rulei_keymask_u32(rulei,
 208                                               MLXSW_AFK_ELEMENT_ETHERTYPE,
 209                                               n_proto_key, n_proto_mask);
 210
 211                ip_proto = key->ip_proto;
 212                mlxsw_sp_acl_rulei_keymask_u32(rulei,
 213                                               MLXSW_AFK_ELEMENT_IP_PROTO,
 214                                               key->ip_proto, mask->ip_proto);
 215        }
 216
 217        if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
 218                struct flow_dissector_key_eth_addrs *key =
 219                        skb_flow_dissector_target(f->dissector,
 220                                                  FLOW_DISSECTOR_KEY_ETH_ADDRS,
 221                                                  f->key);
 222                struct flow_dissector_key_eth_addrs *mask =
 223                        skb_flow_dissector_target(f->dissector,
 224                                                  FLOW_DISSECTOR_KEY_ETH_ADDRS,
 225                                                  f->mask);
 226
 227                mlxsw_sp_acl_rulei_keymask_buf(rulei,
 228                                               MLXSW_AFK_ELEMENT_DMAC,
 229                                               key->dst, mask->dst,
 230                                               sizeof(key->dst));
 231                mlxsw_sp_acl_rulei_keymask_buf(rulei,
 232                                               MLXSW_AFK_ELEMENT_SMAC,
 233                                               key->src, mask->src,
 234                                               sizeof(key->src));
 235        }
 236
 237        if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS)
 238                mlxsw_sp_flower_parse_ipv4(rulei, f);
 239
 240        if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS)
 241                mlxsw_sp_flower_parse_ipv6(rulei, f);
 242
 243        err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto);
 244        if (err)
 245                return err;
 246
 247        return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, rulei, f->exts);
 248}
 249
 250int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
 251                            __be16 protocol, struct tc_cls_flower_offload *f)
 252{
 253        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 254        struct net_device *dev = mlxsw_sp_port->dev;
 255        struct mlxsw_sp_acl_rule_info *rulei;
 256        struct mlxsw_sp_acl_ruleset *ruleset;
 257        struct mlxsw_sp_acl_rule *rule;
 258        int err;
 259
 260        ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, dev, ingress,
 261                                           MLXSW_SP_ACL_PROFILE_FLOWER);
 262        if (IS_ERR(ruleset))
 263                return PTR_ERR(ruleset);
 264
 265        rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset, f->cookie);
 266        if (IS_ERR(rule)) {
 267                err = PTR_ERR(rule);
 268                goto err_rule_create;
 269        }
 270
 271        rulei = mlxsw_sp_acl_rule_rulei(rule);
 272        err = mlxsw_sp_flower_parse(mlxsw_sp, dev, rulei, f);
 273        if (err)
 274                goto err_flower_parse;
 275
 276        err = mlxsw_sp_acl_rulei_commit(rulei);
 277        if (err)
 278                goto err_rulei_commit;
 279
 280        err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
 281        if (err)
 282                goto err_rule_add;
 283
 284        mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
 285        return 0;
 286
 287err_rule_add:
 288err_rulei_commit:
 289err_flower_parse:
 290        mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
 291err_rule_create:
 292        mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
 293        return err;
 294}
 295
 296void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
 297                             struct tc_cls_flower_offload *f)
 298{
 299        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 300        struct mlxsw_sp_acl_ruleset *ruleset;
 301        struct mlxsw_sp_acl_rule *rule;
 302
 303        ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
 304                                           ingress,
 305                                           MLXSW_SP_ACL_PROFILE_FLOWER);
 306        if (IS_ERR(ruleset))
 307                return;
 308
 309        rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset, f->cookie);
 310        if (rule) {
 311                mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
 312                mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
 313        }
 314
 315        mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
 316}
 317