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
This commit is contained in:
Qing Li 2009-05-20 21:07:15 +00:00
parent f6ac50113f
commit c9d763bf41
4 changed files with 91 additions and 0 deletions

View File

@ -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.
*/

View File

@ -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 *);

View File

@ -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;
@ -1081,6 +1082,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.
*/
@ -1232,6 +1247,34 @@ in_lltable_free(struct lltable *llt, struct llentry *lle)
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;

View File

@ -2284,6 +2284,30 @@ in6_lltable_free(struct lltable *llt, struct llentry *lle)
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;