Commit 41a63517 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-Add-support-for-Q-in-VNI'

Ido Schimmel says:

====================
mlxsw: Add support for Q-in-VNI

This patch set adds support for Q-in-VNI over Spectrum-{2,3} ASICs.
Q-in-VNI is like regular VxLAN encapsulation with the sole difference
that overlay packets can contain a VLAN tag. In Linux, this is achieved
by adding the VxLAN device to a 802.1ad bridge instead of a 802.1q
bridge.

From mlxsw perspective, Q-in-VNI support entails two main changes:

1. An outer VLAN tag should always be pushed to the overlay packet
during decapsulation

2. The EtherType used during decapsulation should be 802.1ad (0x88a8)
instead of the default 802.1q (0x8100)

Patch set overview:

Patches #1-#3 add required device registers and fields

Patch #4 performs small refactoring to allow code re-use

Patches #5-#7 make the EtherType used during decapsulation a property of
the tunnel port (i.e., VxLAN). This leads to the driver vetoing
configurations in which VxLAN devices are member in both 802.1ad and
802.1q/802.1d bridges. Will be handled in the future by determining the
overlay EtherType on the egress port instead

Patch #8 adds support for Q-in-VNI for Spectrum-2 and newer ASICs

Patches #9-#10 veto Q-in-VNI for Spectrum-1 ASICs due to some hardware
limitations. Can be worked around, but decided not to support it for now

Patch #11 adjusts mlxsw to stop vetoing addition of VXLAN devices to
802.1ad bridges

Patch #12 adds a generic forwarding test that can be used with both veth
pairs and physical ports with a loopback

Patch #13 adds a test to make sure mlxsw vetoes unsupported Q-in-VNI
configurations
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a8d5dd19 477ce6d9
...@@ -581,6 +581,13 @@ mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index, ...@@ -581,6 +581,13 @@ mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index,
mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto); mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto);
} }
enum mlxsw_reg_tunnel_port {
MLXSW_REG_TUNNEL_PORT_NVE,
MLXSW_REG_TUNNEL_PORT_VPLS,
MLXSW_REG_TUNNEL_PORT_FLEX_TUNNEL0,
MLXSW_REG_TUNNEL_PORT_FLEX_TUNNEL1,
};
/* SFN - Switch FDB Notification Register /* SFN - Switch FDB Notification Register
* ------------------------------------------- * -------------------------------------------
* The switch provides notifications on newly learned FDB entries and * The switch provides notifications on newly learned FDB entries and
...@@ -738,13 +745,6 @@ MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_protocol, MLXSW_REG_SFN_BASE_LEN, 27, ...@@ -738,13 +745,6 @@ MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_protocol, MLXSW_REG_SFN_BASE_LEN, 27,
MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_lsb, MLXSW_REG_SFN_BASE_LEN, 0, MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_lsb, MLXSW_REG_SFN_BASE_LEN, 0,
24, MLXSW_REG_SFN_REC_LEN, 0x0C, false); 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 /* reg_sfn_uc_tunnel_port
* Tunnel port. * Tunnel port.
* Reserved on Spectrum. * Reserved on Spectrum.
...@@ -821,8 +821,16 @@ static inline void mlxsw_reg_spms_vid_pack(char *payload, u16 vid, ...@@ -821,8 +821,16 @@ static inline void mlxsw_reg_spms_vid_pack(char *payload, u16 vid,
MLXSW_REG_DEFINE(spvid, MLXSW_REG_SPVID_ID, MLXSW_REG_SPVID_LEN); MLXSW_REG_DEFINE(spvid, MLXSW_REG_SPVID_ID, MLXSW_REG_SPVID_LEN);
/* reg_spvid_tport
* Port is tunnel port.
* Reserved when SwitchX/-2 or Spectrum-1.
* Access: Index
*/
MLXSW_ITEM32(reg, spvid, tport, 0x00, 24, 1);
/* reg_spvid_local_port /* reg_spvid_local_port
* Local port number. * When tport = 0: Local port number. Not supported for CPU port.
* When tport = 1: Tunnel port.
* Access: Index * Access: Index
*/ */
MLXSW_ITEM32(reg, spvid, local_port, 0x00, 16, 8); MLXSW_ITEM32(reg, spvid, local_port, 0x00, 16, 8);
...@@ -1693,6 +1701,109 @@ static inline void mlxsw_reg_svfa_pack(char *payload, u8 local_port, ...@@ -1693,6 +1701,109 @@ static inline void mlxsw_reg_svfa_pack(char *payload, u8 local_port,
mlxsw_reg_svfa_vid_set(payload, vid); mlxsw_reg_svfa_vid_set(payload, vid);
} }
/* SPVTR - Switch Port VLAN Stacking Register
* ------------------------------------------
* The Switch Port VLAN Stacking register configures the VLAN mode of the port
* to enable VLAN stacking.
*/
#define MLXSW_REG_SPVTR_ID 0x201D
#define MLXSW_REG_SPVTR_LEN 0x10
MLXSW_REG_DEFINE(spvtr, MLXSW_REG_SPVTR_ID, MLXSW_REG_SPVTR_LEN);
/* reg_spvtr_tport
* Port is tunnel port.
* Access: Index
*
* Note: Reserved when SwitchX/-2 or Spectrum-1.
*/
MLXSW_ITEM32(reg, spvtr, tport, 0x00, 24, 1);
/* reg_spvtr_local_port
* When tport = 0: local port number (Not supported from/to CPU).
* When tport = 1: tunnel port.
* Access: Index
*/
MLXSW_ITEM32(reg, spvtr, local_port, 0x00, 16, 8);
/* reg_spvtr_ippe
* Ingress Port Prio Mode Update Enable.
* When set, the Port Prio Mode is updated with the provided ipprio_mode field.
* Reserved on Get operations.
* Access: OP
*/
MLXSW_ITEM32(reg, spvtr, ippe, 0x04, 31, 1);
/* reg_spvtr_ipve
* Ingress Port VID Mode Update Enable.
* When set, the Ingress Port VID Mode is updated with the provided ipvid_mode
* field.
* Reserved on Get operations.
* Access: OP
*/
MLXSW_ITEM32(reg, spvtr, ipve, 0x04, 30, 1);
/* reg_spvtr_epve
* Egress Port VID Mode Update Enable.
* When set, the Egress Port VID Mode is updated with the provided epvid_mode
* field.
* Access: OP
*/
MLXSW_ITEM32(reg, spvtr, epve, 0x04, 29, 1);
/* reg_spvtr_ipprio_mode
* Ingress Port Priority Mode.
* This controls the PCP and DEI of the new outer VLAN
* Note: for SwitchX/-2 the DEI is not affected.
* 0: use port default PCP and DEI (configured by QPDPC).
* 1: use C-VLAN PCP and DEI.
* Has no effect when ipvid_mode = 0.
* Reserved when tport = 1.
* Access: RW
*/
MLXSW_ITEM32(reg, spvtr, ipprio_mode, 0x04, 20, 4);
enum mlxsw_reg_spvtr_ipvid_mode {
/* IEEE Compliant PVID (default) */
MLXSW_REG_SPVTR_IPVID_MODE_IEEE_COMPLIANT_PVID,
/* Push VLAN (for VLAN stacking, except prio tagged packets) */
MLXSW_REG_SPVTR_IPVID_MODE_PUSH_VLAN_FOR_UNTAGGED_PACKET,
/* Always push VLAN (also for prio tagged packets) */
MLXSW_REG_SPVTR_IPVID_MODE_ALWAYS_PUSH_VLAN,
};
/* reg_spvtr_ipvid_mode
* Ingress Port VLAN-ID Mode.
* For Spectrum family, this affects the values of SPVM.i
* Access: RW
*/
MLXSW_ITEM32(reg, spvtr, ipvid_mode, 0x04, 16, 4);
enum mlxsw_reg_spvtr_epvid_mode {
/* IEEE Compliant VLAN membership */
MLXSW_REG_SPVTR_EPVID_MODE_IEEE_COMPLIANT_VLAN_MEMBERSHIP,
/* Pop VLAN (for VLAN stacking) */
MLXSW_REG_SPVTR_EPVID_MODE_POP_VLAN,
};
/* reg_spvtr_epvid_mode
* Egress Port VLAN-ID Mode.
* For Spectrum family, this affects the values of SPVM.e,u,pt.
* Access: WO
*/
MLXSW_ITEM32(reg, spvtr, epvid_mode, 0x04, 0, 4);
static inline void mlxsw_reg_spvtr_pack(char *payload, bool tport,
u8 local_port,
enum mlxsw_reg_spvtr_ipvid_mode ipvid_mode)
{
MLXSW_REG_ZERO(spvtr, payload);
mlxsw_reg_spvtr_tport_set(payload, tport);
mlxsw_reg_spvtr_local_port_set(payload, local_port);
mlxsw_reg_spvtr_ipvid_mode_set(payload, ipvid_mode);
mlxsw_reg_spvtr_ipve_set(payload, true);
}
/* SVPE - Switch Virtual-Port Enabling Register /* SVPE - Switch Virtual-Port Enabling Register
* -------------------------------------------- * --------------------------------------------
* Enables port virtualization. * Enables port virtualization.
...@@ -10507,13 +10618,6 @@ enum mlxsw_reg_tnumt_record_type { ...@@ -10507,13 +10618,6 @@ enum mlxsw_reg_tnumt_record_type {
*/ */
MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4); MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4);
enum mlxsw_reg_tnumt_tunnel_port {
MLXSW_REG_TNUMT_TUNNEL_PORT_NVE,
MLXSW_REG_TNUMT_TUNNEL_PORT_VPLS,
MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL0,
MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL1,
};
/* reg_tnumt_tunnel_port /* reg_tnumt_tunnel_port
* Tunnel port. * Tunnel port.
* Access: RW * Access: RW
...@@ -10561,7 +10665,7 @@ MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false); ...@@ -10561,7 +10665,7 @@ MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false);
static inline void mlxsw_reg_tnumt_pack(char *payload, static inline void mlxsw_reg_tnumt_pack(char *payload,
enum mlxsw_reg_tnumt_record_type type, enum mlxsw_reg_tnumt_record_type type,
enum mlxsw_reg_tnumt_tunnel_port tport, enum mlxsw_reg_tunnel_port tport,
u32 underlay_mc_ptr, bool vnext, u32 underlay_mc_ptr, bool vnext,
u32 next_underlay_mc_ptr, u32 next_underlay_mc_ptr,
u8 record_size) u8 record_size)
...@@ -10725,13 +10829,6 @@ static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn, ...@@ -10725,13 +10829,6 @@ static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn,
MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN); MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN);
enum mlxsw_reg_tnpc_tunnel_port {
MLXSW_REG_TNPC_TUNNEL_PORT_NVE,
MLXSW_REG_TNPC_TUNNEL_PORT_VPLS,
MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL0,
MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL1,
};
/* reg_tnpc_tunnel_port /* reg_tnpc_tunnel_port
* Tunnel port. * Tunnel port.
* Access: Index * Access: Index
...@@ -10751,7 +10848,7 @@ MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1); ...@@ -10751,7 +10848,7 @@ MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1);
MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1); MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1);
static inline void mlxsw_reg_tnpc_pack(char *payload, static inline void mlxsw_reg_tnpc_pack(char *payload,
enum mlxsw_reg_tnpc_tunnel_port tport, enum mlxsw_reg_tunnel_port tport,
bool learn_enable) bool learn_enable)
{ {
MLXSW_REG_ZERO(tnpc, payload); MLXSW_REG_ZERO(tnpc, payload);
...@@ -11320,6 +11417,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { ...@@ -11320,6 +11417,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(slcor), MLXSW_REG(slcor),
MLXSW_REG(spmlr), MLXSW_REG(spmlr),
MLXSW_REG(svfa), MLXSW_REG(svfa),
MLXSW_REG(spvtr),
MLXSW_REG(svpe), MLXSW_REG(svpe),
MLXSW_REG(sfmr), MLXSW_REG(sfmr),
MLXSW_REG(spvmlr), MLXSW_REG(spvmlr),
......
...@@ -384,7 +384,7 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, ...@@ -384,7 +384,7 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
return err; return err;
} }
static int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type) int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type)
{ {
switch (ethtype) { switch (ethtype) {
case ETH_P_8021Q: case ETH_P_8021Q:
......
...@@ -584,6 +584,7 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, ...@@ -584,6 +584,7 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable); int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable);
int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
bool learn_enable); bool learn_enable);
int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type);
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
u16 ethtype); u16 ethtype);
struct mlxsw_sp_port_vlan * struct mlxsw_sp_port_vlan *
...@@ -1202,6 +1203,7 @@ struct mlxsw_sp_nve_params { ...@@ -1202,6 +1203,7 @@ struct mlxsw_sp_nve_params {
enum mlxsw_sp_nve_type type; enum mlxsw_sp_nve_type type;
__be32 vni; __be32 vni;
const struct net_device *dev; const struct net_device *dev;
u16 ethertype;
}; };
extern const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[]; extern const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[];
......
...@@ -368,7 +368,7 @@ mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record) ...@@ -368,7 +368,7 @@ mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record)
next_valid = true; next_valid = true;
} }
mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TNUMT_TUNNEL_PORT_NVE, mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TUNNEL_PORT_NVE,
mc_record->kvdl_index, next_valid, mc_record->kvdl_index, next_valid,
next_kvdl_index, mc_record->num_entries); next_kvdl_index, mc_record->num_entries);
...@@ -798,11 +798,11 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, ...@@ -798,11 +798,11 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
ops = nve->nve_ops_arr[params->type]; ops = nve->nve_ops_arr[params->type];
if (!ops->can_offload(nve, params->dev, extack)) if (!ops->can_offload(nve, params, extack))
return -EINVAL; return -EINVAL;
memset(&config, 0, sizeof(config)); memset(&config, 0, sizeof(config));
ops->nve_config(nve, params->dev, &config); ops->nve_config(nve, params, &config);
if (nve->num_nve_tunnels && if (nve->num_nve_tunnels &&
memcmp(&config, &nve->config, sizeof(config))) { memcmp(&config, &nve->config, sizeof(config))) {
NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration"); NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration");
......
...@@ -18,6 +18,7 @@ struct mlxsw_sp_nve_config { ...@@ -18,6 +18,7 @@ struct mlxsw_sp_nve_config {
u32 ul_tb_id; u32 ul_tb_id;
enum mlxsw_sp_l3proto ul_proto; enum mlxsw_sp_l3proto ul_proto;
union mlxsw_sp_l3addr ul_sip; union mlxsw_sp_l3addr ul_sip;
u16 ethertype;
}; };
struct mlxsw_sp_nve { struct mlxsw_sp_nve {
...@@ -35,10 +36,10 @@ struct mlxsw_sp_nve { ...@@ -35,10 +36,10 @@ struct mlxsw_sp_nve {
struct mlxsw_sp_nve_ops { struct mlxsw_sp_nve_ops {
enum mlxsw_sp_nve_type type; enum mlxsw_sp_nve_type type;
bool (*can_offload)(const struct mlxsw_sp_nve *nve, bool (*can_offload)(const struct mlxsw_sp_nve *nve,
const struct net_device *dev, const struct mlxsw_sp_nve_params *params,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
void (*nve_config)(const struct mlxsw_sp_nve *nve, void (*nve_config)(const struct mlxsw_sp_nve *nve,
const struct net_device *dev, const struct mlxsw_sp_nve_params *params,
struct mlxsw_sp_nve_config *config); struct mlxsw_sp_nve_config *config);
int (*init)(struct mlxsw_sp_nve *nve, int (*init)(struct mlxsw_sp_nve *nve,
const struct mlxsw_sp_nve_config *config); const struct mlxsw_sp_nve_config *config);
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
VXLAN_F_LEARN) VXLAN_F_LEARN)
static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
const struct net_device *dev, const struct mlxsw_sp_nve_params *params,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_dev *vxlan = netdev_priv(params->dev);
struct vxlan_config *cfg = &vxlan->cfg; struct vxlan_config *cfg = &vxlan->cfg;
if (cfg->saddr.sa.sa_family != AF_INET) { if (cfg->saddr.sa.sa_family != AF_INET) {
...@@ -86,11 +86,23 @@ static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, ...@@ -86,11 +86,23 @@ static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
return true; return true;
} }
static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
const struct mlxsw_sp_nve_params *params,
struct netlink_ext_ack *extack)
{
if (params->ethertype == ETH_P_8021AD) {
NL_SET_ERR_MSG_MOD(extack, "VxLAN: 802.1ad bridge is not supported with VxLAN");
return false;
}
return mlxsw_sp_nve_vxlan_can_offload(nve, params, extack);
}
static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
const struct net_device *dev, const struct mlxsw_sp_nve_params *params,
struct mlxsw_sp_nve_config *config) struct mlxsw_sp_nve_config *config)
{ {
struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_dev *vxlan = netdev_priv(params->dev);
struct vxlan_config *cfg = &vxlan->cfg; struct vxlan_config *cfg = &vxlan->cfg;
config->type = MLXSW_SP_NVE_TYPE_VXLAN; config->type = MLXSW_SP_NVE_TYPE_VXLAN;
...@@ -101,6 +113,7 @@ static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, ...@@ -101,6 +113,7 @@ static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
config->ul_proto = MLXSW_SP_L3_PROTO_IPV4; config->ul_proto = MLXSW_SP_L3_PROTO_IPV4;
config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr; config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr;
config->udp_dport = cfg->dst_port; config->udp_dport = cfg->dst_port;
config->ethertype = params->ethertype;
} }
static int __mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp, static int __mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
...@@ -286,7 +299,7 @@ mlxsw_sp_nve_vxlan_clear_offload(const struct net_device *nve_dev, __be32 vni) ...@@ -286,7 +299,7 @@ mlxsw_sp_nve_vxlan_clear_offload(const struct net_device *nve_dev, __be32 vni)
const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = { const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = {
.type = MLXSW_SP_NVE_TYPE_VXLAN, .type = MLXSW_SP_NVE_TYPE_VXLAN,
.can_offload = mlxsw_sp_nve_vxlan_can_offload, .can_offload = mlxsw_sp1_nve_vxlan_can_offload,
.nve_config = mlxsw_sp_nve_vxlan_config, .nve_config = mlxsw_sp_nve_vxlan_config,
.init = mlxsw_sp1_nve_vxlan_init, .init = mlxsw_sp1_nve_vxlan_init,
.fini = mlxsw_sp1_nve_vxlan_fini, .fini = mlxsw_sp1_nve_vxlan_fini,
...@@ -299,16 +312,35 @@ static bool mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp, ...@@ -299,16 +312,35 @@ static bool mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp,
{ {
char tnpc_pl[MLXSW_REG_TNPC_LEN]; char tnpc_pl[MLXSW_REG_TNPC_LEN];
mlxsw_reg_tnpc_pack(tnpc_pl, MLXSW_REG_TNPC_TUNNEL_PORT_NVE, mlxsw_reg_tnpc_pack(tnpc_pl, MLXSW_REG_TUNNEL_PORT_NVE,
learning_en); learning_en);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnpc), tnpc_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnpc), tnpc_pl);
} }
static int
mlxsw_sp2_nve_decap_ethertype_set(struct mlxsw_sp *mlxsw_sp, u16 ethertype)
{
char spvid_pl[MLXSW_REG_SPVID_LEN] = {};
u8 sver_type;
int err;
mlxsw_reg_spvid_tport_set(spvid_pl, true);
mlxsw_reg_spvid_local_port_set(spvid_pl,
MLXSW_REG_TUNNEL_PORT_NVE);
err = mlxsw_sp_ethtype_to_sver_type(ethertype, &sver_type);
if (err)
return err;
mlxsw_reg_spvid_et_vlan_set(spvid_pl, sver_type);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
}
static int static int
mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_nve_config *config) const struct mlxsw_sp_nve_config *config)
{ {
char tngcr_pl[MLXSW_REG_TNGCR_LEN]; char tngcr_pl[MLXSW_REG_TNGCR_LEN];
char spvtr_pl[MLXSW_REG_SPVTR_LEN];
u16 ul_rif_index; u16 ul_rif_index;
int err; int err;
...@@ -329,8 +361,25 @@ mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, ...@@ -329,8 +361,25 @@ mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp,
if (err) if (err)
goto err_tngcr_write; goto err_tngcr_write;
mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE,
MLXSW_REG_SPVTR_IPVID_MODE_ALWAYS_PUSH_VLAN);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl);
if (err)
goto err_spvtr_write;
err = mlxsw_sp2_nve_decap_ethertype_set(mlxsw_sp, config->ethertype);
if (err)
goto err_decap_ethertype_set;
return 0; return 0;
err_decap_ethertype_set:
mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE,
MLXSW_REG_SPVTR_IPVID_MODE_IEEE_COMPLIANT_PVID);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl);
err_spvtr_write:
mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
err_tngcr_write: err_tngcr_write:
mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false); mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false);
err_vxlan_learning_set: err_vxlan_learning_set:
...@@ -340,8 +389,14 @@ mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, ...@@ -340,8 +389,14 @@ mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp2_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp2_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp)
{ {
char spvtr_pl[MLXSW_REG_SPVTR_LEN];
char tngcr_pl[MLXSW_REG_TNGCR_LEN]; char tngcr_pl[MLXSW_REG_TNGCR_LEN];
/* Set default EtherType */
mlxsw_sp2_nve_decap_ethertype_set(mlxsw_sp, ETH_P_8021Q);
mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE,
MLXSW_REG_SPVTR_IPVID_MODE_IEEE_COMPLIANT_PVID);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl);
mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0); mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false); mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false);
......
...@@ -2053,9 +2053,10 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, ...@@ -2053,9 +2053,10 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
} }
static int static int
mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_bridge_vlan_aware_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
const struct net_device *vxlan_dev, u16 vid, const struct net_device *vxlan_dev,
struct netlink_ext_ack *extack) u16 vid, u16 ethertype,
struct netlink_ext_ack *extack)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
...@@ -2063,6 +2064,7 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, ...@@ -2063,6 +2064,7 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
.type = MLXSW_SP_NVE_TYPE_VXLAN, .type = MLXSW_SP_NVE_TYPE_VXLAN,
.vni = vxlan->cfg.vni, .vni = vxlan->cfg.vni,
.dev = vxlan_dev, .dev = vxlan_dev,
.ethertype = ethertype,
}; };
struct mlxsw_sp_fid *fid; struct mlxsw_sp_fid *fid;
int err; int err;
...@@ -2101,6 +2103,15 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, ...@@ -2101,6 +2103,15 @@ mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
return err; return err;
} }
static int
mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
const struct net_device *vxlan_dev, u16 vid,
struct netlink_ext_ack *extack)
{
return mlxsw_sp_bridge_vlan_aware_vxlan_join(bridge_device, vxlan_dev,
vid, ETH_P_8021Q, extack);
}
static struct net_device * static struct net_device *
mlxsw_sp_bridge_8021q_vxlan_dev_find(struct net_device *br_dev, u16 vid) mlxsw_sp_bridge_8021q_vxlan_dev_find(struct net_device *br_dev, u16 vid)
{ {
...@@ -2231,6 +2242,7 @@ mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, ...@@ -2231,6 +2242,7 @@ mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
.type = MLXSW_SP_NVE_TYPE_VXLAN, .type = MLXSW_SP_NVE_TYPE_VXLAN,
.vni = vxlan->cfg.vni, .vni = vxlan->cfg.vni,
.dev = vxlan_dev, .dev = vxlan_dev,
.ethertype = ETH_P_8021Q,
}; };
struct mlxsw_sp_fid *fid; struct mlxsw_sp_fid *fid;
int err; int err;
...@@ -2335,8 +2347,8 @@ mlxsw_sp_bridge_8021ad_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device, ...@@ -2335,8 +2347,8 @@ mlxsw_sp_bridge_8021ad_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
const struct net_device *vxlan_dev, u16 vid, const struct net_device *vxlan_dev, u16 vid,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
NL_SET_ERR_MSG_MOD(extack, "VXLAN is not supported with 802.1ad"); return mlxsw_sp_bridge_vlan_aware_vxlan_join(bridge_device, vxlan_dev,
return -EOPNOTSUPP; vid, ETH_P_8021AD, extack);
} }
static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = { static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021ad_ops = {
...@@ -3308,8 +3320,8 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp, ...@@ -3308,8 +3320,8 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp,
if (!fid) { if (!fid) {
if (!flag_untagged || !flag_pvid) if (!flag_untagged || !flag_pvid)
return 0; return 0;
return mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev,
vxlan_dev, vid, extack); vid, extack);
} }
/* Second case: FID is associated with the VNI and the VLAN associated /* Second case: FID is associated with the VNI and the VLAN associated
...@@ -3348,16 +3360,14 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp, ...@@ -3348,16 +3360,14 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp,
if (!flag_untagged) if (!flag_untagged)
return 0; return 0;
err = mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, vid, err = bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, vid, extack);
extack);
if (err) if (err)
goto err_vxlan_join; goto err_vxlan_join;
return 0; return 0;
err_vxlan_join: err_vxlan_join:
mlxsw_sp_bridge_8021q_vxlan_join(bridge_device, vxlan_dev, old_vid, bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, old_vid, NULL);
NULL);
return err; return err;
} }
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
lib_dir=$(dirname $0)/../../../../net/forwarding
VXPORT=4789
ALL_TESTS="
create_dot1d_and_dot1ad_vxlans
"
NUM_NETIFS=2
source $lib_dir/lib.sh
setup_prepare()
{
swp1=${NETIFS[p1]}
swp2=${NETIFS[p2]}
ip link set dev $swp1 up
ip link set dev $swp2 up
}
cleanup()
{
pre_cleanup
ip link set dev $swp2 down
ip link set dev $swp1 down
}
create_dot1d_and_dot1ad_vxlans()
{
RET=0
ip link add dev br0 type bridge vlan_filtering 1 vlan_protocol 802.1ad \
vlan_default_pvid 0 mcast_snooping 0
ip link set dev br0 up
ip link add name vx100 type vxlan id 1000 local 192.0.2.17 dstport \
"$VXPORT" nolearning noudpcsum tos inherit ttl 100
ip link set dev vx100 up
ip link set dev $swp1 master br0
ip link set dev vx100 master br0
bridge vlan add vid 100 dev vx100 pvid untagged
ip link add dev br1 type bridge vlan_filtering 0 mcast_snooping 0
ip link set dev br1 up
ip link add name vx200 type vxlan id 2000 local 192.0.2.17 dstport \
"$VXPORT" nolearning noudpcsum tos inherit ttl 100
ip link set dev vx200 up
ip link set dev $swp2 master br1
ip link set dev vx200 master br1 2>/dev/null
check_fail $? "802.1d and 802.1ad VxLANs at the same time not rejected"
ip link set dev vx200 master br1 2>&1 >/dev/null \
| grep -q mlxsw_spectrum
check_err $? "802.1d and 802.1ad VxLANs at the same time rejected without extack"
log_test "create 802.1d and 802.1ad VxLANs"
ip link del dev vx200
ip link del dev br1
ip link del dev vx100
ip link del dev br0
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
lib_dir=$(dirname $0)/../../../../net/forwarding
VXPORT=4789
ALL_TESTS="
create_vxlan_on_top_of_8021ad_bridge
"
NUM_NETIFS=2
source $lib_dir/lib.sh
setup_prepare()
{
swp1=${NETIFS[p1]}
swp2=${NETIFS[p2]}
ip link set dev $swp1 up
ip link set dev $swp2 up
}
cleanup()
{
pre_cleanup
ip link set dev $swp2 down
ip link set dev $swp1 down
}
create_vxlan_on_top_of_8021ad_bridge()
{
RET=0
ip link add dev br0 type bridge vlan_filtering 1 vlan_protocol 802.1ad \
vlan_default_pvid 0 mcast_snooping 0
ip link set dev br0 up
ip link add name vx100 type vxlan id 1000 local 192.0.2.17 dstport \
"$VXPORT" nolearning noudpcsum tos inherit ttl 100
ip link set dev vx100 up
ip link set dev $swp1 master br0
ip link set dev vx100 master br0
bridge vlan add vid 100 dev vx100 pvid untagged 2>/dev/null
check_fail $? "802.1ad bridge with VxLAN in Spectrum-1 not rejected"
bridge vlan add vid 100 dev vx100 pvid untagged 2>&1 >/dev/null \
| grep -q mlxsw_spectrum
check_err $? "802.1ad bridge with VxLAN in Spectrum-1 rejected without extack"
log_test "create VxLAN on top of 802.1ad bridge"
ip link del dev vx100
ip link del dev br0
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment