Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Sep 2015 16:48:20 +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: r287789 - in head/sys: net netinet netinet6
Message-ID:  <201509141648.t8EGmK0G062494@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Mon Sep 14 16:48:19 2015
New Revision: 287789
URL: https://svnweb.freebsd.org/changeset/base/287789

Log:
  * Do more fine-grained locking: call eventhandlers/free_entry
    without holding afdata wlock
  * convert per-af delete_address callback to global lltable_delete_entry() and
    more low-level "delete this lle" per-af callback
  * fix some bugs/inconsistencies in IPv4/IPv6 ifscrub procedures
  
  Sponsored by:		Yandex LLC
  Differential Revision:	https://reviews.freebsd.org/D3573

Modified:
  head/sys/net/if_llatbl.c
  head/sys/net/if_llatbl.h
  head/sys/netinet/if_ether.c
  head/sys/netinet/if_ether.h
  head/sys/netinet/in.c
  head/sys/netinet/ip_carp.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/net/if_llatbl.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -186,7 +186,7 @@ htable_unlink_entry(struct llentry *lle)
 }
 
 struct prefix_match_data {
-	const struct sockaddr *prefix;
+	const struct sockaddr *addr;
 	const struct sockaddr *mask;
 	struct llentries dchain;
 	u_int flags;
@@ -199,7 +199,7 @@ htable_prefix_free_cb(struct lltable *ll
 
 	pmd = (struct prefix_match_data *)farg;
 
-	if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
+	if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
 		LLE_WLOCK(lle);
 		LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
 	}
@@ -208,14 +208,14 @@ htable_prefix_free_cb(struct lltable *ll
 }
 
 static void
-htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
+htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
     const struct sockaddr *mask, u_int flags)
 {
 	struct llentry *lle, *next;
 	struct prefix_match_data pmd;
 
 	bzero(&pmd, sizeof(pmd));
-	pmd.prefix = prefix;
+	pmd.addr = addr;
 	pmd.mask = mask;
 	pmd.flags = flags;
 	LIST_INIT(&pmd.dchain);
@@ -427,8 +427,42 @@ lltable_drain(int af)
 }
 #endif
 
+/*
+ * Deletes an address from given lltable.
+ * Used for userland interaction to remove
+ * individual entries. Skips entries added by OS.
+ */
+int
+lltable_delete_addr(struct lltable *llt, u_int flags,
+    const struct sockaddr *l3addr)
+{
+	struct llentry *lle;
+	struct ifnet *ifp;
+
+	ifp = llt->llt_ifp;
+	IF_AFDATA_WLOCK(ifp);
+	lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
+
+	if (lle == NULL) {
+		IF_AFDATA_WUNLOCK(ifp);
+		return (ENOENT);
+	}
+	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
+		IF_AFDATA_WUNLOCK(ifp);
+		LLE_WUNLOCK(lle);
+		return (EPERM);
+	}
+
+	lltable_unlink_entry(llt, lle);
+	IF_AFDATA_WUNLOCK(ifp);
+
+	llt->llt_delete_entry(llt, lle);
+
+	return (0);
+}
+
 void
-lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
+lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
     u_int flags)
 {
 	struct lltable *llt;
@@ -438,7 +472,7 @@ lltable_prefix_free(int af, struct socka
 		if (llt->llt_af != af)
 			continue;
 
-		llt->llt_prefix_free(llt, prefix, mask, flags);
+		llt->llt_prefix_free(llt, addr, mask, flags);
 	}
 	LLTABLE_RUNLOCK();
 }
