Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Aug 2015 17:48:55 +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: r286457 - in head/sys: net netinet netinet6
Message-ID:  <201508081748.t78HmtxL068784@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sat Aug  8 17:48:54 2015
New Revision: 286457
URL: https://svnweb.freebsd.org/changeset/base/286457

Log:
  MFP r274553:
  * Move lle creation/deletion from lla_lookup to separate functions:
    lla_lookup(LLE_CREATE) -> lla_create
    lla_lookup(LLE_DELETE) -> lla_delete
  lla_create now returns with LLE_EXCLUSIVE lock for lle.
  * Provide typedefs for new/existing lltable callbacks.
  
  Reviewed by:	ae

Modified:
  head/sys/net/if_llatbl.c
  head/sys/net/if_llatbl.h
  head/sys/netinet/if_ether.c
  head/sys/netinet/in.c
  head/sys/netinet/toecore.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h
Directory Properties:
  head/sys/   (props changed)

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/net/if_llatbl.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -147,8 +147,7 @@ llentry_alloc(struct ifnet *ifp, struct 
 	if ((la == NULL) &&
 	    (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
 		IF_AFDATA_WLOCK(ifp);
-		la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE),
-		    (struct sockaddr *)dst);
+		la = lla_create(lt, 0, (struct sockaddr *)dst);
 		IF_AFDATA_WUNLOCK(ifp);
 	}
 
@@ -259,7 +258,7 @@ lltable_init(struct ifnet *ifp, int af)
 }
 
 /*
- * Called in route_output when adding/deleting a route to an interface.
+ * Called in route_output when rtm_flags contains RTF_LLDATA.
  */
 int
 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
@@ -270,8 +269,8 @@ lla_rt_output(struct rt_msghdr *rtm, str
 	struct ifnet *ifp;
 	struct lltable *llt;
 	struct llentry *lle;
-	u_int laflags = 0, flags = 0;
-	int error = 0;
+	u_int laflags = 0;
+	int error;
 
 	KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
 	    ("%s: invalid dl\n", __func__));
@@ -283,24 +282,6 @@ lla_rt_output(struct rt_msghdr *rtm, str
 		return EINVAL;
 	}
 
-	switch (rtm->rtm_type) {
-	case RTM_ADD:
-		if (rtm->rtm_flags & RTF_ANNOUNCE)
-			flags |= LLE_PUB;
-		flags |= LLE_CREATE;
-		break;
-
-	case RTM_DELETE:
-		flags |= LLE_DELETE;
-		break;
-
-	case RTM_CHANGE:
-		break;
-
-	default:
-		return EINVAL; /* XXX not implemented yet */
-	}
-
 	/* XXX linked list may be too expensive */
 	LLTABLE_RLOCK();
 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
