Page MenuHomeFreeBSD

D50500.id155947.diff
No OneTemporary

D50500.id155947.diff

diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 24, 2025
+.Dd May 23, 2025
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -2698,8 +2698,10 @@
.It Cm ifpvid Ar interface Ar vlan-id
Set the Port VLAN ID (PVID, sometimes called native VLAN ID) for this
interface.
-Incoming frames which do not have an 802.1Q VLAN tag will inherit the
-PVID from the interface on which they were received.
+The effect of this option is described in the
+.Dq VLAN SUPPORT
+section of
+.Xr bridge 4 .
.El
.Ss Link Aggregation and Link Failover Parameters
The following parameters are specific to lagg interfaces:
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -36,7 +36,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 17, 2025
+.Dd May 23, 2025
.Dt IF_BRIDGE 4
.Os
.Sh NAME
@@ -275,24 +275,25 @@
driver has limited support for virtual LANs (VLANs).
An incoming packet with an 802.1Q tag will be assigned to the
appropriate VLAN.
+The bridge always implements independent VLAN learning, i.e. MAC
+addresses are learnt on a per-VLAN basis, and the same MAC address may
+be learnt on multiple ports on different VLANs.
+.Pp
An interface's Port VLAN ID (PVID, sometimes called native VLAN ID) may
be configured using the
.Xr ifconfig 8
.Cm ifpvid
-option; incoming packets with no 802.1Q tag (or where the VLAN ID in the
-tag is zero) will be assigned to the interface's PVID.
+option.
+This affects handling of both incoming and outgoing frames.
+For incoming frames, if the frame has no 802.1Q tag (or the VLAN ID in
+the tag is zero), a tag will be inserted based on the port's PVID.
+For outgoing frames, if the frame has an 802.1Q tag which matches the
+port's PVID, the tag will be stripped from the frame prior to sending.
.Pp
An interface without a PVID configured will receive frames for all
VLANs.
-An interface with a PVID configured will only receive frames for its
-configured PVID.
-In either case, if the incoming frame has an 802.1Q tag, the tag will be
-preserved in the output frame; if not, no tag will be added to the
-output frame.
-.Pp
-There is no support for adding or removing 802.1Q tags on outgoing
-frames, and for interfaces without a PVID configured, there is no way to
-restrict which VLANs the interface can send or receive frames for.
+An interface with a PVID configured may only send and receive frames for
+its configured PVID.
.Sh PACKET FILTERING
Packet filtering can be used with any firewall package that hooks in via the
.Xr pfil 9
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -332,16 +332,16 @@
static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
static int bridge_enqueue(struct bridge_softc *, struct ifnet *,
- struct mbuf *);
+ struct mbuf *, struct bridge_iflist *);
static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
static void bridge_forward(struct bridge_softc *, struct bridge_iflist *,
- struct mbuf *m, ether_vlanid_t vlan);
+ struct mbuf *m);
static bool bridge_member_ifaddrs(void);
static void bridge_timer(void *);
static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
- struct mbuf *, int, ether_vlanid_t);
+ struct mbuf *, int);
static void bridge_span(struct bridge_softc *, struct mbuf *);
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
@@ -2172,12 +2172,25 @@
*
*/
static int
-bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
+bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m,
+ struct bridge_iflist *bif)
{
int len, err = 0;
short mflags;
struct mbuf *m0;
+ /*
+ * Find the bridge member port this packet is being sent on, if the
+ * caller didn't already provide it.
+ */
+ if (bif == NULL)
+ bif = bridge_lookup_member_if(sc, dst_ifp);
+ if (bif == NULL) {
+ /* Perhaps the interface was removed from the bridge */
+ m_freem(m);
+ return (EINVAL);
+ }
+
/* We may be sending a fragment so traverse the mbuf */
for (; m; m = m0) {
m0 = m->m_nextpkt;
@@ -2185,6 +2198,15 @@
len = m->m_pkthdr.len;
mflags = m->m_flags;
+ /*
+ * If the native VLAN ID of the outgoing interfaces matches the
+ * VLAN ID of this frame, remove the VLAN header.
+ */
+ if (bif->bif_pvid != 0 && VLANTAGOF(m) == bif->bif_pvid) {
+ m->m_flags &= ~M_VLANTAG;
+ m->m_pkthdr.ether_vtag = 0;
+ }
+
/*
* If underlying interface can not do VLAN tag insertion itself
* then attach a packet tag that holds it.
@@ -2256,7 +2278,7 @@
return;
}
- bridge_enqueue(sc, ifp, m);
+ bridge_enqueue(sc, ifp, m, NULL);
}
/*
@@ -2351,7 +2373,7 @@
}
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
if (used == 0)
m_freem(m);
@@ -2369,7 +2391,7 @@
return (0);
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, NULL);
return (0);
}
@@ -2396,9 +2418,9 @@
if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) &&
(dst_if = bridge_rtlookup(sc, eh->ether_dhost, DOT1Q_VID_NULL)) !=
NULL) {
- error = bridge_enqueue(sc, dst_if, m);
+ error = bridge_enqueue(sc, dst_if, m, NULL);
} else
- bridge_broadcast(sc, ifp, m, 0, DOT1Q_VID_NULL);
+ bridge_broadcast(sc, ifp, m, 0);
return (error);
}
@@ -2452,18 +2474,20 @@
*/
static void
bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
- struct mbuf *m, ether_vlanid_t vlan)
+ struct mbuf *m)
{
struct bridge_iflist *dbif;
struct ifnet *src_if, *dst_if, *ifp;
struct ether_header *eh;
uint8_t *dst;
int error;
+ ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
src_if = m->m_pkthdr.rcvif;
ifp = sc->sc_ifp;
+ vlan = VLANTAGOF(m);
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
@@ -2555,7 +2579,7 @@
}
if (dst_if == NULL) {
- bridge_broadcast(sc, src_if, m, 1, vlan);
+ bridge_broadcast(sc, src_if, m, 1);
return;
}
@@ -2592,7 +2616,7 @@
return;
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, dbif);
return;
drop:
@@ -2663,15 +2687,30 @@
}
/*
- * If the frame has no vlan id, take the vlan from the interface.
- * Otherwise, make sure it matches the port's pvid, if any.
+ * If the port has a pvid assigned, do VLAN access checks.
*/
- if (vlan == DOT1Q_VID_NULL)
- vlan = bif->bif_pvid;
- else if ((bif->bif_pvid != DOT1Q_VID_NULL) && (vlan != bif->bif_pvid)) {
- if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
- m_freem(m);
- return (NULL);
+ if (bif->bif_pvid != DOT1Q_VID_NULL) {
+ if (vlan != DOT1Q_VID_NULL && vlan != bif->bif_pvid) {
+ /*
+ * If the frame has a tag, and the tag's vlan id doesn't
+ * match the pvid, drop the frame.
+ */
+ if_inc_counter(bifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ return (NULL);
+ } else if (vlan == DOT1Q_VID_NULL) {
+ /*
+ * If the frame is untagged, set its vlan to the port's
+ * pvid.
+ */
+ vlan = bif->bif_pvid;
+ m->m_pkthdr.ether_vtag = bif->bif_pvid;
+ m->m_flags |= M_VLANTAG;
+ }
+ /*
+ * Otherwise, vlan == bif_pvid, i.e. this is a tagged frame
+ * where the tag matches the pvid, so accept it as-is.
+ */
}
bridge_span(sc, m);
@@ -2700,7 +2739,7 @@
}
/* Perform the bridge forwarding function with the copy. */
- bridge_forward(sc, bif, mc, vlan);
+ bridge_forward(sc, bif, mc);
#ifdef DEV_NETMAP
/*
@@ -2842,7 +2881,7 @@
#undef GRAB_OUR_PACKETS
/* Perform the bridge forwarding function. */
- bridge_forward(sc, bif, m, vlan);
+ bridge_forward(sc, bif, m);
return (NULL);
}
@@ -2880,16 +2919,18 @@
*/
static void
bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
- struct mbuf *m, int runfilt, ether_vlanid_t vlan)
+ struct mbuf *m, int runfilt)
{
struct bridge_iflist *dbif, *sbif;
struct mbuf *mc;
struct ifnet *dst_if;
int used = 0, i;
+ ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
sbif = bridge_lookup_member_if(sc, src_if);
+ vlan = VLANTAGOF(m);
/* Filter on the bridge interface before broadcasting */
if (runfilt && PFIL_HOOKED_OUT_46) {
@@ -2956,7 +2997,7 @@
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, dbif);
}
if (used == 0)
m_freem(m);
@@ -2992,7 +3033,7 @@
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
}
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -856,14 +856,14 @@
vnet_cleanup
}
-atf_test_case "vlan_pvid_tagged" "cleanup"
-vlan_pvid_tagged_head()
+atf_test_case "vlan_pvid_1q" "cleanup"
+vlan_pvid_1q_head()
{
- atf_set descr 'bridge pvid with tagged frames for pvid'
+ atf_set descr '802.1q tag addition and removal'
atf_set require.user root
}
-vlan_pvid_tagged_body()
+vlan_pvid_1q_body()
{
vnet_init
vnet_init_bridge
@@ -874,68 +874,32 @@
vnet_mkjail one ${epone}b
vnet_mkjail two ${eptwo}b
- # Create two tagged interfaces on the appropriate VLANs
- jexec one ifconfig ${epone}b up
- jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up
+ # Set up one jail with an access port, and the other with a trunk port.
+ # This forces the bridge to add and remove .1q tags to bridge the
+ # traffic.
+
+ jexec one ifconfig ${epone}b 192.0.2.1/24 up
jexec two ifconfig ${eptwo}b up
jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up
bridge=$(vnet_mkbridge)
- ifconfig ${bridge} up
- ifconfig ${epone}a up
- ifconfig ${eptwo}a up
+ # ifpvid forces frames on vlan 20 to be untagged.
ifconfig ${bridge} addm ${epone}a ifpvid ${epone}a 20
- ifconfig ${bridge} addm ${eptwo}a ifpvid ${eptwo}a 20
-
- atf_check -o ignore jexec one ping -c 3 -t 1 192.0.2.2
- atf_check -o ignore jexec two ping -c 3 -t 1 192.0.2.1
-}
-
-vlan_pvid_tagged_cleanup()
-{
- vnet_cleanup
-}
-
-atf_test_case "vlan_pvid_tagged_noaccess" "cleanup"
-vlan_pvid_tagged_noaccess_head()
-{
- atf_set descr 'bridge pvid with non-pvid tagged frames'
- atf_set require.user root
-}
-
-vlan_pvid_tagged_noaccess_body()
-{
- vnet_init
- vnet_init_bridge
-
- epone=$(vnet_mkepair)
- eptwo=$(vnet_mkepair)
-
- vnet_mkjail one ${epone}b
- vnet_mkjail two ${eptwo}b
-
- # Create two tagged interfaces on the appropriate VLANs
- jexec one ifconfig ${epone}b up
- jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up
- jexec two ifconfig ${eptwo}b up
- jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up
-
- bridge=$(vnet_mkbridge)
+ # No PVID here, so we send/receive tagged frames.
+ ifconfig ${bridge} addm ${eptwo}a
ifconfig ${bridge} up
ifconfig ${epone}a up
ifconfig ${eptwo}a up
- ifconfig ${bridge} addm ${epone}a ifpvid ${epone}a 20
- ifconfig ${bridge} addm ${eptwo}a ifpvid ${eptwo}a 30
- atf_check -o ignore -s exit:2 jexec one ping -c 3 -t 1 192.0.2.2
- atf_check -o ignore -s exit:2 jexec two ping -c 3 -t 1 192.0.2.1
+ 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
}
-vlan_pvid_tagged_noaccess_cleanup()
+vlan_pvid_1q_cleanup()
{
- vnet_cleanup
+ vnet_cleanup
}
atf_init_test_cases()
@@ -956,7 +920,6 @@
atf_add_test_case "member_ifaddrs_enabled"
atf_add_test_case "member_ifaddrs_disabled"
atf_add_test_case "vlan_pvid"
+ atf_add_test_case "vlan_pvid_1q"
atf_add_test_case "vlan_pvid_filtered"
- atf_add_test_case "vlan_pvid_tagged"
- atf_add_test_case "vlan_pvid_tagged_noaccess"
}

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 21, 9:51 PM (18 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37057829
Default Alt Text
D50500.id155947.diff (11 KB)

Event Timeline