Current implementation of the SW bridge is setting the interfaces in promisc mode when they are added to bridge if learning of the frames is enabled. In case of Ocelot which has HW capabilities to switch frames, it is not needed to set the ports in promisc mode because the HW already capable of doing that. Therefore add NETIF_F_HW_BRIDGE feature to indicate that the HW has bridge capabilities. Therefore the SW bridge doesn't need to set the ports in promisc mode to do the switching. This optimization takes places only if all the interfaces that are part of the bridge have this flag and have the same network driver. If the bridge interfaces is added in promisc mode then also the ports part of the bridge are set in promisc mode. Horatiu Vultur (3): net: Add HW_BRIDGE offload feature net: mscc: Use NETIF_F_HW_BRIDGE net: mscc: Implement promisc mode. drivers/net/ethernet/mscc/ocelot.c | 26 ++++++++++++++++++++++++-- include/linux/netdev_features.h | 3 +++ net/bridge/br_if.c | 29 ++++++++++++++++++++++++++++- net/core/ethtool.c | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) -- 2.7.4
Horatiu Vultur
2019-Aug-22 19:07 UTC
[Bridge] [PATCH 1/3] net: Add HW_BRIDGE offload feature
This patch adds a netdev feature to configure the HW as a switch. The purpose of this flag is to show that the hardware can do switching of the frames. Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com> --- include/linux/netdev_features.h | 3 +++ net/bridge/br_if.c | 29 ++++++++++++++++++++++++++++- net/core/ethtool.c | 1 + 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 4b19c54..34274de 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -78,6 +78,8 @@ enum { NETIF_F_HW_TLS_TX_BIT, /* Hardware TLS TX offload */ NETIF_F_HW_TLS_RX_BIT, /* Hardware TLS RX offload */ + NETIF_F_HW_BRIDGE_BIT, /* Bridge offload support */ + NETIF_F_GRO_HW_BIT, /* Hardware Generic receive offload */ NETIF_F_HW_TLS_RECORD_BIT, /* Offload TLS record */ @@ -150,6 +152,7 @@ enum { #define NETIF_F_GSO_UDP_L4 __NETIF_F(GSO_UDP_L4) #define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX) #define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX) +#define NETIF_F_HW_BRIDGE __NETIF_F(HW_BRIDGE) /* Finds the next feature with the highest number of the range of start till 0. */ diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 4fe30b1..975a34c 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -127,6 +127,31 @@ static void br_port_clear_promisc(struct net_bridge_port *p) p->flags &= ~BR_PROMISC; } +/* Determin if the SW bridge can be offloaded to HW. Return true if all + * the interfaces of the bridge have the feature NETIF_F_HW_SWITCHDEV set + * and have the same netdev_ops. + */ +static int br_hw_offload(struct net_bridge *br) +{ + const struct net_device_ops *ops = NULL; + struct net_bridge_port *p; + + list_for_each_entry(p, &br->port_list, list) { + if (!(p->dev->hw_features & NETIF_F_HW_BRIDGE)) + return 0; + + if (!ops) { + ops = p->dev->netdev_ops; + continue; + } + + if (ops != p->dev->netdev_ops) + return 0; + } + + return 1; +} + /* When a port is added or removed or when certain port flags * change, this function is called to automatically manage * promiscuity setting of all the bridge ports. We are always called @@ -134,6 +159,7 @@ static void br_port_clear_promisc(struct net_bridge_port *p) */ void br_manage_promisc(struct net_bridge *br) { + bool hw_offload = br_hw_offload(br); struct net_bridge_port *p; bool set_all = false; @@ -161,7 +187,8 @@ void br_manage_promisc(struct net_bridge *br) (br->auto_cnt == 1 && br_auto_port(p))) br_port_clear_promisc(p); else - br_port_set_promisc(p); + if (!hw_offload) + br_port_set_promisc(p); } } } diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 6288e69..4e224fe 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -111,6 +111,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_HW_TLS_RECORD_BIT] = "tls-hw-record", [NETIF_F_HW_TLS_TX_BIT] = "tls-hw-tx-offload", [NETIF_F_HW_TLS_RX_BIT] = "tls-hw-rx-offload", + [NETIF_F_HW_BRIDGE_BIT] = "hw-bridge-offload", }; static const char -- 2.7.4
Horatiu Vultur
2019-Aug-22 19:07 UTC
[Bridge] [PATCH 2/3] net: mscc: Use NETIF_F_HW_BRIDGE
Enable HW_BRIDGE feature for ocelot. In this way the HW will do all the switching of the frames so it is not needed for the ports to be in promisc mode. Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com> --- drivers/net/ethernet/mscc/ocelot.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 4d1bce4..c9cf2bee 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2017,8 +2017,10 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, dev->ethtool_ops = &ocelot_ethtool_ops; dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS | - NETIF_F_HW_TC; - dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC; + NETIF_F_HW_TC | NETIF_F_HW_BRIDGE; + dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC | + NETIF_F_HW_BRIDGE; + dev->priv_flags |= IFF_UNICAST_FLT; memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN); dev->dev_addr[ETH_ALEN - 1] += port; -- 2.7.4
Horatiu Vultur
2019-Aug-22 19:07 UTC
[Bridge] [PATCH 3/3] net: mscc: Implement promisc mode.
Before when a port was added to a bridge then the port was added in promisc mode. But because of the patches: commit 6657c3d812dc5d ("net: Add HW_BRIDGE offload feature") commit e2e3678c292f9c (net: mscc: Use NETIF_F_HW_BRIDGE") the port is not needed to be in promisc mode to be part of the bridge. So it is possible to togle the promisc mode of the port even if it is or not part of the bridge. Signed-off-by: Horatiu Vultur <horatiu.vultur at microchip.com> --- drivers/net/ethernet/mscc/ocelot.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index c9cf2bee..9fa97fe 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -691,6 +691,25 @@ static void ocelot_set_rx_mode(struct net_device *dev) __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync); } +static void ocelot_change_rx_flags(struct net_device *dev, int flags) +{ + struct ocelot_port *port = netdev_priv(dev); + struct ocelot *ocelot = port->ocelot; + u32 val; + + if (!(flags & IFF_PROMISC)) + return; + + val = ocelot_read_gix(ocelot, ANA_PORT_CPU_FWD_CFG, + port->chip_port); + if (dev->flags & IFF_PROMISC) + val |= ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA; + else + val &= ~(ANA_PORT_CPU_FWD_CFG_CPU_SRC_COPY_ENA); + + ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port); +} + static int ocelot_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { @@ -1070,6 +1089,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = { .ndo_stop = ocelot_port_stop, .ndo_start_xmit = ocelot_port_xmit, .ndo_set_rx_mode = ocelot_set_rx_mode, + .ndo_change_rx_flags = ocelot_change_rx_flags, .ndo_get_phys_port_name = ocelot_port_get_phys_port_name, .ndo_set_mac_address = ocelot_port_set_mac_address, .ndo_get_stats64 = ocelot_get_stats64, -- 2.7.4
Nikolay Aleksandrov
2019-Aug-22 22:09 UTC
[Bridge] [PATCH 0/3] Add NETIF_F_HW_BRIDGE feature
On 22/08/2019 22:07, Horatiu Vultur wrote:> Current implementation of the SW bridge is setting the interfaces in > promisc mode when they are added to bridge if learning of the frames is > enabled. > In case of Ocelot which has HW capabilities to switch frames, it is not > needed to set the ports in promisc mode because the HW already capable of > doing that. Therefore add NETIF_F_HW_BRIDGE feature to indicate that the > HW has bridge capabilities. Therefore the SW bridge doesn't need to set > the ports in promisc mode to do the switching. > This optimization takes places only if all the interfaces that are part > of the bridge have this flag and have the same network driver. > > If the bridge interfaces is added in promisc mode then also the ports part > of the bridge are set in promisc mode. > > Horatiu Vultur (3): > net: Add HW_BRIDGE offload feature > net: mscc: Use NETIF_F_HW_BRIDGE > net: mscc: Implement promisc mode. > > drivers/net/ethernet/mscc/ocelot.c | 26 ++++++++++++++++++++++++-- > include/linux/netdev_features.h | 3 +++ > net/bridge/br_if.c | 29 ++++++++++++++++++++++++++++- > net/core/ethtool.c | 1 + > 4 files changed, 56 insertions(+), 3 deletions(-) >IMO the name is misleading. Why do the devices have to be from the same driver ? This is too specific targeting some devices. The bridge should not care what's the port device, it should be the other way around, so adding device-specific code to the bridge is not ok. Isn't there a solution where you can use NETDEV_JOIN and handle it all from your driver ? Would all HW-learned entries be hidden from user-space in this case ?
From: Horatiu Vultur <horatiu.vultur at microchip.com> Date: Thu, 22 Aug 2019 21:07:27 +0200> Current implementation of the SW bridge is setting the interfaces in > promisc mode when they are added to bridge if learning of the frames is > enabled. > In case of Ocelot which has HW capabilities to switch frames, it is not > needed to set the ports in promisc mode because the HW already capable of > doing that. Therefore add NETIF_F_HW_BRIDGE feature to indicate that the > HW has bridge capabilities. Therefore the SW bridge doesn't need to set > the ports in promisc mode to do the switching. > This optimization takes places only if all the interfaces that are part > of the bridge have this flag and have the same network driver. > > If the bridge interfaces is added in promisc mode then also the ports part > of the bridge are set in promisc mode.This doesn't look right at all. The Linux bridge provides a software bridge. By default, all hardware must provide a hardware implementation of that software bridge behavior. Anything that deviates from that behavior has to be explicitly asked for by the user by explicit config commands.
On 8/22/19 12:07 PM, Horatiu Vultur wrote:> Current implementation of the SW bridge is setting the interfaces in > promisc mode when they are added to bridge if learning of the frames is > enabled. > In case of Ocelot which has HW capabilities to switch frames, it is not > needed to set the ports in promisc mode because the HW already capable of > doing that. Therefore add NETIF_F_HW_BRIDGE feature to indicate that the > HW has bridge capabilities. Therefore the SW bridge doesn't need to set > the ports in promisc mode to do the switching.Then do not do anything when the ndo_set_rx_mode() for the ocelot network device is called and indicates that IFF_PROMISC is set and that your network port is a bridge port member. That is what mlxsw does AFAICT. As other pointed out, the Linux bridge implements a software bridge by default, and because it needs to operate on a wide variety of network devices, all with different capabilities, the easiest way to make sure that all management (IGMP, BPDU, etc. ) as well as non-management traffic can make it to the bridge ports, is to put the network devices in promiscuous mode. If this is suboptimal for you, you can take shortcuts in your driver that do not hinder the overall functionality.> This optimization takes places only if all the interfaces that are part > of the bridge have this flag and have the same network driver. > > If the bridge interfaces is added in promisc mode then also the ports part > of the bridge are set in promisc mode. > > Horatiu Vultur (3): > net: Add HW_BRIDGE offload feature > net: mscc: Use NETIF_F_HW_BRIDGE > net: mscc: Implement promisc mode. > > drivers/net/ethernet/mscc/ocelot.c | 26 ++++++++++++++++++++++++-- > include/linux/netdev_features.h | 3 +++ > net/bridge/br_if.c | 29 ++++++++++++++++++++++++++++- > net/core/ethtool.c | 1 + > 4 files changed, 56 insertions(+), 3 deletions(-) >-- Florian
Stephen Hemminger
2019-Aug-24 12:05 UTC
[Bridge] [PATCH 0/3] Add NETIF_F_HW_BRIDGE feature
On Thu, 22 Aug 2019 21:07:27 +0200 Horatiu Vultur <horatiu.vultur at microchip.com> wrote:> Current implementation of the SW bridge is setting the interfaces in > promisc mode when they are added to bridge if learning of the frames is > enabled. > In case of Ocelot which has HW capabilities to switch frames, it is not > needed to set the ports in promisc mode because the HW already capable of > doing that. Therefore add NETIF_F_HW_BRIDGE feature to indicate that the > HW has bridge capabilities. Therefore the SW bridge doesn't need to set > the ports in promisc mode to do the switching. > This optimization takes places only if all the interfaces that are part > of the bridge have this flag and have the same network driver. > > If the bridge interfaces is added in promisc mode then also the ports part > of the bridge are set in promisc mode. > > Horatiu Vultur (3): > net: Add HW_BRIDGE offload feature > net: mscc: Use NETIF_F_HW_BRIDGE > net: mscc: Implement promisc mode. > > drivers/net/ethernet/mscc/ocelot.c | 26 ++++++++++++++++++++++++-- > include/linux/netdev_features.h | 3 +++ > net/bridge/br_if.c | 29 ++++++++++++++++++++++++++++- > net/core/ethtool.c | 1 + > 4 files changed, 56 insertions(+), 3 deletions(-) >IMHO there are already enough nerd knobs in bridge to support this. If you hardware can't do real bridging, it is only doing MACVLAN so that is what you should support instead.