From owner-svn-src-all@FreeBSD.ORG Tue Jul 2 16:58:17 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 816C7463; Tue, 2 Jul 2013 16:58:17 +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 737AA1A01; Tue, 2 Jul 2013 16:58:17 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r62GwHph008347; Tue, 2 Jul 2013 16:58:17 GMT (envelope-from hrs@svn.freebsd.org) Received: (from hrs@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r62GwGJI008338; Tue, 2 Jul 2013 16:58:16 GMT (envelope-from hrs@svn.freebsd.org) Message-Id: <201307021658.r62GwGJI008338@svn.freebsd.org> From: Hiroki Sato Date: Tue, 2 Jul 2013 16:58:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r252511 - in head/sys: net netinet6 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 16:58:17 -0000 Author: hrs Date: Tue Jul 2 16:58:15 2013 New Revision: 252511 URL: http://svnweb.freebsd.org/changeset/base/252511 Log: - 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. [*] Submitted by: rpaulo [*] MFC after: 1 week Modified: head/sys/net/if_bridge.c head/sys/net/if_lagg.c head/sys/netinet6/in6.c head/sys/netinet6/in6_ifattach.c head/sys/netinet6/in6_var.h head/sys/netinet6/nd6.c Modified: head/sys/net/if_bridge.c ============================================================================== --- head/sys/net/if_bridge.c Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/net/if_bridge.c Tue Jul 2 16:58:15 2013 (r252511) @@ -118,6 +118,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,94 @@ 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. + */ + 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 +1171,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); } @@ -3408,7 +3473,7 @@ bridge_fragment(struct ifnet *ifp, struc continue; } bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); - } else + } else m_freem(m); } Modified: head/sys/net/if_lagg.c ============================================================================== --- head/sys/net/if_lagg.c Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/net/if_lagg.c Tue Jul 2 16:58:15 2013 (r252511) @@ -63,6 +63,8 @@ __FBSDID("$FreeBSD$"); #ifdef INET6 #include +#include +#include #endif #include @@ -543,6 +545,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: head/sys/netinet6/in6.c ============================================================================== --- head/sys/netinet6/in6.c Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/netinet6/in6.c Tue Jul 2 16:58:15 2013 (r252511) @@ -1987,6 +1987,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: head/sys/netinet6/in6_ifattach.c ============================================================================== --- head/sys/netinet6/in6_ifattach.c Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/netinet6/in6_ifattach.c Tue Jul 2 16:58:15 2013 (r252511) @@ -266,6 +266,7 @@ found: /* get EUI64 */ switch (ifp->if_type) { + case IFT_BRIDGE: case IFT_ETHER: case IFT_L2VLAN: case IFT_FDDI: @@ -727,6 +728,8 @@ in6_ifattach(struct ifnet *ifp, struct i switch (ifp->if_type) { case IFT_PFLOG: case IFT_PFSYNC: + ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; + ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; return; } @@ -734,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. @@ -742,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; } @@ -777,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; @@ -795,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: head/sys/netinet6/in6_var.h ============================================================================== --- head/sys/netinet6/in6_var.h Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/netinet6/in6_var.h Tue Jul 2 16:58:15 2013 (r252511) @@ -800,6 +800,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: head/sys/netinet6/nd6.c ============================================================================== --- head/sys/netinet6/nd6.c Tue Jul 2 16:39:12 2013 (r252510) +++ head/sys/netinet6/nd6.c Tue Jul 2 16:58:15 2013 (r252511) @@ -176,13 +176,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;