OSDN Git Service

net/mlx5e: Rearrange tc tunnel code in a modular way
authorYevgeny Kliteynik <kliteyn@mellanox.com>
Sun, 14 Apr 2019 14:50:01 +0000 (17:50 +0300)
committerSaeed Mahameed <saeedm@mellanox.com>
Fri, 31 May 2019 20:04:26 +0000 (13:04 -0700)
Rearrange tc tunnel code so that it would be easy to add future tunnels:
 - Define tc tunnel object with the fields and callbacks that any
   tunnel must implement.
 - Define tc UDP tunnel object for UDP tunnels, such as VXLAN
 - Move each tunnel code (GRE, VXLAN) to its own separate file
 - Rewrite tc tunnel implementation in a general way - using only
   the objects and their callbacks.

Reviewed-by: Oz Shlomo <ozsh@mellanox.com>
Signed-off-by: Yevgeny Kliteynik <kliteyn@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

index e310272..f1f222f 100644 (file)
@@ -32,7 +32,7 @@ mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
 mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
 mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
 mlx5_core-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
-                                       lib/geneve.o
+                                       lib/geneve.o en/tc_tun_vxlan.o en/tc_tun_gre.o
 
 #
 # Core extra
index 2004d04..6f31b68 100644 (file)
@@ -3,9 +3,19 @@
 
 #include <net/vxlan.h>
 #include <net/gre.h>
-#include "lib/vxlan.h"
 #include "en/tc_tun.h"
 
+struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev)
+{
+       if (netif_is_vxlan(tunnel_dev))
+               return &vxlan_tunnel;
+       else if (netif_is_gretap(tunnel_dev) ||
+                netif_is_ip6gretap(tunnel_dev))
+               return &gre_tunnel;
+       else
+               return NULL;
+}
+
 static int get_route_and_out_devs(struct mlx5e_priv *priv,
                                  struct net_device *dev,
                                  struct net_device **route_dev,
@@ -141,64 +151,15 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
        return 0;
 }
 
