* Do more fine-grained locking: call eventhandlers/free_entry
without holding afdata wlock * convert per-af delete_address callback to global lltable_delete_entry() and more low-level "delete this lle" per-af callback * fix some bugs/inconsistencies in IPv4/IPv6 ifscrub procedures Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D3573
This commit is contained in:
parent
d051ac804a
commit
3e7a2321e3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=287789
@ -186,7 +186,7 @@ htable_unlink_entry(struct llentry *lle)
|
||||
}
|
||||
|
||||
struct prefix_match_data {
|
||||
const struct sockaddr *prefix;
|
||||
const struct sockaddr *addr;
|
||||
const struct sockaddr *mask;
|
||||
struct llentries dchain;
|
||||
u_int flags;
|
||||
@ -199,7 +199,7 @@ htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
|
||||
|
||||
pmd = (struct prefix_match_data *)farg;
|
||||
|
||||
if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
|
||||
if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
|
||||
LLE_WLOCK(lle);
|
||||
LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
|
||||
}
|
||||
@ -208,14 +208,14 @@ htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
|
||||
}
|
||||
|
||||
static void
|
||||
htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
|
||||
htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
|
||||
const struct sockaddr *mask, u_int flags)
|
||||
{
|
||||
struct llentry *lle, *next;
|
||||
struct prefix_match_data pmd;
|
||||
|
||||
bzero(&pmd, sizeof(pmd));
|
||||
pmd.prefix = prefix;
|
||||
pmd.addr = addr;
|
||||
pmd.mask = mask;
|
||||
pmd.flags = flags;
|
||||
LIST_INIT(&pmd.dchain);
|
||||
@ -427,8 +427,42 @@ lltable_drain(int af)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Deletes an address from given lltable.
|
||||
* Used for userland interaction to remove
|
||||
* individual entries. Skips entries added by OS.
|
||||
*/
|
||||
int
|
||||
lltable_delete_addr(struct lltable *llt, u_int flags,
|
||||
const struct sockaddr *l3addr)
|
||||
{
|
||||
struct llentry *lle;
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = llt->llt_ifp;
|
||||
IF_AFDATA_WLOCK(ifp);
|
||||
lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
|
||||
|
||||
if (lle == NULL) {
|
||||
IF_AFDATA_WUNLOCK(ifp);
|
||||
return (ENOENT);
|
||||
}
|
||||
if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
|
||||
IF_AFDATA_WUNLOCK(ifp);
|
||||
LLE_WUNLOCK(lle);
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
lltable_unlink_entry(llt, lle);
|
||||
IF_AFDATA_WUNLOCK(ifp);
|
||||
|
||||
llt->llt_delete_entry(llt, lle);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
|
||||
lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
|
||||
u_int flags)
|
||||
{
|
||||
struct lltable *llt;
|
||||
@ -438,7 +472,7 @@ lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
|
||||
if (llt->llt_af != af)
|
||||
continue;
|
||||
|
||||
llt->llt_prefix_free(llt, prefix, mask, flags);
|
||||
llt->llt_prefix_free(llt, addr, mask, flags);
|
||||
}
|
||||
LLTABLE_RUNLOCK();
|
||||
}
|
||||
@ -651,10 +685,7 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
|
||||
break;
|
||||
|
||||
case RTM_DELETE:
|
||||
IF_AFDATA_WLOCK(ifp);
|
||||
error = lla_delete(llt, 0, dst);
|
||||
IF_AFDATA_WUNLOCK(ifp);
|
||||
return (error == 0 ? 0 : ENOENT);
|
||||
return (lltable_delete_addr(llt, 0, dst));
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
|
@ -135,10 +135,9 @@ typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags,
|
||||
const struct sockaddr *l3addr);
|
||||
typedef struct llentry *(llt_alloc_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_delete_t)(struct lltable *, struct llentry *);
|
||||
typedef void (llt_prefix_free_t)(struct lltable *,
|
||||
const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
|
||||
const struct sockaddr *addr, const struct sockaddr *mask, u_int flags);
|
||||
typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
|
||||
struct sysctl_req *);
|
||||
typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t);
|
||||
@ -162,7 +161,7 @@ struct lltable {
|
||||
|
||||
llt_lookup_t *llt_lookup;
|
||||
llt_alloc_t *llt_alloc_entry;
|
||||
llt_delete_t *llt_delete;
|
||||
llt_delete_t *llt_delete_entry;
|
||||
llt_prefix_free_t *llt_prefix_free;
|
||||
llt_dump_entry_t *llt_dump_entry;
|
||||
llt_hash_t *llt_hash;
|
||||
@ -212,6 +211,8 @@ size_t lltable_drop_entry_queue(struct llentry *);
|
||||
struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
|
||||
const struct sockaddr *l4addr);
|
||||
void lltable_free_entry(struct lltable *llt, struct llentry *lle);
|
||||
int lltable_delete_addr(struct lltable *llt, u_int flags,
|
||||
const struct sockaddr *l3addr);
|
||||
void lltable_link_entry(struct lltable *llt, struct llentry *lle);
|
||||
void lltable_unlink_entry(struct lltable *llt, struct llentry *lle);
|
||||
void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa);
|
||||
@ -230,14 +231,6 @@ lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
|
||||
return (llt->llt_lookup(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>
|
||||
|
@ -140,26 +140,6 @@ static const struct netisr_handler arp_nh = {
|
||||
.nh_policy = NETISR_POLICY_SOURCE,
|
||||
};
|
||||
|
||||
#ifdef AF_INET
|
||||
/*
|
||||
* called by in_scrubprefix() to remove entry from the table when
|
||||
* the interface goes away
|
||||
*/
|
||||
void
|
||||
arp_ifscrub(struct ifnet *ifp, uint32_t addr)
|
||||
{
|
||||
struct sockaddr_in addr4;
|
||||
|
||||
bzero((void *)&addr4, sizeof(addr4));
|
||||
addr4.sin_len = sizeof(addr4);
|
||||
addr4.sin_family = AF_INET;
|
||||
addr4.sin_addr.s_addr = addr;
|
||||
IF_AFDATA_WLOCK(ifp);
|
||||
lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
|
||||
IF_AFDATA_WUNLOCK(ifp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Timeout routine. Age arp_tab entries periodically.
|
||||
*/
|
||||
|
@ -120,7 +120,6 @@ void arprequest(struct ifnet *, const struct in_addr *,
|
||||
const struct in_addr *, u_char *);
|
||||
void arp_ifinit(struct ifnet *, struct ifaddr *);
|
||||
void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
|
||||
void arp_ifscrub(struct ifnet *, uint32_t);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
129
sys/netinet/in.c
129
sys/netinet/in.c
@ -723,6 +723,38 @@ in_addprefix(struct in_ifaddr *target, int flags)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes either all lle entries for given @ia, or lle
|
||||
* corresponding to @ia address.
|
||||
*/
|
||||
static void
|
||||
in_scrubprefixlle(struct in_ifaddr *ia, int all, u_int flags)
|
||||
{
|
||||
struct sockaddr_in addr, mask;
|
||||
struct sockaddr *saddr, *smask;
|
||||
struct ifnet *ifp;
|
||||
|
||||
/*
|
||||
* remove all L2 entries on the given prefix
|
||||
*/
|
||||
saddr = (struct sockaddr *)&addr;
|
||||
bzero(&addr, sizeof(addr));
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = ntohl(ia->ia_addr.sin_addr.s_addr);
|
||||
smask = (struct sockaddr *)&mask;
|
||||
bzero(&mask, sizeof(mask));
|
||||
mask.sin_len = sizeof(mask);
|
||||
mask.sin_family = AF_INET;
|
||||
mask.sin_addr.s_addr = ia->ia_subnetmask;
|
||||
ifp = ia->ia_ifp;
|
||||
|
||||
if (all)
|
||||
lltable_prefix_free(AF_INET, saddr, smask, flags);
|
||||
else
|
||||
lltable_delete_addr(LLTABLE(ifp), LLE_IFADDR, saddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no other address in the system that can serve a route to the
|
||||
* same prefix, remove the route. Hand over the route to the new address
|
||||
@ -735,7 +767,6 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
|
||||
struct in_ifaddr *ia;
|
||||
struct in_addr prefix, mask, p, m;
|
||||
int error = 0;
|
||||
struct sockaddr_in prefix0, mask0;
|
||||
|
||||
/*
|
||||
* Remove the loopback route to the interface address.
|
||||
@ -757,11 +788,6 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
|
||||
error = ifa_del_loopback_route((struct ifaddr *)target,
|
||||
(struct sockaddr *)&target->ia_addr);
|
||||
}
|
||||
|
||||
if (!(target->ia_ifp->if_flags & IFF_NOARP))
|
||||
/* remove arp cache */
|
||||
arp_ifscrub(target->ia_ifp,
|
||||
IA_SIN(target)->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
if (rtinitflags(target)) {
|
||||
@ -817,6 +843,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
|
||||
else
|
||||
log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n",
|
||||
error);
|
||||
/* Scrub all entries IFF interface is different */
|
||||
in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp,
|
||||
flags);
|
||||
error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
|
||||
rtinitflags(ia) | RTF_UP);
|
||||
if (error == 0)
|
||||
@ -833,16 +862,7 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
|
||||
/*
|
||||
* 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, flags);
|
||||
in_scrubprefixlle(target, 1, flags);
|
||||
|
||||
/*
|
||||
* As no-one seem to have this prefix, we can remove the route.
|
||||
@ -1001,22 +1021,38 @@ in_lltable_new(struct in_addr addr4, u_int flags)
|
||||
return (&lle->base);
|
||||
}
|
||||
|
||||
#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
|
||||
(((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
|
||||
#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
|
||||
((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 )
|
||||
|
||||
static int
|
||||
in_lltable_match_prefix(const struct sockaddr *prefix,
|
||||
const struct sockaddr *mask, u_int flags, struct llentry *lle)
|
||||
in_lltable_match_prefix(const struct sockaddr *saddr,
|
||||
const struct sockaddr *smask, u_int flags, struct llentry *lle)
|
||||
{
|
||||
const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
|
||||
const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
|
||||
struct in_addr addr, mask, lle_addr;
|
||||
|
||||
/*
|
||||
* (flags & LLE_STATIC) means deleting all entries
|
||||
* including static ARP entries.
|
||||
*/
|
||||
if (IN_ARE_MASKED_ADDR_EQUAL(lle->r_l3addr.addr4, pfx, msk) &&
|
||||
((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
|
||||
addr = ((const struct sockaddr_in *)saddr)->sin_addr;
|
||||
mask = ((const struct sockaddr_in *)smask)->sin_addr;
|
||||
lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr);
|
||||
|
||||
if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
|
||||
return (0);
|
||||
|
||||
if (lle->la_flags & LLE_IFADDR) {
|
||||
|
||||
/*
|
||||
* Delete LLE_IFADDR records IFF address & flag matches.
|
||||
* Note that addr is the interface address within prefix
|
||||
* being matched.
|
||||
* Note also we should handle 'ifdown' cases without removing
|
||||
* ifaddr macs.
|
||||
*/
|
||||
if (addr.s_addr == lle_addr.s_addr && (flags & LLE_STATIC) != 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* flags & LLE_STATIC means deleting both dynamic and static entries */
|
||||
if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
@ -1166,39 +1202,16 @@ in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
|
||||
return (lle);
|
||||
}
|
||||
|
||||
static int
|
||||
in_lltable_delete(struct lltable *llt, u_int flags,
|
||||
const struct sockaddr *l3addr)
|
||||
static void
|
||||
in_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
|
||||
{
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
|
||||
struct llentry *lle;
|
||||
|
||||
IF_AFDATA_WLOCK_ASSERT(llt->llt_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->la_flags |= LLE_DELETED;
|
||||
EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
|
||||
#ifdef DIAGNOSTIC
|
||||
log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle);
|
||||
log(LOG_INFO, "ifaddr cache = %p is deleted\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);
|
||||
llentry_free(lle);
|
||||
}
|
||||
|
||||
static struct llentry *
|
||||
@ -1334,7 +1347,7 @@ in_lltattach(struct ifnet *ifp)
|
||||
|
||||
llt->llt_lookup = in_lltable_lookup;
|
||||
llt->llt_alloc_entry = in_lltable_alloc;
|
||||
llt->llt_delete = in_lltable_delete;
|
||||
llt->llt_delete_entry = in_lltable_delete_entry;
|
||||
llt->llt_dump_entry = in_lltable_dump_entry;
|
||||
llt->llt_hash = in_lltable_hash;
|
||||
llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
|
||||
|
@ -985,7 +985,7 @@ carp_ifa_delroute(struct ifaddr *ifa)
|
||||
case AF_INET6:
|
||||
ifa_del_loopback_route(ifa,
|
||||
(struct sockaddr *)&ifatoia6(ifa)->ia_addr);
|
||||
nd6_rem_ifa_lle(ifatoia6(ifa));
|
||||
nd6_rem_ifa_lle(ifatoia6(ifa), 1);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -1307,9 +1307,6 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
/* stop DAD processing */
|
||||
nd6_dad_stop(ifa);
|
||||
|
||||
/* Remove local address entry from lltable. */
|
||||
nd6_rem_ifa_lle(ia);
|
||||
|
||||
/* Leave multicast groups. */
|
||||
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
|
||||
LIST_REMOVE(imm, i6mm_chain);
|
||||
@ -1333,6 +1330,7 @@ static void
|
||||
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
{
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
int remove_lle;
|
||||
|
||||
IF_ADDR_WLOCK(ifp);
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
|
||||
@ -1353,15 +1351,21 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
* Release the reference to the base prefix. There should be a
|
||||
* positive reference.
|
||||
*/
|
||||
remove_lle = 0;
|
||||
if (ia->ia6_ndpr == NULL) {
|
||||
nd6log((LOG_NOTICE,
|
||||
"in6_unlink_ifa: autoconf'ed address "
|
||||
"%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia))));
|
||||
} else {
|
||||
ia->ia6_ndpr->ndpr_refcnt--;
|
||||
/* Do not delete lles within prefix if refcont != 0 */
|
||||
if (ia->ia6_ndpr->ndpr_refcnt == 0)
|
||||
remove_lle = 1;
|
||||
ia->ia6_ndpr = NULL;
|
||||
}
|
||||
|
||||
nd6_rem_ifa_lle(ia, remove_lle);
|
||||
|
||||
/*
|
||||
* Also, if the address being removed is autoconf'ed, call
|
||||
* pfxlist_onlink_check() since the release might affect the status of
|
||||
@ -2081,15 +2085,33 @@ in6_lltable_new(const struct in6_addr *addr6, u_int flags)
|
||||
}
|
||||
|
||||
static int
|
||||
in6_lltable_match_prefix(const struct sockaddr *prefix,
|
||||
const struct sockaddr *mask, u_int flags, struct llentry *lle)
|
||||
in6_lltable_match_prefix(const struct sockaddr *saddr,
|
||||
const struct sockaddr *smask, u_int flags, struct llentry *lle)
|
||||
{
|
||||
const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
|
||||
const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
|
||||
const struct in6_addr *addr, *mask, *lle_addr;
|
||||
|
||||
if (IN6_ARE_MASKED_ADDR_EQUAL(&lle->r_l3addr.addr6,
|
||||
&pfx->sin6_addr, &msk->sin6_addr) &&
|
||||
((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
|
||||
addr = &((const struct sockaddr_in6 *)saddr)->sin6_addr;
|
||||
mask = &((const struct sockaddr_in6 *)smask)->sin6_addr;
|
||||
lle_addr = &lle->r_l3addr.addr6;
|
||||
|
||||
if (IN6_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
|
||||
return (0);
|
||||
|
||||
if (lle->la_flags & LLE_IFADDR) {
|
||||
|
||||
/*
|
||||
* Delete LLE_IFADDR records IFF address & flag matches.
|
||||
* Note that addr is the interface address within prefix
|
||||
* being matched.
|
||||
*/
|
||||
if (IN6_ARE_ADDR_EQUAL(addr, lle_addr) &&
|
||||
(flags & LLE_STATIC) != 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* flags & LLE_STATIC means deleting both dynamic and static entries */
|
||||
if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
@ -2200,36 +2222,16 @@ in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
|
||||
return (lle);
|
||||
}
|
||||
|
||||
static int
|
||||
in6_lltable_delete(struct lltable *llt, u_int flags,
|
||||
const struct sockaddr *l3addr)
|
||||
static void
|
||||
in6_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
|
||||
struct llentry *lle;
|
||||
|
||||
IF_AFDATA_LOCK_ASSERT(llt->llt_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);
|
||||
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);
|
||||
}
|
||||
|
||||
return (0);
|
||||
llentry_free(lle);
|
||||
}
|
||||
|
||||
static struct llentry *
|
||||
@ -2369,7 +2371,7 @@ in6_lltattach(struct ifnet *ifp)
|
||||
|
||||
llt->llt_lookup = in6_lltable_lookup;
|
||||
llt->llt_alloc_entry = in6_lltable_alloc;
|
||||
llt->llt_delete = in6_lltable_delete;
|
||||
llt->llt_delete_entry = in6_lltable_delete_entry;
|
||||
llt->llt_dump_entry = in6_lltable_dump_entry;
|
||||
llt->llt_hash = in6_lltable_hash;
|
||||
llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry;
|
||||
|
@ -2245,23 +2245,26 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes ALL lle records for interface address prefix.
|
||||
* XXXME: That's probably not we really want to do, we need
|
||||
* to remove address record only and keep other records
|
||||
* until we determine if given prefix is really going
|
||||
* to be removed.
|
||||
* Removes either all lle entries for given @ia, or lle
|
||||
* corresponding to @ia address.
|
||||
*/
|
||||
void
|
||||
nd6_rem_ifa_lle(struct in6_ifaddr *ia)
|
||||
nd6_rem_ifa_lle(struct in6_ifaddr *ia, int all)
|
||||
{
|
||||
struct sockaddr_in6 mask, addr;
|
||||
struct sockaddr *saddr, *smask;
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = ia->ia_ifa.ifa_ifp;
|
||||
memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
|
||||
memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
|
||||
lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
|
||||
(struct sockaddr *)&mask, LLE_STATIC);
|
||||
saddr = (struct sockaddr *)&addr;
|
||||
smask = (struct sockaddr *)&mask;
|
||||
|
||||
if (all != 0)
|
||||
lltable_prefix_free(AF_INET6, saddr, smask, LLE_STATIC);
|
||||
else
|
||||
lltable_delete_addr(LLTABLE6(ifp), LLE_IFADDR, saddr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -427,7 +427,7 @@ int nd6_flush_holdchain(struct ifnet *, struct ifnet *, struct mbuf *,
|
||||
struct sockaddr_in6 *);
|
||||
int nd6_need_cache(struct ifnet *);
|
||||
int nd6_add_ifa_lle(struct in6_ifaddr *);
|
||||
void nd6_rem_ifa_lle(struct in6_ifaddr *);
|
||||
void nd6_rem_ifa_lle(struct in6_ifaddr *, int);
|
||||
int nd6_storelladdr(struct ifnet *, struct mbuf *,
|
||||
const struct sockaddr *, u_char *, uint32_t *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user