Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142646215
D15406.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D15406.diff
View Options
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -151,6 +151,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 *,
@@ -161,6 +163,8 @@
struct in6_ifaddr *, int, int);
static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *,
struct in6_ifaddr *, int);
+static int in6_handle_rtrequest(int cmd, struct in6_ifaddr *ia,
+ int flags);
#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
#define ia62ifa(ia6) (&((ia6)->ia_ifa))
@@ -198,6 +202,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 = in6_handle_rtrequest(RTM_ADD, ia, 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);
+
+ in6_handle_rtrequest(RTM_DELETE, target, 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.
+ */
+ in6_handle_rtrequest(RTM_DELETE, target, flags);
+ target->ia_flags &= ~IFA_ROUTE;
+ return 0;
+}
+
int
in6_mask2len(struct in6_addr *mask, u_char *lim0)
{
@@ -559,11 +644,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 +676,6 @@
carp_attached = 1;
}
- /*
- * 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.
@@ -1037,19 +1040,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);
+ }
}
}
@@ -1094,6 +1101,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;
@@ -1253,11 +1265,11 @@
}
/*
- * Adds or deletes interface route for p2p ifa.
+ * Adds or deletes interface route for ifa.
* Returns 0 on success or errno.
*/
static int
-in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia)
+in6_handle_rtrequest(int cmd, struct in6_ifaddr *ia, int flags)
{
struct epoch_tracker et;
struct ifaddr *ifa = &ia->ia_ifa;
@@ -1274,14 +1286,23 @@
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_len = sizeof(struct sockaddr_in6),
- .sin6_addr = ia->ia_dstaddr.sin6_addr,
+ .sin6_addr = (flags & RTF_HOST) ?
+ ia->ia_dstaddr.sin6_addr : ia->ia_addr.sin6_addr,
};
+ struct sockaddr_in6 *netmask6 = (flags & RTF_HOST) ?
+ NULL : &ia->ia_prefixmask;
+
+ if (netmask6)
+ IN6_MASK_ADDR(&dst.sin6_addr, &netmask6->sin6_addr);
+
struct rt_addrinfo info = {
.rti_ifa = ifa,
- .rti_flags = RTF_PINNED | RTF_HOST,
+ .rti_flags = flags |
+ (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED,
.rti_info = {
[RTAX_DST] = (struct sockaddr *)&dst,
+ [RTAX_NETMASK] = (struct sockaddr *)netmask6,
[RTAX_GATEWAY] = (struct sockaddr *)&sdl,
},
};
@@ -1294,20 +1315,6 @@
return (error);
}
-static bool
-ifa_is_p2p(struct in6_ifaddr *ia)
-{
- int plen;
-
- plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
-
- if ((plen == 128) && (ia->ia_dstaddr.sin6_family == AF_INET6) &&
- !IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &ia->ia_dstaddr.sin6_addr))
- return (true);
-
- return (false);
-}
-
void
in6_purgeaddr(struct ifaddr *ifa)
{
@@ -1341,14 +1348,9 @@
in6_leavegroup(imm->i6mm_maddr, NULL);
free(imm, M_IP6MADDR);
}
- /* Check if we need to remove p2p route */
- if ((ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) {
- error = in6_handle_dstaddr_rtrequest(RTM_DELETE, ia);
- 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);
@@ -1366,11 +1368,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;
@@ -1387,7 +1384,6 @@
static void
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
- char ip6buf[INET6_ADDRSTRLEN];
int remove_lle;
IF_ADDR_WLOCK(ifp);
@@ -1406,15 +1402,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)
@@ -1448,7 +1439,6 @@
int error = 0, ifacount = 0;
struct ifaddr *ifa;
struct sockaddr_in6 *pdst;
- char ip6buf[INET6_ADDRSTRLEN];
/*
* Give the interface a chance to initialize
@@ -1472,47 +1462,33 @@
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 &&
- (in6_handle_dstaddr_rtrequest(RTM_DELETE, ia) != 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.
- */
- if (!(ia->ia_flags & IFA_ROUTE) && ifa_is_p2p(ia)) {
- error = in6_handle_dstaddr_rtrequest(RTM_ADD, ia);
- 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,
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
--- a/sys/netinet6/in6_ifattach.c
+++ b/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,44 +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, &pr)) != 0)
- return (error);
- /* Reference prefix */
- ia->ia6_ndpr = pr;
- pr->ndpr_addrcnt++;
- } else
- nd6_prefix_rele(pr);
-
return 0;
}
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -1757,6 +1757,13 @@
pr->ndpr_addrcnt++;
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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 22, 8:07 PM (4 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27861388
Default Alt Text
D15406.diff (15 KB)
Attached To
Mode
D15406: Separate ioctl address prefix management from RA prefix management as we have no API for controlling the latter.
Attached
Detach File
Event Timeline
Log In to Comment