From owner-svn-src-head@FreeBSD.ORG Wed May 20 21:07:15 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CC4A2106564A; Wed, 20 May 2009 21:07:15 +0000 (UTC) (envelope-from qingli@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id BA6508FC1F; Wed, 20 May 2009 21:07:15 +0000 (UTC) (envelope-from qingli@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n4KL7F7o043765; Wed, 20 May 2009 21:07:15 GMT (envelope-from qingli@svn.freebsd.org) Received: (from qingli@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4KL7FEp043761; Wed, 20 May 2009 21:07:15 GMT (envelope-from qingli@svn.freebsd.org) Message-Id: <200905202107.n4KL7FEp043761@svn.freebsd.org> From: Qing Li Date: Wed, 20 May 2009 21:07:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r192476 - in head/sys: net netinet netinet6 X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 May 2009 21:07:16 -0000 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;