Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 May 2009 21:07:15 +0000 (UTC)
From:      Qing Li <qingli@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r192476 - in head/sys: net netinet netinet6
Message-ID:  <200905202107.n4KL7FEp043761@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: qingli
Date: Wed May 20 21:07:15 2009
New Revision: 192476
URL: http://svn.freebsd.org/changeset/base/192476

Log:
  When an interface address is removed and the last prefix
  route is also being deleted, the link-layer address table
  (arp or nd6) will flush those L2 llinfo entries that match
  the removed prefix.
  
  Reviewed by:	kmacy

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

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c	Wed May 20 21:04:41 2009	(r192475)
+++ head/sys/net/if_llatbl.c	Wed May 20 21:07:15 2009	(r192476)
@@ -195,6 +195,23 @@ lltable_drain(int af)
 	IFNET_RUNLOCK();
 }
 
+void
+lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask)
+{
+	struct lltable *llt;
+
+	IFNET_RLOCK();
+	SLIST_FOREACH(llt, &lltables, llt_link) {
+		if (llt->llt_af != af)
+			continue;
+
+		llt->llt_prefix_free(llt, prefix, mask);
+	}
+	IFNET_RUNLOCK();
+}
+
+
+
 /*
  * Create a new lltable.
  */

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h	Wed May 20 21:04:41 2009	(r192475)
+++ head/sys/net/if_llatbl.h	Wed May 20 21:07:15 2009	(r192476)
@@ -147,6 +147,9 @@ struct lltable {
 
 	struct llentry *	(*llt_new)(const struct sockaddr *, u_int);
 	void			(*llt_free)(struct lltable *, struct llentry *);
+	void			(*llt_prefix_free)(struct lltable *,
+				    const struct sockaddr *prefix,
+				    const struct sockaddr *mask);
 	struct llentry *	(*llt_lookup)(struct lltable *, u_int flags,
 				    const struct sockaddr *l3addr);
 	int			(*llt_rtcheck)(struct ifnet *,
@@ -174,6 +177,8 @@ MALLOC_DECLARE(M_LLTABLE);
 
 struct lltable *lltable_init(struct ifnet *, int);
 void		lltable_free(struct lltable *);
+void		lltable_prefix_free(int, struct sockaddr *, 
+                       struct sockaddr *);
 void		lltable_drain(int);
 int		lltable_sysctl_dumparp(int, struct sysctl_req *);
 

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Wed May 20 21:04:41 2009	(r192475)
+++ head/sys/netinet/in.c	Wed May 20 21:07:15 2009	(r192476)
@@ -1013,6 +1013,7 @@ in_scrubprefix(struct in_ifaddr *target)
 	struct in_ifaddr *ia;
 	struct in_addr prefix, mask, p;
 	int error;
+	struct sockaddr_in prefix0, mask0;
 	struct rt_addrinfo info;
 	struct sockaddr_dl null_sdl;
 
@@ -1082,6 +1083,20 @@ 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);
+
+	/*
 	 * As no-one seem to have this prefix, we can remove the route.
 	 */
 	rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
@@ -1232,6 +1247,34 @@ in_lltable_free(struct lltable *llt, str
 	free(lle, M_LLTABLE);
 }
 
+
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)	(			\
+	    (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
+
+static void
+in_lltable_prefix_free(struct lltable *llt, 
+		       const struct sockaddr *prefix,
+		       const struct sockaddr *mask)
+{
+	const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
+	const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+	struct llentry *lle, *next;
+	register int i;
+
+	for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+
+			if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in *)L3_ADDR(lle), 
+						     pfx, msk)) {
+				callout_drain(&lle->la_timer);
+				LLE_WLOCK(lle);
+				llentry_free(lle);
+			}
+		}
+	}
+}
+
+
 static int
 in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
 {
@@ -1422,6 +1465,7 @@ in_domifattach(struct ifnet *ifp)
 	if (llt != NULL) {
 		llt->llt_new = in_lltable_new;
 		llt->llt_free = in_lltable_free;
+		llt->llt_prefix_free = in_lltable_prefix_free;
 		llt->llt_rtcheck = in_lltable_rtcheck;
 		llt->llt_lookup = in_lltable_lookup;
 		llt->llt_dump = in_lltable_dump;

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Wed May 20 21:04:41 2009	(r192475)
+++ head/sys/netinet6/in6.c	Wed May 20 21:07:15 2009	(r192476)
@@ -2284,6 +2284,30 @@ in6_lltable_free(struct lltable *llt, st
 	free(lle, M_LLTABLE);
 }
 
+static void
+in6_lltable_prefix_free(struct lltable *llt, 
+			const struct sockaddr *prefix,
+			const struct sockaddr *mask)
+{
+	const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
+	const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
+	struct llentry *lle, *next;
+	register int i;
+
+	for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+			if (IN6_ARE_MASKED_ADDR_EQUAL(
+				    &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr, 
+				    &pfx->sin6_addr, 
+				    &msk->sin6_addr)) {
+				callout_drain(&lle->la_timer);
+				LLE_WLOCK(lle);
+				llentry_free(lle);
+			}
+		}
+	}
+}
+
 static int
 in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
 {
@@ -2490,6 +2514,7 @@ in6_domifattach(struct ifnet *ifp)
 	if (ext->lltable != NULL) {
 		ext->lltable->llt_new = in6_lltable_new;
 		ext->lltable->llt_free = in6_lltable_free;
+		ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
 		ext->lltable->llt_rtcheck = in6_lltable_rtcheck;
 		ext->lltable->llt_lookup = in6_lltable_lookup;
 		ext->lltable->llt_dump = in6_lltable_dump;



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