svn commit: r253239 - in stable/9: share/man/man4 sys/net sys/netinet6

Hiroki Sato hrs at FreeBSD.org
Fri Jul 12 01:52:33 UTC 2013


Author: hrs
Date: Fri Jul 12 01:52:31 2013
New Revision: 253239
URL: http://svnweb.freebsd.org/changeset/base/253239

Log:
  MFC 232379, 252511, 252548, 253060:
  
  - Allow to configure net.inet6.ip6.{accept_rtadv,no_radr} by the
    loader tunables as well because they have to be configured before
    interface initialization for AF_INET6.
  
  - Allow ND6_IFF_AUTO_LINKLOCAL for IFT_BRIDGE.  An interface with IFT_BRIDGE
    is initialized with !ND6_IFF_AUTO_LINKLOCAL && !ND6_IFF_ACCEPT_RTADV
    regardless of net.inet6.ip6.accept_rtadv and net.inet6.ip6.auto_linklocal.
    To configure an autoconfigured link-local address (RFC 4862), the
    following rc.conf(5) configuration can be used:
  
     ifconfig_bridge0_ipv6="inet6 auto_linklocal"
  
  - if_bridge(4) now removes IPv6 addresses on a member interface to be
    added when the parent interface or one of the existing member
    interfaces has an IPv6 address.  if_bridge(4) merges each link-local
    scope zone which the member interfaces form respectively, so it causes
    address scope violation.  Removal of the IPv6 addresses prevents it.
  
  - if_lagg(4) now removes IPv6 addresses on a member interfaces
    unconditionally.
  
  - Set reasonable flags to non-IPv6-capable interfaces.

Modified:
  stable/9/share/man/man4/bridge.4
  stable/9/sys/net/if_bridge.c
  stable/9/sys/net/if_lagg.c
  stable/9/sys/netinet6/in6.c
  stable/9/sys/netinet6/in6_ifattach.c
  stable/9/sys/netinet6/in6_var.h
  stable/9/sys/netinet6/ip6_input.c
  stable/9/sys/netinet6/nd6.c
Directory Properties:
  stable/9/share/man/man4/   (props changed)
  stable/9/sys/   (props changed)

Modified: stable/9/share/man/man4/bridge.4
==============================================================================
--- stable/9/share/man/man4/bridge.4	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/share/man/man4/bridge.4	Fri Jul 12 01:52:31 2013	(r253239)
@@ -35,7 +35,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 9, 2010
+.Dd July 3, 2013
 .Dt IF_BRIDGE 4
 .Os
 .Sh NAME
@@ -142,6 +142,79 @@ This can be used to multiplex the input 
 stream.
 This is useful for reconstructing the traffic for network taps
 that transmit the RX/TX signals out through two separate interfaces.
+.Sh IPV6 SUPPORT
+.Nm
+supports the
+.Li AF_INET6
+address family on bridge interfaces.
+The following
+.Xr rc.conf 5
+variable configures an IPv6 link-local address on
+.Li bridge0
+interface: 
+.Bd -literal -offset indent
+ifconfig_bridge0_ipv6="up"
+.Ed
+.Pp
+or in a more explicit manner:
+.Bd -literal -offset indent
+ifconfig_bridge0_ipv6="inet6 auto_linklocal"
+.Ed
+.Pp
+However, the
+.Li AF_INET6
+address family has a concept of scope zone.
+Bridging multiple interfaces change the zone configuration because
+multiple links are merged to each other and form a new single link
+while the member interfaces still work individually.
+This means each member interface still has a separate link-local scope
+zone and the
+.Nm
+interface has another single,
+aggregated link-local scope zone at the same time.
+This situation is clearly against the description
+.Qq zones of the same scope cannot overlap
+in Section 5,
+RFC 4007.
+Although it works in most cases,
+it can cause some conterintuitive or undesirable behavior in some
+edge cases when both of the
+.Nm
+interface and one of the member interface have an IPv6 address
+and applications use both of them.
+.Pp
+To prevent this situation,
+.Nm
+checks whether an link-local scoped IPv6 address is configured on
+a member interface to be added and the 
+.Nm
+interface.
+When the
+.Nm
+interface has IPv6 addresses,
+IPv6 addresses on the member interface will be automatically removed
+before the interface is added.
+When both
+.Nm
+interface and the existing member interfaces do not have one,
+adding an interface with IPv6 addresses as a new member interface is allowed.
+These means only one interface in the link-local scope zone where the
+.Nm
+interface forms can have link-local scoped IPv6 addresses.
+.Pp
+Note that
+.Li ACCEPT_RTADV
+and
+.Li AUTO_LINKLOCAL
+interface flag are not enabled by default on
+.Nm
+interface even when
+.Va net.inet6.ip6.accept_rtadv
+and/or
+.Va net.inet6.ip6.auto_linklocal
+is set to
+.Li 1 .
+.Ed
 .Sh SPANNING TREE
 The
 .Nm

