Skip to content

Commit

Permalink
Merge branch 'mlxsw-Add-VxLAN-learning-support'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
mlxsw: Add VxLAN learning support

This patchset adds VxLAN learning support in the mlxsw driver.

The first five patches from Petr add the required switchdev APIs which
allow device drivers to notify the VxLAN driver about learned / aged-out
FDB entries.

First in patch #1, an unnecessary argument is dropped from
__vxlan_fdb_delete().

In patches #2-#4, the VxLAN FDB handling code is extended to make
sending the switchdev events configurable; to mark user-added entries as
such; and to make sure HW-learned FDB entries do not take over
user-added ones.

Finally in patch #5, the necessary switchdev notifications are added and
handled by VxLAN, similarly to how this is handled in the bridge driver.

Patch #6 allows changing of the VxLAN's device ageing time since it is
useful for the selftest in the last patch.

Patch #7 adds support for querying bridge port flags of a given
netdevice, as a new entry should not be learned and notified to the
bridge driver in case learning is disabled on the bridge port.

Next patches gradually add learning support in mlxsw.

The last patch adds a new test case for VxLAN learning.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 22, 2018
2 parents d59da3f + c39c56a commit f072df9
Show file tree
Hide file tree
Showing 13 changed files with 606 additions and 75 deletions.
64 changes: 64 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,10 @@ enum mlxsw_reg_sfn_rec_type {
MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC = 0x7,
/* Aged-out MAC address on a LAG port. */
MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG = 0x8,
/* Learned unicast tunnel record. */
MLXSW_REG_SFN_REC_TYPE_LEARNED_UNICAST_TUNNEL = 0xD,
/* Aged-out unicast tunnel record. */
MLXSW_REG_SFN_REC_TYPE_AGED_OUT_UNICAST_TUNNEL = 0xE,
};

/* reg_sfn_rec_type
Expand Down Expand Up @@ -704,6 +708,66 @@ static inline void mlxsw_reg_sfn_mac_lag_unpack(char *payload, int rec_index,
*p_lag_id = mlxsw_reg_sfn_mac_lag_lag_id_get(payload, rec_index);
}

/* reg_sfn_uc_tunnel_uip_msb
* When protocol is IPv4, the most significant byte of the underlay IPv4
* address of the remote VTEP.
* When protocol is IPv6, reserved.
* Access: RO
*/
MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_msb, MLXSW_REG_SFN_BASE_LEN, 24,
8, MLXSW_REG_SFN_REC_LEN, 0x08, false);

enum mlxsw_reg_sfn_uc_tunnel_protocol {
MLXSW_REG_SFN_UC_TUNNEL_PROTOCOL_IPV4,
MLXSW_REG_SFN_UC_TUNNEL_PROTOCOL_IPV6,
};

/* reg_sfn_uc_tunnel_protocol
* IP protocol.
* Access: RO
*/
MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_protocol, MLXSW_REG_SFN_BASE_LEN, 27,
1, MLXSW_REG_SFN_REC_LEN, 0x0C, false);

/* reg_sfn_uc_tunnel_uip_lsb
* When protocol is IPv4, the least significant bytes of the underlay
* IPv4 address of the remote VTEP.
* When protocol is IPv6, ipv6_id to be queried from TNIPSD.
* Access: RO
*/
MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_lsb, MLXSW_REG_SFN_BASE_LEN, 0,
24, MLXSW_REG_SFN_REC_LEN, 0x0C, false);

enum mlxsw_reg_sfn_tunnel_port {
MLXSW_REG_SFN_TUNNEL_PORT_NVE,
MLXSW_REG_SFN_TUNNEL_PORT_VPLS,
MLXSW_REG_SFN_TUNNEL_FLEX_TUNNEL0,
MLXSW_REG_SFN_TUNNEL_FLEX_TUNNEL1,
};

/* reg_sfn_uc_tunnel_port
* Tunnel port.
* Reserved on Spectrum.
* Access: RO
*/
MLXSW_ITEM32_INDEXED(reg, sfn, tunnel_port, MLXSW_REG_SFN_BASE_LEN, 0, 4,
MLXSW_REG_SFN_REC_LEN, 0x10, false);

static inline void
mlxsw_reg_sfn_uc_tunnel_unpack(char *payload, int rec_index, char *mac,
u16 *p_fid, u32 *p_uip,
enum mlxsw_reg_sfn_uc_tunnel_protocol *p_proto)
{
u32 uip_msb, uip_lsb;

mlxsw_reg_sfn_rec_mac_memcpy_from(payload, rec_index, mac);
*p_fid = mlxsw_reg_sfn_mac_fid_get(payload, rec_index);
uip_msb = mlxsw_reg_sfn_uc_tunnel_uip_msb_get(payload, rec_index);
uip_lsb = mlxsw_reg_sfn_uc_tunnel_uip_lsb_get(payload, rec_index);
*p_uip = uip_msb << 24 | uip_lsb;
*p_proto = mlxsw_reg_sfn_uc_tunnel_protocol_get(payload, rec_index);
}