@@ -311,58 +292,62 @@ lla_rt_output(struct rt_msghdr *rtm, str
 	LLTABLE_RUNLOCK();
 	KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
 
-	if (flags & LLE_CREATE)
-		flags |= LLE_EXCLUSIVE;
+	error = 0;
 
-	IF_AFDATA_LOCK(ifp);
-	lle = lla_lookup(llt, flags, dst);
-	IF_AFDATA_UNLOCK(ifp);
-	if (LLE_IS_VALID(lle)) {
-		if (flags & LLE_CREATE) {
-			/*
-			 * If we delay the delete, then a subsequent
-			 * "arp add" should look up this entry, reset the
-			 * LLE_DELETED flag, and reset the expiration timer
-			 */
-			bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
-			lle->la_flags |= (flags & LLE_PUB);
-			lle->la_flags |= LLE_VALID;
-			lle->la_flags &= ~LLE_DELETED;
+	switch (rtm->rtm_type) {
+	case RTM_ADD:
+		/* Add static LLE */
+		IF_AFDATA_WLOCK(ifp);
+		lle = lla_create(llt, 0, dst);
+		if (lle == NULL) {
+			IF_AFDATA_WUNLOCK(ifp);
+			return (ENOMEM);
+		}
+
+
+		bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
+		if ((rtm->rtm_flags & RTF_ANNOUNCE))
+			lle->la_flags |= LLE_PUB;
+		lle->la_flags |= LLE_VALID;
 #ifdef INET6
-			/*
-			 * ND6
-			 */
-			if (dst->sa_family == AF_INET6)
-				lle->ln_state = ND6_LLINFO_REACHABLE;
+		/*
+		 * ND6
+		 */
+		if (dst->sa_family == AF_INET6)
+			lle->ln_state = ND6_LLINFO_REACHABLE;
 #endif
-			/*
-			 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
-			 */
-
-			if (rtm->rtm_rmx.rmx_expire == 0) {
-				lle->la_flags |= LLE_STATIC;
-				lle->la_expire = 0;
-			} else
-				lle->la_expire = rtm->rtm_rmx.rmx_expire;
-			laflags = lle->la_flags;
-			LLE_WUNLOCK(lle);
+		/*
+		 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
+		 */
+
+		if (rtm->rtm_rmx.rmx_expire == 0) {
+			lle->la_flags |= LLE_STATIC;
+			lle->la_expire = 0;
+		} else
+			lle->la_expire = rtm->rtm_rmx.rmx_expire;
+		laflags = lle->la_flags;
+		LLE_WUNLOCK(lle);
+		IF_AFDATA_WUNLOCK(ifp);
 #ifdef INET
-			/* gratuitous ARP */
-			if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
-				arprequest(ifp,
-				    &((struct sockaddr_in *)dst)->sin_addr,
-				    &((struct sockaddr_in *)dst)->sin_addr,
-				    (u_char *)LLADDR(dl));
+		/* gratuitous ARP */
+		if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
+			arprequest(ifp,
+			    &((struct sockaddr_in *)dst)->sin_addr,
+			    &((struct sockaddr_in *)dst)->sin_addr,
+			    (u_char *)LLADDR(dl));
 #endif
-		} else {
-			if (flags & LLE_EXCLUSIVE)
-				LLE_WUNLOCK(lle);
-			else
-				LLE_RUNLOCK(lle);
-		}
-	} else if ((lle == NULL) && (flags & LLE_DELETE))
-		error = EINVAL;
 
+		break;
+
+	case RTM_DELETE:
+		IF_AFDATA_WLOCK(ifp);
+		error = lla_delete(llt, 0, dst);
+		IF_AFDATA_WUNLOCK(ifp);
+		return (error == 0 ? 0 : ENOENT);
+
+	default:
+		error = EINVAL;
+	}
 
 	return (error);
 }

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/net/if_llatbl.h	Sat Aug  8 17:48:54 2015	(r286457)
@@ -144,25 +144,33 @@ struct llentry {
 #define	LLTBL_HASHMASK	(LLTBL_HASHTBL_SIZE - 1)
 #endif
 
+typedef	struct llentry *(llt_lookup_t)(struct lltable *, u_int flags,
+    const struct sockaddr *l3addr);
+typedef	struct llentry *(llt_create_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_prefix_free_t)(struct lltable *,
+    const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
+typedef int (llt_dump_t)(struct lltable *, struct sysctl_req *);
+
 struct lltable {
 	SLIST_ENTRY(lltable)	llt_link;
 	struct llentries	lle_head[LLTBL_HASHTBL_SIZE];
 	int			llt_af;
 	struct ifnet		*llt_ifp;
 
-	void			(*llt_prefix_free)(struct lltable *,
-				    const struct sockaddr *prefix,
-				    const struct sockaddr *mask,
-				    u_int flags);
-	struct llentry *	(*llt_lookup)(struct lltable *, u_int flags,
-				    const struct sockaddr *l3addr);
-	int			(*llt_dump)(struct lltable *,
-				    struct sysctl_req *);
+	llt_lookup_t		*llt_lookup;
+	llt_create_t		*llt_create;
+	llt_delete_t		*llt_delete;
+	llt_prefix_free_t	*llt_prefix_free;
+	llt_dump_t		*llt_dump;
 };
+
 MALLOC_DECLARE(M_LLTABLE);
 
 /*
- * flags to be passed to arplookup.
+ * LLentry flags
  */
 #define	LLE_DELETED	0x0001	/* entry must be deleted */
 #define	LLE_STATIC	0x0002	/* entry is static */
@@ -170,9 +178,8 @@ MALLOC_DECLARE(M_LLTABLE);
 #define	LLE_VALID	0x0008	/* ll_addr is valid */
 #define	LLE_PUB		0x0020	/* publish entry ??? */
 #define	LLE_LINKED	0x0040	/* linked to lookup structure */
+/* LLE request flags */
 #define	LLE_EXCLUSIVE	0x2000	/* return lle xlocked  */
-#define	LLE_DELETE	0x4000	/* delete on a lookup - match LLE_IFADDR */
-#define	LLE_CREATE	0x8000	/* create on a lookup miss */
 
 #define LLATBL_HASH(key, mask) \
 	(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
@@ -196,9 +203,25 @@ struct llentry  *llentry_alloc(struct if
 static __inline struct llentry *
 lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
 {
-	return llt->llt_lookup(llt, flags, l3addr);
+
+	return (llt->llt_lookup(llt, flags, l3addr));
 }
 
+static __inline struct llentry *
+lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+
+	return (llt->llt_create(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	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet/if_ether.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -152,8 +152,7 @@ arp_ifscrub(struct ifnet *ifp, uint32_t 
 	addr4.sin_family = AF_INET;
 	addr4.sin_addr.s_addr = addr;
 	IF_AFDATA_WLOCK(ifp);
-	lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
-	    (struct sockaddr *)&addr4);
+	lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
 	IF_AFDATA_WUNLOCK(ifp);
 }
 #endif
@@ -325,11 +324,12 @@ arpresolve(struct ifnet *ifp, int is_gw,
 	u_int flags = 0;
 	struct mbuf *curr = NULL;
 	struct mbuf *next = NULL;
-	int error, renew;
+	int create, error, renew;
 
 	if (pflags != NULL)
 		*pflags = 0;
 
+	create = 0;
 	if (m != NULL) {
 		if (m->m_flags & M_BCAST) {
 			/* broadcast */
@@ -349,13 +349,14 @@ retry:
 	IF_AFDATA_RUNLOCK(ifp);
 	if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0)
 	    && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) {
-		flags |= (LLE_CREATE | LLE_EXCLUSIVE);
+		create = 1;
+		flags |= LLE_EXCLUSIVE;
 		IF_AFDATA_WLOCK(ifp);
-		la = lla_lookup(LLTABLE(ifp), flags, dst);
+		la = lla_create(LLTABLE(ifp), flags, dst);
 		IF_AFDATA_WUNLOCK(ifp);
 	}
 	if (la == NULL) {
-		if (flags & LLE_CREATE)
+		if (create != 0)
 			log(LOG_DEBUG,
 			    "arpresolve: can't allocate llinfo for %s on %s\n",
 			    inet_ntoa(SIN(dst)->sin_addr), ifp->if_xname);
@@ -578,7 +579,7 @@ in_arpinput(struct mbuf *m)
 	int op, flags;
 	int req_len;
 	int bridged = 0, is_bridge = 0;
-	int carped;
+	int carped, create;
 	struct sockaddr_in sin;
 	sin.sin_len = sizeof(struct sockaddr_in);
 	sin.sin_family = AF_INET;
@@ -729,10 +730,13 @@ match:
 	sin.sin_len = sizeof(struct sockaddr_in);
 	sin.sin_family = AF_INET;
 	sin.sin_addr = isaddr;
-	flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0;
-	flags |= LLE_EXCLUSIVE;
+	create = (itaddr.s_addr == myaddr.s_addr) ? 1 : 0;
+	flags = LLE_EXCLUSIVE;
 	IF_AFDATA_LOCK(ifp);
-	la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
+	if (create != 0)
+		la = lla_create(LLTABLE(ifp), 0, (struct sockaddr *)&sin);
+	else
+		la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
 	IF_AFDATA_UNLOCK(ifp);
 	if (la != NULL) {
 		/* the following is not an error when doing bridging */
@@ -947,14 +951,14 @@ arp_ifinit(struct ifnet *ifp, struct ifa
 		 * that L2 entry as permanent
 		 */
 		IF_AFDATA_LOCK(ifp);
-		lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC),
+		lle = lla_create(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC,
 				 (struct sockaddr *)IA_SIN(ifa));
 		IF_AFDATA_UNLOCK(ifp);
 		if (lle == NULL)
 			log(LOG_INFO, "arp_ifinit: cannot create arp "
 			    "entry for interface address\n");
 		else
-			LLE_RUNLOCK(lle);
+			LLE_WUNLOCK(lle);
 	}
 	ifa->ifa_rtrequest = NULL;
 }

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet/in.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -1107,6 +1107,117 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 	return (0);
 }
 
+static inline struct llentry *
+in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
+{
+	struct llentry *lle;
+	struct llentries *lleh;
+	struct sockaddr_in *sin;
+	u_int hashkey;
+
+	hashkey = dst.s_addr;
+	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+	LIST_FOREACH(lle, lleh, lle_next) {
+		sin = satosin(L3_ADDR(lle));
+		if (lle->la_flags & LLE_DELETED)
+			continue;
+		if (sin->sin_addr.s_addr == dst.s_addr)
+			break;
+	}
+
+	return (lle);
+}
+
+static int
+in_lltable_delete(struct lltable *llt, u_int flags,
+    const struct sockaddr *l3addr)
+{
+	const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
+	struct ifnet *ifp = llt->llt_ifp;
+	struct llentry *lle;
+
+	IF_AFDATA_WLOCK_ASSERT(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);
+#ifdef DIAGNOSTIC
+		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);
+}
+
+static struct llentry *
+in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+	const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
+	struct ifnet *ifp = llt->llt_ifp;
+	struct llentry *lle;
+	struct llentries *lleh;
+	u_int hashkey;
+
+	IF_AFDATA_WLOCK_ASSERT(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) {
+		LLE_WLOCK(lle);
+		return (lle);
+	}
+
+	/* no existing record, we need to create new one */
+
+	/*
+	 * A route that covers the given address must have
+	 * been installed 1st because we are doing a resolution,
+	 * verify this.
+	 */
+	if (!(flags & LLE_IFADDR) &&
+	    in_lltable_rtcheck(ifp, flags, l3addr) != 0)
+		return (NULL);
+
+	lle = in_lltable_new(l3addr, flags);
+	if (lle == NULL) {
+		log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
+		return (NULL);
+	}
+	lle->la_flags = flags;
+	if ((flags & LLE_IFADDR) == LLE_IFADDR) {
+		bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+		lle->la_flags |= (LLE_VALID | LLE_STATIC);
+	}
+
+	hashkey = sin->sin_addr.s_addr;
+	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+
+	lle->lle_tbl  = llt;
+	lle->lle_head = lleh;
+	lle->la_flags |= LLE_LINKED;
+	LIST_INSERT_HEAD(lleh, lle, lle_next);
+	LLE_WLOCK(lle);
+
+	return (lle);
+}
+
 /*
  * Return NULL if not found or marked for deletion.
  * If found return lle read locked.
@@ -1133,62 +1244,15 @@ in_lltable_lookup(struct lltable *llt, u
 		if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr)
 			break;
 	}
-	if (lle == NULL) {
-#ifdef DIAGNOSTIC
-		if (flags & LLE_DELETE)
-			log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);
-#endif
-		if (!(flags & LLE_CREATE))
-			return (NULL);
-		IF_AFDATA_WLOCK_ASSERT(ifp);
-		/*
-		 * A route that covers the given address must have
-		 * been installed 1st because we are doing a resolution,
-		 * verify this.
-		 */
-		if (!(flags & LLE_IFADDR) &&
-		    in_lltable_rtcheck(ifp, flags, l3addr) != 0)
-			goto done;
-
-		lle = in_lltable_new(l3addr, flags);
-		if (lle == NULL) {
-			log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
-			goto done;
-		}
-		lle->la_flags = flags & ~LLE_CREATE;
-		if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
-			bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
-			lle->la_flags |= (LLE_VALID | LLE_STATIC);
-		}
 
-		lle->lle_tbl  = llt;
-		lle->lle_head = lleh;
-		lle->la_flags |= LLE_LINKED;
-		LIST_INSERT_HEAD(lleh, lle, lle_next);
-	} else if (flags & LLE_DELETE) {
-		if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-			LLE_WLOCK(lle);
-			lle->la_flags |= LLE_DELETED;
-			EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
-#ifdef DIAGNOSTIC
-			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);
-		}
-		lle = (void *)-1;
+	if (lle == NULL)
+		return (NULL);
+
+	if (flags & LLE_EXCLUSIVE)
+		LLE_WLOCK(lle);
+	else
+		LLE_RLOCK(lle);
 
