Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jan 2014 16:07:28 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r260882 - in head/sys: netinet netinet6
Message-ID:  <201401191607.s0JG7SsM084760@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sun Jan 19 16:07:27 2014
New Revision: 260882
URL: http://svnweb.freebsd.org/changeset/base/260882

Log:
  Further rework netinet6 address handling code:
  * Set ia address/mask values BEFORE attaching to address lists.
  Inet6 address assignment is not atomic, so the simplest way to
  do this atomically is to fill in ia before attach.
  * Validate irfa->ia_addr field before use (we permit ANY sockaddr in old code).
  * Do some renamings:
    in6_ifinit -> in6_notify_ifa (interaction with other subsystems is here)
    in6_setup_ifa -> in6_broadcast_ifa (LLE/Multicast/DaD code)
    in6_ifaddloop -> nd6_add_ifa_lle
    in6_ifremloop -> nd6_rem_ifa_lle
  * Split working with LLE and route announce code for last two.
  Add temporary in6_newaddrmsg() function to mimic current rtsock behaviour.
  * Call device SIOCSIFADDR handler IFF we're adding first address.
  In IPv4 we have to call it on every address change since ARP record
  is installed by arp_ifinit() which is called by given handler.
  IPv6 stack, on the opposite is responsible to call nd6_add_ifa_lle() so
  there is no reason to call SIOCSIFADDR often.

Modified:
  head/sys/netinet/ip_carp.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/in6_var.h
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h

Modified: head/sys/netinet/ip_carp.c
==============================================================================
--- head/sys/netinet/ip_carp.c	Sun Jan 19 13:51:46 2014	(r260881)
+++ head/sys/netinet/ip_carp.c	Sun Jan 19 16:07:27 2014	(r260882)
@@ -964,7 +964,7 @@ carp_ifa_addroute(struct ifaddr *ifa)
 	case AF_INET6:
 		ifa_add_loopback_route(ifa,
 		    (struct sockaddr *)&ifatoia6(ifa)->ia_addr);
-		in6_ifaddloop(ifa);
+		nd6_add_ifa_lle(ifatoia6(ifa));
 		break;
 #endif
 	}
@@ -995,7 +995,7 @@ carp_ifa_delroute(struct ifaddr *ifa)
 	case AF_INET6:
 		ifa_del_loopback_route(ifa,
 		    (struct sockaddr *)&ifatoia6(ifa)->ia_addr);
-		in6_ifremloop(ifa);
+		nd6_rem_ifa_lle(ifatoia6(ifa));
 		break;
 #endif
 	}

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Sun Jan 19 13:51:46 2014	(r260881)
+++ head/sys/netinet6/in6.c	Sun Jan 19 16:07:27 2014	(r260882)
@@ -133,8 +133,8 @@ const struct in6_addr in6mask128 = IN6MA
 const struct sockaddr_in6 sa6_any =
 	{ sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 };
 
-static int in6_ifinit(struct ifnet *, struct in6_ifaddr *,
-	struct sockaddr_in6 *, int);
+static int in6_notify_ifa(struct ifnet *, struct in6_ifaddr *,
+	struct in6_aliasreq *, int);
 static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
 
 int	(*faithprefix_p)(struct in6_addr *);
@@ -145,44 +145,26 @@ static struct in6_ifaddr *in6_alloc_ifa(
     struct in6_aliasreq *, int flags);
 static int in6_update_ifa_internal(struct ifnet *, struct in6_aliasreq *,
     struct in6_ifaddr *, int, int);
-static int in6_setup_ifa(struct ifnet *, struct in6_aliasreq *,
+static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *,
     struct in6_ifaddr *, int);
 
 #define ifa2ia6(ifa)	((struct in6_ifaddr *)(ifa))
 #define ia62ifa(ia6)	(&((ia6)->ia_ifa))
 
+
 void