-static int mlx5e_gen_vxlan_header(char buf[],
-                                 const struct ip_tunnel_key *tun_key)
-{
-       __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
-       struct udphdr *udp = (struct udphdr *)(buf);
-       struct vxlanhdr *vxh = (struct vxlanhdr *)
-                              ((char *)udp + sizeof(struct udphdr));
-
-       udp->dest = tun_key->tp_dst;
-       vxh->vx_flags = VXLAN_HF_VNI;
-       vxh->vx_vni = vxlan_vni_field(tun_id);
-
-       return 0;
-}
-
-static int mlx5e_gen_gre_header(char buf[], const struct ip_tunnel_key *tun_key)
-{
-       __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
-       int hdr_len;
-       struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
-
-       /* the HW does not calculate GRE csum or sequences */
-       if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
-               return -EOPNOTSUPP;
-
-       greh->protocol = htons(ETH_P_TEB);
-
-       /* GRE key */
-       hdr_len = gre_calc_hlen(tun_key->tun_flags);
-       greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
-       if (tun_key->tun_flags & TUNNEL_KEY) {
-               __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
-
-               *ptr = tun_id;
-       }
-
-       return 0;
-}
-
 static int mlx5e_gen_ip_tunnel_header(char buf[], __u8 *ip_proto,
                                      struct mlx5e_encap_entry *e)
 {
-       int err = 0;
-       const struct ip_tunnel_key *key = &e->tun_info->key;
-
-       if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
-               *ip_proto = IPPROTO_UDP;
-               err = mlx5e_gen_vxlan_header(buf, key);
-       } else if  (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
-               *ip_proto = IPPROTO_GRE;
-               err = mlx5e_gen_gre_header(buf, key);
-       } else {
-               pr_warn("mlx5: Cannot generate tunnel header for tunnel type (%d)\n"
-                       , e->tunnel_type);
-               err = -EOPNOTSUPP;
+       if (!e->tunnel) {
+               pr_warn("mlx5: Cannot generate tunnel header for this tunnel\n");
+               return -EOPNOTSUPP;
        }
 
-       return err;
+       return e->tunnel->generate_ip_tun_hdr(buf, ip_proto, e);
 }
 
 static char *gen_eth_tnl_hdr(char *buf, struct net_device *dev,
@@ -254,7 +215,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
        ipv4_encap_size =
                (is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
                sizeof(struct iphdr) +
-               e->tunnel_hlen;
+               e->tunnel->calc_hlen(e);
 
        if (max_encap_size < ipv4_encap_size) {
                mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
@@ -370,7 +331,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
        ipv6_encap_size =
                (is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
                sizeof(struct ipv6hdr) +
-               e->tunnel_hlen;
+               e->tunnel->calc_hlen(e);
 
        if (max_encap_size < ipv6_encap_size) {
                mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
@@ -456,27 +417,12 @@ out:
        return err;
 }
 
-int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev)
-{
-       if (netif_is_vxlan(tunnel_dev))
-               return MLX5E_TC_TUNNEL_TYPE_VXLAN;
-       else if (netif_is_gretap(tunnel_dev) ||
-                netif_is_ip6gretap(tunnel_dev))
-               return MLX5E_TC_TUNNEL_TYPE_GRETAP;
-       else
-               return MLX5E_TC_TUNNEL_TYPE_UNKNOWN;
-}
-
 bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
                                    struct net_device *netdev)
 {
-       int tunnel_type = mlx5e_tc_tun_get_type(netdev);
+       struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(netdev);
 
-       if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN &&
-           MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
-               return true;
-       else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP &&
-                MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap))
+       if (tunnel && tunnel->can_offload(priv))
                return true;
        else
                return false;
@@ -487,71 +433,87 @@ int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
                                 struct mlx5e_encap_entry *e,
                                 struct netlink_ext_ack *extack)
 {
-       e->tunnel_type = mlx5e_tc_tun_get_type(tunnel_dev);
+       struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(tunnel_dev);
 
-       if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
-               int dst_port = be16_to_cpu(e->tun_info->key.tp_dst);
-
-               if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
-                       NL_SET_ERR_MSG_MOD(extack,
-                                          "vxlan udp dport was not registered with the HW");
-                       netdev_warn(priv->netdev,
-                                   "%d isn't an offloaded vxlan udp dport\n",
-                                   dst_port);
-                       return -EOPNOTSUPP;
-               }
-               e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
-               e->tunnel_hlen = VXLAN_HLEN;
-       } else if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
-               e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
-               e->tunnel_hlen = gre_calc_hlen(e->tun_info->key.tun_flags);
-       } else {
+       if (!tunnel) {
                e->reformat_type = -1;
-               e->tunnel_hlen = -1;
                return -EOPNOTSUPP;
        }
-       return 0;
+
+       return tunnel->init_encap_attr(tunnel_dev, priv, e, extack);
 }
 
-static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
-                                   struct mlx5_flow_spec *spec,
-                                   struct tc_cls_flower_offload *f,
-                                   void *headers_c,
-                                   void *headers_v)
+int mlx5e_tc_tun_parse(struct net_device *filter_dev,
+                      struct mlx5e_priv *priv,
+                      struct mlx5_flow_spec *spec,
+                      struct tc_cls_flower_offload *f,
+                      void *headers_c,
+                      void *headers_v, u8 *match_level)
+{
+       struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(filter_dev);
+       int err = 0;
+
+       if (!tunnel) {
+               netdev_warn(priv->netdev,
+                           "decapsulation offload is not supported for %s net device\n",
+                           mlx5e_netdev_kind(filter_dev));
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       *match_level = tunnel->match_level;
+
+       if (tunnel->parse_udp_ports) {
+               err = tunnel->parse_udp_ports(priv, spec, f,
+                                             headers_c, headers_v);
+               if (err)
+                       goto out;
+       }
+
+       if (tunnel->parse_tunnel) {
+               err = tunnel->parse_tunnel(priv, spec, f,
+                                          headers_c, headers_v);
+               if (err)
+                       goto out;
+       }
+
+out:
+       return err;
+}
+
+int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
+                                struct mlx5_flow_spec *spec,
+                                struct tc_cls_flower_offload *f,
+                                void *headers_c,
+                                void *headers_v)
 {
        struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
        struct netlink_ext_ack *extack = f->common.extack;
-       void *misc_c = MLX5_ADDR_OF(fte_match_param,
-                                   spec->match_criteria,
-                                   misc_parameters);
-       void *misc_v = MLX5_ADDR_OF(fte_match_param,
-                                   spec->match_value,
-                                   misc_parameters);
        struct flow_match_ports enc_ports;
 
-       flow_rule_match_enc_ports(rule, &enc_ports);
-
        /* Full udp dst port must be given */
-       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
-           memchr_inv(&enc_ports.mask->dst, 0xff, sizeof(enc_ports.mask->dst))) {
+
+       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
                NL_SET_ERR_MSG_MOD(extack,
-                                  "VXLAN decap filter must include enc_dst_port condition");
+                                  "UDP tunnel decap filter must include enc_dst_port condition");
                netdev_warn(priv->netdev,
-                           "VXLAN decap filter must include enc_dst_port condition\n");
+                           "UDP tunnel decap filter must include enc_dst_port condition\n");
                return -EOPNOTSUPP;
        }
 