-	}
-	if (LLE_IS_VALID(lle)) {
-		if (flags & LLE_EXCLUSIVE)
-			LLE_WLOCK(lle);
-		else
-			LLE_RLOCK(lle);
-	}
-done:
 	return (lle);
 }
 
@@ -1279,6 +1343,8 @@ in_domifattach(struct ifnet *ifp)
 	if (llt != NULL) {
 		llt->llt_prefix_free = in_lltable_prefix_free;
 		llt->llt_lookup = in_lltable_lookup;
+		llt->llt_create = in_lltable_create;
+		llt->llt_delete = in_lltable_delete;
 		llt->llt_dump = in_lltable_dump;
 	}
 	ii->ii_llt = llt;

Modified: head/sys/netinet/toecore.c
==============================================================================
--- head/sys/netinet/toecore.c	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet/toecore.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -463,8 +463,7 @@ restart:
 	IF_AFDATA_RUNLOCK(ifp);
 	if (lle == NULL) {
 		IF_AFDATA_LOCK(ifp);
-		lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE,
-		    ifp);
+		lle = nd6_create(&sin6->sin6_addr, 0, ifp);
 		IF_AFDATA_UNLOCK(ifp);
 		if (lle == NULL)
 			return (ENOMEM); /* Couldn't create entry in cache. */

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet6/in6.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -2152,81 +2152,134 @@ in6_lltable_rtcheck(struct ifnet *ifp,
 	return 0;
 }
 