-in6_ifaddloop(struct ifaddr *ifa)
+in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
 {
 	struct sockaddr_dl gateway;
 	struct sockaddr_in6 mask, addr;
 	struct rtentry rt;
-	struct in6_ifaddr *ia;
-	struct ifnet *ifp;
-	struct llentry *ln;
 
-	ia = ifa2ia6(ifa);
-	ifp = ifa->ifa_ifp;
-	IF_AFDATA_LOCK(ifp);
-	ifa->ifa_rtrequest = nd6_rtrequest;
-	ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
-	    LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
-	IF_AFDATA_UNLOCK(ifp);
-	if (ln != NULL) {
-		ln->la_expire = 0;  /* for IPv6 this means permanent */
-		ln->ln_state = ND6_LLINFO_REACHABLE;
-		/*
-		 * initialize for rtmsg generation
-		 */
-		bzero(&gateway, sizeof(gateway));
-		gateway.sdl_len = sizeof(gateway);
-		gateway.sdl_family = AF_LINK;
-		gateway.sdl_nlen = 0;
-		gateway.sdl_alen = 6;
-		memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned,
-		    sizeof(ln->ll_addr));
-		LLE_WUNLOCK(ln);
-	}
+	/*
+	 * initialize for rtmsg generation
+	 */
+	bzero(&gateway, sizeof(gateway));
+	gateway.sdl_len = sizeof(gateway);
+	gateway.sdl_family = AF_LINK;
 
 	bzero(&rt, sizeof(rt));
 	rt.rt_gateway = (struct sockaddr *)&gateway;
@@ -190,42 +172,11 @@ in6_ifaddloop(struct ifaddr *ifa)
 	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
 	rt_mask(&rt) = (struct sockaddr *)&mask;
 	rt_key(&rt) = (struct sockaddr *)&addr;
-	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+	rt.rt_flags = RTF_HOST | RTF_STATIC;
+	if (cmd == RTM_ADD)
+		rt.rt_flags |= RTF_UP;
 	/* Announce arrival of local address to all FIBs. */
-	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
-}
-
-void
-in6_ifremloop(struct ifaddr *ifa)
-{
-	struct sockaddr_dl gateway;
-	struct sockaddr_in6 mask, addr;
-	struct rtentry rt0;
-	struct in6_ifaddr *ia;
-	struct ifnet *ifp;
-
-	ia = ifa2ia6(ifa);
-	ifp = ifa->ifa_ifp;
-	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
-	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
-	lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
-	            (struct sockaddr *)&mask, LLE_STATIC);
-
-	/*
-	 * initialize for rtmsg generation
-	 */
-	bzero(&gateway, sizeof(gateway));
-	gateway.sdl_len = sizeof(gateway);
-	gateway.sdl_family = AF_LINK;
-	gateway.sdl_nlen = 0;
-	gateway.sdl_alen = ifp->if_addrlen;
-	bzero(&rt0, sizeof(rt0));
-	rt0.rt_gateway = (struct sockaddr *)&gateway;
-	rt_mask(&rt0) = (struct sockaddr *)&mask;
-	rt_key(&rt0) = (struct sockaddr *)&addr;
-	rt0.rt_flags = RTF_HOST | RTF_STATIC;
-	/* Announce removal of local address to all FIBs. */
-	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
+	rt_newaddrmsg(cmd, &ia->ia_ifa, 0, &rt);
 }
 
 int
@@ -1031,13 +982,13 @@ in6_update_ifa(struct ifnet *ifp, struct
 	}
 
 	if (hostIsNew)
-		error = in6_setup_ifa(ifp, ifra, ia, flags);
+		error = in6_broadcast_ifa(ifp, ifra, ia, flags);
 
 	return (error);
 }
 
 /*
- * Fill in basic IPv6 address request info
+ * Fill in basic IPv6 address request info.
  */
 void
 in6_prepare_ifra(struct in6_aliasreq *ifra, const struct in6_addr *addr,
@@ -1078,6 +1029,14 @@ in6_validate_ifra(struct ifnet *ifp, str
 	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
 	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
 		return (EAFNOSUPPORT);
+
+	/*
+	 * Validate address
+	 */
+	if (ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6) ||
+	    ifra->ifra_addr.sin6_family != AF_INET6)
+		return (EINVAL);
+
 	/*
 	 * validate ifra_prefixmask.  don't check sin6_family, netmask
 	 * does not carry fields other than sin6_len.
@@ -1211,10 +1170,12 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
 	ia->ia_addr.sin6_family = AF_INET6;
 	ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
+	/* XXX: Can we assign ,sin6_addr and skip the rest? */
+	ia->ia_addr = ifra->ifra_addr;
 	ia->ia6_createtime = time_uptime;
 	if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
 		/*
-		 * XXX: some functions expect that ifa_dstaddr is not
+		 * Some functions expect that ifa_dstaddr is not
 		 * NULL for p2p interfaces.
 		 */
 		ia->ia_ifa.ifa_dstaddr =
@@ -1222,7 +1183,15 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	} else {
 		ia->ia_ifa.ifa_dstaddr = NULL;
 	}
