FreeBSD Bugzilla – Attachment 116263 Details for
Bug 158185
[ip6] IPv6 does not manage the NIC's route when doing ifconfig down/up
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
file.diff
file.diff (text/plain), 10.32 KB, created by
Doug Ambrisko
on 2011-06-23 00:50:09 UTC
(
hide
)
Description:
file.diff
Filename:
MIME Type:
Creator:
Doug Ambrisko
Created:
2011-06-23 00:50:09 UTC
Size:
10.32 KB
patch
obsolete
>diff -upr ../src/sys/net/if.c sys/net/if.c >--- ../src/sys/net/if.c 2009-07-27 12:48:10.000000000 -0700 >+++ sys/net/if.c 2011-05-17 12:51:38.000000000 -0700 >@@ -1449,6 +1449,9 @@ if_unroute(struct ifnet *ifp, int flag, > carp_carpdev_state(ifp->if_carp); > #endif > rt_ifmsg(ifp); >+#ifdef INET6 >+ in6_if_down(ifp); >+#endif > } > > /* >diff -upr ../src/sys/netinet6/in6.c sys/netinet6/in6.c >--- ../src/sys/netinet6/in6.c 2009-07-27 12:48:10.000000000 -0700 >+++ sys/netinet6/in6.c 2011-05-17 12:59:27.000000000 -0700 >@@ -132,6 +132,9 @@ static void in6_unlink_ifa(struct in6_if > > struct in6_multihead in6_multihead; /* XXX BSS initialization */ > int (*faithprefix_p)(struct in6_addr *); >+static int in6_join_multicast_groups(struct ifnet *ifp, >+ struct in6_aliasreq *ifra, struct in6_ifaddr *ia, int flags, >+ int hostIsNew); > > /* > * Subroutine for in6_ifaddloop() and in6_ifremloop(). >@@ -788,6 +791,7 @@ in6_control(struct socket *so, u_long cm > return (0); > } > >+ > /* > * Update parameters of an IPv6 interface address. > * If necessary, a new entry is created and linked into address chains. >@@ -802,10 +806,6 @@ in6_update_ifa(struct ifnet *ifp, struct > struct in6_ifaddr *oia; > struct sockaddr_in6 dst6; > struct in6_addrlifetime *lt; >- struct in6_multi_mship *imm; >- struct in6_multi *in6m_sol; >- struct rtentry *rt; >- int delay; > char ip6buf[INET6_ADDRSTRLEN]; > > /* Validate parameters */ >@@ -1049,6 +1049,41 @@ in6_update_ifa(struct ifnet *ifp, struct > * not just go to unlink. > */ > >+ if ((error = in6_join_multicast_groups(ifp, ifra, ia, flags, hostIsNew))) { >+ goto cleanup; >+ } >+ >+ >+ return (error); >+ >+ unlink: >+ /* >+ * XXX: if a change of an existing address failed, keep the entry >+ * anyway. >+ */ >+ if (hostIsNew) >+ in6_unlink_ifa(ia, ifp); >+ return (error); >+ >+ cleanup: >+ in6_purgeaddr(&ia->ia_ifa); >+ return error; >+} >+ >+static int >+in6_join_multicast_groups(struct ifnet *ifp, struct in6_aliasreq *ifra, >+ struct in6_ifaddr *ia, int flags, int hostIsNew) >+{ >+ int error = 0; >+ struct in6_multi_mship *imm; >+ struct rtentry *rt; >+ struct in6_multi *in6m_sol; >+ int delay; >+ char ip6buf[INET6_ADDRSTRLEN]; >+ >+/* Up the interface */ >+ifp->if_flags |= IFF_UP; >+ > /* Join necessary multicast groups */ > in6m_sol = NULL; > if ((ifp->if_flags & IFF_MULTICAST) != 0) { >@@ -1263,7 +1295,7 @@ in6_update_ifa(struct ifnet *ifp, struct > ip6_sprintf(ip6buf, &mltaddr.sin6_addr), > if_name(ifp), error)); > goto cleanup; >- } >+ } > LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); > #undef MLTMASK_LEN > } >@@ -1306,20 +1338,8 @@ in6_update_ifa(struct ifnet *ifp, struct > nd6_dad_start((struct ifaddr *)ia, delay); > } > >+ cleanup: > return (error); >- >- unlink: >- /* >- * XXX: if a change of an existing address failed, keep the entry >- * anyway. >- */ >- if (hostIsNew) >- in6_unlink_ifa(ia, ifp); >- return (error); >- >- cleanup: >- in6_purgeaddr(&ia->ia_ifa); >- return error; > } > > void >@@ -1727,7 +1747,7 @@ in6_ifinit(struct ifnet *ifp, struct in6 > > /* we could do in(6)_socktrim here, but just omit it at this moment. */ > >- if (newhost && nd6_need_cache(ifp) != 0) { >+ if (newhost) { > /* > * set the rtrequest function to create llinfo. It also > * adjust outgoing interface of the route for the local >@@ -2120,6 +2140,93 @@ in6_ifawithifp(struct ifnet *ifp, struct > return NULL; > } > >+extern struct inpcbinfo udbinfo; >+extern struct inpcbinfo ripcbinfo; >+/*static*/ void in6_purgemaddrs(struct ifnet *); >+ >+void >+in6_if_down(struct ifnet *ifp) >+{ >+ struct in6_ifaddr *ia /*, *oia*/; >+ struct ifaddr *ifa, *next; >+ struct rtentry *rt; >+ short rtflags; >+ struct sockaddr_in6 sin6; >+ struct in6_multi_mship *imm; >+ >+ /* remove neighbor management table */ >+ nd6_purge(ifp); >+ >+ /* undo everything done by in6_ifattach(), just in case */ >+ for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { >+ next = ifa->ifa_list.tqe_next; >+ >+ if (ifa->ifa_addr->sa_family != AF_INET6 >+ /* DJA || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr) */) { >+ continue; >+ } >+ >+ ia = (struct in6_ifaddr *)ifa; >+ >+ /* >+ * leave from multicast groups we have joined for the interface >+ */ >+ while ((imm = ia->ia6_memberships.lh_first) != NULL) { >+ LIST_REMOVE(imm, i6mm_chain); >+ in6_leavegroup(imm); >+ } >+ >+#define rtinitflags(x) \ >+ ((((x)->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ >+ ? RTF_HOST : RTF_UP) >+ /* remove from the routing table */ >+ if ((ia->ia_flags & IFA_ROUTE) && >+ (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { >+ rtflags = rt->rt_flags; >+ rtfree(rt); >+ if(ifa->ifa_addr->sa_family == AF_INET6) >+ rtinit(ifa, (int)RTM_DELETE, >+ rtinitflags(ifp)); >+ } >+ >+ } >+ >+ in6_pcbpurgeif0(&udbinfo, ifp); >+ in6_pcbpurgeif0(&ripcbinfo, ifp); >+ /* leave from all multicast groups joined */ >+ in6_purgemaddrs(ifp); >+ >+ /* >+ * remove neighbor management table. we call it twice just to make >+ * sure we nuke everything. maybe we need just one call. >+ * XXX: since the first call did not release addresses, some prefixes >+ * might remain. We should call nd6_purge() again to release the >+ * prefixes after removing all addresses above. >+ * (Or can we just delay calling nd6_purge until at this point?) >+ */ >+ nd6_purge(ifp); >+ >+ /* remove route to link-local allnodes multicast (ff02::1) */ >+ bzero(&sin6, sizeof(sin6)); >+ sin6.sin6_len = sizeof(struct sockaddr_in6); >+ sin6.sin6_family = AF_INET6; >+ sin6.sin6_addr = in6addr_linklocal_allnodes; >+ if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) >+ /* XXX: should not fail */ >+ return; >+ /* XXX grab lock first to avoid LOR */ >+ if (rt_tables[0][AF_INET6] != NULL) { >+ RADIX_NODE_HEAD_LOCK(rt_tables[0][AF_INET6]); >+ rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED); >+ if (rt) { >+ if (rt->rt_ifp == ifp) >+ rtexpunge(rt); >+ RTFREE_LOCKED(rt); >+ } >+ RADIX_NODE_HEAD_UNLOCK(rt_tables[0][AF_INET6]); >+ } >+} >+ > /* > * perform DAD when interface becomes IFF_UP. > */ >@@ -2128,20 +2235,92 @@ in6_if_up(struct ifnet *ifp) > { > struct ifaddr *ifa; > struct in6_ifaddr *ia; >+ struct in6_aliasreq ifra_store, *ifra; > >+ /* DJA */ > TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { > if (ifa->ifa_addr->sa_family != AF_INET6) > continue; > ia = (struct in6_ifaddr *)ifa; >- if (ia->ia6_flags & IN6_IFF_TENTATIVE) { >+ >+ >+ in6_ifinit(ifp, ia, &ia->ia_addr, 1); >+ >+ ifra = &ifra_store; >+ bzero(&ifra_store, sizeof(ifra_store)); >+ bcopy(if_name(ifp), ifra_store.ifra_name, >+ sizeof(ifra_store.ifra_name)); >+ bcopy(&ia->ia_addr, &ifra_store.ifra_addr, >+ sizeof(ifra_store.ifra_addr)); >+ bcopy(&ia->ia_dstaddr, &ifra_store.ifra_dstaddr, >+ sizeof(ifra_store.ifra_dstaddr)); >+ bcopy(&ia->ia_prefixmask, &ifra_store.ifra_prefixmask, >+ sizeof(ifra_store.ifra_prefixmask)); >+ ifra_store.ifra_flags = ia->ia6_flags; >+ bcopy(&ia->ia6_lifetime, &ifra_store.ifra_lifetime, >+ sizeof(ifra->ifra_lifetime)); >+ >+ /* Join necessary multicast groups */ >+ if (in6_join_multicast_groups(ifp, ifra, ia, 0, 0)) { >+ in6_purgeaddr(&ia->ia_ifa); >+ continue; >+ } >+ >+ int i, error = 0; >+ struct nd_prefixctl pr0; >+ struct nd_prefix *pr; >+ /* >+ * 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) { >+ continue; /* we don't need to install a host route. */ >+ } >+ pr0.ndpr_prefix = ifra->ifra_addr; >+ /* apply the mask for safety. */ >+ for (i = 0; i < 4; i++) { >+ pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= >+ ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; >+ } >+ >+ /* >+ * 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) { > /* >- * The TENTATIVE flag was likely set by hand >- * beforehand, implicitly indicating the need for DAD. >- * We may be able to skip the random delay in this >- * case, but we impose delays just in case. >+ * nd6_prelist_add will install the corresponding >+ * interface route. > */ >- nd6_dad_start(ifa, >- arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); >+ if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) >+ return; >+ if (pr == NULL) { >+ log(LOG_ERR, "nd6_prelist_add succeeded but " >+ "no prefix\n"); >+ return; /* XXX panic here? */ >+ } > } > } > >Only in sys/netinet6: in6.c.orig >Only in sys/netinet6: in6.c~ >diff -upr ../src/sys/netinet6/in6.h sys/netinet6/in6.h >--- ../src/sys/netinet6/in6.h 2009-04-14 20:14:26.000000000 -0700 >+++ sys/netinet6/in6.h 2011-04-19 09:41:23.000000000 -0700 >@@ -620,6 +620,7 @@ int in6_localaddr __P((struct in6_addr * > int in6_addrscope __P((struct in6_addr *)); > struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *)); > extern void in6_if_up __P((struct ifnet *)); >+extern void in6_if_down __P((struct ifnet *)); > struct sockaddr; > extern u_char ip6_protox[]; > >diff -upr ../src/sys/netinet6/in6_ifattach.c sys/netinet6/in6_ifattach.c >--- ../src/sys/netinet6/in6_ifattach.c 2009-04-14 20:14:26.000000000 -0700 >+++ sys/netinet6/in6_ifattach.c 2011-04-19 10:29:31.000000000 -0700 >@@ -78,7 +78,7 @@ static int generate_tmp_ifid(u_int8_t *, > static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); > static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); > static int in6_ifattach_loopback(struct ifnet *); >-static void in6_purgemaddrs(struct ifnet *); >+/*static*/ void in6_purgemaddrs(struct ifnet *); > > #define EUI64_GBIT 0x01 > #define EUI64_UBIT 0x02 >@@ -886,7 +886,7 @@ in6_tmpaddrtimer(void *ignored_arg) > splx(s); > } > >-static void >+/*static*/ void > in6_purgemaddrs(struct ifnet *ifp) > { > struct in6_multi *in6m;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 158185
: 116263