mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 02:23:16 +00:00
Merge branch 'mlxsw-Support-VLAN-devices-in-mirroring-offloads'
Ido Schimmel says: ==================== mlxsw: Support VLAN devices in mirroring offloads Petr says: When offloading "tc action mirred mirror", there are several scenarios where VLAN devices can show up, that mlxsw can offload on Spectrum machines. I) A direct mirror to a VLAN device on top of a front-panel port device (commonly referred to as "RSPAN") II) VLAN device in egress path of a packet when resolving a mirror to gretap or ip6gretap netdevice. Specifically in the latter case, the following are the cases that can be offloaded: IIa) VLAN device directly above a physical device. IIb) A VLAN-unaware bridge where the egress device is as in IIa. IIc) VLAN device on top of a VLAN-aware bridge where the egress device is a physical device. This patch set implements all the above cases. First, in patch #1, br_vlan_get_info() is extended to allow bridge master argument. Case I is then implemented in patches #2 and #3, case II in patch #4. Note that handling of VLAN protocol is not included. In case I, mirrored packets may end up being double-tagged, and it might be reasonable for the outer tag to be an 802.1ad. However, the protocol type configuration would have to be put on the same VLAN netdevice that represents normal VLAN traffic, and mlxsw currently ignores this setting in that case. Thus this support was left out and the encapsulation always uses 802.1q protocol. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ccb0263814
@ -6833,6 +6833,12 @@ enum mlxsw_reg_mpat_span_type {
|
||||
*/
|
||||
MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH = 0x0,
|
||||
|
||||
/* Remote SPAN Ethernet VLAN.
|
||||
* The packet is forwarded to the monitoring port on the monitoring
|
||||
* VLAN.
|
||||
*/
|
||||
MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH = 0x1,
|
||||
|
||||
/* Encapsulated Remote SPAN Ethernet L3 GRE.
|
||||
* The packet is encapsulated with GRE header.
|
||||
*/
|
||||
|
@ -176,21 +176,23 @@ mlxsw_sp_span_entry_bridge_8021q(const struct net_device *br_dev,
|
||||
{
|
||||
struct bridge_vlan_info vinfo;
|
||||
struct net_device *edev;
|
||||
u16 pvid;
|
||||
u16 vid = *p_vid;
|
||||
|
||||
if (WARN_ON(br_vlan_get_pvid(br_dev, &pvid)))
|
||||
if (!vid && WARN_ON(br_vlan_get_pvid(br_dev, &vid)))
|
||||
return NULL;
|
||||
if (!pvid)
|
||||
if (!vid ||
|
||||
br_vlan_get_info(br_dev, vid, &vinfo) ||
|
||||
!(vinfo.flags & BRIDGE_VLAN_INFO_BRENTRY))
|
||||
return NULL;
|
||||
|
||||
edev = br_fdb_find_port(br_dev, dmac, pvid);
|
||||
edev = br_fdb_find_port(br_dev, dmac, vid);
|
||||
if (!edev)
|
||||
return NULL;
|
||||
|
||||
if (br_vlan_get_info(edev, pvid, &vinfo))
|
||||
if (br_vlan_get_info(edev, vid, &vinfo))
|
||||
return NULL;
|
||||
if (!(vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED))
|
||||
*p_vid = pvid;
|
||||
*p_vid = vid;
|
||||
return edev;
|
||||
}
|
||||
|
||||
@ -208,13 +210,13 @@ mlxsw_sp_span_entry_bridge(const struct net_device *br_dev,
|
||||
{
|
||||
struct mlxsw_sp_bridge_port *bridge_port;
|
||||
enum mlxsw_reg_spms_state spms_state;
|
||||
struct net_device *dev = NULL;
|
||||
struct mlxsw_sp_port *port;
|
||||
struct net_device *dev;
|
||||
u8 stp_state;
|
||||
|
||||
if (br_vlan_enabled(br_dev))
|
||||
dev = mlxsw_sp_span_entry_bridge_8021q(br_dev, dmac, p_vid);
|
||||
else
|
||||
else if (!*p_vid)
|
||||
dev = mlxsw_sp_span_entry_bridge_8021d(br_dev, dmac);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
@ -235,6 +237,14 @@ mlxsw_sp_span_entry_bridge(const struct net_device *br_dev,
|
||||
return dev;
|
||||
}
|
||||
|
||||
static struct net_device *
|
||||
mlxsw_sp_span_entry_vlan(const struct net_device *vlan_dev,
|
||||
u16 *p_vid)
|
||||
{
|
||||
*p_vid = vlan_dev_vlan_id(vlan_dev);
|
||||
return vlan_dev_real_dev(vlan_dev);
|
||||
}
|
||||
|
||||
static __maybe_unused int
|
||||
mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *l3edev,
|
||||
union mlxsw_sp_l3addr saddr,
|
||||
@ -253,12 +263,21 @@ mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *l3edev,
|
||||
if (!l3edev || mlxsw_sp_span_dmac(tbl, &gw, l3edev, dmac))
|
||||
goto unoffloadable;
|
||||
|
||||
if (is_vlan_dev(l3edev))
|
||||
l3edev = mlxsw_sp_span_entry_vlan(l3edev, &vid);
|
||||
|
||||
if (netif_is_bridge_master(l3edev)) {
|
||||
l3edev = mlxsw_sp_span_entry_bridge(l3edev, dmac, &vid);
|
||||
if (!l3edev)
|
||||
goto unoffloadable;
|
||||
}
|
||||
|
||||
if (is_vlan_dev(l3edev)) {
|
||||
if (vid || !(l3edev->flags & IFF_UP))
|
||||
goto unoffloadable;
|
||||
l3edev = mlxsw_sp_span_entry_vlan(l3edev, &vid);
|
||||
}
|
||||
|
||||
if (!mlxsw_sp_port_dev_check(l3edev))
|
||||
goto unoffloadable;
|
||||
|
||||
@ -477,6 +496,61 @@ struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6 = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static bool
|
||||
mlxsw_sp_span_vlan_can_handle(const struct net_device *dev)
|
||||
{
|
||||
return is_vlan_dev(dev) &&
|
||||
mlxsw_sp_port_dev_check(vlan_dev_real_dev(dev));
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_span_entry_vlan_parms(const struct net_device *to_dev,
|
||||
struct mlxsw_sp_span_parms *sparmsp)
|
||||
{
|
||||
struct net_device *real_dev;
|
||||
u16 vid;
|
||||
|
||||
if (!(to_dev->flags & IFF_UP))
|
||||
return mlxsw_sp_span_entry_unoffloadable(sparmsp);
|
||||
|
||||
real_dev = mlxsw_sp_span_entry_vlan(to_dev, &vid);
|
||||
sparmsp->dest_port = netdev_priv(real_dev);
|
||||
sparmsp->vid = vid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_span_entry_vlan_configure(struct mlxsw_sp_span_entry *span_entry,
|
||||
struct mlxsw_sp_span_parms sparms)
|
||||
{
|
||||
struct mlxsw_sp_port *dest_port = sparms.dest_port;
|
||||
struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
|
||||
u8 local_port = dest_port->local_port;
|
||||
char mpat_pl[MLXSW_REG_MPAT_LEN];
|
||||
int pa_id = span_entry->id;
|
||||
|
||||
mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
|
||||
MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH);
|
||||
mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid);
|
||||
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_span_entry_vlan_deconfigure(struct mlxsw_sp_span_entry *span_entry)
|
||||
{
|
||||
mlxsw_sp_span_entry_deconfigure_common(span_entry,
|
||||
MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH);
|
||||
}
|
||||
|
||||
static const
|
||||
struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_vlan = {
|
||||
.can_handle = mlxsw_sp_span_vlan_can_handle,
|
||||
.parms = mlxsw_sp_span_entry_vlan_parms,
|
||||
.configure = mlxsw_sp_span_entry_vlan_configure,
|
||||
.deconfigure = mlxsw_sp_span_entry_vlan_deconfigure,
|
||||
};
|
||||
|
||||
static const
|
||||
struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
|
||||
&mlxsw_sp_span_entry_ops_phys,
|
||||
@ -486,6 +560,7 @@ struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
|
||||
#if IS_ENABLED(CONFIG_IPV6_GRE)
|
||||
&mlxsw_sp_span_entry_ops_gretap6,
|
||||
#endif
|
||||
&mlxsw_sp_span_entry_ops_vlan,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -1176,6 +1176,8 @@ int br_vlan_get_info(const struct net_device *dev, u16 vid,
|
||||
p = br_port_get_check_rtnl(dev);
|
||||
if (p)
|
||||
vg = nbp_vlan_group(p);
|
||||
else if (netif_is_bridge_master(dev))
|
||||
vg = br_vlan_group(netdev_priv(dev));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user