Do not enforce particular lle storage scheme:

* move lltable allocation to per-domain callbacks.
* make llentry_link/unlink functions overridable llt methods.
* make hash table traversal another overridable llt method.
This commit is contained in:
Alexander V. Chernikov 2014-12-07 17:32:06 +00:00
parent a743ccd468
commit 721cd2e032
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/routing/; revision=275578
7 changed files with 193 additions and 89 deletions

View File

@ -71,14 +71,46 @@ static void vnet_lltable_init(void);
struct rwlock lltable_rwlock;
RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
static void lltable_unlink(struct lltable *llt);
static void llentries_unlink(struct lltable *llt, struct llentries *head);
/* Default lltable methods */
static void llentry_link(struct lltable *llt, struct llentry *lle);
static void llentry_unlink(struct llentry *lle);
static int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
void *farg);
static void lltable_free_tbl(struct lltable *llt);
/*
* Runs specified callback for each entry in @llt.
* Called does the locking.
*
*/
static int
lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
{
struct llentry *lle, *next;
int i, error;
error = 0;
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
error = f(llt, lle, farg);
if (error != 0)
break;
}
}
return (error);
}
/*
* Dump lle state for a specific address family.
*/
static int
lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
{
struct llentry *lle;
int i, error;
int error;
LLTABLE_LOCK_ASSERT();
@ -87,13 +119,8 @@ lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
error = 0;
IF_AFDATA_CFG_RLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
error = llt->llt_dump_entry(llt, lle, wr);
if (error != 0)
break;
}
}
error = lltable_foreach_lle(llt,
(llt_foreach_cb_t *)llt->llt_dump_entry, wr);
IF_AFDATA_CFG_RUNLOCK(llt->llt_ifp);
return (error);
@ -119,7 +146,7 @@ lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
}
void
static void
llentry_link(struct lltable *llt, struct llentry *lle)
{
struct llentries *lleh;
@ -139,7 +166,7 @@ llentry_link(struct lltable *llt, struct llentry *lle)
LIST_INSERT_HEAD(lleh, lle, lle_next);
}
void
static void
llentry_unlink(struct llentry *lle)
{
@ -152,14 +179,13 @@ llentry_unlink(struct llentry *lle)
}
}
void
llentries_unlink(struct llentries *head)
static void
llentries_unlink(struct lltable *llt, struct llentries *head)
{
struct llentry *lle, *next;
LIST_FOREACH_SAFE(lle, head, lle_chain, next) {
llentry_unlink(lle);
}
LIST_FOREACH_SAFE(lle, head, lle_chain, next)
llt->llt_unlink_entry(lle);
}
/*
@ -236,36 +262,73 @@ llentry_alloc(struct ifnet *ifp, struct lltable *lt,
/*
* Free all entries from given table and free itself.
*/
static int
lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
{
struct llentries *dchain;
dchain = (struct llentries *)farg;
LLE_WLOCK(lle);
LIST_INSERT_HEAD(dchain, lle, lle_chain);
return (0);
}
static void
lltable_free_tbl(struct lltable *llt)
{
free(llt, M_LLTABLE);
}
void
lltable_free(struct lltable *llt)
{
struct llentry *lle, *next;
struct llentries dchain;
int i;
KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
LLTABLE_WLOCK();
SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
LLTABLE_WUNLOCK();
lltable_unlink(llt);
LIST_INIT(&dchain);
IF_AFDATA_CFG_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
LLE_WLOCK(lle);
LIST_INSERT_HEAD(&dchain, lle, lle_chain);
}
}
/* Push all lles to @dchain */
lltable_foreach_lle(llt, lltable_free_cb, &dchain);
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentries_unlink(&dchain);
llentries_unlink(llt, &dchain);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WUNLOCK(llt->llt_ifp);
LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next)
llt->llt_clear_entry(llt, lle);
free(llt, M_LLTABLE);
llt->llt_free_tbl(llt);
}
struct prefix_match_data {
const struct sockaddr *prefix;
const struct sockaddr *mask;
struct llentries *dchain;
u_int flags;
};
static int
lltable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
{
struct prefix_match_data *pmd;
pmd = (struct prefix_match_data *)farg;
if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
LLE_WLOCK(lle);
LIST_INSERT_HEAD(pmd->dchain, lle, lle_chain);
}
return (0);
}
static void
@ -274,20 +337,21 @@ lltable_prefix_free_af(struct lltable *llt, const struct sockaddr *prefix,
{
struct llentries dchain;
struct llentry *lle, *next;
int i;
struct prefix_match_data pmd;
LIST_INIT(&dchain);
memset(&pmd, 0, sizeof(pmd));
pmd.prefix = prefix;
pmd.mask = mask;
pmd.flags = flags;
pmd.dchain = &dchain;
IF_AFDATA_CFG_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
if (llt->llt_match_prefix(prefix, mask, flags, lle)) {
LLE_WLOCK(lle);
LIST_INSERT_HEAD(&dchain, lle, lle_chain);
}
}
}
/* Push matching lles to chain */
lltable_foreach_lle(llt, lltable_prefix_free_cb, &pmd);
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentries_unlink(&dchain);
llentries_unlink(llt, &dchain);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WUNLOCK(llt->llt_ifp);
@ -339,29 +403,36 @@ lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
LLTABLE_RUNLOCK();
}
/*
* Create a new lltable.
* Links lltable to global llt list.
*/
struct lltable *
lltable_init(struct ifnet *ifp, int af)
void
lltable_link(struct lltable *llt)
{
struct lltable *llt;
register int i;
llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK);
llt->llt_af = af;
llt->llt_ifp = ifp;
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
LIST_INIT(&llt->lle_head[i]);
/* Provide default verions of hash table methods */
if (llt->llt_link_entry == NULL)
llt->llt_link_entry = llentry_link;
if (llt->llt_unlink_entry == NULL)
llt->llt_unlink_entry = llentry_unlink;
if (llt->llt_foreach_entry == NULL)
llt->llt_foreach_entry = lltable_foreach_lle;
if (llt->llt_free_tbl == NULL)
llt->llt_free_tbl = lltable_free_tbl;
LLTABLE_WLOCK();
SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
LLTABLE_WUNLOCK();
}
static void
lltable_unlink(struct lltable *llt)
{
LLTABLE_WLOCK();
SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
LLTABLE_WUNLOCK();
return (llt);
}
/*

View File

@ -159,6 +159,13 @@ typedef uint32_t (llt_hash_t)(const struct llentry *);
typedef int (llt_match_prefix_t)(const struct sockaddr *,
const struct sockaddr *, u_int, struct llentry *);
typedef void (llt_clear_entry_t)(struct lltable *, struct llentry *);
typedef void (llt_free_tbl_t)(struct lltable *);
typedef void (llt_link_entry_t)(struct lltable *, struct llentry *);
typedef void (llt_unlink_entry_t)(struct llentry *);
typedef int (llt_foreach_cb_t)(struct lltable *, struct llentry *, void *);
typedef int (llt_foreach_entry_t)(struct lltable *, llt_foreach_cb_t *, void *);
struct lltable {
SLIST_ENTRY(lltable) llt_link;
@ -173,6 +180,10 @@ struct lltable {
llt_hash_t *llt_hash;
llt_match_prefix_t *llt_match_prefix;
llt_clear_entry_t *llt_clear_entry;
llt_foreach_entry_t *llt_foreach_entry;
llt_link_entry_t *llt_link_entry;
llt_unlink_entry_t *llt_unlink_entry;
llt_free_tbl_t *llt_free_tbl;
};
MALLOC_DECLARE(M_LLTABLE);
@ -199,7 +210,7 @@ MALLOC_DECLARE(M_LLTABLE);
#define LLATBL_HASH(key, mask) \
(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
struct lltable *lltable_init(struct ifnet *, int);
void lltable_link(struct lltable *);
void lltable_free(struct lltable *);
void lltable_prefix_free(int, struct sockaddr *,
struct sockaddr *, u_int);
@ -208,9 +219,6 @@ void lltable_drain(int);
#endif
int lltable_sysctl_dumparp(int, struct sysctl_req *);
void llentry_link(struct lltable *, struct llentry *);
void llentry_unlink(struct llentry *);
void llentries_unlink(struct llentries *);
size_t llentry_free(struct llentry *);
struct llentry *llentry_alloc(struct ifnet *, struct lltable *,
struct sockaddr_storage *);
@ -242,6 +250,19 @@ lltable_delete_lle(struct lltable *llt, u_int flags,
return llt->llt_delete(llt, flags, l3addr);
}
static __inline void
lltable_link_entry(struct lltable *llt, struct llentry *lle)
{
llt->llt_link_entry(llt, lle);
}
static __inline void
lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
{
llt->llt_unlink_entry(lle);
}
int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);

View File

@ -291,7 +291,7 @@ arp_lltable_clear_entry(struct lltable *llt, struct llentry *lle)
LLE_REMREF(lle);
IF_AFDATA_RUN_WLOCK(ifp);
llentry_unlink(lle);
lltable_unlink_entry(llt, lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
@ -544,7 +544,7 @@ arpresolve_slow(struct ifnet *ifp, int is_gw, struct mbuf *m,
* No entry has been found. Link new one.
*/
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(LLTABLE(ifp), la);
lltable_link_entry(LLTABLE(ifp), la);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);
@ -1076,7 +1076,7 @@ arp_update_lle_addr(struct arphdr *ah, struct ifnet *ifp, struct llentry *la)
la->r_flags |= RLLE_VALID;
if ((la->la_flags & LLE_STATIC) == 0)
la->la_expire = time_uptime + V_arpt_keep;
llentry_link(LLTABLE(ifp), la);
lltable_link_entry(LLTABLE(ifp), la);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
@ -1254,7 +1254,7 @@ arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
lle->la_flags |= (LLE_VALID | LLE_STATIC);
lle->r_flags |= RLLE_VALID;
llentry_link(LLTABLE(ifp), lle);
lltable_link_entry(LLTABLE(ifp), lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);

