For hostentry cache, replace FIB with a hash table using (IP, dep table) as a key.
This commit is contained in:
parent
852b7062e3
commit
f2b76f2c45
2 changed files with 131 additions and 28 deletions
13
nest/route.h
13
nest/route.h
|
@ -150,20 +150,27 @@ typedef struct network {
|
||||||
} net;
|
} net;
|
||||||
|
|
||||||
struct hostcache {
|
struct hostcache {
|
||||||
struct fib htable;
|
slab *slab; /* Slab holding all hostentries */
|
||||||
|
struct hostentry **hash_table; /* Hash table for hostentries */
|
||||||
|
unsigned hash_order, hash_shift;
|
||||||
|
unsigned hash_max, hash_min;
|
||||||
|
unsigned hash_items;
|
||||||
|
|
||||||
list hostentries;
|
list hostentries;
|
||||||
byte update_hostcache;
|
byte update_hostcache;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hostentry {
|
struct hostentry {
|
||||||
struct fib_node fn;
|
|
||||||
node ln;
|
node ln;
|
||||||
|
ip_addr addr; /* IP of host, part of key */
|
||||||
|
struct rtable *tab; /* Dependent table, part of key*/
|
||||||
|
struct hostentry *next; /* Next in hash chain */
|
||||||
|
unsigned hash_key; /* Hash key */
|
||||||
unsigned uc; /* Use count */
|
unsigned uc; /* Use count */
|
||||||
struct iface *iface; /* Chosen outgoing interface */
|
struct iface *iface; /* Chosen outgoing interface */
|
||||||
ip_addr gw; /* Chosen next hop */
|
ip_addr gw; /* Chosen next hop */
|
||||||
byte dest; /* Chosen route destination type (RTD_...) */
|
byte dest; /* Chosen route destination type (RTD_...) */
|
||||||
byte pxlen; /* Pxlen from net that matches route */
|
byte pxlen; /* Pxlen from net that matches route */
|
||||||
struct rtable *tab;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rte {
|
typedef struct rte {
|
||||||
|
|
146
nest/rt-table.c
146
nest/rt-table.c
|
@ -1287,11 +1287,106 @@ rt_feed_baby_abort(struct proto *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
hostentry_init(struct fib_node *fn)
|
static inline unsigned
|
||||||
|
ptr_hash(void *ptr)
|
||||||
{
|
{
|
||||||
((struct hostentry *) fn)->uc = 0;
|
uintptr_t p = (uintptr_t) ptr;
|
||||||
((struct hostentry *) fn)->tab = NULL;
|
return p ^ (p << 8) ^ (p >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
hc_hash(ip_addr a, rtable *dep)
|
||||||
|
{
|
||||||
|
return (ipa_hash(a) ^ ptr_hash(dep)) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hc_insert(struct hostcache *hc, struct hostentry *he)
|
||||||
|
{
|
||||||
|
unsigned int k = he->hash_key >> hc->hash_shift;
|
||||||
|
he->next = hc->hash_table[k];
|
||||||
|
hc->hash_table[k] = he;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hc_remove(struct hostcache *hc, struct hostentry *he)
|
||||||
|
{
|
||||||
|
struct hostentry **hep;
|
||||||
|
unsigned int k = he->hash_key >> hc->hash_shift;
|
||||||
|
|
||||||
|
for (hep = &hc->hash_table[k]; *hep != he; hep = &(*hep)->next);
|
||||||
|
*hep = he->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HC_DEF_ORDER 10
|
||||||
|
#define HC_HI_MARK *4
|
||||||
|
#define HC_HI_STEP 2
|
||||||
|
#define HC_HI_ORDER 16 /* Must be at most 16 */
|
||||||
|
#define HC_LO_MARK /5
|
||||||
|
#define HC_LO_STEP 2
|
||||||
|
#define HC_LO_ORDER 10
|
||||||
|
|
||||||
|
static void
|
||||||
|
hc_alloc_table(struct hostcache *hc, unsigned order)
|
||||||
|
{
|
||||||
|
unsigned hsize = 1 << order;
|
||||||
|
hc->hash_order = order;
|
||||||
|
hc->hash_shift = 16 - order;
|
||||||
|
hc->hash_max = (order >= HC_HI_ORDER) ? ~0 : (hsize HC_HI_MARK);
|
||||||
|
hc->hash_min = (order <= HC_LO_ORDER) ? 0 : (hsize HC_LO_MARK);
|
||||||
|
|
||||||
|
hc->hash_table = mb_allocz(rt_table_pool, hsize * sizeof(struct hostentry *));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hc_resize(struct hostcache *hc, unsigned new_order)
|
||||||
|
{
|
||||||
|
unsigned old_size = 1 << hc->hash_order;
|
||||||
|
struct hostentry **old_table = hc->hash_table;
|
||||||
|
struct hostentry *he, *hen;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
hc_alloc_table(hc, new_order);
|
||||||
|
for (i = 0; i < old_size; i++)
|
||||||
|
for (he = old_table[i]; he != NULL; he=hen)
|
||||||
|
{
|
||||||
|
hen = he->next;
|
||||||
|
hc_insert(hc, he);
|
||||||
|
}
|
||||||
|
mb_free(old_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct hostentry *
|
||||||
|
hc_new_hostentry(struct hostcache *hc, ip_addr a, rtable *dep, unsigned k)
|
||||||
|
{
|
||||||
|
struct hostentry *he = sl_alloc(hc->slab);
|
||||||
|
|
||||||
|
he->addr = a;
|
||||||
|
he->tab = dep;
|
||||||
|
he->hash_key = k;
|
||||||
|
he->uc = 0;
|
||||||
|
|
||||||
|
add_tail(&hc->hostentries, &he->ln);
|
||||||
|
hc_insert(hc, he);
|
||||||
|
|
||||||
|
hc->hash_items++;
|
||||||
|
if (hc->hash_items > hc->hash_max)
|
||||||
|
hc_resize(hc, hc->hash_order + HC_HI_STEP);
|
||||||
|
|
||||||
|
return he;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
|
||||||
|
{
|
||||||
|
rem_node(&he->ln);
|
||||||
|
hc_remove(hc, he);
|
||||||
|
sl_free(hc->slab, he);
|
||||||
|
|
||||||
|
hc->hash_items--;
|
||||||
|
if (hc->hash_items < hc->hash_min)
|
||||||
|
hc_resize(hc, hc->hash_order - HC_LO_STEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1299,7 +1394,11 @@ rt_init_hostcache(rtable *tab)
|
||||||
{
|
{
|
||||||
struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
|
struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
|
||||||
init_list(&hc->hostentries);
|
init_list(&hc->hostentries);
|
||||||
fib_init(&hc->htable, rt_table_pool, sizeof(struct hostentry), 0, hostentry_init);
|
|
||||||
|
hc->hash_items = 0;
|
||||||
|
hc_alloc_table(hc, HC_DEF_ORDER);
|
||||||
|
hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
|
||||||
|
|
||||||
tab->hostcache = hc;
|
tab->hostcache = hc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1316,7 +1415,8 @@ rt_free_hostcache(rtable *tab)
|
||||||
log(L_ERR "Hostcache is not empty in table %s", tab->name);
|
log(L_ERR "Hostcache is not empty in table %s", tab->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fib_free(&hc->htable);
|
rfree(hc->slab);
|
||||||
|
mb_free(hc->hash_table);
|
||||||
mb_free(hc);
|
mb_free(hc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1332,7 +1432,7 @@ rt_notify_hostcache(rtable *tab, net *net)
|
||||||
WALK_LIST(n, hc->hostentries)
|
WALK_LIST(n, hc->hostentries)
|
||||||
{
|
{
|
||||||
struct hostentry *he = SKIP_BACK(struct hostentry, ln, n);
|
struct hostentry *he = SKIP_BACK(struct hostentry, ln, n);
|
||||||
if (ipa_in_net(he->fn.prefix, net->n.prefix, net->n.pxlen) &&
|
if (ipa_in_net(he->addr, net->n.prefix, net->n.pxlen) &&
|
||||||
(he->pxlen <= net->n.pxlen))
|
(he->pxlen <= net->n.pxlen))
|
||||||
{
|
{
|
||||||
rt_schedule_hcu(tab);
|
rt_schedule_hcu(tab);
|
||||||
|
@ -1360,18 +1460,18 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||||
ip_addr old_gw = he->gw;
|
ip_addr old_gw = he->gw;
|
||||||
byte old_dest = he->dest;
|
byte old_dest = he->dest;
|
||||||
|
|
||||||
net *n = fib_route(&tab->fib, he->fn.prefix, MAX_PREFIX_LENGTH);
|
net *n = fib_route(&tab->fib, he->addr, MAX_PREFIX_LENGTH);
|
||||||
if (n && n->routes)
|
if (n && n->routes)
|
||||||
{
|
{
|
||||||
rta *a = n->routes->attrs;
|
rta *a = n->routes->attrs;
|
||||||
|
|
||||||
if (a->dest == RTD_DEVICE)
|
if (a->dest == RTD_DEVICE)
|
||||||
{
|
{
|
||||||
if (if_local_addr(he->fn.prefix, a->iface))
|
if (if_local_addr(he->addr, a->iface))
|
||||||
{
|
{
|
||||||
/* The host address is a local address, this is not valid */
|
/* The host address is a local address, this is not valid */
|
||||||
log(L_WARN "Next hop address %I is a local address of iface %s",
|
log(L_WARN "Next hop address %I is a local address of iface %s",
|
||||||
he->fn.prefix, a->iface->name);
|
he->addr, a->iface->name);
|
||||||
he->iface = NULL;
|
he->iface = NULL;
|
||||||
he->gw = IPA_NONE;
|
he->gw = IPA_NONE;
|
||||||
he->dest = RTD_UNREACHABLE;
|
he->dest = RTD_UNREACHABLE;
|
||||||
|
@ -1380,7 +1480,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||||
{
|
{
|
||||||
/* The host is directly reachable, us it as a gateway */
|
/* The host is directly reachable, us it as a gateway */
|
||||||
he->iface = a->iface;
|
he->iface = a->iface;
|
||||||
he->gw = he->fn.prefix;
|
he->gw = he->addr;
|
||||||
he->dest = RTD_ROUTER;
|
he->dest = RTD_ROUTER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1419,9 +1519,7 @@ rt_update_hostcache(rtable *tab)
|
||||||
he = SKIP_BACK(struct hostentry, ln, n);
|
he = SKIP_BACK(struct hostentry, ln, n);
|
||||||
if (!he->uc)
|
if (!he->uc)
|
||||||
{
|
{
|
||||||
/* Delete a hostentry */
|
hc_delete_hostentry(hc, he);
|
||||||
rem_node(&he->ln);
|
|
||||||
fib_delete(&hc->htable, he);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,30 +1531,28 @@ rt_update_hostcache(rtable *tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hostentry *
|
static struct hostentry *
|
||||||
rt_find_hostentry(rtable *tab, ip_addr *a, rtable *dep)
|
rt_find_hostentry(rtable *tab, ip_addr a, rtable *dep)
|
||||||
{
|
{
|
||||||
struct hostentry *he;
|
struct hostentry *he;
|
||||||
|
|
||||||
if (!tab->hostcache)
|
if (!tab->hostcache)
|
||||||
rt_init_hostcache(tab);
|
rt_init_hostcache(tab);
|
||||||
|
|
||||||
he = fib_get(&tab->hostcache->htable, a, MAX_PREFIX_LENGTH);
|
unsigned int k = hc_hash(a, dep);
|
||||||
if (!he->tab)
|
struct hostcache *hc = tab->hostcache;
|
||||||
{
|
for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next)
|
||||||
/* New entry */
|
if (ipa_equal(he->addr, a) && (he->tab == dep))
|
||||||
add_tail(&tab->hostcache->hostentries, &he->ln);
|
return he;
|
||||||
he->tab = dep;
|
|
||||||
|
|
||||||
rt_update_hostentry(tab, he);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
he = hc_new_hostentry(hc, a, dep, k);
|
||||||
|
rt_update_hostentry(tab, he);
|
||||||
return he;
|
return he;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw)
|
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw)
|
||||||
{
|
{
|
||||||
rta_apply_hostentry(a, rt_find_hostentry(tab, gw, dep));
|
rta_apply_hostentry(a, rt_find_hostentry(tab, *gw, dep));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue