From owner-svn-src-stable@FreeBSD.ORG Fri Jul 12 01:52:33 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id A9F13803; Fri, 12 Jul 2013 01:52:33 +0000 (UTC) (envelope-from hrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 9B52611A5; Fri, 12 Jul 2013 01:52:33 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r6C1qXDV006239; Fri, 12 Jul 2013 01:52:33 GMT (envelope-from hrs@svn.freebsd.org) Received: (from hrs@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r6C1qVdS006230; Fri, 12 Jul 2013 01:52:31 GMT (envelope-from hrs@svn.freebsd.org) Message-Id: <201307120152.r6C1qVdS006230@svn.freebsd.org> From: Hiroki Sato Date: Fri, 12 Jul 2013 01:52:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r253239 - in stable/9: share/man/man4 sys/net sys/netinet6 X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 12 Jul 2013 01:52:33 -0000 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 #include +#include #endif #if defined(INET) || defined(INET6) #include @@ -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 +#include +#include #endif #include @@ -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 */