/* SPMS - Switch Port MSTP/RSTP State Register
* -------------------------------------------
* Configures the spanning tree state of a physical port.
Expand Down
8 changes: 7 additions & 1 deletion drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,14 +721,17 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_prio_qopt_offload *p);

/* spectrum_fid.c */
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
u16 fid_index);
int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex);
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
__be32 vni);
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);
int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni, int nve_ifindex);
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,
Expand Down Expand Up @@ -810,6 +813,9 @@ struct mlxsw_sp_nve_params {
extern const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[];
extern const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[];

int mlxsw_sp_nve_learned_ip_resolve(struct mlxsw_sp *mlxsw_sp, u32 uip,
enum mlxsw_sp_l3proto proto,
union mlxsw_sp_l3addr *addr);
int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fid *fid,
enum mlxsw_sp_l3proto proto,
Expand Down
56 changes: 53 additions & 3 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
struct mlxsw_sp_fid_family;

struct mlxsw_sp_fid_core {
struct rhashtable fid_ht;
struct rhashtable vni_ht;
struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
unsigned int *port_fid_mappings;
Expand All @@ -26,10 +27,12 @@ struct mlxsw_sp_fid {
unsigned int ref_count;
u16 fid_index;
struct mlxsw_sp_fid_family *fid_family;
struct rhash_head ht_node;

struct rhash_head vni_ht_node;
__be32 vni;
u32 nve_flood_index;
int nve_ifindex;
u8 vni_valid:1,
nve_flood_index_valid:1;
};
Expand All @@ -44,6 +47,12 @@ struct mlxsw_sp_fid_8021d {
int br_ifindex;
};

static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
};

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),
Expand Down Expand Up @@ -113,6 +122,29 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = {
[MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
};

struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
u16 fid_index)
{
struct mlxsw_sp_fid *fid;

fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
mlxsw_sp_fid_ht_params);
if (fid)
fid->ref_count++;

return fid;
}

int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
{
if (!fid->vni_valid)
return -EINVAL;

*nve_ifindex = fid->nve_ifindex;

return 0;
}

struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
__be32 vni)
{
Expand Down Expand Up @@ -173,7 +205,7 @@ 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)
int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni, int nve_ifindex)
{
struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
Expand All @@ -183,6 +215,7 @@ int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
if (WARN_ON(!ops->vni_set || fid->vni_valid))
return -EINVAL;

fid->nve_ifindex = nve_ifindex;
fid->vni = vni;
err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
&fid->vni_ht_node,
Expand Down Expand Up @@ -944,10 +977,17 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_configure;

err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
mlxsw_sp_fid_ht_params);
if (err)
goto err_rhashtable_insert;

list_add(&fid->list, &fid_family->fids_list);
fid->ref_count++;
return fid;

err_rhashtable_insert:
fid->fid_family->ops->deconfigure(fid);
err_configure:
__clear_bit(fid_index - fid_family->start_index,
fid_family->fids_bitmap);
Expand All @@ -959,6 +999,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
{
struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;

if (--fid->ref_count == 1 && fid->rif) {
/* Destroy the associated RIF and let it drop the last
Expand All @@ -967,6 +1008,8 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
return mlxsw_sp_rif_destroy(fid->rif);
} else if (fid->ref_count == 0) {
list_del(&fid->list);
rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
&fid->ht_node, mlxsw_sp_fid_ht_params);
fid->fid_family->ops->deconfigure(fid);
__clear_bit(fid->fid_index - fid_family->start_index,
fid_family->fids_bitmap);
Expand Down Expand Up @@ -1126,9 +1169,13 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
return -ENOMEM;
mlxsw_sp->fid_core = fid_core;

err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
if (err)
goto err_rhashtable_fid_init;

err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
if (err)
goto err_rhashtable_init;
goto err_rhashtable_vni_init;

fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
GFP_KERNEL);
Expand Down Expand Up @@ -1157,7 +1204,9 @@ 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:
err_rhashtable_vni_init:
rhashtable_destroy(&fid_core->fid_ht);
err_rhashtable_fid_init:
kfree(fid_core);
return err;
}
Expand All @@ -1172,5 +1221,6 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
fid_core->fid_family_arr[i]);
kfree(fid_core->port_fid_mappings);
rhashtable_destroy(&fid_core->vni_ht);
rhashtable_destroy(&fid_core->fid_ht);
kfree(fid_core);
}
16 changes: 15 additions & 1 deletion drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,20 @@ mlxsw_sp_nve_mc_record_ops_arr[] = {
[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_nve_mc_record_ipv6_ops,
};

int mlxsw_sp_nve_learned_ip_resolve(struct mlxsw_sp *mlxsw_sp, u32 uip,
enum mlxsw_sp_l3proto proto,
union mlxsw_sp_l3addr *addr)
{
switch (proto) {
case MLXSW_SP_L3_PROTO_IPV4:
addr->addr4 = cpu_to_be32(uip);
return 0;
default:
WARN_ON(1);
return -EINVAL;
}
}

static struct mlxsw_sp_nve_mc_list *
mlxsw_sp_nve_mc_list_find(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_nve_mc_list_key *key)
Expand Down Expand Up @@ -803,7 +817,7 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
return err;
}

err = mlxsw_sp_fid_vni_set(fid, params->vni);
err = mlxsw_sp_fid_vni_set(fid, params->vni, params->dev->ifindex);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to set VNI on FID");
goto err_fid_vni_set;
Expand Down
8 changes: 2 additions & 6 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
#define MLXSW_SP_NVE_VXLAN_PARSING_DEPTH 128
#define MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH 96

#define MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS VXLAN_F_UDP_ZERO_CSUM_TX
#define MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS (VXLAN_F_UDP_ZERO_CSUM_TX | \
VXLAN_F_LEARN)

static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
const struct net_device *dev,
Expand Down Expand Up @@ -61,11 +62,6 @@ static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
return false;
}

if (cfg->flags & VXLAN_F_LEARN) {
NL_SET_ERR_MSG_MOD(extack, "VxLAN: Learning is not supported");
return false;
}

if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) {
NL_SET_ERR_MSG_MOD(extack, "VxLAN: UDP checksum is not supported");
return false;
Expand Down
Loading

0 comments on commit f072df9

Please sign in to comment.