mirror of https://gitee.com/openkylin/linux.git
mlxsw: spectrum_fid: Allow setting and clearing NVE properties on FID
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>
This commit is contained in:
parent
aadd435591
commit
d3d19d4b8c
|
@ -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);
|
||||
|
|
|
@ -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 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue