Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 7 Dec 2014 23:08:07 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r275586 - in projects/routing/sys: net netinet netinet6
Message-ID:  <201412072308.sB7N87wO084516@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sun Dec  7 23:08:07 2014
New Revision: 275586
URL: https://svnweb.freebsd.org/changeset/base/275586

Log:
  * Retire abstract llentry_free() in favor of lltable_drop_entry_queue()
     and explicit calls to RTENTRY_FREE_LOCKED()
  * Use lltable_prefix_free() in arp_ifscrub to be consistent with nd6.
  * Rename <lltable_|llt>_delete function to _delete_addr() to note that
     this function is used to external callers. Make this function maintain
     its own locking.
  * Use lookup/unlink/clear call chain from internal callers instead of
      delete_addr.
  * Fix LLE_DELETED flag handling

Modified:
  projects/routing/sys/net/if_llatbl.c
  projects/routing/sys/net/if_llatbl.h
  projects/routing/sys/netinet/if_ether.c
  projects/routing/sys/netinet/in.c
  projects/routing/sys/netinet6/in6.c
  projects/routing/sys/netinet6/nd6.c

Modified: projects/routing/sys/net/if_llatbl.c
==============================================================================
--- projects/routing/sys/net/if_llatbl.c	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/net/if_llatbl.c	Sun Dec  7 23:08:07 2014	(r275586)
@@ -189,21 +189,17 @@ llentries_unlink(struct lltable *llt, st
 }
 
 /*
- * Deletes an address from the address table.
- * This function is called by the timer functions
- * such as arptimer() and nd6_llinfo_timer(), and
- * the caller does the locking.
+ * Helper function user to drop all mbufs in hold queue.
  *
  * Returns the number of held packets, if any, that were dropped.
  */
 size_t
-llentry_free(struct llentry *lle)
+lltable_drop_entry_queue(struct llentry *lle)
 {
 	size_t pkts_dropped;
 	struct mbuf *next;
 
 	LLE_WLOCK_ASSERT(lle);
-	KASSERT((lle->la_flags & LLE_LINKED) == 0, ("Freeing linked lle"));
 
 	pkts_dropped = 0;
 	while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
@@ -218,8 +214,6 @@ llentry_free(struct llentry *lle)
 		("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
 		 lle->la_numheld, pkts_dropped));
 
-	LLE_FREE_LOCKED(lle);
-
 	return (pkts_dropped);
 }
 
@@ -522,9 +516,7 @@ lla_rt_output(struct rt_msghdr *rtm, str
 		break;
 
 	case RTM_DELETE:
-		IF_AFDATA_CFG_WLOCK(ifp);
-		error = (llt->llt_delete(llt, 0, dst));
-		IF_AFDATA_CFG_WUNLOCK(ifp);
+		error = lltable_delete_addr(llt, 0, dst);
 		return (error == 0 ? 0 : ENOENT);
 
 	default:

Modified: projects/routing/sys/net/if_llatbl.h
==============================================================================
--- projects/routing/sys/net/if_llatbl.h	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/net/if_llatbl.h	Sun Dec  7 23:08:07 2014	(r275586)
@@ -151,7 +151,7 @@ typedef	struct llentry *(llt_lookup_t)(s
     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,
+typedef	int (llt_delete_addr_t)(struct lltable *, u_int flags,
     const struct sockaddr *l3addr);
 typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
     struct sysctl_req *);
@@ -175,7 +175,7 @@ struct lltable {
 
 	llt_lookup_t		*llt_lookup;
 	llt_create_t		*llt_create;
-	llt_delete_t		*llt_delete;
+	llt_delete_addr_t	*llt_delete_addr;
 	llt_dump_entry_t	*llt_dump_entry;
 	llt_hash_t		*llt_hash;
 	llt_match_prefix_t	*llt_match_prefix;
@@ -219,10 +219,12 @@ void		lltable_drain(int);
 #endif
 int		lltable_sysctl_dumparp(int, struct sysctl_req *);
 
-size_t		llentry_free(struct llentry *);
 struct llentry  *llentry_alloc(struct ifnet *, struct lltable *,
 		    struct sockaddr_storage *);
 
+/* helper functions */
+size_t		lltable_drop_entry_queue(struct llentry *);
+
 /*
  * Generic link layer address lookup function.
  */
@@ -243,11 +245,11 @@ lltable_create_lle(struct lltable *llt, 
 }
 
 static __inline int
-lltable_delete_lle(struct lltable *llt, u_int flags,
+lltable_delete_addr(struct lltable *llt, u_int flags,
     const struct sockaddr *l3addr)
 {
 
-	return llt->llt_delete(llt, flags, l3addr);
+	return llt->llt_delete_addr(llt, flags, l3addr);
 }
 
 static __inline void

Modified: projects/routing/sys/netinet/if_ether.c
==============================================================================
--- projects/routing/sys/netinet/if_ether.c	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/netinet/if_ether.c	Sun Dec  7 23:08:07 2014	(r275586)
@@ -162,16 +162,19 @@ static const struct netisr_handler arp_n
 void
 arp_ifscrub(struct ifnet *ifp, uint32_t addr)
 {
-	struct sockaddr_in addr4;
+	struct sockaddr_in addr4, mask4;
 
 	bzero((void *)&addr4, sizeof(addr4));
 	addr4.sin_len    = sizeof(addr4);
 	addr4.sin_family = AF_INET;
 	addr4.sin_addr.s_addr = addr;
-	IF_AFDATA_CFG_WLOCK(ifp);
-	lltable_delete_lle(LLTABLE(ifp), LLE_IFADDR,
-	    (struct sockaddr *)&addr4);
-	IF_AFDATA_CFG_WUNLOCK(ifp);
+	bzero(&mask4, sizeof(mask4));
+	mask4.sin_len    = sizeof(mask4);
+	mask4.sin_family = AF_INET;
+	mask4.sin_addr.s_addr = INADDR_ANY;
+
+	lltable_prefix_free(AF_INET, (struct sockaddr *)&addr4,
+	    (struct sockaddr *)&mask4, LLE_STATIC);
 }
 #endif
 
@@ -305,9 +308,14 @@ arp_lltable_clear_entry(struct lltable *
 		}
 	}
 
-	/* Finally, free entry */
-	pkts_dropped = llentry_free(lle);
+	lle->la_flags |= LLE_DELETED;
+
+	/* Drop hold queue */
+	pkts_dropped = lltable_drop_entry_queue(lle);
 	ARPSTAT_ADD(dropped, pkts_dropped);
+
+	/* Finally, free entry */
+	LLE_FREE_LOCKED(lle);
 }
 
 /*
@@ -1208,8 +1216,9 @@ arp_update_lle(struct arphdr *ah, struct
 void
 arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
 {
-	struct llentry *lle;
+	struct llentry *lle, *lle_tmp;
 	struct in_addr addr;
+	struct lltable *llt;
 
 	if (ifa->ifa_carp != NULL)
 		return;
@@ -1238,6 +1247,7 @@ arp_ifinit(struct ifnet *ifp, struct ifa
 	}
 
 	IF_AFDATA_CFG_WLOCK(ifp);
+	llt = LLTABLE(ifp);
 
 	/* Lock or new shiny lle */
 	LLE_WLOCK(lle);
@@ -1247,18 +1257,26 @@ arp_ifinit(struct ifnet *ifp, struct ifa
 	 * Instead of dealing with callouts/flags/etc we simply
 	 * delete it and add new one.
 	 */
-	lltable_delete_lle(LLTABLE(ifp), LLE_IFADDR,
+	lle_tmp = lltable_lookup_lle(llt, LLE_EXCLUSIVE,
 	    (struct sockaddr *)IA_SIN(ifa));
 
 	IF_AFDATA_RUN_WLOCK(ifp);
+	if (lle_tmp != NULL)
+		lltable_unlink_entry(llt, lle_tmp);
 	bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
 	lle->la_flags |= (LLE_VALID | LLE_STATIC);
 	lle->r_flags |= RLLE_VALID;
-	lltable_link_entry(LLTABLE(ifp), lle);
+	lltable_link_entry(llt, lle);
 	IF_AFDATA_RUN_WUNLOCK(ifp);
 
 	IF_AFDATA_CFG_WUNLOCK(ifp);
+	/* XXX: eventhandler */
 	LLE_WUNLOCK(lle);
+
+	if (lle_tmp != NULL) {
+		/* XXX: eventhandler */
+		llt->llt_clear_entry(llt, lle_tmp);
+	}
 }
 
 void

Modified: projects/routing/sys/netinet/in.c
==============================================================================
--- projects/routing/sys/netinet/in.c	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/netinet/in.c	Sun Dec  7 23:08:07 2014	(r275586)
@@ -1137,33 +1137,38 @@ in_lltable_delete(struct lltable *llt, u
 	struct ifnet *ifp = llt->llt_ifp;
 	struct llentry *lle;
 
-	IF_AFDATA_CFG_WLOCK_ASSERT(ifp);
+	IF_AFDATA_CFG_UNLOCK_ASSERT(ifp);
 	KASSERT(l3addr->sa_family == AF_INET,
 	    ("sin_family %d", l3addr->sa_family));
 
+	IF_AFDATA_CFG_WLOCK(ifp);
 	lle = in_lltable_find_dst(llt, sin->sin_addr);
 	if (lle == NULL) {
+		IF_AFDATA_CFG_WUNLOCK(ifp);
 #ifdef DIAGNOSTIC
-		log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);
+		log(LOG_INFO, "interface address is missing from cache = %p\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);
-		IF_AFDATA_RUN_WLOCK(ifp);
-		lltable_unlink_entry(llt, lle);
-		IF_AFDATA_RUN_WUNLOCK(ifp);
+	/* Skipping LLE_IFADDR record */
+	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
+		IF_AFDATA_CFG_WUNLOCK(ifp);
+		return (0);
+	}
+
+	LLE_WLOCK(lle);
+	IF_AFDATA_RUN_WLOCK(ifp);
+	lltable_unlink_entry(llt, lle);
+	IF_AFDATA_RUN_WUNLOCK(ifp);
+	IF_AFDATA_CFG_WUNLOCK(ifp);
+
+	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);
-	}
+	llt->llt_clear_entry(llt, lle);
 
 	return (0);
 }