-       /* udp dst port must be knonwn as a VXLAN port */
-       if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(enc_ports.key->dst))) {
+       flow_rule_match_enc_ports(rule, &enc_ports);
+
+       if (memchr_inv(&enc_ports.mask->dst, 0xff,
+                      sizeof(enc_ports.mask->dst))) {
                NL_SET_ERR_MSG_MOD(extack,
-                                  "Matched UDP port is not registered as a VXLAN port");
+                                  "UDP tunnel decap filter must match enc_dst_port fully");
                netdev_warn(priv->netdev,
-                           "UDP port %d is not registered as a VXLAN port\n",
-                           be16_to_cpu(enc_ports.key->dst));
+                           "UDP tunnel decap filter must match enc_dst_port fully\n");
                return -EOPNOTSUPP;
        }
 
-       /* dst UDP port is valid here */
+       /* match on UDP protocol and dst port number */
+
        MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
        MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
 
@@ -560,92 +522,15 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
        MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
                 ntohs(enc_ports.key->dst));
 
+       /* UDP src port on outer header is generated by HW,
+        * so it is probably a bad idea to request matching it.
+        * Nonetheless, it is allowed.
+        */
+
        MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
                 ntohs(enc_ports.mask->src));
        MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
                 ntohs(enc_ports.key->src));
 
-       /* match on VNI */
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
-               struct flow_match_enc_keyid enc_keyid;
-
-               flow_rule_match_enc_keyid(rule, &enc_keyid);
-
-               MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
-                        be32_to_cpu(enc_keyid.mask->keyid));
-               MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
-                        be32_to_cpu(enc_keyid.key->keyid));
-       }
-       return 0;
-}
-
-static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
-                                    struct mlx5_flow_spec *spec,
-                                    struct tc_cls_flower_offload *f,
-                                    void *outer_headers_c,
-                                    void *outer_headers_v)
-{
-       void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
-                                   misc_parameters);
-       void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
-                                   misc_parameters);
-       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
-
-       if (!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap)) {
-               NL_SET_ERR_MSG_MOD(f->common.extack,
-                                  "GRE HW offloading is not supported");
-               netdev_warn(priv->netdev, "GRE HW offloading is not supported\n");
-               return -EOPNOTSUPP;
-       }
-
-       MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
-       MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v,
-                ip_protocol, IPPROTO_GRE);
-
-       /* gre protocol*/
-       MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
-       MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
-
-       /* gre key */
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
-               struct flow_match_enc_keyid enc_keyid;
-
-               flow_rule_match_enc_keyid(rule, &enc_keyid);
-               MLX5_SET(fte_match_set_misc, misc_c,
-                        gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
-               MLX5_SET(fte_match_set_misc, misc_v,
-                        gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
-       }
-
        return 0;
 }
