Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Apr 2012 09:55:50 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r234487 - head/sys/net
Message-ID:  <201204200955.q3K9toPQ032775@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Fri Apr 20 09:55:50 2012
New Revision: 234487
URL: http://svn.freebsd.org/changeset/base/234487

Log:
  Add linkstate to bridge(4), set the link to up when at least one underlying
  interface is up, otherwise the link is down.
  
  This, among other things, allows carp to work on a bridge.
  
  Prodded by:	glebius
  Tested by:	Alexander Lunev

Modified:
  head/sys/net/bridgestp.c
  head/sys/net/bridgestp.h
  head/sys/net/if.c
  head/sys/net/if_bridge.c

Modified: head/sys/net/bridgestp.c
==============================================================================
--- head/sys/net/bridgestp.c	Fri Apr 20 09:43:42 2012	(r234486)
+++ head/sys/net/bridgestp.c	Fri Apr 20 09:55:50 2012	(r234487)
@@ -1767,28 +1767,16 @@ bstp_notify_rtage(void *arg, int pending
 }
 
 void
-bstp_linkstate(struct ifnet *ifp, int state)
+bstp_linkstate(struct bstp_port *bp)
 {
-	struct bstp_state *bs;
-	struct bstp_port *bp;
+	struct bstp_state *bs = bp->bp_bs;
 
-	/* search for the stp port */
-	mtx_lock(&bstp_list_mtx);
-	LIST_FOREACH(bs, &bstp_list, bs_list) {
-		BSTP_LOCK(bs);
-		LIST_FOREACH(bp, &bs->bs_bplist, bp_next) {
-			if (bp->bp_ifp == ifp) {
-				bstp_ifupdstatus(bs, bp);
-				bstp_update_state(bs, bp);
-				/* it only exists once so return */
-				BSTP_UNLOCK(bs);
-				mtx_unlock(&bstp_list_mtx);
-				return;
-			}
-		}
-		BSTP_UNLOCK(bs);
+	BSTP_LOCK(bs);
+	if (bp->bp_active) {
+		bstp_ifupdstatus(bs, bp);
+		bstp_update_state(bs, bp);
 	}
-	mtx_unlock(&bstp_list_mtx);
+	BSTP_UNLOCK(bs);
 }
 
 static void
@@ -2103,10 +2091,8 @@ bstp_modevent(module_t mod, int type, vo
 	case MOD_LOAD:
 		mtx_init(&bstp_list_mtx, "bridgestp list", NULL, MTX_DEF);
 		LIST_INIT(&bstp_list);
-		bstp_linkstate_p = bstp_linkstate;
 		break;
 	case MOD_UNLOAD:
-		bstp_linkstate_p = NULL;
 		mtx_destroy(&bstp_list_mtx);
 		break;
 	default:

Modified: head/sys/net/bridgestp.h
==============================================================================
--- head/sys/net/bridgestp.h	Fri Apr 20 09:43:42 2012	(r234486)
+++ head/sys/net/bridgestp.h	Fri Apr 20 09:55:50 2012	(r234487)
@@ -369,8 +369,6 @@ struct bstp_state {
 
 extern const uint8_t bstp_etheraddr[];
 
-extern	void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
-
 void	bstp_attach(struct bstp_state *, struct bstp_cb_ops *);
 void	bstp_detach(struct bstp_state *);
 void	bstp_init(struct bstp_state *);
@@ -379,7 +377,7 @@ int	bstp_create(struct bstp_state *, str
 int	bstp_enable(struct bstp_port *);
 void	bstp_disable(struct bstp_port *);
 void	bstp_destroy(struct bstp_port *);
-void	bstp_linkstate(struct ifnet *, int);
+void	bstp_linkstate(struct bstp_port *);
 int	bstp_set_htime(struct bstp_state *, int);
 int	bstp_set_fdelay(struct bstp_state *, int);
 int	bstp_set_maxage(struct bstp_state *, int);

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Fri Apr 20 09:43:42 2012	(r234486)
+++ head/sys/net/if.c	Fri Apr 20 09:55:50 2012	(r234487)
@@ -124,7 +124,7 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr
 static struct sx ifdescr_sx;
 SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
 
-void	(*bstp_linkstate_p)(struct ifnet *ifp, int state);
+void	(*bridge_linkstate_p)(struct ifnet *ifp);
 void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
 void	(*lagg_linkstate_p)(struct ifnet *ifp, int state);
 /* These are external hooks for CARP. */
@@ -1910,7 +1910,7 @@ do_link_state_change(void *arg, int pend
 	if (ifp->if_carp)
 		(*carp_linkstate_p)(ifp);
 	if (ifp->if_bridge)
-		(*bstp_linkstate_p)(ifp, link_state);
+		(*bridge_linkstate_p)(ifp);
 	if (ifp->if_lagg)
 		(*lagg_linkstate_p)(ifp, link_state);
 

Modified: head/sys/net/if_bridge.c
==============================================================================
--- head/sys/net/if_bridge.c	Fri Apr 20 09:43:42 2012	(r234486)
+++ head/sys/net/if_bridge.c	Fri Apr 20 09:55:50 2012	(r234487)
@@ -333,6 +333,9 @@ static int	bridge_ip6_checkbasic(struct 
 #endif /* INET6 */
 static int	bridge_fragment(struct ifnet *, struct mbuf *,
 		    struct ether_header *, int, struct llc *);
+static void	bridge_linkstate(struct ifnet *ifp);
+
+extern void (*bridge_linkstate_p)(struct ifnet *ifp);
 
 /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
 #define	VLANTAGOF(_m)	\
@@ -496,6 +499,7 @@ bridge_modevent(module_t mod, int type, 
 		bridge_input_p = bridge_input;
 		bridge_output_p = bridge_output;
 		bridge_dn_p = bridge_dummynet;
+		bridge_linkstate_p = bridge_linkstate;
 		bridge_detach_cookie = EVENTHANDLER_REGISTER(
 		    ifnet_departure_event, bridge_ifdetach, NULL,
 		    EVENTHANDLER_PRI_ANY);
@@ -508,6 +512,7 @@ bridge_modevent(module_t mod, int type, 
 		bridge_input_p = NULL;
 		bridge_output_p = NULL;
 		bridge_dn_p = NULL;
+		bridge_linkstate_p = NULL;
 		mtx_destroy(&bridge_list_mtx);
 		break;
 	default:
@@ -988,6 +993,7 @@ bridge_delete_member(struct bridge_softc
 		bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
 	}
 	bstp_destroy(&bif->bif_stp);	/* prepare to free */
+	bridge_linkstate(ifs);
 	BRIDGE_LOCK(sc);
 	free(bif, M_DEVBUF);
 }
@@ -1087,17 +1093,17 @@ bridge_ioctl_add(struct bridge_softc *sc
 	/* Set interface capabilities to the intersection set of all members */
 	bridge_mutecaps(sc);
 
+	BRIDGE_UNLOCK(sc);
+	/* Update the linkstate for the bridge */
+	bridge_linkstate(ifs);
+	/* Place the interface into promiscuous mode */
 	switch (ifs->if_type) {
-	case IFT_ETHER:
-	case IFT_L2VLAN:
-		/*
-		 * Place the interface into promiscuous mode.
-		 */
-		BRIDGE_UNLOCK(sc);
-		error = ifpromisc(ifs, 1);
-		BRIDGE_LOCK(sc);
-		break;
+		case IFT_ETHER:
+		case IFT_L2VLAN:
+			error = ifpromisc(ifs, 1);
+			break;
 	}
+	BRIDGE_LOCK(sc);
 	if (error)
 		bridge_delete_member(sc, bif, 0);
 out:
@@ -3475,3 +3481,38 @@ out:
 		m_freem(m);
 	return (error);
 }
+
+static void
+bridge_linkstate(struct ifnet *ifp)
+{
+	struct bridge_softc *sc = ifp->if_bridge;
+	struct bridge_iflist *bif, *bif2;
+	int new_link, hasls;
+
+	BRIDGE_LOCK(sc);
+	bif = bridge_lookup_member_if(sc, ifp);
+	if (bif == NULL) {
+		BRIDGE_UNLOCK(sc);
+		return;
+	}
+	new_link = LINK_STATE_DOWN;
+	hasls = 0;
+	/* Our link is considered up if at least one of our ports is active */
+	LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
+		if (bif2->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
+			hasls++;
+		if (bif2->bif_ifp->if_link_state == LINK_STATE_UP) {
+			new_link = LINK_STATE_UP;
+			break;
+		}
+	}
+	if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) {
+		/* If no interfaces support link-state then we default to up */
+		new_link = LINK_STATE_UP;
+	}
+	if_link_state_change(sc->sc_ifp, new_link);
+	BRIDGE_UNLOCK(sc);
+
+	bstp_linkstate(&bif->bif_stp);
+}
+



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204200955.q3K9toPQ032775>