Modified: stable/9/sys/net/if_bridge.c
==============================================================================
--- stable/9/sys/net/if_bridge.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/net/if_bridge.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -119,6 +119,7 @@ __FBSDID("$FreeBSD$");
 #ifdef INET6
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
+#include <netinet6/in6_ifattach.h>
 #endif
 #if defined(INET) || defined(INET6)
 #include <netinet/ip_carp.h>
@@ -1041,14 +1042,6 @@ bridge_ioctl_add(struct bridge_softc *sc
 	if (ifs->if_bridge != NULL)
 		return (EBUSY);
 
-	bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
-	if (bif == NULL)
-		return (ENOMEM);
-
-	bif->bif_ifp = ifs;
-	bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
-	bif->bif_savedcaps = ifs->if_capenable;
-
 	switch (ifs->if_type) {
 	case IFT_ETHER:
 	case IFT_L2VLAN:
@@ -1056,20 +1049,95 @@ bridge_ioctl_add(struct bridge_softc *sc
 		/* permitted interface types */
 		break;
 	default:
-		error = EINVAL;
-		goto out;
+		return (EINVAL);
 	}
 
+#ifdef INET6
+	/*
+	 * Two valid inet6 addresses with link-local scope must not be
+	 * on the parent interface and the member interfaces at the
+	 * same time.  This restriction is needed to prevent violation
+	 * of link-local scope zone.  Attempts to add a member
+	 * interface which has inet6 addresses when the parent has
+	 * inet6 triggers removal of all inet6 addresses on the member
+	 * interface.
+	 */
+
+	/* Check if the parent interface has a link-local scope addr. */
+	if (in6ifa_llaonifp(sc->sc_ifp) != NULL) {
+		/*
+		 * If any, remove all inet6 addresses from the member
+		 * interfaces.
+		 */
+		BRIDGE_XLOCK(sc);
+		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+ 			if (in6ifa_llaonifp(bif->bif_ifp)) {
+				BRIDGE_UNLOCK(sc);
+				in6_ifdetach(bif->bif_ifp);
+				BRIDGE_LOCK(sc);
+				if_printf(sc->sc_ifp,
+				    "IPv6 addresses on %s have been removed "
+				    "before adding it as a member to prevent "
+				    "IPv6 address scope violation.\n",
+				    bif->bif_ifp->if_xname);
+			}
+		}
+		BRIDGE_XDROP(sc);
+		if (in6ifa_llaonifp(ifs)) {
+			BRIDGE_UNLOCK(sc);
+			in6_ifdetach(ifs);
+			BRIDGE_LOCK(sc);
+			if_printf(sc->sc_ifp,
+			    "IPv6 addresses on %s have been removed "
+			    "before adding it as a member to prevent "
+			    "IPv6 address scope violation.\n",
+			    ifs->if_xname);
+		}
+	} else {
+		struct in6_ifaddr *ia6_m, *ia6_s;
+		/*
+		 * If not, check whether one of the existing member
+		 * interfaces have inet6 address.  If any, remove
+		 * inet6 addresses on the interface to be added.
+		 */
+		ia6_m = NULL;
+		BRIDGE_XLOCK(sc);
+		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+			ia6_m = in6ifa_llaonifp(bif->bif_ifp);
+			if (ia6_m != NULL)
+				break;
+		}
+		BRIDGE_XDROP(sc);
+		ia6_s = in6ifa_llaonifp(ifs);
+
+		if (ia6_m != NULL && ia6_s != NULL) {
+			BRIDGE_UNLOCK(sc);
+			in6_ifdetach(ifs);
+			BRIDGE_LOCK(sc);
+			if_printf(sc->sc_ifp, "IPv6 addresses on %s have "
+				  "been removed before adding it as a member "
+				  "to prevent IPv6 address scope violation.\n",
+				  ifs->if_xname);
+		}
+	}
+#endif
 	/* Allow the first Ethernet member to define the MTU */
 	if (LIST_EMPTY(&sc->sc_iflist))
 		sc->sc_ifp->if_mtu = ifs->if_mtu;
 	else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
 		if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n",
 		    ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu);
-		error = EINVAL;
-		goto out;
+		return (EINVAL);
 	}
 