-static struct llentry *
-in6_lltable_lookup(struct lltable *llt, u_int flags,
-	const struct sockaddr *l3addr)
+static inline struct llentry *
+in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
 {
-	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
-	struct ifnet *ifp = llt->llt_ifp;
 	struct llentry *lle;
 	struct llentries *lleh;
+	const struct sockaddr_in6 *sin6;
 	u_int hashkey;
 
-	IF_AFDATA_LOCK_ASSERT(ifp);
-	KASSERT(l3addr->sa_family == AF_INET6,
-	    ("sin_family %d", l3addr->sa_family));
-
-	hashkey = sin6->sin6_addr.s6_addr32[3];
+	hashkey = dst->s6_addr32[3];
 	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
 	LIST_FOREACH(lle, lleh, lle_next) {
-		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle);
+		sin6 = (const struct sockaddr_in6 *)L3_ADDR(lle);
 		if (lle->la_flags & LLE_DELETED)
 			continue;
-		if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
-		    sizeof(struct in6_addr)) == 0)
+		if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, dst))
 			break;
 	}
 
-	if (lle == NULL) {
-		if (!(flags & LLE_CREATE))
-			return (NULL);
-		IF_AFDATA_WLOCK_ASSERT(ifp);
-		/*
-		 * A route that covers the given address must have
-		 * been installed 1st because we are doing a resolution,
-		 * verify this.
-		 */
-		if (!(flags & LLE_IFADDR) &&
-		    in6_lltable_rtcheck(ifp, flags, l3addr) != 0)
-			return NULL;
-
-		lle = in6_lltable_new(l3addr, flags);
-		if (lle == NULL) {
-			log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
-			return NULL;
-		}
-		lle->la_flags = flags & ~LLE_CREATE;
-		if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
-			bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
-			lle->la_flags |= (LLE_VALID | LLE_STATIC);
-		}
+	return (lle);
+}
 
