The branch main has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=7d99569d40510b627f0790c2b9630b5903e926b9
commit 7d99569d40510b627f0790c2b9630b5903e926b9 Author: Lexi Winter <i...@freebsd.org> AuthorDate: 2025-08-05 18:18:52 +0000 Commit: Lexi Winter <i...@freebsd.org> CommitDate: 2025-08-05 18:35:30 +0000 bridge: Make the vlan(4) shunt more robust When bridge(4) and vlan(4) are both configured on the same physical interface, bridge handles incoming packets first and needs to shunt some packets to vlan(4). Right now, that shunt is done if the packet is destined for the Ethernet address of the member interface it was received on, and has a vlan tag. This is not ideal for two reasons: * It leaks some of the "special" behaviour of member_ifaddrs=1 even when member_ifaddrs is set to 0. * It means the vlan interface only receives locally-destined traffic, so anything that needs to receive other traffic won't work. Change the behaviour so that if a member interface has a vlan trunk configured, *all* tagged packets are unconditionally passed back to ether_input, which will send them to vlan(4). This somewhat changes the observable behaviour of vlan(4): since bridge(4) places all member interfaces in promiscuous mode, the vlan interface will now receive all traffic on that vlan. This shouldn't break any real-world configurations because it's only receiving more traffic; any traffic that was previously received is still received. Configuring both vlan(4) and bridge(4) on the same interface is probably not something we want to support long term, but for now this makes the code cleaner and the user-visible behaviour simpler and more predictable. Differential Revision: https://reviews.freebsd.org/D51677 --- sys/net/if_bridge.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 945318c5af1a..3aed54c58e04 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -2871,6 +2871,16 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) eh = mtod(m, struct ether_header *); vlan = VLANTAGOF(m); + /* + * If this frame has a VLAN tag and the receiving interface has a + * vlan(4) trunk, then it is is destined for vlan(4), not for us. + * This means if vlan(4) and bridge(4) are configured on the same + * interface, vlan(4) is preferred, which is what users typically + * expect. + */ + if (vlan != DOT1Q_VID_NULL && ifp->if_vlantrunk != NULL) + return (m); + bif = ifp->if_bridge; if (bif) sc = bif->bif_sc; @@ -3071,19 +3081,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) do { GRAB_OUR_PACKETS(bifp) } while (0); /* - * Check the interface the packet arrived on. For tagged frames, - * we need to do this even if member_ifaddrs is disabled because - * vlan(4) might need to handle the traffic. + * If member_ifaddrs is enabled, see if the packet is destined for + * one of the members' addresses. */ - if (V_member_ifaddrs || (vlan && ifp->if_vlantrunk)) + if (V_member_ifaddrs) { + /* Check the interface the packet arrived on. */ do { GRAB_OUR_PACKETS(ifp) } while (0); - /* - * We only need to check other members interface if member_ifaddrs - * is enabled; otherwise we should have never traffic destined for - * a member's lladdr. - */ - if (V_member_ifaddrs) { CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { GRAB_OUR_PACKETS(bif2->bif_ifp) }