@@ -651,10 +685,7 @@ lla_rt_output(struct rt_msghdr *rtm, str
 		break;
 
 	case RTM_DELETE:
-		IF_AFDATA_WLOCK(ifp);
-		error = lla_delete(llt, 0, dst);
-		IF_AFDATA_WUNLOCK(ifp);
-		return (error == 0 ? 0 : ENOENT);
+		return (lltable_delete_addr(llt, 0, dst));
 
 	default:
 		error = EINVAL;

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/net/if_llatbl.h	Mon Sep 14 16:48:19 2015	(r287789)
@@ -135,10 +135,9 @@ typedef	struct llentry *(llt_lookup_t)(s
     const struct sockaddr *l3addr);
 typedef	struct llentry *(llt_alloc_t)(struct lltable *, u_int flags,
     const struct sockaddr *l3addr);
-typedef	int (llt_delete_t)(struct lltable *, u_int flags,
-    const struct sockaddr *l3addr);
+typedef	void (llt_delete_t)(struct lltable *, struct llentry *);
 typedef void (llt_prefix_free_t)(struct lltable *,
-    const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
+    const struct sockaddr *addr, const struct sockaddr *mask, u_int flags);
 typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
     struct sysctl_req *);
 typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t);
@@ -162,7 +161,7 @@ struct lltable {
 
 	llt_lookup_t		*llt_lookup;
 	llt_alloc_t		*llt_alloc_entry;
-	llt_delete_t		*llt_delete;
+	llt_delete_t		*llt_delete_entry;
 	llt_prefix_free_t	*llt_prefix_free;
 	llt_dump_entry_t	*llt_dump_entry;
 	llt_hash_t		*llt_hash;
@@ -212,6 +211,8 @@ size_t lltable_drop_entry_queue(struct l
 struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
     const struct sockaddr *l4addr);
 void lltable_free_entry(struct lltable *llt, struct llentry *lle);
+int lltable_delete_addr(struct lltable *llt, u_int flags,
+    const struct sockaddr *l3addr);
 void lltable_link_entry(struct lltable *llt, struct llentry *lle);
 void lltable_unlink_entry(struct lltable *llt, struct llentry *lle);
 void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa);
@@ -230,14 +231,6 @@ lla_lookup(struct lltable *llt, u_int fl
 	return (llt->llt_lookup(llt, flags, l3addr));
 }
 
-static __inline int
-lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
-{
-
-	return (llt->llt_delete(llt, flags, l3addr));
-}
-
-
 int		lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
 
 #include <sys/eventhandler.h>

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet/if_ether.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -140,26 +140,6 @@ static const struct netisr_handler arp_n
 	.nh_policy = NETISR_POLICY_SOURCE,
 };
 
-#ifdef AF_INET
-/*
- * called by in_scrubprefix() to remove entry from the table when
- * the interface goes away
- */
-void
-arp_ifscrub(struct ifnet *ifp, uint32_t addr)
-{
-	struct sockaddr_in addr4;
-
-	bzero((void *)&addr4, sizeof(addr4));
-	addr4.sin_len    = sizeof(addr4);
-	addr4.sin_family = AF_INET;
-	addr4.sin_addr.s_addr = addr;
-	IF_AFDATA_WLOCK(ifp);
-	lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
-	IF_AFDATA_WUNLOCK(ifp);
-}
-#endif
-
 /*
  * Timeout routine.  Age arp_tab entries periodically.
  */

Modified: head/sys/netinet/if_ether.h
==============================================================================
--- head/sys/netinet/if_ether.h	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet/if_ether.h	Mon Sep 14 16:48:19 2015	(r287789)
@@ -120,7 +120,6 @@ void	arprequest(struct ifnet *, const st
 	    const struct in_addr *, u_char *);
 void	arp_ifinit(struct ifnet *, struct ifaddr *);
 void	arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