-		lle->lle_tbl  = llt;
-		lle->lle_head = lleh;
-		lle->la_flags |= LLE_LINKED;
-		LIST_INSERT_HEAD(lleh, lle, lle_next);
-	} else if (flags & LLE_DELETE) {
-		if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-			LLE_WLOCK(lle);
-			lle->la_flags |= LLE_DELETED;
-			EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+static int
+in6_lltable_delete(struct lltable *llt, u_int flags,
+	const struct sockaddr *l3addr)
+{
+	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
+	struct ifnet *ifp = llt->llt_ifp;
+	struct llentry *lle;
+
+	IF_AFDATA_LOCK_ASSERT(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);
 #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);
-		}
-		lle = (void *)-1;
-	}
-	if (LLE_IS_VALID(lle)) {
-		if (flags & LLE_EXCLUSIVE)
-			LLE_WLOCK(lle);
+		if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
+			llentry_free(lle);
 		else
-			LLE_RLOCK(lle);
+			LLE_WUNLOCK(lle);
 	}
+
+	return (0);
+}
+
+static struct llentry *
+in6_lltable_create(struct lltable *llt, u_int flags,
+	const struct sockaddr *l3addr)
+{
+	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
+	struct ifnet *ifp = llt->llt_ifp;
+	struct llentry *lle;
+	struct llentries *lleh;
+	u_int hashkey;
+
+	IF_AFDATA_WLOCK_ASSERT(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) {
+		LLE_WLOCK(lle);
+		return (lle);
+	}
+
+	/*
+	 * A route that covers the given address must have
+	 * been installed 1st because we are doing a resolution,
+	 * verify this.
+	 */
+	if (!(flags & LLE_IFADDR) &&
+	    in6_lltable_rtcheck(ifp, flags, l3addr) != 0)
+		return (NULL);
+
+	lle = in6_lltable_new(l3addr, flags);
+	if (lle == NULL) {
+		log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
+		return (NULL);
+	}
+	lle->la_flags = flags;
+	if ((flags & LLE_IFADDR) == LLE_IFADDR) {
+		bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+		lle->la_flags |= (LLE_VALID | LLE_STATIC);
+	}
+
+	hashkey = sin6->sin6_addr.s6_addr32[3];
+	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+
+	lle->lle_tbl  = llt;
+	lle->lle_head = lleh;
+	lle->la_flags |= LLE_LINKED;
+	LIST_INSERT_HEAD(lleh, lle, lle_next);
+	LLE_WLOCK(lle);
+
+	return (lle);
+}
+
+static struct llentry *
+in6_lltable_lookup(struct lltable *llt, u_int flags,
+	const struct sockaddr *l3addr)
+{
+	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
+	struct ifnet *ifp = llt->llt_ifp;
+	struct llentry *lle;
+
+	IF_AFDATA_LOCK_ASSERT(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 (NULL);
+
+	if (flags & LLE_EXCLUSIVE)
+		LLE_WLOCK(lle);
+	else
+		LLE_RLOCK(lle);
 	return (lle);
 }
 
@@ -2340,6 +2393,8 @@ in6_domifattach(struct ifnet *ifp)
 	if (ext->lltable != NULL) {
 		ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
 		ext->lltable->llt_lookup = in6_lltable_lookup;
+		ext->lltable->llt_create = in6_lltable_create;
+		ext->lltable->llt_delete = in6_lltable_delete;
 		ext->lltable->llt_dump = in6_lltable_dump;
 	}
 

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet6/nd6.c	Sat Aug  8 17:48:54 2015	(r286457)
@@ -937,16 +937,33 @@ nd6_lookup(struct in6_addr *addr6, int f
 
 	IF_AFDATA_LOCK_ASSERT(ifp);
 
-	llflags = 0;
-	if (flags & ND6_CREATE)
-	    llflags |= LLE_CREATE;
-	if (flags & ND6_EXCLUSIVE)
-	    llflags |= LLE_EXCLUSIVE;	
-	
+	llflags = (flags & ND6_EXCLUSIVE) ? LLE_EXCLUSIVE : 0;
 	ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6);
-	if ((ln != NULL) && (llflags & LLE_CREATE))
+
+	return (ln);
+}
+
+/*
+ * the caller acquires and releases the lock on the lltbls
+ * Returns the llentry wlocked
+ */
+struct llentry *
+nd6_create(struct in6_addr *addr6, int flags, struct ifnet *ifp)
+{
+	struct sockaddr_in6 sin6;
+	struct llentry *ln;
+
+	bzero(&sin6, sizeof(sin6));
+	sin6.sin6_len = sizeof(struct sockaddr_in6);
+	sin6.sin6_family = AF_INET6;
+	sin6.sin6_addr = *addr6;
+
+	IF_AFDATA_WLOCK_ASSERT(ifp);
+
+	ln = lla_create(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6);
+	if (ln != NULL)
 		ln->ln_state = ND6_LLINFO_NOSTATE;
-	
+
 	return (ln);
 }
 