+	bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
+	if (bif == NULL)
+		return (ENOMEM);
+
+	bif->bif_ifp = ifs;
+	bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
+	bif->bif_savedcaps = ifs->if_capenable;
+
 	/*
 	 * Assign the interface's MAC address to the bridge if it's the first
 	 * member and the MAC address of the bridge has not been changed from
@@ -1104,12 +1172,10 @@ bridge_ioctl_add(struct bridge_softc *sc
 			BRIDGE_LOCK(sc);
 			break;
 	}
-	if (error)
-		bridge_delete_member(sc, bif, 0);
-out:
+
 	if (error) {
-		if (bif != NULL)
-			free(bif, M_DEVBUF);
+		bridge_delete_member(sc, bif, 0);
+		free(bif, M_DEVBUF);
 	}
 	return (error);
 }
@@ -3473,7 +3539,7 @@ bridge_fragment(struct ifnet *ifp, struc
 				continue;
 			}
 			bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
-		} else 
+		} else
 			m_freem(m);
 	}
 

Modified: stable/9/sys/net/if_lagg.c
==============================================================================
--- stable/9/sys/net/if_lagg.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/net/if_lagg.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -63,6 +63,8 @@ __FBSDID("$FreeBSD$");
 
 #ifdef INET6
 #include <netinet/ip6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/in6_ifattach.h>
 #endif
 
 #include <net/if_vlan_var.h>
@@ -532,6 +534,34 @@ lagg_port_create(struct lagg_softc *sc, 
 	if (ifp->if_type != IFT_ETHER)
 		return (EPROTONOSUPPORT);
 
+#ifdef INET6
+	/*
+	 * The member interface should not have inet6 address because
+	 * two interfaces with a valid link-local scope zone must not be
+	 * merged in any form.  This restriction is needed to
+	 * prevent violation of link-local scope zone.  Attempts to
+	 * add a member interface which has inet6 addresses triggers
+	 * removal of all inet6 addresses on the member interface.
+	 */
+	SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+		if (in6ifa_llaonifp(lp->lp_ifp)) {
+			in6_ifdetach(lp->lp_ifp);
+			if_printf(sc->sc_ifp,
+			    "IPv6 addresses on %s have been removed "
+			    "before adding it as a member to prevent "
+			    "IPv6 address scope violation.\n",
+			    lp->lp_ifp->if_xname);
+		}
+	}
+	if (in6ifa_llaonifp(ifp)) {
+		in6_ifdetach(ifp);
+		if_printf(sc->sc_ifp,
+		    "IPv6 addresses on %s have been removed "
+		    "before adding it as a member to prevent "
+		    "IPv6 address scope violation.\n",
+		    ifp->if_xname);
+	}
+#endif
 	/* Allow the first Ethernet member to define the MTU */
 	if (SLIST_EMPTY(&sc->sc_ports))
 		sc->sc_ifp->if_mtu = ifp->if_mtu;

Modified: stable/9/sys/netinet6/in6.c
==============================================================================
--- stable/9/sys/netinet6/in6.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/netinet6/in6.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -1961,6 +1961,32 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, st
 }
 
 /*
+ * Find a link-local scoped address on ifp and return it if any.
+ */
+struct in6_ifaddr *
+in6ifa_llaonifp(struct ifnet *ifp)
+{
+	struct sockaddr_in6 *sin6;
+	struct ifaddr *ifa;
+
+	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
+		return (NULL);
+	if_addr_rlock(ifp);
+	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+		if (ifa->ifa_addr->sa_family != AF_INET6)
+			continue;
+		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+		if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
+		    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) ||
+		    IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr))
+			break;
+	}
+	if_addr_runlock(ifp);
+
+	return ((struct in6_ifaddr *)ifa);
+}
+
+/*
  * Convert IP6 address to printable (loggable) representation. Caller
  * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long.
  */

