Andrew, This version should address the comments you had on my initial submission. Does this one look better now?
Thanks, Daniel On 6/20/20 9:39 PM, Daniel Mack wrote: > The driver for Marvell switches puts all ports in IGMP snooping mode > which results in all IGMP/MLD frames that ingress on the ports to be > forwarded to the CPU only. > > The bridge code in the kernel can then interpret these frames and act > upon them, for instance by updating the mdb in the switch to reflect > multicast memberships of stations connected to the ports. However, > the IGMP/MLD frames must then also be forwarded to other ports of the > bridge so external IGMP queriers can track membership reports, and > external multicast clients can receive query reports from foreign IGMP > queriers. > > Currently, this is impossible as the EDSA tagger sets offload_fwd_mark > on the skb when it unwraps the tagged frames, and that will make the > switchdev layer prevent the skb from egressing on any other port of > the same switch. > > To fix that, look at the To_CPU code in the DSA header and make > forwarding of the frame possible for trapped IGMP packets. > > Introduce some #defines for the frame types to make the code a bit more > comprehensive. > > This was tested on a Marvell 88E6352 variant. > > Signed-off-by: Daniel Mack <dan...@zonque.org> > --- > v2: > * Limit IGMP handling to TO_CPU frames > * Use #defines for the TO_CPU codes and the frame types > > net/dsa/tag_edsa.c | 37 ++++++++++++++++++++++++++++++++++--- > 1 file changed, 34 insertions(+), 3 deletions(-) > > diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c > index e8eaa804ccb9e..d6200ff982007 100644 > --- a/net/dsa/tag_edsa.c > +++ b/net/dsa/tag_edsa.c > @@ -13,6 +13,16 @@ > #define DSA_HLEN 4 > #define EDSA_HLEN 8 > > +#define FRAME_TYPE_TO_CPU 0x00 > +#define FRAME_TYPE_FORWARD 0x03 > + > +#define TO_CPU_CODE_MGMT_TRAP 0x00 > +#define TO_CPU_CODE_FRAME2REG 0x01 > +#define TO_CPU_CODE_IGMP_MLD_TRAP 0x02 > +#define TO_CPU_CODE_POLICY_TRAP 0x03 > +#define TO_CPU_CODE_ARP_MIRROR 0x04 > +#define TO_CPU_CODE_POLICY_MIRROR 0x05 > + > static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev) > { > struct dsa_port *dp = dsa_slave_to_port(dev); > @@ -77,6 +87,8 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct > net_device *dev, > struct packet_type *pt) > { > u8 *edsa_header; > + int frame_type; > + int code; > int source_device; > int source_port; > > @@ -91,8 +103,29 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, > struct net_device *dev, > /* > * Check that frame type is either TO_CPU or FORWARD. > */ > - if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0) > + frame_type = edsa_header[0] >> 6; > + > + switch (frame_type) { > + case FRAME_TYPE_TO_CPU: > + code = (edsa_header[1] & 0x6) | ((edsa_header[2] >> 4) & 1); > + > + /* > + * Mark the frame to never egress on any port of the same switch > + * unless it's a trapped IGMP/MLD packet, in which case the > + * bridge might want to forward it. > + */ > + if (code != TO_CPU_CODE_IGMP_MLD_TRAP) > + skb->offload_fwd_mark = 1; > + > + break; > + > + case FRAME_TYPE_FORWARD: > + skb->offload_fwd_mark = 1; > + break; > + > + default: > return NULL; > + } > > /* > * Determine source device and port. > @@ -156,8 +189,6 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, > struct net_device *dev, > 2 * ETH_ALEN); > } > > - skb->offload_fwd_mark = 1; > - > return skb; > } > >