-void	arp_ifscrub(struct ifnet *, uint32_t);
 #endif
 
 #endif

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet/in.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -724,6 +724,38 @@ in_addprefix(struct in_ifaddr *target, i
 }
 
 /*
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
+ */
+static void
+in_scrubprefixlle(struct in_ifaddr *ia, int all, u_int flags)
+{
+	struct sockaddr_in addr, mask;
+	struct sockaddr *saddr, *smask;
+	struct ifnet *ifp;
+
+	/*
+	 * remove all L2 entries on the given prefix
+	 */
+	saddr = (struct sockaddr *)&addr;
+	bzero(&addr, sizeof(addr));
+	addr.sin_len = sizeof(addr);
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = ntohl(ia->ia_addr.sin_addr.s_addr);
+	smask = (struct sockaddr *)&mask;
+	bzero(&mask, sizeof(mask));
+	mask.sin_len = sizeof(mask);
+	mask.sin_family = AF_INET;
+	mask.sin_addr.s_addr = ia->ia_subnetmask;
+	ifp = ia->ia_ifp;
+
+	if (all)
+		lltable_prefix_free(AF_INET, saddr, smask, flags);
+	else
+		lltable_delete_addr(LLTABLE(ifp), LLE_IFADDR, saddr);
+}
+
+/*
  * If there is no other address in the system that can serve a route to the
  * same prefix, remove the route.  Hand over the route to the new address
  * otherwise.
@@ -735,7 +767,6 @@ in_scrubprefix(struct in_ifaddr *target,
 	struct in_ifaddr *ia;
 	struct in_addr prefix, mask, p, m;
 	int error = 0;
-	struct sockaddr_in prefix0, mask0;
 
 	/*
 	 * Remove the loopback route to the interface address.
@@ -757,11 +788,6 @@ in_scrubprefix(struct in_ifaddr *target,
 			error = ifa_del_loopback_route((struct ifaddr *)target,
 			    (struct sockaddr *)&target->ia_addr);
 		}
-
-		if (!(target->ia_ifp->if_flags & IFF_NOARP))
-			/* remove arp cache */
-			arp_ifscrub(target->ia_ifp,
-			    IA_SIN(target)->sin_addr.s_addr);
 	}
 
 	if (rtinitflags(target)) {
@@ -817,6 +843,9 @@ in_scrubprefix(struct in_ifaddr *target,
 			else
 				log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n",
 					error);
+			/* Scrub all entries IFF interface is different */
+			in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp,
+			    flags);
 			error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
 			    rtinitflags(ia) | RTF_UP);
 			if (error == 0)
@@ -833,16 +862,7 @@ in_scrubprefix(struct in_ifaddr *target,
 	/*
 	 * remove all L2 entries on the given prefix
 	 */
-	bzero(&prefix0, sizeof(prefix0));
-	prefix0.sin_len = sizeof(prefix0);
-	prefix0.sin_family = AF_INET;
-	prefix0.sin_addr.s_addr = target->ia_subnet;
-	bzero(&mask0, sizeof(mask0));
-	mask0.sin_len = sizeof(mask0);
-	mask0.sin_family = AF_INET;
-	mask0.sin_addr.s_addr = target->ia_subnetmask;
-	lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
-	    (struct sockaddr *)&mask0, flags);
+	in_scrubprefixlle(target, 1, flags);
 
 	/*
 	 * As no-one seem to have this prefix, we can remove the route.
@@ -1001,22 +1021,38 @@ in_lltable_new(struct in_addr addr4, u_i
 	return (&lle->base);
 }
 
-#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)	(			\
-	    (((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)	(		\
+	((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 )
 
 static int
-in_lltable_match_prefix(const struct sockaddr *prefix,
-    const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in_lltable_match_prefix(const struct sockaddr *saddr,
+    const struct sockaddr *smask, u_int flags, struct llentry *lle)
 {
-	const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
-	const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+	struct in_addr addr, mask, lle_addr;
 
-	/*
-	 * (flags & LLE_STATIC) means deleting all entries
-	 * including static ARP entries.
-	 */
-	if (IN_ARE_MASKED_ADDR_EQUAL(lle->r_l3addr.addr4, pfx, msk) &&
-	    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+	addr = ((const struct sockaddr_in *)saddr)->sin_addr;
+	mask = ((const struct sockaddr_in *)smask)->sin_addr;
+	lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr);
+
+	if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+		return (0);
+
+	if (lle->la_flags & LLE_IFADDR) {
+
+		/*
+		 * Delete LLE_IFADDR records IFF address & flag matches.
+		 * Note that addr is the interface address within prefix
+		 * being matched.
+		 * Note also we should handle 'ifdown' cases without removing
+		 * ifaddr macs.
+		 */
+		if (addr.s_addr == lle_addr.s_addr && (flags & LLE_STATIC) != 0)
+			return (1);
+		return (0);
+	}
+
+	/* flags & LLE_STATIC means deleting both dynamic and static entries */
+	if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
 		return (1);
 
 	return (0);