@@ -1664,7 +1681,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
 	if (ln == NULL) {
 		flags |= ND6_EXCLUSIVE;
 		IF_AFDATA_LOCK(ifp);
-		ln = nd6_lookup(from, flags | ND6_CREATE, ifp);
+		ln = nd6_create(from, 0, ifp);
 		IF_AFDATA_UNLOCK(ifp);
 		is_newentry = 1;
 	} else {
@@ -2020,7 +2037,6 @@ nd6_output_lle(struct ifnet *ifp, struct
     struct sockaddr_in6 *dst)
 {
 	struct llentry *lle = NULL;
-	int flags = 0;
 
 	KASSERT(m != NULL, ("NULL mbuf, nothing to send"));
 	/* discard the packet if IPv6 operation is disabled on the interface */
@@ -2051,9 +2067,8 @@ nd6_output_lle(struct ifnet *ifp, struct
 			 * the condition below is not very efficient.  But we believe
 			 * it is tolerable, because this should be a rare case.
 			 */
-			flags = ND6_CREATE | ND6_EXCLUSIVE;
 			IF_AFDATA_LOCK(ifp);
-			lle = nd6_lookup(&dst->sin6_addr, flags, ifp);
+			lle = nd6_create(&dst->sin6_addr, 0, ifp);
 			IF_AFDATA_UNLOCK(ifp);
 		}
 	} 
@@ -2237,8 +2252,8 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
 		return (0);
 	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);
