The branch main has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=43ac5806a5a3150f561e14a11866dd56cf1b4d42
commit 43ac5806a5a3150f561e14a11866dd56cf1b4d42 Author: Lexi Winter <i...@freebsd.org> AuthorDate: 2025-08-10 15:11:32 +0000 Commit: Lexi Winter <i...@freebsd.org> CommitDate: 2025-08-10 15:36:40 +0000 bridge: Divorce ifuntagged from vlanfilter The ifuntagged option was added as part of the VLAN filtering feature, but it's useful on its own to be able to place interface traffic in a VLAN without having to configure every interface for VLAN filtering. Always do the pvid processing in bridge even if IFBRF_VLANFILTER isn't enabled, and don't prohibit configuring it. Add a test for the specific case of setting untagged without vlanfilter. This has no effect on bridges which don't have at least one interface configured with ifuntagged. Differential Revision: https://reviews.freebsd.org/D51760 --- sys/net/if_bridge.c | 28 ++++++++++++--------- tests/sys/net/if_bridge_test.sh | 54 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 1e444be93e9f..66555fd1feb5 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1500,8 +1500,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; bif->bif_savedcaps = ifs->if_capenable; bif->bif_vlanproto = ETHERTYPE_VLAN; - if (sc->sc_flags & IFBRF_VLANFILTER) - bif->bif_pvid = sc->sc_defpvid; + bif->bif_pvid = sc->sc_defpvid; if (sc->sc_flags & IFBRF_DEFQINQ) bif->bif_flags |= IFBIF_QINQ; @@ -1970,9 +1969,6 @@ bridge_ioctl_sifpvid(struct bridge_softc *sc, void *arg) struct ifbreq *req = arg; struct bridge_iflist *bif; - if ((sc->sc_flags & IFBRF_VLANFILTER) == 0) - return (EXTERROR(EINVAL, "VLAN filtering not enabled")); - bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (EXTERROR(ENOENT, "Interface is not a bridge member")); @@ -2410,12 +2406,10 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, mflags = m->m_flags; /* - * If VLAN filtering is enabled, and the native VLAN ID of the - * outgoing interface matches the VLAN ID of the frame, remove - * the VLAN header. + * If the native VLAN ID of the outgoing interface matches the + * VLAN ID of the frame, remove the VLAN tag. */ - if ((sc->sc_flags & IFBRF_VLANFILTER) && - bif->bif_pvid != DOT1Q_VID_NULL && + if (bif->bif_pvid != DOT1Q_VID_NULL && VLANTAGOF(m) == bif->bif_pvid) { m->m_flags &= ~M_VLANTAG; m->m_pkthdr.ether_vtag = 0; @@ -3296,9 +3290,19 @@ bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m) if (vlan > DOT1Q_VID_MAX) return (false); - /* If VLAN filtering isn't enabled, pass everything. */ - if ((sbif->bif_sc->sc_flags & IFBRF_VLANFILTER) == 0) + /* + * If VLAN filtering isn't enabled, pass everything, but add a tag + * if the port has a pvid configured. + */ + if ((sbif->bif_sc->sc_flags & IFBRF_VLANFILTER) == 0) { + if (vlan == DOT1Q_VID_NULL && + sbif->bif_pvid != DOT1Q_VID_NULL) { + m->m_pkthdr.ether_vtag = sbif->bif_pvid; + m->m_flags |= M_VLANTAG; + } + return (true); + } /* If Q-in-Q is disabled, check for stacked tags. */ if ((sbif->bif_flags & IFBIF_QINQ) == 0) { diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh index 906f586d2483..0c19903714b1 100755 --- a/tests/sys/net/if_bridge_test.sh +++ b/tests/sys/net/if_bridge_test.sh @@ -899,7 +899,7 @@ member_ifaddrs_vlan_cleanup() atf_test_case "vlan_pvid" "cleanup" vlan_pvid_head() { - atf_set descr 'bridge with two ports with pvid set' + atf_set descr 'bridge with two ports with pvid and vlanfilter set' atf_set require.user root } @@ -1327,6 +1327,56 @@ bridge_svi_in_bridge_cleanup() vnet_cleanup } +atf_test_case "vlan_untagged" "cleanup" +vlan_untagged_head() +{ + atf_set descr 'bridge with two ports with untagged set' + atf_set require.user root +} + +vlan_untagged_body() +{ + vnet_init + vnet_init_bridge + + epone=$(vnet_mkepair) + eptwo=$(vnet_mkepair) + + vnet_mkjail one ${epone}b + vnet_mkjail two ${eptwo}b + + jexec one ifconfig ${epone}b 192.0.2.1/24 up + jexec two ifconfig ${eptwo}b 192.0.2.2/24 up + + bridge=$(vnet_mkbridge) + + ifconfig ${bridge} up + ifconfig ${epone}a up + ifconfig ${eptwo}a up + ifconfig ${bridge} addm ${epone}a untagged 20 + ifconfig ${bridge} addm ${eptwo}a untagged 30 + + # With two ports on different VLANs, traffic should not be passed. + atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 + atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 + + # Move the second port to VLAN 20; now traffic should be passed. + atf_check -s exit:0 ifconfig ${bridge} ifuntagged ${eptwo}a 20 + atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 + atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 + + # Remove the first's port untagged config, now traffic should + # not pass again. + atf_check -s exit:0 ifconfig ${bridge} -ifuntagged ${epone}a + atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 + atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 +} + +vlan_untagged_cleanup() +{ + vnet_cleanup +} + atf_test_case "vlan_defuntagged" "cleanup" vlan_defuntagged_head() { @@ -1340,7 +1390,6 @@ vlan_defuntagged_body() vnet_init_bridge bridge=$(vnet_mkbridge) - atf_check -s exit:0 ifconfig ${bridge} vlanfilter # Invalid VLAN IDs atf_check -s exit:1 -ematch:"invalid vlan id: 0" \ @@ -1407,6 +1456,7 @@ atf_init_test_cases() atf_add_test_case "vlan_ifconfig_iftagged" atf_add_test_case "vlan_svi" atf_add_test_case "vlan_qinq" + atf_add_test_case "vlan_untagged" atf_add_test_case "vlan_defuntagged" atf_add_test_case "bridge_svi_in_bridge" }