On Fri, 22 May 2020 at 15:38, Nikolay Aleksandrov <niko...@cumulusnetworks.com> wrote: > > On 22/05/2020 00:10, Vladimir Oltean wrote: > > From: Vladimir Oltean <vladimir.olt...@nxp.com> > > > > In cases where the bridge is offloaded by a switchdev, there are > > situations where we can optimize RX filtering towards the host. To be > > precise, the host only needs to do termination, which it can do by > > responding at the MAC addresses of the slave ports and of the bridge > > interface itself. But most notably, it doesn't need to do forwarding, > > so there is no need to see packets with unknown destination address. > > > > But there are, however, cases when a switchdev does need to flood to the > > CPU. Such an example is when the switchdev is bridged with a foreign > > interface, and since there is no offloaded datapath, packets need to > > pass through the CPU. Currently this is the only identified case, but it > > can be extended at any time. > > > > So far, switchdev implementers made driver-level assumptions, such as: > > this chip is never integrated in SoCs where it can be bridged with a > > foreign interface, so I'll just disable host flooding and save some CPU > > cycles. Or: I can never know what else can be bridged with this > > switchdev port, so I must leave host flooding enabled in any case. > > > > Let the bridge drive the host flooding decision, and pass it to > > switchdev via the same mechanism as the external flooding flags. > > > > Signed-off-by: Vladimir Oltean <vladimir.olt...@nxp.com> > > --- > > include/linux/if_bridge.h | 3 +++ > > net/bridge/br_if.c | 40 +++++++++++++++++++++++++++++++++++++++ > > net/bridge/br_switchdev.c | 4 +++- > > 3 files changed, 46 insertions(+), 1 deletion(-) > > > > diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h > > index b3a8d3054af0..6891a432862d 100644 > > --- a/include/linux/if_bridge.h > > +++ b/include/linux/if_bridge.h > > @@ -49,6 +49,9 @@ struct br_ip_list { > > #define BR_ISOLATED BIT(16) > > #define BR_MRP_AWARE BIT(17) > > #define BR_MRP_LOST_CONT BIT(18) > > +#define BR_HOST_FLOOD BIT(19) > > +#define BR_HOST_MCAST_FLOOD BIT(20) > > +#define BR_HOST_BCAST_FLOOD BIT(21) > > > > #define BR_DEFAULT_AGEING_TIME (300 * HZ) > > > > diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c > > index a0e9a7937412..aae59d1e619b 100644 > > --- a/net/bridge/br_if.c > > +++ b/net/bridge/br_if.c > > @@ -166,6 +166,45 @@ void br_manage_promisc(struct net_bridge *br) > > } > > } > > > > +static int br_manage_host_flood(struct net_bridge *br) > > +{ > > + const unsigned long mask = BR_HOST_FLOOD | BR_HOST_MCAST_FLOOD | > > + BR_HOST_BCAST_FLOOD; > > + struct net_bridge_port *p, *q; > > + > > + list_for_each_entry(p, &br->port_list, list) { > > + unsigned long flags = p->flags; > > + bool sw_bridging = false; > > + int err; > > + > > + list_for_each_entry(q, &br->port_list, list) { > > + if (p == q) > > + continue; > > + > > + if (!netdev_port_same_parent_id(p->dev, q->dev)) { > > + sw_bridging = true; > > + break; > > + } > > + } > > + > > + if (sw_bridging) > > + flags |= mask; > > + else > > + flags &= ~mask; > > + > > + if (flags == p->flags) > > + continue; > > + > > + err = br_switchdev_set_port_flag(p, flags, mask); > > + if (err) > > + return err; > > + > > + p->flags = flags; > > + } > > + > > + return 0; > > +} > > + > > int nbp_backup_change(struct net_bridge_port *p, > > struct net_device *backup_dev) > > { > > @@ -231,6 +270,7 @@ static void nbp_update_port_count(struct net_bridge *br) > > br->auto_cnt = cnt; > > br_manage_promisc(br); > > } > > + br_manage_host_flood(br); > > } > > > > Can we do this only at port add/del ? > Right now it will be invoked also by br_port_flags_change() upon BR_AUTO_MASK > flag change. >
Yes, we can do that. Actually I have some doubts about BR_HOST_BCAST_FLOOD. We can't disable that in the no-foreign-interface case, can we? For IPv6, it looks like the stack does take care of installing dev_mc addresses for the neighbor discovery protocol, but for IPv4 I guess the assumption is that broadcast ARP should always be processed? > > static void nbp_delete_promisc(struct net_bridge_port *p) > > diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c > > index 015209bf44aa..360806ac7463 100644 > > --- a/net/bridge/br_switchdev.c > > +++ b/net/bridge/br_switchdev.c > > @@ -56,7 +56,9 @@ bool nbp_switchdev_allowed_egress(const struct > > net_bridge_port *p, > > > > /* Flags that can be offloaded to hardware */ > > #define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \ > > - BR_MCAST_FLOOD | BR_BCAST_FLOOD) > > + BR_MCAST_FLOOD | BR_BCAST_FLOOD | \ > > + BR_HOST_FLOOD | BR_HOST_MCAST_FLOOD | \ > > + BR_HOST_BCAST_FLOOD) > > > > int br_switchdev_set_port_flag(struct net_bridge_port *p, > > unsigned long flags, > > > Thanks, -Vladimir