+	ln = lla_create(LLTABLE6(ifp), LLE_IFADDR,
+	    (struct sockaddr *)&ia->ia_addr);
 	IF_AFDATA_UNLOCK(ifp);
 	if (ln != NULL) {
 		ln->la_expire = 0;  /* for IPv6 this means permanent */

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Sat Aug  8 16:39:28 2015	(r286456)
+++ head/sys/netinet6/nd6.h	Sat Aug  8 17:48:54 2015	(r286457)
@@ -89,7 +89,6 @@ struct nd_ifinfo {
 #define ND6_IFF_NO_PREFER_IFACE	0x80 /* XXX: not related to ND. */
 #define ND6_IFF_NO_DAD		0x100
 
-#define	ND6_CREATE		LLE_CREATE
 #define	ND6_EXCLUSIVE		LLE_EXCLUSIVE
 
 #ifdef _KERNEL
@@ -407,7 +406,8 @@ int nd6_is_addr_neighbor(struct sockaddr
 void nd6_option_init(void *, int, union nd_opts *);
 struct nd_opt_hdr *nd6_option(union nd_opts *);
 int nd6_options(union nd_opts *);
-struct	llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_create(struct in6_addr *, int, struct ifnet *);
 void nd6_setmtu(struct ifnet *);
 void nd6_llinfo_settimer(struct llentry *, long);
 void nd6_llinfo_settimer_locked(struct llentry *, long);



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