Page MenuHomeFreeBSD

D15406.id77828.diff
No OneTemporary

D15406.id77828.diff

Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -150,6 +150,8 @@
static int in6_notify_ifa(struct ifnet *, struct in6_ifaddr *,
struct in6_aliasreq *, int);
+static int in6_ifaddprefix(struct in6_ifaddr *);
+static int in6_ifremprefix(struct in6_ifaddr *);
static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
static int in6_validate_ifra(struct ifnet *, struct in6_aliasreq *,
@@ -197,6 +199,87 @@
}
}
+/* Add prefix route for the network. */
+static int
+in6_ifaddprefix(struct in6_ifaddr *ia)
+{
+ int error, flags = 0;
+
+ if (in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) == 128) {
+ if (ia->ia_dstaddr.sin6_family != AF_INET6)
+ /* We don't need to install a host route. */
+ return 0;
+ flags |= RTF_HOST;
+ }
+
+ if ((error = rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP | flags)) == 0)
+ ia->ia_flags |= IFA_ROUTE;
+ else if (error == EEXIST)
+ /* Existance of the route is not an error. */
+ error = 0;
+
+ return error;
+}
+
+/*
+ * Delete network prefix route if present.
+ * Re-add it to another address if the prefix matches.
+ */
+static int
+in6_ifremprefix(struct in6_ifaddr *target)
+{
+ int error, flags = 0;
+ struct rm_priotracker in6_ifa_tracker;
+ struct in6_ifaddr *ia;
+
+ if ((target->ia_flags & IFA_ROUTE) == 0)
+ return 0;
+
+ if (in6_mask2len(&target->ia_prefixmask.sin6_addr, NULL) == 128 &&
+ target->ia_dstaddr.sin6_family == AF_INET6)
+ flags |= RTF_HOST;
+
+ IN6_IFADDR_RLOCK(&in6_ifa_tracker);
+ CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+ if (target->ia_dstaddr.sin6_len) {
+ if (ia->ia_dstaddr.sin6_len == 0 ||
+ !IN6_ARE_ADDR_EQUAL(&ia->ia_dstaddr.sin6_addr,
+ &target->ia_dstaddr.sin6_addr))
+ continue;
+ } else {
+ if (!IN6_ARE_MASKED_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
+ &target->ia_addr.sin6_addr,
+ &target->ia_prefixmask.sin6_addr))
+ continue;
+ }
+
+ /*
+ * if we got a matching prefix route, move IFA_ROUTE to him
+ */
+ if ((ia->ia_flags & IFA_ROUTE) == 0) {
+ ifa_ref(&ia->ia_ifa);
+ IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
+
+ rtinit(&target->ia_ifa, RTM_DELETE, flags);
+ target->ia_flags &= ~IFA_ROUTE;
+
+ error = in6_ifaddprefix(ia);
+
+ ifa_free(&ia->ia_ifa);
+
+ return error;
+ }
+ }
+ IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
+
+ /*
+ * noone seem to have prefix route. remove it.
+ */
+ rtinit(&target->ia_ifa, RTM_DELETE, flags);
+ target->ia_flags &= ~IFA_ROUTE;
+ return 0;
+}
+
int
in6_mask2len(struct in6_addr *mask, u_char *lim0)
{
@@ -558,11 +641,8 @@
case SIOCAIFADDR_IN6:
{
- struct nd_prefixctl pr0;
- struct nd_prefix *pr;
-
/*
- * first, make or update the interface address structure,
+ * make or update the interface address structure,
* and link it to the list.
*/
if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
@@ -594,85 +674,6 @@
}
/*
- * then, make the prefix on-link on the interface.
- * XXX: we'd rather create the prefix before the address, but
- * we need at least one address to install the corresponding
- * interface route, so we configure the address first.
- */
-
- /*
- * convert mask to prefix length (prefixmask has already
- * been validated in in6_update_ifa().
- */
- bzero(&pr0, sizeof(pr0));
- pr0.ndpr_ifp = ifp;
- pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
- NULL);
- if (pr0.ndpr_plen == 128) {
- /* we don't need to install a host route. */
- goto aifaddr_out;
- }
- pr0.ndpr_prefix = ifra->ifra_addr;
- /* apply the mask for safety. */
- IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr,
- &ifra->ifra_prefixmask.sin6_addr);
-
- /*
- * XXX: since we don't have an API to set prefix (not address)
- * lifetimes, we just use the same lifetimes as addresses.
- * The (temporarily) installed lifetimes can be overridden by
- * later advertised RAs (when accept_rtadv is non 0), which is
- * an intended behavior.
- */
- pr0.ndpr_raf_onlink = 1; /* should be configurable? */
- pr0.ndpr_raf_auto =
- ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
- pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
- pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
-
- /* add the prefix if not yet. */
- if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
- /*
- * nd6_prelist_add will install the corresponding
- * interface route.
- */
- if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
- if (carp_attached)
- (*carp_detach_p)(&ia->ia_ifa, false);
- goto out;
- }
- }
-
- /* relate the address to the prefix */
- if (ia->ia6_ndpr == NULL) {
- ia->ia6_ndpr = pr;
- pr->ndpr_addrcnt++;
-
- /*
- * If this is the first autoconf address from the
- * prefix, create a temporary address as well
- * (when required).
- */
- if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
- V_ip6_use_tempaddr && pr->ndpr_addrcnt == 1) {
- int e;
- if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
- log(LOG_NOTICE, "in6_control: failed "
- "to create a temporary address, "
- "errno=%d\n", e);
- }
- }
- }
- nd6_prefix_rele(pr);
-
- /*
- * this might affect the status of autoconfigured addresses,
- * that is, this address might make other addresses detached.
- */
- pfxlist_onlink_check();
-
-aifaddr_out:
- /*
* Try to clear the flag when a new IPv6 address is added
* onto an IFDISABLED interface and it succeeds.
*/
@@ -701,11 +702,6 @@
/*
* If the address being deleted is the only one that owns
* the corresponding prefix, expire the prefix as well.
- * XXX: theoretically, we don't have to worry about such
- * relationship, since we separate the address management
- * and the prefix management. We do this, however, to provide
- * as much backward compatibility as possible in terms of
- * the ioctl operation.
* Note that in6_purgeaddr() will decrement ndpr_addrcnt.
*/
pr = ia->ia6_ndpr;
@@ -1057,19 +1053,23 @@
/* Check prefix mask */
if (ia != NULL && ifra->ifra_prefixmask.sin6_len != 0) {
- /*
- * We prohibit changing the prefix length of an existing
- * address, because
- * + such an operation should be rare in IPv6, and
- * + the operation would confuse prefix management.
- */
- if (ia->ia_prefixmask.sin6_len != 0 &&
- in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
- nd6log((LOG_INFO, "in6_validate_ifa: the prefix length "
- "of an existing %s address should not be changed\n",
- ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
+ if (ia->ia_prefixmask.sin6_len != 0) {
+ /*
+ * We prohibit changing the prefix length of an
+ * existing address, because
+ * + such an operation should be rare in IPv6, and
+ * + the operation would confuse prefix management.
+ */
+ if (ia->ia6_ndpr != NULL &&
+ in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) !=
+ plen) {
+ nd6log((LOG_INFO, "in6_validate_ifa: the "
+ "prefix length of an existing %s address "
+ "should not be changed\n",
+ ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
- return (EINVAL);
+ return (EINVAL);
+ }
}
}
@@ -1114,6 +1114,11 @@
/* set prefix mask if any */
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
if (ifra->ifra_prefixmask.sin6_len != 0) {
+ if (ia->ia_prefixmask.sin6_len != 0) {
+ if (!IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr,
+ &ifra->ifra_prefixmask.sin6_addr))
+ in6_ifremprefix(ia);
+ }
ia->ia_prefixmask.sin6_family = AF_INET6;
ia->ia_prefixmask.sin6_len = ifra->ifra_prefixmask.sin6_len;
ia->ia_prefixmask.sin6_addr = ifra->ifra_prefixmask.sin6_addr;
@@ -1278,7 +1283,7 @@
struct ifnet *ifp = ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
struct in6_multi_mship *imm;
- int plen, error;
+ int error;
if (ifa->ifa_carp)
(*carp_detach_p)(ifa, false);
@@ -1305,16 +1310,10 @@
in6_leavegroup(imm->i6mm_maddr, NULL);
free(imm, M_IP6MADDR);
}
- plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
- if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
- error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
- (ia->ia_dstaddr.sin6_family == AF_INET6 ? RTF_HOST : 0));
- if (error != 0)
- log(LOG_INFO, "%s: err=%d, destination address delete "
- "failed\n", __func__, error);
- ia->ia_flags &= ~IFA_ROUTE;
- }
+ /* Delete any network route. */
+ in6_ifremprefix(ia);
+
in6_newaddrmsg(ia, RTM_DELETE);
in6_unlink_ifa(ia, ifp);
}
@@ -1322,7 +1321,6 @@
static void
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
- char ip6buf[INET6_ADDRSTRLEN];
int remove_lle;
IF_ADDR_WLOCK(ifp);
@@ -1341,15 +1339,10 @@
IN6_IFADDR_WUNLOCK();
/*
- * Release the reference to the base prefix. There should be a
- * positive reference.
+ * Release the reference to the ND prefix.
*/
remove_lle = 0;
- if (ia->ia6_ndpr == NULL) {
- nd6log((LOG_NOTICE,
- "in6_unlink_ifa: autoconf'ed address "
- "%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia))));
- } else {
+ if (ia->ia6_ndpr != NULL) {
ia->ia6_ndpr->ndpr_addrcnt--;
/* Do not delete lles within prefix if refcont != 0 */
if (ia->ia6_ndpr->ndpr_addrcnt == 0)
@@ -1380,10 +1373,9 @@
in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
struct in6_aliasreq *ifra, int hostIsNew)
{
- int error = 0, plen, ifacount = 0;
+ int error = 0, ifacount = 0;
struct ifaddr *ifa;
struct sockaddr_in6 *pdst;
- char ip6buf[INET6_ADDRSTRLEN];
/*
* Give the interface a chance to initialize
@@ -1407,56 +1399,34 @@
goto done;
}
- /*
- * If a new destination address is specified, scrub the old one and
- * install the new destination. Note that the interface must be
- * p2p or loopback.
- */
+ /* Set destination address. */
pdst = &ifra->ifra_dstaddr;
- if (pdst->sin6_family == AF_INET6 &&
- !IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
- if ((ia->ia_flags & IFA_ROUTE) != 0 &&
- (rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) {
- nd6log((LOG_ERR, "in6_update_ifa_internal: failed to "
- "remove a route to the old destination: %s\n",
- ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
- /* proceed anyway... */
- } else
- ia->ia_flags &= ~IFA_ROUTE;
+ if (pdst->sin6_family == AF_INET6) {
+ if (!IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr,
+ &ia->ia_dstaddr.sin6_addr))
+ in6_ifremprefix(ia);
ia->ia_dstaddr = *pdst;
}
/*
- * If a new destination address is specified for a point-to-point
- * interface, install a route to the destination as an interface
- * direct route.
- * XXX: the logic below rejects assigning multiple addresses on a p2p
- * interface that share the same destination.
- */
- plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
- if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
- ia->ia_dstaddr.sin6_family == AF_INET6) {
- int rtflags = RTF_UP | RTF_HOST;
- /*
- * Handle the case for ::1 .
- */
- if (ifp->if_flags & IFF_LOOPBACK)
- ia->ia_flags |= IFA_RTSELF;
- error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
- if (error)
- goto done;
- ia->ia_flags |= IFA_ROUTE;
- }
-
- /*
* add a loopback route to self if not exists
*/
if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) {
error = ifa_add_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);
- if (error == 0)
- ia->ia_flags |= IFA_RTSELF;
+ if (error)
+ goto done;
+ ia->ia_flags |= IFA_RTSELF;
}
+
+ /* Add the network prefix route. */
+ if ((error = in6_ifaddprefix(ia)) != 0) {
+ if (hostIsNew != 0) {
+ if (ifa_del_loopback_route((struct ifaddr *)ia,
+ (struct sockaddr *)&ia->ia_addr) == 0)
+ ia->ia_flags &= ~IFA_RTSELF;
+ }
+ }
done:
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"Invoking IPv6 network device address event may sleep");
Index: sys/netinet6/in6_ifattach.c
===================================================================
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -422,9 +422,7 @@
{
struct in6_ifaddr *ia;
struct in6_aliasreq ifra;
- struct nd_prefixctl pr0;
struct epoch_tracker et;
- struct nd_prefix *pr;
int error;
/*
@@ -490,41 +488,6 @@
}
ifa_free(&ia->ia_ifa);
- /*
- * Make the link-local prefix (fe80::%link/64) as on-link.
- * Since we'd like to manage prefixes separately from addresses,
- * we make an ND6 prefix structure for the link-local prefix,
- * and add it to the prefix list as a never-expire prefix.
- * XXX: this change might affect some existing code base...
- */
- bzero(&pr0, sizeof(pr0));
- pr0.ndpr_ifp = ifp;
- /* this should be 64 at this moment. */
- pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
- pr0.ndpr_prefix = ifra.ifra_addr;
- /* apply the mask for safety. (nd6_prelist_add will apply it again) */
- IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr, &in6mask64);
- /*
- * Initialize parameters. The link-local prefix must always be
- * on-link, and its lifetimes never expire.
- */
- pr0.ndpr_raf_onlink = 1;
- pr0.ndpr_raf_auto = 1; /* probably meaningless */
- pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
- pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
- /*
- * Since there is no other link-local addresses, nd6_prefix_lookup()
- * probably returns NULL. However, we cannot always expect the result.
- * For example, if we first remove the (only) existing link-local
- * address, and then reconfigure another one, the prefix is still
- * valid with referring to the old link-local address.
- */
- if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
- if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
- return (error);
- } else
- nd6_prefix_rele(pr);
-
return 0;
}
Index: sys/netinet6/nd6_rtr.c
===================================================================
--- sys/netinet6/nd6_rtr.c
+++ sys/netinet6/nd6_rtr.c
@@ -1753,6 +1753,13 @@
ia6->ia6_ndpr = pr;
/*
+ * toggle onlink state if the address was assigned
+ * a prefix route.
+ */
+ if (ia6->ia_flags & IFA_ROUTE)
+ pr->ndpr_stateflags |= NDPRF_ONLINK;
+
+ /*
* RFC 3041 3.3 (2).
* When a new public address is created as described
* in RFC2462, also create a new temporary address.

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 16, 11:22 AM (6 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14657870
Default Alt Text
D15406.id77828.diff (14 KB)

Event Timeline