Page MenuHomeFreeBSD

D36306.diff
No OneTemporary

D36306.diff

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

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)

Event Timeline