if_bridge VIMAGE patch

Nikos Vassiliadis nvass9573 at gmx.com
Thu Jan 13 12:44:00 UTC 2011


Hi,

Please, review the attached patch. It is against yesterday's HEAD
and it virtualizes if_bridge.

You can use the bridgetest script to create quickly a topology
with redundant links to test STP.

Thanks, Nikos
-------------- next part --------------
#!/bin/sh


__macaddress__()
(
	openssl rand 5 | od -tx1 | sed '1s/0000000/0/; s/  */ /g; s/ *$//; s/ /:/g;q'
)

__link__()
(
	a=$(($# - 1))
	for f in `jot $a`
	do
		eval p$f=`ifconfig epair create | sed 's at a$@@'`
	done

	a=0
	center=$1
	shift
	for f in $*
	do
		a=$(($a + 1))
		pair=`echo '$'p$a`
		pair=`eval echo $pair`
		ifconfig ${pair}a vnet $center
		jexec $center ifconfig ${pair}a description "link to $f"
		jexec $center ifconfig ${pair}a ether `__macaddress__`
		ifconfig ${pair}b vnet $f
		jexec $f ifconfig ${pair}b description "link to $center"
		jexec $f ifconfig ${pair}b ether `__macaddress__`
	done
)

link()
(
	if [ $# -ne 2 ]; then
		echo can link only two nodes
		return 1
	fi
	__link__ $*
)

star()
(
	if [ $# -lt 3 ]; then
		echo three nodes at least are needed to form a star
		return 1
	fi
	__link__ $*
)

params=`csh -c 'echo rootbridge{1,2,3,4} bridge{1,2,3,4} pc{1,2,3,4}{1,2,3}'`
apply 'jail -c vnet persist name=%1' $params

star rootbridge1 rootbridge2 rootbridge3 rootbridge4
star rootbridge2 rootbridge3 rootbridge4 rootbridge1
star rootbridge3 rootbridge4 rootbridge1 rootbridge2
star rootbridge4 rootbridge1 rootbridge2 rootbridge3

star bridge1 rootbridge1 rootbridge2
star bridge2 rootbridge2 rootbridge3
star bridge3 rootbridge3 rootbridge4
star bridge4 rootbridge4 rootbridge1

for f in 1 2 3 4
do
	link bridge$f pc${f}1
	link bridge$f pc${f}2
	link bridge$f pc${f}3
done

## patching ends here

for f in 1 2 3 4 5 6 7 8
do
	ifconfig bridge$f create
done
ifconfig bridge1 vnet rootbridge1
ifconfig bridge2 vnet rootbridge2
ifconfig bridge3 vnet rootbridge3
ifconfig bridge4 vnet rootbridge4
ifconfig bridge5 vnet bridge1
ifconfig bridge6 vnet bridge2
ifconfig bridge7 vnet bridge3
ifconfig bridge8 vnet bridge4

#jexec rootbridge1 ifconfig bridge1 create 
#jexec rootbridge2 ifconfig bridge2 create 
#jexec rootbridge3 ifconfig bridge3 create 
#jexec rootbridge4 ifconfig bridge4 create 
#jexec bridge1 ifconfig bridge5 create 
#jexec bridge2 ifconfig bridge6 create
#jexec bridge3 ifconfig bridge7 create
#jexec bridge4 ifconfig bridge8 create

a=0
for f in `csh -c 'echo rootbridge{1,2,3,4} bridge{1,2,3,4}'`
do
	a=$(($a + 1))
	jexec $f ifconfig lo0 127.1
	apply "jexec $f ifconfig %1 up" `jexec $f ifconfig -l`
	bridge=`jexec $f ifconfig -l | tr ' ' '\n' | grep bridge`
	apply "jexec $f ifconfig $bridge addm %1 stp %1" `jexec $f ifconfig -l | tr ' ' '\n' | grep epair`
	jexec $f ifconfig $bridge 10.16.0.$a
done

for f in `csh -c 'echo rootbridge{1,2,3,4}'`
do
	bridge=`jexec $f ifconfig -l | tr ' ' '\n' | grep bridge`
	jexec $f ifconfig $bridge priority 16384
done

for f in `csh -c 'echo pc{1,2,3,4}{1,2,3}'`
do
	jexec $f ifconfig lo0 127.1
	ip=`echo $f | sed 's/pc/10.255.0./'`
	jexec $f ifconfig `jexec $f ifconfig -l | tr ' ' '\n' | grep epair` $ip
done

-------------- next part --------------
Index: sys/net/if_bridge.c
===================================================================
--- sys/net/if_bridge.c	(revision 217337)
+++ sys/net/if_bridge.c	(working copy)
@@ -332,6 +332,9 @@
 #endif /* INET6 */
 static int	bridge_fragment(struct ifnet *, struct mbuf *,
 		    struct ether_header *, int, struct llc *);
+#ifdef VIMAGE
+static void	bridge_reassign(struct ifnet *, struct vnet *, char *unused);
+#endif
 
 /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
 #define	VLANTAGOF(_m)	\
@@ -345,30 +348,38 @@
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
 
-static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */
-static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */
-static int pfil_member = 1; /* run pfil hooks on the member interface */
-static int pfil_ipfw = 0;   /* layer2 filter with ipfw */
-static int pfil_ipfw_arp = 0;   /* layer2 filter with ipfw */
-static int pfil_local_phys = 0; /* run pfil hooks on the physical interface for
+static VNET_DEFINE(int, pfil_onlyip) = 1; /* only pass IP[46] packets when pfil is enabled */
+static VNET_DEFINE(int, pfil_bridge) = 1; /* run pfil hooks on the bridge interface */
+static VNET_DEFINE(int, pfil_member) = 1; /* run pfil hooks on the member interface */
+static VNET_DEFINE(int, pfil_ipfw) = 0;   /* layer2 filter with ipfw */
+static VNET_DEFINE(int, pfil_ipfw_arp) = 0;   /* layer2 filter with ipfw */
+static VNET_DEFINE(int, pfil_local_phys) = 0; /* run pfil hooks on the physical interface for
                                    locally destined packets */
-static int log_stp   = 0;   /* log STP state changes */
-static int bridge_inherit_mac = 0;   /* share MAC with first bridge member */
-SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW,
-    &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW,
-    &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW,
-    &pfil_bridge, 0, "Packet filter on the bridge interface");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW,
-    &pfil_member, 0, "Packet filter on the member interface");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW,
-    &pfil_local_phys, 0,
+static VNET_DEFINE(int, log_stp)  = 0;   /* log STP state changes */
+static VNET_DEFINE(int, bridge_inherit_mac) = 0;   /* share MAC with first bridge member */
+#define V_pfil_onlyip		VNET(pfil_onlyip)
+#define V_pfil_bridge		VNET(pfil_bridge)
+#define V_pfil_member		VNET(pfil_member)
+#define V_pfil_ipfw		VNET(pfil_ipfw)
+#define V_pfil_ipfw_arp		VNET(pfil_ipfw_arp)
+#define V_pfil_local_phys	VNET(pfil_local_phys)
+#define V_log_stp		VNET(log_stp)
+#define V_bridge_inherit_mac	VNET(bridge_inherit_mac)
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW,
+    &VNET_NAME(pfil_onlyip), 0, "Only pass IP packets when pfil is enabled");
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW,
+    &VNET_NAME(pfil_ipfw_arp), 0, "Filter ARP packets through IPFW layer2");
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW,
+    &VNET_NAME(pfil_bridge), 0, "Packet filter on the bridge interface");
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW,
+    &VNET_NAME(pfil_member), 0, "Packet filter on the member interface");
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW,
+    &VNET_NAME(pfil_local_phys), 0,
     "Packet filter on the physical interface for locally destined packets");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW,