Modified: stable/9/sys/netinet6/in6_ifattach.c
==============================================================================
--- stable/9/sys/netinet6/in6_ifattach.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/netinet6/in6_ifattach.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -266,6 +266,7 @@ found:
 
 	/* get EUI64 */
 	switch (ifp->if_type) {
+	case IFT_BRIDGE:
 	case IFT_ETHER:
 	case IFT_L2VLAN:
 	case IFT_FDDI:
@@ -727,7 +728,8 @@ in6_ifattach(struct ifnet *ifp, struct i
 	switch (ifp->if_type) {
 	case IFT_PFLOG:
 	case IFT_PFSYNC:
-	case IFT_CARP:
+		ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
+		ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
 		return;
 	}
 
@@ -735,7 +737,6 @@ in6_ifattach(struct ifnet *ifp, struct i
 	 * quirks based on interface type
 	 */
 	switch (ifp->if_type) {
-#ifdef IFT_STF
 	case IFT_STF:
 		/*
 		 * 6to4 interface is a very special kind of beast.
@@ -743,8 +744,8 @@ in6_ifattach(struct ifnet *ifp, struct i
 		 * linklocals for 6to4 interface, but there's no use and
 		 * it is rather harmful to have one.
 		 */
-		goto statinit;
-#endif
+		ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL;
+		break;
 	default:
 		break;
 	}
@@ -778,8 +779,7 @@ in6_ifattach(struct ifnet *ifp, struct i
 	/*
 	 * assign a link-local address, if there's none.
 	 */
-	if (ifp->if_type != IFT_BRIDGE &&
-	    !(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+	if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
 	    ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
 		int error;
 
@@ -796,10 +796,6 @@ in6_ifattach(struct ifnet *ifp, struct i
 			ifa_free(&ia->ia_ifa);
 	}
 
-#ifdef IFT_STF			/* XXX */
-statinit:
-#endif
-
 	/* update dynamically. */
 	if (V_in6_maxmtu < ifp->if_mtu)
 		V_in6_maxmtu = ifp->if_mtu;

Modified: stable/9/sys/netinet6/in6_var.h
==============================================================================
--- stable/9/sys/netinet6/in6_var.h	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/netinet6/in6_var.h	Fri Jul 12 01:52:31 2013	(r253239)
@@ -765,6 +765,7 @@ void	in6_setmaxmtu(void);
 int	in6_if2idlen(struct ifnet *);
 struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);
 struct in6_ifaddr *in6ifa_ifpwithaddr(struct ifnet *, struct in6_addr *);
+struct in6_ifaddr *in6ifa_llaonifp(struct ifnet *);
 char	*ip6_sprintf(char *, const struct in6_addr *);
 int	in6_addr2zoneid(struct ifnet *, struct in6_addr *, u_int32_t *);
 int	in6_matchlen(struct in6_addr *, struct in6_addr *);

Modified: stable/9/sys/netinet6/ip6_input.c
==============================================================================
--- stable/9/sys/netinet6/ip6_input.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/netinet6/ip6_input.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -166,6 +166,8 @@ ip6_init(void)
 
 	TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal",
 	    &V_ip6_auto_linklocal);
+	TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv);
+	TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr);
 
 	TAILQ_INIT(&V_in6_ifaddrhead);
 

Modified: stable/9/sys/netinet6/nd6.c
==============================================================================
--- stable/9/sys/netinet6/nd6.c	Fri Jul 12 01:34:24 2013	(r253238)
+++ stable/9/sys/netinet6/nd6.c	Fri Jul 12 01:52:31 2013	(r253239)
@@ -184,13 +184,25 @@ nd6_ifattach(struct ifnet *ifp)
 
 	nd->flags = ND6_IFF_PERFORMNUD;
 
-	/* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. */
-	if (V_ip6_auto_linklocal || (ifp->if_flags & IFF_LOOPBACK))
+	/* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL.
+	 * XXXHRS: Clear ND6_IFF_AUTO_LINKLOCAL on an IFT_BRIDGE interface by
+	 * default regardless of the V_ip6_auto_linklocal configuration to
+	 * give a reasonable default behavior.
+	 */
+	if ((V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) ||
+	    (ifp->if_flags & IFF_LOOPBACK))
 		nd->flags |= ND6_IFF_AUTO_LINKLOCAL;
-
-	/* A loopback interface does not need to accept RTADV. */
-	if (V_ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK))
-		nd->flags |= ND6_IFF_ACCEPT_RTADV;
+	/*
+	 * A loopback interface does not need to accept RTADV.
+	 * XXXHRS: Clear ND6_IFF_ACCEPT_RTADV on an IFT_BRIDGE interface by
+	 * default regardless of the V_ip6_accept_rtadv configuration to
+	 * prevent the interface from accepting RA messages arrived
+	 * on one of the member interfaces with ND6_IFF_ACCEPT_RTADV.
+	 */
+	if (V_ip6_accept_rtadv &&
+	    !(ifp->if_flags & IFF_LOOPBACK) &&
+	    (ifp->if_type != IFT_BRIDGE))
+			nd->flags |= ND6_IFF_ACCEPT_RTADV;
 	if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK))
 		nd->flags |= ND6_IFF_NO_RADR;
 
@@ -1360,16 +1372,6 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
 		struct ifaddr *ifa;
 		struct in6_ifaddr *ia;
 
-		/*
-		 * Try to clear ifdisabled flag when enabling
-		 * accept_rtadv or auto_linklocal.
-		 */
-		if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
-		    !(ND.flags & ND6_IFF_IFDISABLED) &&
-		    (ND.flags & (ND6_IFF_ACCEPT_RTADV |
-		    ND6_IFF_AUTO_LINKLOCAL)))
-			ND.flags &= ~ND6_IFF_IFDISABLED;
-
 		if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
 		    !(ND.flags & ND6_IFF_IFDISABLED)) {
 			/* ifdisabled 1->0 transision */


More information about the svn-src-stable-9 mailing list