mlxsw: spectrum_fid: Allow setting and clearing NVE properties on FID
authorIdo Schimmel <idosch@mellanox.com>
Wed, 17 Oct 2018 08:53:03 +0000 (08:53 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 18 Oct 2018 00:45:07 +0000 (17:45 -0700)
In the device, the VNI and the list of remote VTEPs a packet should be
flooded to is a property of the filtering identifier (FID).

During encapsulation, the VNI is taken from the FID the packet was
classified to. During decapsulation, the overlay packet is injected into
a bridge and classified to a FID based on the VNI it came with.

Allow NVE configuration for a FID. Currently, this is only supported
with 802.1D FIDs which are used for VLAN-unaware bridges. However, NVE
configuration is going to be supported with 802.1Q FIDs which is why the
related fields are placed in the common FID struct.

Since the device requires a 1:1 mapping between FID and VNI, the driver
maintains a hashtable keyed by VNI and checks if the VNI is already
associated with an existing FID.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c

index 1f68ac2..7f96953 100644 (file)
@@ -679,6 +679,14 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
                           struct tc_prio_qopt_offload *p);
 
 /* spectrum_fid.c */
+int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni);
+int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+                                    u32 nve_flood_index);
+void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid);
+bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid);
+int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni);
+void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid);
+bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid);
 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
                           enum mlxsw_sp_flood_type packet_type, u8 local_port,
                           bool member);
index 715d24f..7e07cf3 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/if_vlan.h>
 #include <linux/if_bridge.h>
 #include <linux/netdevice.h>
+#include <linux/rhashtable.h>
 #include <linux/rtnetlink.h>
 
 #include "spectrum.h"
@@ -14,6 +15,7 @@
 struct mlxsw_sp_fid_family;
 
 struct mlxsw_sp_fid_core {
+       struct rhashtable vni_ht;
        struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
        unsigned int *port_fid_mappings;
 };
@@ -24,6 +26,12 @@ struct mlxsw_sp_fid {
        unsigned int ref_count;
        u16 fid_index;
        struct mlxsw_sp_fid_family *fid_family;
+
+       struct rhash_head vni_ht_node;
+       __be32 vni;
+       u32 nve_flood_index;
+       u8 vni_valid:1,
+          nve_flood_index_valid:1;
 };
 
 struct mlxsw_sp_fid_8021q {
@@ -36,6 +44,12 @@ struct mlxsw_sp_fid_8021d {
        int br_ifindex;
 };
 
+static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
+       .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
+       .key_offset = offsetof(struct mlxsw_sp_fid, vni),
+       .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
+};
+
 struct mlxsw_sp_flood_table {
        enum mlxsw_sp_flood_type packet_type;
        enum mlxsw_reg_sfgc_bridge_type bridge_type;
@@ -56,6 +70,11 @@ struct mlxsw_sp_fid_ops {
                            struct mlxsw_sp_port *port, u16 vid);
        void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
                               struct mlxsw_sp_port *port, u16 vid);
+       int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
+       void (*vni_clear)(struct mlxsw_sp_fid *fid);
+       int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
+                                  u32 nve_flood_index);
+       void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
 };
 
 struct mlxsw_sp_fid_family {
@@ -94,6 +113,104 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = {
        [MLXSW_SP_FLOOD_TYPE_MC]        = mlxsw_sp_sfgc_mc_packet_types,
 };
 
+int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
+{
+       if (!fid->vni_valid)
+               return -EINVAL;
+
+       *vni = fid->vni;
+
+       return 0;
+}
+
+int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+                                    u32 nve_flood_index)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+       const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+       int err;
+
+       if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
+               return -EINVAL;
+
+       err = ops->nve_flood_index_set(fid, nve_flood_index);
+       if (err)
+               return err;
+
+       fid->nve_flood_index = nve_flood_index;
+       fid->nve_flood_index_valid = true;
+
+       return 0;
+}
+
+void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+       const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+
+       if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
+               return;
+
+       fid->nve_flood_index_valid = false;
+       ops->nve_flood_index_clear(fid);
+}
+
+bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
+{
+       return fid->nve_flood_index_valid;
+}
+
+int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+       const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+       struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+       int err;
+
+       if (WARN_ON(!ops->vni_set || fid->vni_valid))
+               return -EINVAL;
+
+       fid->vni = vni;
+       err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
+                                           &fid->vni_ht_node,
+                                           mlxsw_sp_fid_vni_ht_params);
+       if (err)
+               return err;
+
+       err = ops->vni_set(fid, vni);
+       if (err)
+               goto err_vni_set;
+
+       fid->vni_valid = true;
+
+       return 0;
+
+err_vni_set:
+       rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
+                              mlxsw_sp_fid_vni_ht_params);
+       return err;
+}
+
+void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+       const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+       struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+
+       if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
+               return;
+
+       fid->vni_valid = false;
+       ops->vni_clear(fid);
+       rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
+                              mlxsw_sp_fid_vni_ht_params);
+}
+
+bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
+{
+       return fid->vni_valid;
+}
+
 static const struct mlxsw_sp_flood_table *
 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
                                enum mlxsw_sp_flood_type packet_type)
@@ -217,6 +334,21 @@ static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
+static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+                              __be32 vni, bool vni_valid, u32 nve_flood_index,
+                              bool nve_flood_index_valid)
+{
+       char sfmr_pl[MLXSW_REG_SFMR_LEN];
+
+       mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
+                           0);
+       mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
+       mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
+       mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
+       mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
+}
+
 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
                                u16 vid, bool valid)
 {
@@ -531,6 +663,41 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
                                    mlxsw_sp_port->local_port, vid, false);
 }
 
+static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+       return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
+                                  true, fid->nve_flood_index,
+                                  fid->nve_flood_index_valid);
+}
+
+static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+       mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
+                           fid->nve_flood_index, fid->nve_flood_index_valid);
+}
+
+static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+                                                 u32 nve_flood_index)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+       return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
+                                  fid->vni, fid->vni_valid, nve_flood_index,
+                                  true);
+}
+
+static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+       mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
+                           fid->vni_valid, 0, false);
+}
+
 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
        .setup                  = mlxsw_sp_fid_8021d_setup,
        .configure              = mlxsw_sp_fid_8021d_configure,
@@ -540,6 +707,10 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
        .flood_index            = mlxsw_sp_fid_8021d_flood_index,
        .port_vid_map           = mlxsw_sp_fid_8021d_port_vid_map,
        .port_vid_unmap         = mlxsw_sp_fid_8021d_port_vid_unmap,
+       .vni_set                = mlxsw_sp_fid_8021d_vni_set,
+       .vni_clear              = mlxsw_sp_fid_8021d_vni_clear,
+       .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
+       .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
 };
 
 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
@@ -918,6 +1089,10 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
                return -ENOMEM;
        mlxsw_sp->fid_core = fid_core;
 
+       err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
+       if (err)
+               goto err_rhashtable_init;
+
        fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
                                              GFP_KERNEL);
        if (!fid_core->port_fid_mappings) {
@@ -944,6 +1119,8 @@ err_fid_ops_register:
        }
        kfree(fid_core->port_fid_mappings);
 err_alloc_port_fid_mappings:
+       rhashtable_destroy(&fid_core->vni_ht);
+err_rhashtable_init:
        kfree(fid_core);
        return err;
 }
@@ -957,5 +1134,6 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
                mlxsw_sp_fid_family_unregister(mlxsw_sp,
                                               fid_core->fid_family_arr[i]);
        kfree(fid_core->port_fid_mappings);
+       rhashtable_destroy(&fid_core->vni_ht);
        kfree(fid_core);
 }