@@ -1166,39 +1202,16 @@ in_lltable_find_dst(struct lltable *llt,
 	return (lle);
 }
 
-static int
-in_lltable_delete(struct lltable *llt, u_int flags,
-    const struct sockaddr *l3addr)
+static void
+in_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
 {
-	const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
-	struct llentry *lle;
-
-	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
-	KASSERT(l3addr->sa_family == AF_INET,
-	    ("sin_family %d", l3addr->sa_family));
 
-	lle = in_lltable_find_dst(llt, sin->sin_addr);
-	if (lle == NULL) {
-#ifdef DIAGNOSTIC
-		log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);
-#endif
-		return (ENOENT);
-	}
-
-	if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-		LLE_WLOCK(lle);
-		lle->la_flags |= LLE_DELETED;
-		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+	lle->la_flags |= LLE_DELETED;
+	EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
 #ifdef DIAGNOSTIC
-		log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+	log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
 #endif
-		if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
-			llentry_free(lle);
-		else
-			LLE_WUNLOCK(lle);
-	}
-
-	return (0);
+	llentry_free(lle);
 }
 
 static struct llentry *
@@ -1334,7 +1347,7 @@ in_lltattach(struct ifnet *ifp)
 
 	llt->llt_lookup = in_lltable_lookup;
 	llt->llt_alloc_entry = in_lltable_alloc;
-	llt->llt_delete = in_lltable_delete;
+	llt->llt_delete_entry = in_lltable_delete_entry;
 	llt->llt_dump_entry = in_lltable_dump_entry;
 	llt->llt_hash = in_lltable_hash;
 	llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;

Modified: head/sys/netinet/ip_carp.c
==============================================================================
--- head/sys/netinet/ip_carp.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet/ip_carp.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -985,7 +985,7 @@ carp_ifa_delroute(struct ifaddr *ifa)
 	case AF_INET6:
 		ifa_del_loopback_route(ifa,
 		    (struct sockaddr *)&ifatoia6(ifa)->ia_addr);
-		nd6_rem_ifa_lle(ifatoia6(ifa));
+		nd6_rem_ifa_lle(ifatoia6(ifa), 1);
 		break;
 #endif
 	}

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet6/in6.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -1307,9 +1307,6 @@ in6_purgeaddr(struct ifaddr *ifa)
 	/* stop DAD processing */
 	nd6_dad_stop(ifa);
 
-	/* Remove local address entry from lltable. */
-	nd6_rem_ifa_lle(ia);
-
 	/* Leave multicast groups. */
 	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
 		LIST_REMOVE(imm, i6mm_chain);