+
+	/* set prefix mask if any */
 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
+	if (ifra->ifra_prefixmask.sin6_len != 0) {
+		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_ifp = ifp;
 	ifa_ref(&ia->ia_ifa);			/* if_addrhead */
 	IF_ADDR_WLOCK(ifp);
@@ -1232,30 +1201,28 @@ in6_alloc_ifa(struct ifnet *ifp, struct 
 	ifa_ref(&ia->ia_ifa);			/* in6_ifaddrhead */
 	IN6_IFADDR_WLOCK();
 	TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
-	LIST_INSERT_HEAD(IN6ADDR_HASH(&ifra->ifra_addr.sin6_addr),
-	    ia, ia6_hash);
+	LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash);
 	IN6_IFADDR_WUNLOCK();
 
 	return (ia);
 }
 
+/*
+ * Update/configure interface address parameters:
+ *
+ * 1) Update lifetime
+ * 2) Update interface metric ad flags
+ * 3) Notify other subsystems
+ */
 static int
 in6_update_ifa_internal(struct ifnet *ifp, struct in6_aliasreq *ifra,
     struct in6_ifaddr *ia, int hostIsNew, int flags)
 {
-	struct sockaddr_in6 *pdst;
 	int error;
-	char ip6buf[INET6_ADDRSTRLEN];
 
 	/* update timestamp */
 	ia->ia6_updatetime = time_uptime;
 
-	/* set prefix mask */
-	if (ifra->ifra_prefixmask.sin6_len != 0) {
-		ia->ia_prefixmask = ifra->ifra_prefixmask;
-		ia->ia_prefixmask.sin6_family = AF_INET6;
-	}
-
 	/*
 	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
 	 * to see if the address is deprecated or invalidated, but initialize
@@ -1282,6 +1249,9 @@ in6_update_ifa_internal(struct ifnet *if
 		ia->ia6_lifetime.ia6t_preferred = time_uptime;
 	}
 
+	/* Update metric */
+	ia->ia_ifa.ifa_metric = ifp->if_metric;
+
 	/*
 	 * configure address flags.
 	 */
@@ -1300,53 +1270,40 @@ in6_update_ifa_internal(struct ifnet *if
 	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
 		ia->ia6_flags |= IN6_IFF_TENTATIVE;
 
-	/*
-	 * 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 (see the check above.)
-	 */
-	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;
-		ia->ia_dstaddr = *pdst;
-	}
-
-	/* reset the interface and routing table appropriately. */
-	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) {
-	/*
-	 * XXX: if a change of an existing address failed, keep the entry
-	 * anyway.
-	 */
-	}
+	/* notify other subsystems */
+	error = in6_notify_ifa(ifp, ia, ifra, hostIsNew);
 
 	return (error);
 }
 
+/*
+ * Do link-level ifa job:
+ * 1) Add lle entry for added address
+ * 2) Notifies routing socket users about new address
+ * 3) join appropriate multicast group
+ * 4) start DAD if enabled
+ */
 static int
-in6_setup_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
+in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
     struct in6_ifaddr *ia, int flags)
 {
 	struct in6_multi *in6m_sol;
 	int error = 0;
 
 	/* Add local address to lltable, if necessary (ex. on p2p link). */
-	in6_ifaddloop(&(ia->ia_ifa));
+	if ((error = nd6_add_ifa_lle(ia)) != 0) {
+		in6_purgeaddr(&ia->ia_ifa);
+		ifa_free(&ia->ia_ifa);
+		return (error);
+	}
 
 	/* Join necessary multicast groups. */
 	in6m_sol = NULL;
 	if ((ifp->if_flags & IFF_MULTICAST) != 0) {
 		error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
 		if (error != 0) {
-			ifa_free(&ia->ia_ifa);
 			in6_purgeaddr(&ia->ia_ifa);
+			ifa_free(&ia->ia_ifa);
 			return (error);
 		}
 	}
@@ -1571,7 +1528,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	nd6_dad_stop(ifa);
 
 	/* Remove local address entry from lltable. */
-	in6_ifremloop(ifa);
+	nd6_rem_ifa_lle(ia);
 
 	/* Leave multicast groups. */
 	error = in6_purgeaddr_mc(ifp, ia, ifa0);
@@ -1650,29 +1607,33 @@ in6_purgeif(struct ifnet *ifp)
 }
 
 /*
- * Initialize an interface's IPv6 address and routing table entry.
+ * Notifies other other subsystems about address change/arrival:
+ * 1) Notifies device handler on first IPv6 address assignment
+ * 2) Handle routing table changes for P2P links and route
+ * 3) Handle routing table changes for address host route
  */
 static int
-in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
-    struct sockaddr_in6 *sin6, int newhost)
+in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia,
+    struct in6_aliasreq *ifra, int hostIsNew)
 {
 	int	error = 0, plen, ifacount = 0;
 	struct ifaddr *ifa;
+	struct sockaddr_in6 *pdst;
+	char ip6buf[INET6_ADDRSTRLEN];
 
 	/*
 	 * Give the interface a chance to initialize
 	 * if this is its first address,
-	 * and to validate the address if necessary.
 	 */
-	IF_ADDR_RLOCK(ifp);
-	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-		if (ifa->ifa_addr->sa_family != AF_INET6)
-			continue;
-		ifacount++;
+	if (hostIsNew != 0) {
+		IF_ADDR_RLOCK(ifp);
+		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+			if (ifa->ifa_addr->sa_family != AF_INET6)
+				continue;
+			ifacount++;
+		}
+		IF_ADDR_RUNLOCK(ifp);
 	}