@@ -1304,7 +1309,7 @@ in_domifattach(struct ifnet *ifp)
 
 	llt->llt_lookup = in_lltable_lookup;
 	llt->llt_create = in_lltable_create;
-	llt->llt_delete = in_lltable_delete;
+	llt->llt_delete_addr = in_lltable_delete;
 	llt->llt_dump_entry = in_lltable_dump_entry;
 	llt->llt_hash = in_lltable_hash;
 	llt->llt_clear_entry = arp_lltable_clear_entry;

Modified: projects/routing/sys/netinet6/in6.c
==============================================================================
--- projects/routing/sys/netinet6/in6.c	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/netinet6/in6.c	Sun Dec  7 23:08:07 2014	(r275586)
@@ -2173,31 +2173,40 @@ in6_lltable_delete(struct lltable *llt, 
 	const struct sockaddr *l3addr)
 {
 	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
+	struct ifnet *ifp;
 	struct llentry *lle;
 
-	IF_AFDATA_CFG_WLOCK_ASSERT(llt->llt_ifp);
+	ifp = llt->llt_ifp;
+
+	IF_AFDATA_CFG_UNLOCK_ASSERT(ifp);
 	KASSERT(l3addr->sa_family == AF_INET6,
 	    ("sin_family %d", l3addr->sa_family));
 
+	IF_AFDATA_CFG_WLOCK(ifp);
 	lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
 
-	if (lle == NULL)
+	if (lle == NULL) {
+		IF_AFDATA_CFG_WUNLOCK(ifp);
 		return (ENOENT);
+	}
+
+	/* Skipping LLE_IFADDR record */
+	if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
+		IF_AFDATA_CFG_WUNLOCK(ifp);
+		return (0);
+	}
+
+	LLE_WLOCK(lle);
+	IF_AFDATA_RUN_WLOCK(ifp);
+	lltable_unlink_entry(llt, lle);
+	IF_AFDATA_RUN_WUNLOCK(ifp);
+	IF_AFDATA_CFG_WUNLOCK(ifp);
 