-    &log_stp, 0, "Log STP state changes");
-SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW,
-    &bridge_inherit_mac, 0,
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW,
+    &VNET_NAME(log_stp), 0, "Log STP state changes");
+SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW,
+    &VNET_NAME(bridge_inherit_mac), 0,
     "Inherit MAC address from the first bridge member");
 
 struct bridge_control {
@@ -523,14 +534,14 @@
 static int
 sysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS)
 {
-	int enable = pfil_ipfw;
+	int enable = V_pfil_ipfw;
 	int error;
 
 	error = sysctl_handle_int(oidp, &enable, 0, req);
 	enable = (enable) ? 1 : 0;
 
-	if (enable != pfil_ipfw) {
-		pfil_ipfw = enable;
+	if (enable != V_pfil_ipfw) {
+		V_pfil_ipfw = enable;
 
 		/*
 		 * Disable pfil so that ipfw doesnt run twice, if the user
@@ -538,17 +549,17 @@
 		 * pfil_member. Also allow non-ip packets as ipfw can filter by
 		 * layer2 type.
 		 */
-		if (pfil_ipfw) {
-			pfil_onlyip = 0;
-			pfil_bridge = 0;
-			pfil_member = 0;
+		if (V_pfil_ipfw) {
+			V_pfil_onlyip = 0;
+			V_pfil_bridge = 0;
+			V_pfil_member = 0;
 		}
 	}
 
 	return (error);
 }
-SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW,
-	    &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW");
+SYSCTL_VNET_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW,
+	    &VNET_NAME(pfil_ipfw), 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW");
 
 /*
  * bridge_clone_create:
@@ -620,6 +631,11 @@
 	/* Now undo some of the damage... */
 	ifp->if_baudrate = 0;
 	ifp->if_type = IFT_BRIDGE;
+#ifdef VIMAGE
+	ifp->if_reassign = bridge_reassign;
+#else
+	ifp->if_reassign = NULL;
+#endif
 
 	mtx_lock(&bridge_list_mtx);
 	LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
@@ -923,7 +939,7 @@
 	 * the mac address of the bridge to the address of the next member, or
 	 * to its default address if no members are left.
 	 */
-	if (bridge_inherit_mac && sc->sc_ifaddr == ifs) {
+	if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) {
 		if (LIST_EMPTY(&sc->sc_iflist)) {
 			bcopy(sc->sc_defaddr,
 			    IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
@@ -1046,7 +1062,7 @@
 	 * member and the MAC address of the bridge has not been changed from
 	 * the default randomly generated one.
 	 */
-	if (bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) &&
+	if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) &&
 	    !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) {
 		bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
 		sc->sc_ifaddr = ifs;
@@ -2279,7 +2295,7 @@
 			ETHER_BPF_MTAP(iface, m);			\
 			iface->if_ipackets++;				\
 			/* Filter on the physical interface. */		\
-			if (pfil_local_phys &&				\
+			if (V_pfil_local_phys &&				\
 			    (PFIL_HOOKED(&V_inet_pfil_hook)		\
 			     OR_PFIL_HOOKED_INET6)) {			\
 				if (bridge_pfil(&m, NULL, ifp,		\
@@ -2937,9 +2953,11 @@
 		"discarding"
 	};
 
-	if (log_stp)
+	CURVNET_SET(ifp->if_vnet);
+	if (V_log_stp)
 		log(LOG_NOTICE, "%s: state changed to %s on %s\n",
 		    sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname);
+	CURVNET_RESTORE();
 }
 
 /*
@@ -2966,7 +2984,7 @@
 	KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__));
 #endif
 
-	if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0)
+	if (V_pfil_bridge == 0 && V_pfil_member == 0 && V_pfil_ipfw == 0)
 		return (0); /* filtering is disabled */
 
 	i = min((*mp)->m_pkthdr.len, max_protohdr);
@@ -3008,7 +3026,7 @@
 	switch (ether_type) {
 		case ETHERTYPE_ARP:
 		case ETHERTYPE_REVARP:
-			if (pfil_ipfw_arp == 0)
+			if (V_pfil_ipfw_arp == 0)
 				return (0); /* Automatically pass */
 			break;
 
@@ -3023,7 +3041,7 @@
 			 * packets, these will not be checked by pfil(9) and
 			 * passed unconditionally so the default is to drop.
 			 */
-			if (pfil_onlyip)
+			if (V_pfil_onlyip)
 				goto bad;
 	}
 
@@ -3059,7 +3077,7 @@
 
 	/* XXX this section is also in if_ethersubr.c */
 	// XXX PFIL_OUT or DIR_OUT ?
-	if (V_ip_fw_chk_ptr && pfil_ipfw != 0 &&
+	if (V_ip_fw_chk_ptr && V_pfil_ipfw != 0 &&
 			dir == PFIL_OUT && ifp != NULL) {
 		struct m_tag *mtag;
 
@@ -3136,21 +3154,21 @@
 		 * Keep the order:
 		 *   in_if -> bridge_if -> out_if
 		 */
-		if (pfil_bridge && dir == PFIL_OUT && bifp != NULL)
+		if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
 			error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
 					dir, NULL);
 
 		if (*mp == NULL || error != 0) /* filter may consume */
 			break;
 
-		if (pfil_member && ifp != NULL)
+		if (V_pfil_member && ifp != NULL)
 			error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp,
 					dir, NULL);
 
 		if (*mp == NULL || error != 0) /* filter may consume */
 			break;
 
-		if (pfil_bridge && dir == PFIL_IN && bifp != NULL)
+		if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
 			error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
 					dir, NULL);
 
@@ -3158,7 +3176,7 @@
 			break;
 
 		/* check if we need to fragment the packet */
-		if (pfil_member && ifp != NULL && dir == PFIL_OUT) {
+		if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) {
 			i = (*mp)->m_pkthdr.len;
 			if (i > ifp->if_mtu) {
 				error = bridge_fragment(ifp, *mp, &eh2, snap,
@@ -3190,21 +3208,21 @@
 		break;
 #ifdef INET6
 	case ETHERTYPE_IPV6:
-		if (pfil_bridge && dir == PFIL_OUT && bifp != NULL)
+		if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
 			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
 					dir, NULL);
 
 		if (*mp == NULL || error != 0) /* filter may consume */
 			break;
 
-		if (pfil_member && ifp != NULL)
+		if (V_pfil_member && ifp != NULL)
 			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp,
 					dir, NULL);
 
 		if (*mp == NULL || error != 0) /* filter may consume */
 			break;
 
-		if (pfil_bridge && dir == PFIL_IN && bifp != NULL)
+		if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
 			error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
 					dir, NULL);
 		break;
@@ -3454,3 +3472,26 @@
 		m_freem(m);
 	return (error);
 }
+
+#ifdef VIMAGE
+void
+bridge_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused)
+{
+	struct bridge_softc *sc = ifp->if_softc;
+	struct bridge_iflist *bif;
+
+	BRIDGE_LOCK(sc);
+
+	bridge_stop(ifp, 1);
+	ifp->if_flags &= ~IFF_UP;
+
+	while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
+		bridge_delete_member(sc, bif, 0);
+
+	while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) {
+		bridge_delete_span(sc, bif);
+	}
+
+	BRIDGE_UNLOCK(sc);
+}
+#endif /* VIMAGE */
Index: sys/net/bridgestp.c
===================================================================
--- sys/net/bridgestp.c	(revision 217337)
+++ sys/net/bridgestp.c	(working copy)
@@ -1804,12 +1804,19 @@
 	bzero((char *)&ifmr, sizeof(ifmr));
 	error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
 
-	if ((error == 0) && (ifp->if_flags & IFF_UP)) {
-		if (ifmr.ifm_status & IFM_ACTIVE) {
+	if (ifp->if_flags & IFF_UP) {
+		if (ifp->if_link_state == LINK_STATE_UP) {
 			/* A full-duplex link is assumed to be point to point */
 			if (bp->bp_flags & BSTP_PORT_AUTOPTP) {
-				bp->bp_ptp_link =
-				    ifmr.ifm_active & IFM_FDX ? 1 : 0;
+				/* Interfaces that do not support ifmedia,
+				 * are assumed to be full-duplex. if_epair
+				 * and ng_eiface fall into this category.
+				 */
+				if (error == 0)
+					bp->bp_ptp_link =
+					    ifmr.ifm_active & IFM_FDX ? 1 : 0;
+				else if (error == EINVAL)
+					bp->bp_ptp_link = 1;
 			}
 
 			/* Calc the cost if the link was down previously */



More information about the freebsd-virtualization mailing list