-
-int mlx5e_tc_tun_parse(struct net_device *filter_dev,
-                      struct mlx5e_priv *priv,
-                      struct mlx5_flow_spec *spec,
-                      struct tc_cls_flower_offload *f,
-                      void *headers_c,
-                      void *headers_v, u8 *match_level)
-{
-       int tunnel_type;
-       int err = 0;
-
-       tunnel_type = mlx5e_tc_tun_get_type(filter_dev);
-       if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
-               *match_level = MLX5_MATCH_L4;
-               err = mlx5e_tc_tun_parse_vxlan(priv, spec, f,
-                                              headers_c, headers_v);
-       } else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
-               *match_level = MLX5_MATCH_L3;
-               err = mlx5e_tc_tun_parse_gretap(priv, spec, f,
-                                               headers_c, headers_v);
-       } else {
-               netdev_warn(priv->netdev,
-                           "decapsulation offload is not supported for %s (kind: \"%s\")\n",
-                           netdev_name(filter_dev),
-                           mlx5e_netdev_kind(filter_dev));
-
-               return -EOPNOTSUPP;
-       }
-       return err;
-}
index b63f15d..ca1d337 100644 (file)
 enum {
        MLX5E_TC_TUNNEL_TYPE_UNKNOWN,
        MLX5E_TC_TUNNEL_TYPE_VXLAN,
-       MLX5E_TC_TUNNEL_TYPE_GRETAP
+       MLX5E_TC_TUNNEL_TYPE_GRETAP,
 };
 
+struct mlx5e_tc_tunnel {
+       int tunnel_type;
+       enum mlx5_flow_match_level match_level;
+
+       bool (*can_offload)(struct mlx5e_priv *priv);
+       int (*calc_hlen)(struct mlx5e_encap_entry *e);
+       int (*init_encap_attr)(struct net_device *tunnel_dev,
+                              struct mlx5e_priv *priv,
+                              struct mlx5e_encap_entry *e,
+                              struct netlink_ext_ack *extack);
+       int (*generate_ip_tun_hdr)(char buf[],
+                                  __u8 *ip_proto,
+                                  struct mlx5e_encap_entry *e);
+       int (*parse_udp_ports)(struct mlx5e_priv *priv,
+                              struct mlx5_flow_spec *spec,
+                              struct tc_cls_flower_offload *f,
+                              void *headers_c,
+                              void *headers_v);
+       int (*parse_tunnel)(struct mlx5e_priv *priv,
+                           struct mlx5_flow_spec *spec,
+                           struct tc_cls_flower_offload *f,
+                           void *headers_c,
+                           void *headers_v);
+};
+
+extern struct mlx5e_tc_tunnel vxlan_tunnel;
+extern struct mlx5e_tc_tunnel gre_tunnel;
+
+struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev);
+
 int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
                                 struct mlx5e_priv *priv,
                                 struct mlx5e_encap_entry *e,
@@ -30,7 +60,6 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
                                    struct net_device *mirred_dev,
                                    struct mlx5e_encap_entry *e);
 
-int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev);
 bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
                                    struct net_device *netdev);
 
@@ -41,4 +70,10 @@ int mlx5e_tc_tun_parse(struct net_device *filter_dev,
                       void *headers_c,
                       void *headers_v, u8 *match_level);
 