@@ -1333,6 +1330,7 @@ static void
 in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
 {
 	char ip6buf[INET6_ADDRSTRLEN];
+	int remove_lle;
 
 	IF_ADDR_WLOCK(ifp);
 	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
@@ -1353,15 +1351,21 @@ in6_unlink_ifa(struct in6_ifaddr *ia, st
 	 * Release the reference to the base prefix.  There should be a
 	 * positive reference.
 	 */
+	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 {
 		ia->ia6_ndpr->ndpr_refcnt--;
+		/* Do not delete lles within prefix if refcont != 0 */
+		if (ia->ia6_ndpr->ndpr_refcnt == 0)
+			remove_lle = 1;
 		ia->ia6_ndpr = NULL;
 	}
 
+	nd6_rem_ifa_lle(ia, remove_lle);
+
 	/*
 	 * Also, if the address being removed is autoconf'ed, call
 	 * pfxlist_onlink_check() since the release might affect the status of
@@ -2081,15 +2085,33 @@ in6_lltable_new(const struct in6_addr *a
 }
 
 static int
-in6_lltable_match_prefix(const struct sockaddr *prefix,
-    const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in6_lltable_match_prefix(const struct sockaddr *saddr,
+    const struct sockaddr *smask, u_int flags, struct llentry *lle)
 {
-	const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
-	const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
+	const struct in6_addr *addr, *mask, *lle_addr;
+
+	addr = &((const struct sockaddr_in6 *)saddr)->sin6_addr;
+	mask = &((const struct sockaddr_in6 *)smask)->sin6_addr;
+	lle_addr = &lle->r_l3addr.addr6;
+
+	if (IN6_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+		return (0);
+
+	if (lle->la_flags & LLE_IFADDR) {
 
-	if (IN6_ARE_MASKED_ADDR_EQUAL(&lle->r_l3addr.addr6,
-	    &pfx->sin6_addr, &msk->sin6_addr) &&
-	    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+		/*
+		 * Delete LLE_IFADDR records IFF address & flag matches.
+		 * Note that addr is the interface address within prefix
+		 * being matched.
+		 */
+		if (IN6_ARE_ADDR_EQUAL(addr, lle_addr) &&
+		    (flags & LLE_STATIC) != 0)
+			return (1);
+		return (0);
+	}
+
+	/* flags & LLE_STATIC means deleting both dynamic and static entries */
+	if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
 		return (1);
 
 	return (0);
@@ -2200,36 +2222,16 @@ in6_lltable_find_dst(struct lltable *llt
 	return (lle);
 }
 
-static int
-in6_lltable_delete(struct lltable *llt, u_int flags,
-	const struct sockaddr *l3addr)
+static void
+in6_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
 {
-	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
-	struct llentry *lle;
-
-	IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
-	KASSERT(l3addr->sa_family == AF_INET6,
-	    ("sin_family %d", l3addr->sa_family));
-
-	lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
 
-	if (lle == NULL)
-		return (ENOENT);
-
-	if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-		LLE_WLOCK(lle);
-		lle->la_flags |= LLE_DELETED;
-		EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+	lle->la_flags |= LLE_DELETED;
+	EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
 #ifdef DIAGNOSTIC
-		log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+	log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
 #endif
-		if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
-			llentry_free(lle);
-		else
-			LLE_WUNLOCK(lle);
-	}
-
-	return (0);
+	llentry_free(lle);
 }
 
 static struct llentry *
@@ -2369,7 +2371,7 @@ in6_lltattach(struct ifnet *ifp)
 
 	llt->llt_lookup = in6_lltable_lookup;
 	llt->llt_alloc_entry = in6_lltable_alloc;
-	llt->llt_delete = in6_lltable_delete;
+	llt->llt_delete_entry = in6_lltable_delete_entry;
 	llt->llt_dump_entry = in6_lltable_dump_entry;
 	llt->llt_hash = in6_lltable_hash;
 	llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry;

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet6/nd6.c	Mon Sep 14 16:48:19 2015	(r287789)
@@ -2245,23 +2245,26 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
 }
 
 /*
- * 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.
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
  */
 void
-nd6_rem_ifa_lle(struct in6_ifaddr *ia)
+nd6_rem_ifa_lle(struct in6_ifaddr *ia, int all)
 {
 	struct sockaddr_in6 mask, addr;
+	struct sockaddr *saddr, *smask;
 	struct ifnet *ifp;
 
 	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);
+	saddr = (struct sockaddr *)&addr;
+	smask = (struct sockaddr *)&mask;
+
+	if (all != 0)
+		lltable_prefix_free(AF_INET6, saddr, smask, LLE_STATIC);
+	else
+		lltable_delete_addr(LLTABLE6(ifp), LLE_IFADDR, saddr);
 }
 
 /*

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Mon Sep 14 15:47:25 2015	(r287788)
+++ head/sys/netinet6/nd6.h	Mon Sep 14 16:48:19 2015	(r287789)
@@ -427,7 +427,7 @@ int nd6_flush_holdchain(struct ifnet *, 
     struct sockaddr_in6 *);
 int nd6_need_cache(struct ifnet *);
 int nd6_add_ifa_lle(struct in6_ifaddr *);
-void nd6_rem_ifa_lle(struct in6_ifaddr *);
+void nd6_rem_ifa_lle(struct in6_ifaddr *, int);
 int nd6_storelladdr(struct ifnet *, struct mbuf *,
 	const struct sockaddr *, u_char *, uint32_t *); 
 



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