- 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
This commit is contained in:
parent
e32d93954d
commit
af8056441e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=252511
@ -118,6 +118,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, void *arg)
|
||||
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, void *arg)
|
||||
/* 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, void *arg)
|
||||
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, struct mbuf *m, struct ether_header *eh,
|
||||
continue;
|
||||
}
|
||||
bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN);
|
||||
} else
|
||||
} else
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
@ -543,6 +545,34 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
|
||||
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;
|
||||
|
@ -1986,6 +1986,32 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
|
||||
return ((struct in6_ifaddr *)ifa);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -266,6 +266,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
|
||||
|
||||
/* 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 ifnet *altifp)
|
||||
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 ifnet *altifp)
|
||||
* 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 ifnet *altifp)
|
||||
* 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 ifnet *altifp)
|
||||
/*
|
||||
* 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 ifnet *altifp)
|
||||
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;
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user