+int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
+                                struct mlx5_flow_spec *spec,
+                                struct tc_cls_flower_offload *f,
+                                void *headers_c,
+                                void *headers_v);
+
 #endif //__MLX5_EN_TC_TUNNEL_H__
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
new file mode 100644 (file)
index 0000000..0690844
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include <net/gre.h>
+#include "en/tc_tun.h"
+
+static bool mlx5e_tc_tun_can_offload_gretap(struct mlx5e_priv *priv)
+{
+       return !!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap);
+}
+
+static int mlx5e_tc_tun_calc_hlen_gretap(struct mlx5e_encap_entry *e)
+{
+       return gre_calc_hlen(e->tun_info->key.tun_flags);
+}
+
+static int mlx5e_tc_tun_init_encap_attr_gretap(struct net_device *tunnel_dev,
+                                              struct mlx5e_priv *priv,
+                                              struct mlx5e_encap_entry *e,
+                                              struct netlink_ext_ack *extack)
+{
+       e->tunnel = &gre_tunnel;
+       e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
+       return 0;
+}
+
+static int mlx5e_gen_ip_tunnel_header_gretap(char buf[],
+                                            __u8 *ip_proto,
+                                            struct mlx5e_encap_entry *e)
+{
+       const struct ip_tunnel_key *tun_key  = &e->tun_info->key;
+       struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
+       __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
+       int hdr_len;
+
+       *ip_proto = IPPROTO_GRE;
+
+       /* the HW does not calculate GRE csum or sequences */
+       if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
+               return -EOPNOTSUPP;
+
+       greh->protocol = htons(ETH_P_TEB);
+
+       /* GRE key */
+       hdr_len = mlx5e_tc_tun_calc_hlen_gretap(e);
+       greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
+       if (tun_key->tun_flags & TUNNEL_KEY) {
+               __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
+               *ptr = tun_id;
+       }
+
+       return 0;
+}
+
+static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
+                                    struct mlx5_flow_spec *spec,
+                                    struct tc_cls_flower_offload *f,
+                                    void *headers_c,
+                                    void *headers_v)
+{
+       void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+       void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+
+       MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
+       MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
+
+       /* gre protocol */
+       MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
+       MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
+
+       /* gre key */
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+               struct flow_match_enc_keyid enc_keyid;
+
+               flow_rule_match_enc_keyid(rule, &enc_keyid);
+               MLX5_SET(fte_match_set_misc, misc_c,
+                        gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
+               MLX5_SET(fte_match_set_misc, misc_v,
+                        gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
+       }
+
+       return 0;
+}
+
+struct mlx5e_tc_tunnel gre_tunnel = {
+       .tunnel_type          = MLX5E_TC_TUNNEL_TYPE_GRETAP,
+       .match_level          = MLX5_MATCH_L3,
+       .can_offload          = mlx5e_tc_tun_can_offload_gretap,
+       .calc_hlen            = mlx5e_tc_tun_calc_hlen_gretap,
+       .init_encap_attr      = mlx5e_tc_tun_init_encap_attr_gretap,
+       .generate_ip_tun_hdr  = mlx5e_gen_ip_tunnel_header_gretap,
+       .parse_udp_ports      = NULL,
+       .parse_tunnel         = mlx5e_tc_tun_parse_gretap,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
new file mode 100644 (file)
index 0000000..2857b38
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2018 Mellanox Technologies. */
+
+#include <net/vxlan.h>
+#include "lib/vxlan.h"
+#include "en/tc_tun.h"
+
+static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv)
+{
+       return !!MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap);
+}
+
+static int mlx5e_tc_tun_calc_hlen_vxlan(struct mlx5e_encap_entry *e)
+{
+       return VXLAN_HLEN;
+}
+
+static int mlx5e_tc_tun_check_udp_dport_vxlan(struct mlx5e_priv *priv,
+                                             struct tc_cls_flower_offload *f)
+{
+       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+       struct netlink_ext_ack *extack = f->common.extack;
+       struct flow_match_ports enc_ports;
+
+       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS))
+               return -EOPNOTSUPP;
+
+       flow_rule_match_enc_ports(rule, &enc_ports);
+
+       /* check the UDP destination port validity */
+
+       if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan,
+                                   be16_to_cpu(enc_ports.key->dst))) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Matched UDP dst port is not registered as a VXLAN port");
+               netdev_warn(priv->netdev,
+                           "UDP port %d is not registered as a VXLAN port\n",
+                           be16_to_cpu(enc_ports.key->dst));
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int mlx5e_tc_tun_parse_udp_ports_vxlan(struct mlx5e_priv *priv,
+                                             struct mlx5_flow_spec *spec,
+                                             struct tc_cls_flower_offload *f,
+                                             void *headers_c,
+                                             void *headers_v)
+{
+       int err = 0;
+
+       err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
+       if (err)
+               return err;
+
+       return mlx5e_tc_tun_check_udp_dport_vxlan(priv, f);
+}
+
+static int mlx5e_tc_tun_init_encap_attr_vxlan(struct net_device *tunnel_dev,
+                                             struct mlx5e_priv *priv,
+                                             struct mlx5e_encap_entry *e,
+                                             struct netlink_ext_ack *extack)
+{
+       int dst_port = be16_to_cpu(e->tun_info->key.tp_dst);
+
+       e->tunnel = &vxlan_tunnel;
+
+       if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "vxlan udp dport was not registered with the HW");
+               netdev_warn(priv->netdev,
+                           "%d isn't an offloaded vxlan udp dport\n",
+                           dst_port);
+               return -EOPNOTSUPP;
+       }
+
+       e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
+       return 0;
+}
+
+static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
+                                           __u8 *ip_proto,
+                                           struct mlx5e_encap_entry *e)
+{
+       const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+       __be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
+       struct udphdr *udp = (struct udphdr *)(buf);
+       struct vxlanhdr *vxh;
+
+       vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
+       *ip_proto = IPPROTO_UDP;
+
+       udp->dest = tun_key->tp_dst;
+       vxh->vx_flags = VXLAN_HF_VNI;
+       vxh->vx_vni = vxlan_vni_field(tun_id);
+
+       return 0;
+}
+
+static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
+                                   struct mlx5_flow_spec *spec,
+                                   struct tc_cls_flower_offload *f,
+                                   void *headers_c,
+                                   void *headers_v)
+{
+       struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
+       struct netlink_ext_ack *extack = f->common.extack;
+       struct flow_match_enc_keyid enc_keyid;
+       void *misc_c, *misc_v;
+
+       misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
+       misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
+
+       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
+               return 0;
+
+       flow_rule_match_enc_keyid(rule, &enc_keyid);
+
+       if (!enc_keyid.mask->keyid)
+               return 0;
+
+       /* match on VNI is required */
+
+       if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
+                                       ft_field_support.outer_vxlan_vni)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Matching on VXLAN VNI is not supported");
+               netdev_warn(priv->netdev,
+                           "Matching on VXLAN VNI is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
+                be32_to_cpu(enc_keyid.mask->keyid));
+       MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
+                be32_to_cpu(enc_keyid.key->keyid));
+
+       return 0;
+}
+
+struct mlx5e_tc_tunnel vxlan_tunnel = {
+       .tunnel_type          = MLX5E_TC_TUNNEL_TYPE_VXLAN,
+       .match_level          = MLX5_MATCH_L4,
+       .can_offload          = mlx5e_tc_tun_can_offload_vxlan,
+       .calc_hlen            = mlx5e_tc_tun_calc_hlen_vxlan,
+       .init_encap_attr      = mlx5e_tc_tun_init_encap_attr_vxlan,
+       .generate_ip_tun_hdr  = mlx5e_gen_ip_tunnel_header_vxlan,
+       .parse_udp_ports      = mlx5e_tc_tun_parse_udp_ports_vxlan,
+       .parse_tunnel         = mlx5e_tc_tun_parse_vxlan,
+};
index 5472bb4..d4585f3 100644 (file)
@@ -155,8 +155,7 @@ struct mlx5e_encap_entry {
 
        struct net_device *out_dev;
        struct net_device *route_dev;
-       int tunnel_type;
-       int tunnel_hlen;
+       struct mlx5e_tc_tunnel *tunnel;
        int reformat_type;
        u8 flags;
        char *encap_header;
index 8b06c98..915f0ab 100644 (file)
@@ -2569,20 +2569,20 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
 
 struct encap_key {
        const struct ip_tunnel_key *ip_tun_key;
-       int tunnel_type;
+       struct mlx5e_tc_tunnel *tc_tunnel;
 };
 
 static inline int cmp_encap_info(struct encap_key *a,
                                 struct encap_key *b)
 {
        return memcmp(a->ip_tun_key, b->ip_tun_key, sizeof(*a->ip_tun_key)) ||
-              a->tunnel_type != b->tunnel_type;
+              a->tc_tunnel->tunnel_type != b->tc_tunnel->tunnel_type;
 }
 
 static inline int hash_encap_info(struct encap_key *key)
 {
        return jhash(key->ip_tun_key, sizeof(*key->ip_tun_key),
-                    key->tunnel_type);
+                    key->tc_tunnel->tunnel_type);
 }
 
 
@@ -2624,14 +2624,14 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
        tun_info = parse_attr->tun_info[out_index];
        family = ip_tunnel_info_af(tun_info);
        key.ip_tun_key = &tun_info->key;
-       key.tunnel_type = mlx5e_tc_tun_get_type(mirred_dev);
+       key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
 
        hash_key = hash_encap_info(&key);
 
        hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
                                   encap_hlist, hash_key) {
                e_key.ip_tun_key = &e->tun_info->key;
-               e_key.tunnel_type = e->tunnel_type;
+               e_key.tc_tunnel = e->tunnel;
                if (!cmp_encap_info(&e_key, &key)) {
                        found = true;
                        break;