Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142701222
D50500.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D50500.diff
View Options
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
@@ -298,8 +298,11 @@
to that VLAN, and the interface may receive outgoing untagged frames
in that VLAN.
.Pp
-There is no support for adding or removing 802.1Q tags from frames
-processed by the bridge.
+The bridge will automatically insert or remove 802.1q tags as needed,
+based on the interface configuration, when forwarding frames between
+interfaces.
+This tag processing is only done for interfaces with VLAN filtering
+enabled.
.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 *,
@@ -2175,12 +2175,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;
@@ -2188,6 +2201,18 @@
len = m->m_pkthdr.len;
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 ((bif->bif_flags & IFBIF_VLANFILTER) &&
+ bif->bif_untagged != DOT1Q_VID_NULL &&
+ VLANTAGOF(m) == bif->bif_untagged) {
+ 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.
@@ -2259,7 +2284,7 @@
return;
}
- bridge_enqueue(sc, ifp, m);
+ bridge_enqueue(sc, ifp, m, NULL);
}
/*
@@ -2354,7 +2379,7 @@
}
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
if (used == 0)
m_freem(m);
@@ -2372,7 +2397,7 @@
return (0);
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, NULL);
return (0);
}
@@ -2399,9 +2424,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);
}
@@ -2455,18 +2480,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);
@@ -2558,7 +2585,7 @@
}
if (dst_if == NULL) {
- bridge_broadcast(sc, src_if, m, 1, vlan);
+ bridge_broadcast(sc, src_if, m, 1);
return;
}
@@ -2593,7 +2620,7 @@
return;
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, dbif);
return;
drop:
@@ -2682,6 +2709,8 @@
/* Otherwise, assign the untagged frame to the correct vlan. */
vlan = bif->bif_untagged;
+ m->m_pkthdr.ether_vtag = bif->bif_untagged;
+ m->m_flags |= M_VLANTAG;
}
bridge_span(sc, m);
@@ -2710,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
/*
@@ -2849,7 +2878,7 @@
#undef GRAB_OUR_PACKETS
/* Perform the bridge forwarding function. */
- bridge_forward(sc, bif, m, vlan);
+ bridge_forward(sc, bif, m);
return (NULL);
}
@@ -2887,16 +2916,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) {
@@ -2962,7 +2993,7 @@
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, dbif);
}
if (used == 0)
m_freem(m);
@@ -2998,7 +3029,7 @@
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
}
@@ -3040,17 +3071,6 @@
if (vlan == DOT1Q_VID_NULL)
return (false);
- /*
- * If the frame was received with a vlan tag then drop it,
- * since we only support untagged ports.
- *
- * If the egress port doesn't have an untagged vlan configured,
- * it doesn't want untagged frames, so drop it.
- */
- if (VLANTAGOF(m) != DOT1Q_VID_NULL ||
- dbif->bif_untagged == DOT1Q_VID_NULL)
- return (false);
-
/*
* Make sure the frame's vlan matches the port's untagged vlan.
*/
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
@@ -952,6 +952,51 @@
{
vnet_cleanup
}
+
+atf_test_case "vlan_pvid_1q" "cleanup"
+vlan_pvid_1q_head()
+{
+ atf_set descr '802.1q tag addition and removal'
+ atf_set require.user root
+}
+
+vlan_pvid_1q_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ # 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} addm ${epone}a untagged ${epone}a 20
+ ifconfig ${bridge} addm ${eptwo}a
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+
+ 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_1q_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "bridge_transmit_ipv4_unicast"
@@ -971,6 +1016,7 @@
atf_add_test_case "member_ifaddrs_disabled"
atf_add_test_case "member_ifaddrs_vlan"
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"
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 23, 10:22 AM (1 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27882221
Default Alt Text
D50500.diff (7 KB)
Attached To
Mode
D50500: bridge: transparently add and remove VLAN tags
Attached
Detach File
Event Timeline
Log In to Comment