-	if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-		LLE_WLOCK(lle);
-		lle->la_flags |= LLE_DELETED;
-		IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
-		lltable_unlink_entry(llt, lle);
-		IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
 #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);
-	}
+	EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+	llt->llt_clear_entry(llt, lle);
 	
 	return (0);
 }
@@ -2365,7 +2374,7 @@ in6_domifattach(struct ifnet *ifp)
 
 	llt->llt_lookup = in6_lltable_lookup;
 	llt->llt_create = in6_lltable_create;
-	llt->llt_delete = in6_lltable_delete;
+	llt->llt_delete_addr = in6_lltable_delete;
 	llt->llt_dump_entry = in6_lltable_dump_entry;
 	llt->llt_hash = in6_lltable_hash;
 	llt->llt_clear_entry = nd6_lltable_clear_entry;

Modified: projects/routing/sys/netinet6/nd6.c
==============================================================================
--- projects/routing/sys/netinet6/nd6.c	Sun Dec  7 22:30:54 2014	(r275585)
+++ projects/routing/sys/netinet6/nd6.c	Sun Dec  7 23:08:07 2014	(r275586)
@@ -1081,7 +1081,7 @@ nd6_free(struct llentry *ln, int gc)
 	if ((ln->la_flags & LLE_DELETED) != 0) {
 		/* Unlinked entry. Stop timer/callout. */
 		nd6_llinfo_settimer_locked(ln, -1);
-		llentry_free(ln);
+		LLE_FREE_LOCKED(ln);
 		return;
 	}
 
@@ -1132,8 +1132,13 @@ nd6_lltable_clear_entry(struct lltable *
 	/* Check if default router needs to be recalculated */
 	nd6_check_recalc_defrtr(llt, ln);
 
+	/* Drop hold queue */
+	lltable_drop_entry_queue(ln);
+
+	ln->la_flags |= LLE_DELETED;
+
 	/* Finally, free entry */
-	llentry_free(ln);
+	LLE_FREE_LOCKED(ln);
 }
 
 /*
@@ -2460,7 +2465,8 @@ int
 nd6_add_ifa_lle(struct in6_ifaddr *ia)
 {
 	struct ifnet *ifp;
-	struct llentry *ln;
+	struct llentry *ln, *ln_tmp;
+	struct lltable *llt;
 
 	ifp = ia->ia_ifa.ifa_ifp;
 	ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
@@ -2476,20 +2482,36 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
 	ln->ln_state = ND6_LLINFO_REACHABLE;
 
 	IF_AFDATA_CFG_WLOCK(ifp);
+	llt = LLTABLE6(ifp);
 	/* Lock or new shiny lle */
 	LLE_WLOCK(ln);
 
-	lltable_delete_lle(LLTABLE6(ifp), LLE_IFADDR,
+	/*
+	 * Check if we already have some corresponding entry.
+	 * Instead of dealing with callouts/flags/etc we simply
+	 * delete it and add new one.
+	 */
+	ln_tmp = lltable_lookup_lle(llt, LLE_EXCLUSIVE,
 	    (struct sockaddr *)&ia->ia_addr);
 
 	bcopy(IF_LLADDR(ifp), &ln->ll_addr, ifp->if_addrlen);
 	/* Finally, link our lle to the list */
 	IF_AFDATA_RUN_WLOCK(ifp);
-	lltable_link_entry(LLTABLE6(ifp), ln);
+	if (ln_tmp != NULL)
+		lltable_unlink_entry(llt, ln_tmp);
+	lltable_link_entry(llt, ln);
 	IF_AFDATA_RUN_WUNLOCK(ifp);
 	IF_AFDATA_CFG_WUNLOCK(ifp);
 
+	/* XXX: event handler? */
 	LLE_WUNLOCK(ln);
+
+	if (ln_tmp != NULL) {
+		/* XXX: event handler ? */
+		llt->llt_clear_entry(llt, ln_tmp);
+	}
+
+
 	in6_newaddrmsg(ia, RTM_ADD);
 	return (0);
 }



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