Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148438511
D36306.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D36306.diff
View Options
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -236,6 +236,112 @@
return x * 8 + y;
}
+int
+in6_prefix_rtrequest(int cmd, struct in6_ifaddr *ia)
+{
+ struct ifnet *ifp = ia->ia_ifp;
+ uint32_t fibnum = ifp->if_fib;
+ struct epoch_tracker et;
+ int error;
+
+ struct sockaddr_in6 dst6 = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(struct sockaddr_in6),
+ .sin6_addr = ia->ia_addr.sin6_addr,
+ };
+
+ struct sockaddr_in6 netmask6 = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(struct sockaddr_in6),
+ .sin6_addr = ia->ia_prefixmask.sin6_addr,
+ };
+
+ struct sockaddr_dl_short sdl = {
+ .sdl_family = AF_LINK,
+ .sdl_len = sizeof(struct sockaddr_dl_short),
+ .sdl_type = ifp->if_type,
+ .sdl_index = ifp->if_index,
+ };
+
+ struct rt_addrinfo info = {
+ .rti_ifa = &ia->ia_ifa,
+ .rti_ifp = ifp,
+ .rti_flags = RTF_PINNED,
+ .rti_info = {
+ [RTAX_DST] = (struct sockaddr *)&dst6,
+ [RTAX_GATEWAY] = (struct sockaddr *)&sdl,
+ },
+ };
+
+ if (ia->ia_dstaddr.sin6_len != 0)
+ dst6.sin6_addr = ia->ia_dstaddr.sin6_addr;
+ else
+ dst6.sin6_addr = ia->ia_addr.sin6_addr;
+ IN6_MASK_ADDR(&dst6.sin6_addr, &netmask6.sin6_addr);
+
+ if (in6_mask2len(&netmask6.sin6_addr, NULL) == 128) {
+ if (ia->ia_dstaddr.sin6_family != AF_INET6)
+ /* We don't need to install a host route */
+ return 0;
+ info.rti_flags |= RTF_HOST;
+ } else
+ info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&netmask6;
+
+ NET_EPOCH_ENTER(et);
+ error = rib_handle_ifaddr_info(fibnum, cmd, &info);
+ NET_EPOCH_EXIT(et);
+
+ 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)
+{
+ struct rm_priotracker in6_ifa_tracker;
+ struct in6_ifaddr *ia;
+ int error = 0;
+
+ if ((target->ia_flags & IFA_ROUTE) == 0)
+ return 0;
+
+ 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 it. */
+ if ((ia->ia_flags & IFA_ROUTE) == 0) {
+ in6_prefix_rtrequest(RTM_DELETE, target);
+ target->ia_flags &= ~IFA_ROUTE;
+ nd6_rem_ifa_lle(target, 1);
+
+ error = in6_prefix_rtrequest(RTM_ADD, ia);
+ if (error == 0)
+ ia->ia_flags |= IFA_ROUTE;
+ return error;
+ }
+ }
+ IN6_IFADDR_RUNLOCK(&in6_ifa_tracker);
+
+ /* No-one has the prefix, so remove it. */
+ in6_prefix_rtrequest(RTM_DELETE, target);
+ target->ia_flags &= ~IFA_ROUTE;
+ nd6_rem_ifa_lle(target, 1);
+
+ return error;
+}
+
#ifdef COMPAT_FREEBSD32
struct in6_ndifreq32 {
char ifname[IFNAMSIZ];
@@ -252,7 +358,6 @@
struct in6_ifaddr *ia = NULL;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
struct sockaddr_in6 *sa6;
- int carp_attached = 0;
int error;
u_long ocmd = cmd;
@@ -560,10 +665,6 @@
break;
case SIOCAIFADDR_IN6:
- {
- struct nd_prefixctl pr0;
- struct nd_prefix *pr;
-
/*
* first, make or update the interface address structure,
* and link it to the list.
@@ -592,89 +693,8 @@
error = EPROTONOSUPPORT;
if (error)
goto out;
- else
- 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.
@@ -695,7 +715,6 @@
*/
}
break;
- }
case SIOCDIFADDR_IN6:
in6_purgeifaddr(ia);
@@ -1107,12 +1126,15 @@
}
/* set prefix mask if any */
- ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
if (ifra->ifra_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;
}
+ ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
ia->ia_ifp = ifp;
ifa_ref(&ia->ia_ifa); /* if_addrhead */
@@ -1267,49 +1289,6 @@
return (error);
}
-/*
- * Adds or deletes interface route for p2p ifa.
- * Returns 0 on success or errno.
- */
-static int
-in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia)
-{
- struct epoch_tracker et;
- struct ifaddr *ifa = &ia->ia_ifa;
- int error;
-
- /* Prepare gateway */
- struct sockaddr_dl_short sdl = {
- .sdl_family = AF_LINK,
- .sdl_len = sizeof(struct sockaddr_dl_short),
- .sdl_type = ifa->ifa_ifp->if_type,
- .sdl_index = ifa->ifa_ifp->if_index,
- };
-
- struct sockaddr_in6 dst = {
- .sin6_family = AF_INET6,
- .sin6_len = sizeof(struct sockaddr_in6),
- .sin6_addr = ia->ia_dstaddr.sin6_addr,
- };
-
- struct rt_addrinfo info = {
- .rti_ifa = ifa,
- .rti_ifp = ifa->ifa_ifp,
- .rti_flags = RTF_PINNED | RTF_HOST,
- .rti_info = {
- [RTAX_DST] = (struct sockaddr *)&dst,
- [RTAX_GATEWAY] = (struct sockaddr *)&sdl,
- },
- };
- /* Don't set additional per-gw filters on removal */
-
- NET_EPOCH_ENTER(et);
- error = rib_handle_ifaddr_info(ifa->ifa_ifp->if_fib, cmd, &info);
- NET_EPOCH_EXIT(et);
-
- return (error);
-}
-
static bool
ifa_is_p2p(struct in6_ifaddr *ia)
{
@@ -1357,14 +1336,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;
- }
+
+ /* Remove any prefix route */
+ in6_ifremprefix(ia);
in6_newaddrmsg(ia, RTM_DELETE);
in6_unlink_ifa(ia, ifp);
@@ -1403,7 +1377,6 @@
static void
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
- char ip6buf[INET6_ADDRSTRLEN];
int remove_lle;
IF_ADDR_WLOCK(ifp);
@@ -1422,15 +1395,10 @@
IN6_IFADDR_WUNLOCK();
/*
- * Release the reference to the base prefix. There should be a
- * positive reference.
+ * Release the reference to the base 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)
@@ -1464,7 +1432,6 @@
int error = 0, ifacount = 0;
struct ifaddr *ifa;
struct sockaddr_in6 *pdst;
- char ip6buf[INET6_ADDRSTRLEN];
/*
* Give the interface a chance to initialize
@@ -1496,14 +1463,7 @@
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;
+ in6_ifremprefix(ia);
ia->ia_dstaddr = *pdst;
}
@@ -1514,11 +1474,29 @@
* 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)
+ if (!(ia->ia_flags & IFA_ROUTE)) {
+ error = in6_prefix_rtrequest(RTM_ADD, ia);
+ if (error == 0) {
+ ia->ia_flags |= IFA_ROUTE;
+
+ /*
+ * 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) {
+ 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);
+ }
+ }
+ } else if (error == EEXIST)
+ error = 0;
+ else
goto done;
- ia->ia_flags |= IFA_ROUTE;
}
/*
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,45 +488,13 @@
}
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);
+ error = in6_prefix_rtrequest(RTM_ADD, ia);
+ if (error == 0)
+ ia->ia_flags |= IFA_ROUTE;
+ else if (error == EEXIST)
+ error = 0;
- return 0;
+ return error;
}
/*
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -881,6 +881,7 @@
#define IN6_IFAUPDATE_DADDELAY 0x1 /* first time to configure an address */
int in6_mask2len(struct in6_addr *, u_char *);
+int in6_prefix_rtrequest(int, struct in6_ifaddr *);
int in6_control(struct socket *, u_long, void *, struct ifnet *,
struct thread *);
int in6_update_ifa(struct ifnet *, struct in6_aliasreq *,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 18, 9:29 PM (5 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29908707
Default Alt Text
D36306.diff (13 KB)
Attached To
Mode
D36306: inet6: manally added addresses manage their own prefix
Attached
Detach File
Event Timeline
Log In to Comment