-	IF_ADDR_RUNLOCK(ifp);
-
-	ia->ia_addr = *sin6;
 
 	if (ifacount <= 1 && ifp->if_ioctl) {
 		error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
@@ -1680,12 +1641,26 @@ in6_ifinit(struct ifnet *ifp, struct in6
 			return (error);
 	}
 
-	ia->ia_ifa.ifa_metric = ifp->if_metric;
-
-	/* we could do in(6)_socktrim here, but just omit it at this moment. */
+	/*
+	 * 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.
+	 */
+	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;
+		ia->ia_dstaddr = *pdst;
+	}
 
 	/*
-	 * Special case:
 	 * If a new destination address is specified for a point-to-point
 	 * interface, install a route to the destination as an interface
 	 * direct route.
@@ -1696,19 +1671,19 @@ in6_ifinit(struct ifnet *ifp, struct in6
 	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
 	    ia->ia_dstaddr.sin6_family == AF_INET6) {
 		int rtflags = RTF_UP | RTF_HOST;
-		error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
-		if (error)
-			return (error);
-		ia->ia_flags |= IFA_ROUTE;
 		/*
 		 * 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)
+			return (error);
+		ia->ia_flags |= IFA_ROUTE;
 	}
 
 	/*
-	 * add a loopback route to self
+	 * 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,

Modified: head/sys/netinet6/in6_var.h
==============================================================================
--- head/sys/netinet6/in6_var.h	Sun Jan 19 13:51:46 2014	(r260881)
+++ head/sys/netinet6/in6_var.h	Sun Jan 19 16:07:27 2014	(r260882)
@@ -822,12 +822,11 @@ int	in6_prefix_ioctl(struct socket *, u_
 int	in6_prefix_add_ifid(int, struct in6_ifaddr *);
 void	in6_prefix_remove_ifid(int, struct in6_ifaddr *);
 void	in6_purgeprefix(struct ifnet *);
-void	in6_ifremloop(struct ifaddr *);
-void	in6_ifaddloop(struct ifaddr *);
 
 int	in6_is_addr_deprecated(struct sockaddr_in6 *);
 int	in6_src_ioctl(u_long, caddr_t);
 
+void	in6_newaddrmsg(struct in6_ifaddr *, int);
 /*
  * Extended API for IPv6 FIB support.
  */

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Sun Jan 19 13:51:46 2014	(r260881)
+++ head/sys/netinet6/nd6.c	Sun Jan 19 16:07:27 2014	(r260882)
@@ -133,6 +133,7 @@ static int regen_tmpaddr(struct in6_ifad
 static struct llentry *nd6_free(struct llentry *, int);
 static void nd6_llinfo_timer(void *);
 static void clear_llinfo_pqueue(struct llentry *);
+static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 
 static VNET_DEFINE(struct callout, nd6_slowtimo_ch);
 #define	V_nd6_slowtimo_ch		VNET(nd6_slowtimo_ch)
@@ -2177,6 +2178,62 @@ nd6_need_cache(struct ifnet *ifp)
 }
 
 /*
+ * Add pernament ND6 link-layer record for given
+ * interface address.
+ *
+ * Very similar to IPv4 arp_ifinit(), but:
+ * 1) IPv6 DAD is performed in different place
+ * 2) It is called by IPv6 protocol stack in contrast to
+ * arp_ifinit() which is typically called in SIOCSIFADDR
+ * driver ioctl handler.
+ *
+ */
+int
+nd6_add_ifa_lle(struct in6_ifaddr *ia)
+{
+	struct ifnet *ifp;
+	struct llentry *ln;
+
+	ifp = ia->ia_ifa.ifa_ifp;
+	IF_AFDATA_LOCK(ifp);
+	ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+	ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
+	    LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
+	IF_AFDATA_UNLOCK(ifp);
+	if (ln != NULL) {
+		ln->la_expire = 0;  /* for IPv6 this means permanent */
+		ln->ln_state = ND6_LLINFO_REACHABLE;
+		LLE_WUNLOCK(ln);
+		in6_newaddrmsg(ia, RTM_ADD);
+		return (0);
+	}
+
+	return (ENOBUFS);
+}
+
+/*
+ * Removes ALL lle records for interface address prefix.
+ * XXXME: That's probably not we really want to do, we need
+ * to remove address record only and keep other records
+ * until we determine if given prefix is really going 
+ * to be removed.
+ */
+void
+nd6_rem_ifa_lle(struct in6_ifaddr *ia)
+{
+	struct sockaddr_in6 mask, addr;
+	struct ifnet *ifp;
+
+	in6_newaddrmsg(ia, RTM_DELETE);
+
+	ifp = ia->ia_ifa.ifa_ifp;
+	memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
+	memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
+	lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
+	            (struct sockaddr *)&mask, LLE_STATIC);
+}
+
+/*
  * the callers of this function need to be re-worked to drop
  * the lle lock, drop here for now
  */

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Sun Jan 19 13:51:46 2014	(r260881)
+++ head/sys/netinet6/nd6.h	Sun Jan 19 16:07:27 2014	(r260882)
@@ -404,7 +404,6 @@ void nd6_purge(struct ifnet *);
 void nd6_nud_hint(struct rtentry *, struct in6_addr *, int);
 int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *,
 	struct sockaddr *, u_char *);
-void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 int nd6_ioctl(u_long, caddr_t, struct ifnet *);
 struct llentry *nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
 	char *, int, int, int);
@@ -416,6 +415,8 @@ int nd6_output_lle(struct ifnet *, struc
 int nd6_output_flush(struct ifnet *, struct ifnet *, struct mbuf *,
 	struct sockaddr_in6 *, struct route *);
 int nd6_need_cache(struct ifnet *);
+int nd6_add_ifa_lle(struct in6_ifaddr *);
+void nd6_rem_ifa_lle(struct in6_ifaddr *);
 int nd6_storelladdr(struct ifnet *, struct mbuf *,
 	const struct sockaddr *, u_char *, struct llentry **);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401191607.s0JG7SsM084760>