View File

@ -1154,7 +1154,7 @@ in_lltable_delete(struct lltable *llt, u_int flags,
lle->la_flags |= LLE_DELETED;
EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
IF_AFDATA_RUN_WLOCK(ifp);
llentry_unlink(lle);
lltable_unlink_entry(llt, lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
@ -1294,21 +1294,25 @@ in_domifattach(struct ifnet *ifp)
{
struct in_ifinfo *ii;
struct lltable *llt;
int i;
llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
llt->llt_af = AF_INET;
llt->llt_ifp = ifp;
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
LIST_INIT(&llt->lle_head[i]);
llt->llt_lookup = in_lltable_lookup;
llt->llt_create = in_lltable_create;
llt->llt_delete = 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;
llt->llt_match_prefix = in_lltable_match_prefix;
lltable_link(llt);
ii = malloc(sizeof(struct in_ifinfo), M_IFADDR, M_WAITOK|M_ZERO);
llt = lltable_init(ifp, AF_INET);
if (llt != NULL) {
llt->llt_lookup = in_lltable_lookup;
llt->llt_create = in_lltable_create;
llt->llt_delete = 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;
llt->llt_match_prefix = in_lltable_match_prefix;
}
ii->ii_llt = llt;
ii->ii_igmp = igmp_domifattach(ifp);
return ii;

View File

@ -477,7 +477,7 @@ toe_nd6_resolve(struct ifnet *ifp, struct sockaddr *sa, uint8_t *lladdr)
* No entry has been found. Link new one.
*/
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(LLTABLE6(ifp), lle);
lltable_link_entry(LLTABLE6(ifp), lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);

View File

@ -2188,7 +2188,7 @@ in6_lltable_delete(struct lltable *llt, u_int flags,
LLE_WLOCK(lle);
lle->la_flags |= LLE_DELETED;
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentry_unlink(lle);
lltable_unlink_entry(llt, lle);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
@ -2330,6 +2330,8 @@ void *
in6_domifattach(struct ifnet *ifp)
{
struct in6_ifextra *ext;
struct lltable *llt;
int i;
/* There are not IPv6-capable interfaces. */
switch (ifp->if_type) {
@ -2354,16 +2356,22 @@ in6_domifattach(struct ifnet *ifp)
ext->nd_ifinfo = nd6_ifattach(ifp);
ext->scope6_id = scope6_ifattach(ifp);
ext->lltable = lltable_init(ifp, AF_INET6);
if (ext->lltable != NULL) {
ext->lltable->llt_lookup = in6_lltable_lookup;
ext->lltable->llt_create = in6_lltable_create;
ext->lltable->llt_delete = in6_lltable_delete;
ext->lltable->llt_dump_entry = in6_lltable_dump_entry;
ext->lltable->llt_hash = in6_lltable_hash;
ext->lltable->llt_clear_entry = nd6_lltable_clear_entry;
ext->lltable->llt_match_prefix = in6_lltable_match_prefix;
}
llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
llt->llt_af = AF_INET6;
llt->llt_ifp = ifp;
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
LIST_INIT(&llt->lle_head[i]);
llt->llt_lookup = in6_lltable_lookup;
llt->llt_create = in6_lltable_create;
llt->llt_delete = 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;
llt->llt_match_prefix = in6_lltable_match_prefix;
lltable_link(llt);
ext->lltable = llt;
ext->mld_ifinfo = mld_domifattach(ifp);

View File

@ -1120,7 +1120,7 @@ nd6_lltable_clear_entry(struct lltable *llt, struct llentry *ln)
LLE_REMREF(ln);
IF_AFDATA_RUN_WLOCK(ifp);
llentry_unlink(ln);
lltable_unlink_entry(llt, ln);
IF_AFDATA_RUN_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
@ -1892,7 +1892,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
if (r_update != 0) {
IF_AFDATA_RUN_WLOCK(ifp);
if (is_newentry != 0)
llentry_link(LLTABLE6(ifp), ln);
lltable_link_entry(LLTABLE6(ifp), ln);
if (lladdr != NULL) {
bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen);
ln->la_flags |= LLE_VALID;
@ -2197,7 +2197,7 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
* Link new one.
*/
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(LLTABLE6(ifp), lle);
lltable_link_entry(LLTABLE6(ifp), lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);
@ -2485,7 +2485,7 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
bcopy(IF_LLADDR(ifp), &ln->ll_addr, ifp->if_addrlen);
/* Finally, link our lle to the list */
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(LLTABLE6(ifp), ln);
lltable_link_entry(LLTABLE6(ifp), ln);
IF_AFDATA_RUN_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);