mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Replacing table FIB by netindex and simple pointer block
Using the netindex data structure to simplify route storage inside route tables. This should also help with future unlocking of route import.
This commit is contained in:
parent
54d5e36ec0
commit
548dbb2252
23
nest/route.h
23
nest/route.h
@ -14,6 +14,7 @@
|
|||||||
#include "lib/bitmap.h"
|
#include "lib/bitmap.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/net.h"
|
#include "lib/net.h"
|
||||||
|
#include "lib/netindex.h"
|
||||||
#include "lib/type.h"
|
#include "lib/type.h"
|
||||||
#include "lib/fib.h"
|
#include "lib/fib.h"
|
||||||
#include "lib/route.h"
|
#include "lib/route.h"
|
||||||
@ -108,6 +109,7 @@ extern uint rtable_max_id;
|
|||||||
DOMAIN(rtable) lock; /* Lock to take to access the private parts */ \
|
DOMAIN(rtable) lock; /* Lock to take to access the private parts */ \
|
||||||
struct rtable_config *config; /* Configuration of this table */ \
|
struct rtable_config *config; /* Configuration of this table */ \
|
||||||
struct birdloop *loop; /* Service thread */ \
|
struct birdloop *loop; /* Service thread */ \
|
||||||
|
netindex_hash *netindex; /* Prefix index for this table */ \
|
||||||
|
|
||||||
/* The complete rtable structure */
|
/* The complete rtable structure */
|
||||||
struct rtable_private {
|
struct rtable_private {
|
||||||
@ -118,10 +120,12 @@ struct rtable_private {
|
|||||||
/* Here the private items not to be accessed without locking */
|
/* Here the private items not to be accessed without locking */
|
||||||
pool *rp; /* Resource pool to allocate everything from, including itself */
|
pool *rp; /* Resource pool to allocate everything from, including itself */
|
||||||
struct slab *rte_slab; /* Slab to allocate route objects */
|
struct slab *rte_slab; /* Slab to allocate route objects */
|
||||||
struct fib fib;
|
struct network *routes; /* Actual route objects in the table */
|
||||||
|
u32 routes_block_size; /* Size of the route object pointer block */
|
||||||
struct f_trie *trie; /* Trie of prefixes defined in fib */
|
struct f_trie *trie; /* Trie of prefixes defined in fib */
|
||||||
int use_count; /* Number of protocols using this table */
|
int use_count; /* Number of protocols using this table */
|
||||||
u32 rt_count; /* Number of routes in the table */
|
u32 rt_count; /* Number of routes in the table */
|
||||||
|
u32 net_count; /* Number of nets in the table */
|
||||||
u32 debug; /* Debugging flags (D_*) */
|
u32 debug; /* Debugging flags (D_*) */
|
||||||
|
|
||||||
list imports; /* Registered route importers */
|
list imports; /* Registered route importers */
|
||||||
@ -152,8 +156,8 @@ struct rtable_private {
|
|||||||
byte export_used; /* Pending Export pruning is scheduled */
|
byte export_used; /* Pending Export pruning is scheduled */
|
||||||
byte cork_active; /* Cork has been activated */
|
byte cork_active; /* Cork has been activated */
|
||||||
struct rt_cork_threshold cork_threshold; /* Threshold for table cork */
|
struct rt_cork_threshold cork_threshold; /* Threshold for table cork */
|
||||||
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
|
u32 prune_index; /* Rtable prune FIB iterator */
|
||||||
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
|
u32 nhu_index; /* Next Hop Update FIB iterator */
|
||||||
struct f_trie *trie_new; /* New prefix trie defined during pruning */
|
struct f_trie *trie_new; /* New prefix trie defined during pruning */
|
||||||
struct f_trie *trie_old; /* Old prefix trie waiting to be freed */
|
struct f_trie *trie_old; /* Old prefix trie waiting to be freed */
|
||||||
u32 trie_lock_count; /* Prefix trie locked by walks */
|
u32 trie_lock_count; /* Prefix trie locked by walks */
|
||||||
@ -228,7 +232,6 @@ static inline int rt_cork_check(event *e)
|
|||||||
typedef struct network {
|
typedef struct network {
|
||||||
struct rte_storage *routes; /* Available routes for this network */
|
struct rte_storage *routes; /* Available routes for this network */
|
||||||
struct rt_pending_export *first, *last;
|
struct rt_pending_export *first, *last;
|
||||||
struct fib_node n; /* FIB flags reserved for kernel syncer */
|
|
||||||
} net;
|
} net;
|
||||||
|
|
||||||
struct rte_storage {
|
struct rte_storage {
|
||||||
@ -248,6 +251,8 @@ struct rte_storage {
|
|||||||
|
|
||||||
#define RTES_WRITE(r) (((r) != ((struct rte_storage *) 0)) ? ((struct rte *) &(r)->rte) : NULL)
|
#define RTES_WRITE(r) (((r) != ((struct rte_storage *) 0)) ? ((struct rte *) &(r)->rte) : NULL)
|
||||||
|
|
||||||
|
#define RTE_GET_NETINDEX(e) NET_TO_INDEX((e)->net)
|
||||||
|
|
||||||
/* Table-channel connections */
|
/* Table-channel connections */
|
||||||
|
|
||||||
struct rt_prefilter {
|
struct rt_prefilter {
|
||||||
@ -391,7 +396,7 @@ struct rt_table_export_hook {
|
|||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
|
u32 feed_index; /* Routing table iterator used during feeding */
|
||||||
struct {
|
struct {
|
||||||
struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */
|
struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */
|
||||||
struct f_trie *walk_lock; /* Locked trie for walking */
|
struct f_trie *walk_lock; /* Locked trie for walking */
|
||||||
@ -614,11 +619,9 @@ void rt_flowspec_link(rtable *src, rtable *dst);
|
|||||||
void rt_flowspec_unlink(rtable *src, rtable *dst);
|
void rt_flowspec_unlink(rtable *src, rtable *dst);
|
||||||
rtable *rt_setup(pool *, struct rtable_config *);
|
rtable *rt_setup(pool *, struct rtable_config *);
|
||||||
|
|
||||||
static inline net *net_find(struct rtable_private *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
|
static inline net *net_find(struct rtable_private *tab, const struct netindex *i)
|
||||||
static inline net *net_find_valid(struct rtable_private *tab, const net_addr *addr)
|
{ return (i->index < tab->routes_block_size) ? &(tab->routes[i->index]) : NULL; }
|
||||||
{ net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; }
|
|
||||||
static inline net *net_get(struct rtable_private *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
|
|
||||||
net *net_route(struct rtable_private *tab, const net_addr *n);
|
|
||||||
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
|
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
|
||||||
rte *rt_export_merged(struct channel *c, const net_addr *n, const rte ** feed, uint count, linpool *pool, int silent);
|
rte *rt_export_merged(struct channel *c, const net_addr *n, const rte ** feed, uint count, linpool *pool, int silent);
|
||||||
void rt_refresh_begin(struct rt_import_request *);
|
void rt_refresh_begin(struct rt_import_request *);
|
||||||
|
308
nest/rt-table.c
308
nest/rt-table.c
@ -109,6 +109,7 @@
|
|||||||
#include "lib/alloca.h"
|
#include "lib/alloca.h"
|
||||||
#include "lib/flowspec.h"
|
#include "lib/flowspec.h"
|
||||||
#include "lib/idm.h"
|
#include "lib/idm.h"
|
||||||
|
#include "lib/netindex_private.h"
|
||||||
|
|
||||||
#ifdef CONFIG_BGP
|
#ifdef CONFIG_BGP
|
||||||
#include "proto/bgp/bgp.h"
|
#include "proto/bgp/bgp.h"
|
||||||
@ -121,6 +122,8 @@ pool *rt_table_pool;
|
|||||||
list routing_tables;
|
list routing_tables;
|
||||||
list deleted_routing_tables;
|
list deleted_routing_tables;
|
||||||
|
|
||||||
|
netindex_hash *rt_global_netindex_hash;
|
||||||
|
|
||||||
struct rt_cork rt_cork;
|
struct rt_cork rt_cork;
|
||||||
|
|
||||||
/* Data structures for export journal */
|
/* Data structures for export journal */
|
||||||
@ -212,21 +215,41 @@ static inline rtable *rt_pub_to_pub(rtable *tab) { return tab; }
|
|||||||
log(L_TRACE "%s.%s: " fmt, c->proto->name, c->name, ##args);\
|
log(L_TRACE "%s.%s: " fmt, c->proto->name, c->name, ##args);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void
|
static inline net *
|
||||||
net_init_with_trie(struct fib *f, void *N)
|
net_find_valid(struct rtable_private *tab, struct netindex_hash_private *nh, const net_addr *addr)
|
||||||
{
|
{
|
||||||
struct rtable_private *tab = SKIP_BACK(struct rtable_private, fib, f);
|
struct netindex *i = net_find_index_fragile(nh, addr);
|
||||||
net *n = N;
|
net *n = i ? net_find(tab, i) : NULL;
|
||||||
|
return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline net *
|
||||||
|
net_get(struct rtable_private *tab, const struct netindex *i)
|
||||||
|
{
|
||||||
|
/* Expand the routes block if insufficient */
|
||||||
|
u32 nbs = tab->routes_block_size;
|
||||||
|
while (i->index >= nbs)
|
||||||
|
nbs *= 2;
|
||||||
|
|
||||||
|
if (nbs > tab->routes_block_size)
|
||||||
|
{
|
||||||
|
struct network *nb = mb_realloc(tab->routes, sizeof (struct network) * nbs);
|
||||||
|
memset(&nb[tab->routes_block_size], 0, (nbs - tab->routes_block_size) * sizeof (struct network));
|
||||||
|
tab->routes = nb;
|
||||||
|
tab->routes_block_size = nbs;
|
||||||
|
}
|
||||||
|
|
||||||
if (tab->trie)
|
if (tab->trie)
|
||||||
trie_add_prefix(tab->trie, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
|
trie_add_prefix(tab->trie, i->addr, i->addr->pxlen, i->addr->pxlen);
|
||||||
|
|
||||||
if (tab->trie_new)
|
if (tab->trie_new)
|
||||||
trie_add_prefix(tab->trie_new, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
|
trie_add_prefix(tab->trie_new, i->addr, i->addr->pxlen, i->addr->pxlen);
|
||||||
|
|
||||||
|
return &tab->routes[i->index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
net_route_ip6_sadr_trie(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
net_route_ip6_sadr_trie(struct rtable_private *t, struct netindex_hash_private *nh, const net_addr_ip6_sadr *n0)
|
||||||
{
|
{
|
||||||
TRIE_WALK_TO_ROOT_IP6(t->trie, (const net_addr_ip6 *) n0, px)
|
TRIE_WALK_TO_ROOT_IP6(t->trie, (const net_addr_ip6 *) n0, px)
|
||||||
{
|
{
|
||||||
@ -237,18 +260,23 @@ net_route_ip6_sadr_trie(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
|||||||
/* We need to do dst first matching. Since sadr addresses are hashed on dst
|
/* We need to do dst first matching. Since sadr addresses are hashed on dst
|
||||||
prefix only, find the hash table chain and go through it to find the
|
prefix only, find the hash table chain and go through it to find the
|
||||||
match with the longest matching src prefix. */
|
match with the longest matching src prefix. */
|
||||||
for (struct fib_node *fn = fib_get_chain(&t->fib, (net_addr *) &n); fn; fn = fn->next)
|
for (struct netindex *i = net_find_index_fragile_chain(nh, (net_addr *) &n); i; i = i->next)
|
||||||
{
|
{
|
||||||
net_addr_ip6_sadr *a = (void *) fn->addr;
|
net_addr_ip6_sadr *a = (void *) i->addr;
|
||||||
|
|
||||||
if (net_equal_dst_ip6_sadr(&n, a) &&
|
if ((i->index < t->routes_block_size) &&
|
||||||
|
net_equal_dst_ip6_sadr(&n, a) &&
|
||||||
net_in_net_src_ip6_sadr(&n, a) &&
|
net_in_net_src_ip6_sadr(&n, a) &&
|
||||||
(a->src_pxlen >= best_pxlen))
|
(a->src_pxlen >= best_pxlen))
|
||||||
{
|
{
|
||||||
best = fib_node_to_user(&t->fib, fn);
|
net *cur = &t->routes[i->index];
|
||||||
|
if (cur->routes && rte_is_valid(&cur->routes->rte))
|
||||||
|
{
|
||||||
|
best = cur;
|
||||||
best_pxlen = a->src_pxlen;
|
best_pxlen = a->src_pxlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (best)
|
if (best)
|
||||||
return best;
|
return best;
|
||||||
@ -260,7 +288,7 @@ net_route_ip6_sadr_trie(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
|||||||
|
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
net_route_ip6_sadr_fib(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
net_route_ip6_sadr_fib(struct rtable_private *t, struct netindex_hash_private *nh, const net_addr_ip6_sadr *n0)
|
||||||
{
|
{
|
||||||
net_addr_ip6_sadr n;
|
net_addr_ip6_sadr n;
|
||||||
net_copy_ip6_sadr(&n, n0);
|
net_copy_ip6_sadr(&n, n0);
|
||||||
@ -273,18 +301,23 @@ net_route_ip6_sadr_fib(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
|||||||
/* We need to do dst first matching. Since sadr addresses are hashed on dst
|
/* We need to do dst first matching. Since sadr addresses are hashed on dst
|
||||||
prefix only, find the hash table chain and go through it to find the
|
prefix only, find the hash table chain and go through it to find the
|
||||||
match with the longest matching src prefix. */
|
match with the longest matching src prefix. */
|
||||||
for (struct fib_node *fn = fib_get_chain(&t->fib, (net_addr *) &n); fn; fn = fn->next)
|
for (struct netindex *i = net_find_index_fragile_chain(nh, (net_addr *) &n); i; i = i->next)
|
||||||
{
|
{
|
||||||
net_addr_ip6_sadr *a = (void *) fn->addr;
|
net_addr_ip6_sadr *a = (void *) i->addr;
|
||||||
|
|
||||||
if (net_equal_dst_ip6_sadr(&n, a) &&
|
if ((i->index < t->routes_block_size) &&
|
||||||
|
net_equal_dst_ip6_sadr(&n, a) &&
|
||||||
net_in_net_src_ip6_sadr(&n, a) &&
|
net_in_net_src_ip6_sadr(&n, a) &&
|
||||||
(a->src_pxlen >= best_pxlen))
|
(a->src_pxlen >= best_pxlen))
|
||||||
{
|
{
|
||||||
best = fib_node_to_user(&t->fib, fn);
|
net *cur = &t->routes[i->index];
|
||||||
|
if (cur->routes && rte_is_valid(&cur->routes->rte))
|
||||||
|
{
|
||||||
|
best = cur;
|
||||||
best_pxlen = a->src_pxlen;
|
best_pxlen = a->src_pxlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (best)
|
if (best)
|
||||||
return best;
|
return best;
|
||||||
@ -299,9 +332,11 @@ net_route_ip6_sadr_fib(struct rtable_private *t, const net_addr_ip6_sadr *n0)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
net *
|
static net *
|
||||||
net_route(struct rtable_private *tab, const net_addr *n)
|
net_route(struct rtable_private *tab, const net_addr *n)
|
||||||
{
|
{
|
||||||
|
NH_LOCK(tab->netindex, nh);
|
||||||
|
|
||||||
ASSERT(tab->addr_type == n->type);
|
ASSERT(tab->addr_type == n->type);
|
||||||
net_addr_union *nu = SKIP_BACK(net_addr_union, n, n);
|
net_addr_union *nu = SKIP_BACK(net_addr_union, n, n);
|
||||||
|
|
||||||
@ -319,7 +354,7 @@ net_route(struct rtable_private *tab, const net_addr *n)
|
|||||||
} while(0); return NULL;
|
} while(0); return NULL;
|
||||||
|
|
||||||
#define FVR_IP(ipv, var) \
|
#define FVR_IP(ipv, var) \
|
||||||
net *r; if (r = net_find_valid(tab, (net_addr *) &var)) return r;
|
net *r; if (r = net_find_valid(tab, nh, (net_addr *) &var)) return r;
|
||||||
|
|
||||||
#define FVR_VPN(ipv, var) \
|
#define FVR_VPN(ipv, var) \
|
||||||
net_addr_vpn##ipv _var0 = NET_ADDR_VPN##ipv(var.prefix, var.pxlen, nu->vpn##ipv.rd); FVR_IP(ipv, _var0);
|
net_addr_vpn##ipv _var0 = NET_ADDR_VPN##ipv(var.prefix, var.pxlen, nu->vpn##ipv.rd); FVR_IP(ipv, _var0);
|
||||||
@ -332,7 +367,7 @@ net_route(struct rtable_private *tab, const net_addr *n)
|
|||||||
case NET_VPN6: TW(6, FVR_VPN);
|
case NET_VPN6: TW(6, FVR_VPN);
|
||||||
|
|
||||||
case NET_IP6_SADR:
|
case NET_IP6_SADR:
|
||||||
return net_route_ip6_sadr_trie(tab, (net_addr_ip6_sadr *) n);
|
return net_route_ip6_sadr_trie(tab, nh, (net_addr_ip6_sadr *) n);
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -344,7 +379,7 @@ net_route(struct rtable_private *tab, const net_addr *n)
|
|||||||
case NET_VPN6: FW(6, FVR_VPN);
|
case NET_VPN6: FW(6, FVR_VPN);
|
||||||
|
|
||||||
case NET_IP6_SADR:
|
case NET_IP6_SADR:
|
||||||
return net_route_ip6_sadr_fib (tab, (net_addr_ip6_sadr *) n);
|
return net_route_ip6_sadr_fib (tab, nh, (net_addr_ip6_sadr *) n);
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -376,7 +411,6 @@ net_roa_check(rtable *tp, const net_addr *n, u32 asn)
|
|||||||
{
|
{
|
||||||
net_addr_union *nu = SKIP_BACK(net_addr_union, n, n);
|
net_addr_union *nu = SKIP_BACK(net_addr_union, n, n);
|
||||||
int anything = 0;
|
int anything = 0;
|
||||||
struct fib_node *fn;
|
|
||||||
|
|
||||||
#define TW(ipv) do { \
|
#define TW(ipv) do { \
|
||||||
TRIE_WALK_TO_ROOT_IP##ipv(tab->trie, &(nu->ip##ipv), var) { \
|
TRIE_WALK_TO_ROOT_IP##ipv(tab->trie, &(nu->ip##ipv), var) { \
|
||||||
@ -396,11 +430,13 @@ net_roa_check(rtable *tp, const net_addr *n, u32 asn)
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ROA_PARTIAL_CHECK(ipv) do { \
|
#define ROA_PARTIAL_CHECK(ipv) do { \
|
||||||
for (fn = fib_get_chain(&tab->fib, (net_addr *) &roa0); fn; fn = fn->next) \
|
for (struct netindex *i = net_find_index_fragile_chain(nh, (net_addr *) &roa0); i; i = i->next)\
|
||||||
{ \
|
{ \
|
||||||
net_addr_roa##ipv *roa = (void *) fn->addr; \
|
if (tab->routes_block_size < i->index) continue; \
|
||||||
net *r = fib_node_to_user(&tab->fib, fn); \
|
net_addr_roa##ipv *roa = (void *) i->addr; \
|
||||||
if (net_equal_prefix_roa##ipv(roa, &roa0) && rte_is_valid(r->routes)) \
|
if (!net_equal_prefix_roa##ipv(roa, &roa0)) continue; \
|
||||||
|
net *r = &tab->routes[i->index]; \
|
||||||
|
if (r->routes && rte_is_valid(&r->routes->rte)) \
|
||||||
{ \
|
{ \
|
||||||
anything = 1; \
|
anything = 1; \
|
||||||
if (asn && (roa->asn == asn) && (roa->max_pxlen >= nu->ip##ipv.pxlen)) \
|
if (asn && (roa->asn == asn) && (roa->max_pxlen >= nu->ip##ipv.pxlen)) \
|
||||||
@ -411,6 +447,7 @@ net_roa_check(rtable *tp, const net_addr *n, u32 asn)
|
|||||||
|
|
||||||
RT_LOCKED(tp, tab)
|
RT_LOCKED(tp, tab)
|
||||||
{
|
{
|
||||||
|
NH_LOCK(tab->netindex, nh);
|
||||||
if ((tab->addr_type == NET_ROA4) && (n->type == NET_IP4))
|
if ((tab->addr_type == NET_ROA4) && (n->type == NET_IP4))
|
||||||
{
|
{
|
||||||
if (tab->trie) TW(4);
|
if (tab->trie) TW(4);
|
||||||
@ -450,13 +487,14 @@ rte_find(net *net, struct rte_src *src)
|
|||||||
|
|
||||||
|
|
||||||
struct rte_storage *
|
struct rte_storage *
|
||||||
rte_store(const rte *r, net *net, struct rtable_private *tab)
|
rte_store(const rte *r, struct netindex *i, struct rtable_private *tab)
|
||||||
{
|
{
|
||||||
struct rte_storage *s = sl_alloc(tab->rte_slab);
|
struct rte_storage *s = sl_alloc(tab->rte_slab);
|
||||||
struct rte *e = RTES_WRITE(s);
|
struct rte *e = RTES_WRITE(s);
|
||||||
|
|
||||||
*e = *r;
|
*e = *r;
|
||||||
e->net = net->n.addr;
|
e->net = i->addr;
|
||||||
|
net_lock_index(tab->netindex, i);
|
||||||
|
|
||||||
rt_lock_source(e->src);
|
rt_lock_source(e->src);
|
||||||
|
|
||||||
@ -477,9 +515,13 @@ rte_store(const rte *r, net *net, struct rtable_private *tab)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
rte_free(struct rte_storage *e)
|
rte_free(struct rte_storage *e, struct rtable_private *tab)
|
||||||
{
|
{
|
||||||
|
struct netindex *i = RTE_GET_NETINDEX(&e->rte);
|
||||||
|
net_unlock_index(tab->netindex, i);
|
||||||
|
|
||||||
rt_unlock_source(e->rte.src);
|
rt_unlock_source(e->rte.src);
|
||||||
|
|
||||||
rta_free(e->rte.attrs);
|
rta_free(e->rte.attrs);
|
||||||
sl_free(e);
|
sl_free(e);
|
||||||
}
|
}
|
||||||
@ -538,8 +580,8 @@ rte_mergable(const rte *pri, const rte *sec)
|
|||||||
static void
|
static void
|
||||||
rte_trace(const char *name, const rte *e, int dir, const char *msg)
|
rte_trace(const char *name, const rte *e, int dir, const char *msg)
|
||||||
{
|
{
|
||||||
log(L_TRACE "%s %c %s %N src %luL %uG %uS id %u %s",
|
log(L_TRACE "%s %c %s %N (%u) src %luL %uG %uS id %u %s",
|
||||||
name, dir, msg, e->net,
|
name, dir, msg, e->net, NET_TO_INDEX(e->net)->index,
|
||||||
e->src->private_id, e->src->global_id, e->stale_cycle, e->id,
|
e->src->private_id, e->src->global_id, e->stale_cycle, e->id,
|
||||||
rta_dest_name(rte_dest(e)));
|
rta_dest_name(rte_dest(e)));
|
||||||
}
|
}
|
||||||
@ -1083,10 +1125,12 @@ rte_export(struct rt_table_export_hook *th, struct rt_pending_export *rpe)
|
|||||||
uint count = 0;
|
uint count = 0;
|
||||||
const rte **feed = NULL;
|
const rte **feed = NULL;
|
||||||
|
|
||||||
net *net = SKIP_BACK(struct network, n.addr, (net_addr (*)[0]) n);
|
const struct netindex *i = SKIP_BACK(struct netindex, addr, (net_addr (*)[0]) n);
|
||||||
|
|
||||||
RT_LOCKED(tab, tp)
|
RT_LOCKED(tab, tp)
|
||||||
{
|
{
|
||||||
|
ASSERT_DIE(i->index < tp->routes_block_size);
|
||||||
|
struct network *net = &tp->routes[i->index];
|
||||||
last = net->last;
|
last = net->last;
|
||||||
if (count = rte_feed_count(net))
|
if (count = rte_feed_count(net))
|
||||||
{
|
{
|
||||||
@ -1146,9 +1190,12 @@ ignore:
|
|||||||
* done outside of scope of rte_announce().
|
* done outside of scope of rte_announce().
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
rte_announce(struct rtable_private *tab, net *net, struct rte_storage *new, struct rte_storage *old,
|
rte_announce(struct rtable_private *tab, const struct netindex *i, net *net, struct rte_storage *new, struct rte_storage *old,
|
||||||
struct rte_storage *new_best, struct rte_storage *old_best)
|
struct rte_storage *new_best, struct rte_storage *old_best)
|
||||||
{
|
{
|
||||||
|
/* Update network count */
|
||||||
|
tab->net_count += (!!new_best - !!old_best);
|
||||||
|
|
||||||
int new_best_valid = rte_is_valid(RTE_OR_NULL(new_best));
|
int new_best_valid = rte_is_valid(RTE_OR_NULL(new_best));
|
||||||
int old_best_valid = rte_is_valid(RTE_OR_NULL(old_best));
|
int old_best_valid = rte_is_valid(RTE_OR_NULL(old_best));
|
||||||
|
|
||||||
@ -1167,7 +1214,7 @@ rte_announce(struct rtable_private *tab, net *net, struct rte_storage *new, stru
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
hmap_clear(&tab->id_map, old->rte.id);
|
hmap_clear(&tab->id_map, old->rte.id);
|
||||||
rte_free(old);
|
rte_free(old, tab);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1211,7 +1258,7 @@ rte_announce(struct rtable_private *tab, net *net, struct rte_storage *new, stru
|
|||||||
"old=%p id %u from %s, "
|
"old=%p id %u from %s, "
|
||||||
"new_best=%p id %u, "
|
"new_best=%p id %u, "
|
||||||
"old_best=%p id %u seq=%lu",
|
"old_best=%p id %u seq=%lu",
|
||||||
net->n.addr,
|
i->addr,
|
||||||
new, new ? new->rte.id : 0, new ? new->rte.sender->req->name : NULL,
|
new, new ? new->rte.id : 0, new ? new->rte.sender->req->name : NULL,
|
||||||
old, old ? old->rte.id : 0, old ? old->rte.sender->req->name : NULL,
|
old, old ? old->rte.id : 0, old ? old->rte.sender->req->name : NULL,
|
||||||
new_best, new_best ? new_best->rte.id : 0,
|
new_best, new_best ? new_best->rte.id : 0,
|
||||||
@ -1464,7 +1511,7 @@ rte_same(const rte *x, const rte *y)
|
|||||||
static inline int rte_is_ok(const rte *e) { return e && !rte_is_filtered(e); }
|
static inline int rte_is_ok(const rte *e) { return e && !rte_is_filtered(e); }
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net, rte *new, struct rte_src *src)
|
rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, struct netindex *i, net *net, rte *new, struct rte_src *src)
|
||||||
{
|
{
|
||||||
struct rt_import_request *req = c->req;
|
struct rt_import_request *req = c->req;
|
||||||
struct rt_import_stats *stats = &c->stats;
|
struct rt_import_stats *stats = &c->stats;
|
||||||
@ -1479,7 +1526,7 @@ rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net
|
|||||||
struct rte_storage *new_stored = NULL;
|
struct rte_storage *new_stored = NULL;
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
new_stored = rte_store(new, net, table);
|
new_stored = rte_store(new, i, table);
|
||||||
new = RTES_WRITE(new_stored);
|
new = RTES_WRITE(new_stored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1499,10 +1546,10 @@ rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net
|
|||||||
{
|
{
|
||||||
if (!old->generation && !new->generation)
|
if (!old->generation && !new->generation)
|
||||||
bug("Two protocols claim to author a route with the same rte_src in table %s: %N %s/%u:%u",
|
bug("Two protocols claim to author a route with the same rte_src in table %s: %N %s/%u:%u",
|
||||||
c->table->name, net->n.addr, old->src->owner->name, old->src->private_id, old->src->global_id);
|
c->table->name, i->addr, old->src->owner->name, old->src->private_id, old->src->global_id);
|
||||||
|
|
||||||
log_rl(&table->rl_pipe, L_ERR "Route source collision in table %s: %N %s/%u:%u",
|
log_rl(&table->rl_pipe, L_ERR "Route source collision in table %s: %N %s/%u:%u",
|
||||||
c->table->name, net->n.addr, old->src->owner->name, old->src->private_id, old->src->global_id);
|
c->table->name, i->addr, old->src->owner->name, old->src->private_id, old->src->global_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new && rte_same(old, &new_stored->rte))
|
if (new && rte_same(old, &new_stored->rte))
|
||||||
@ -1517,7 +1564,7 @@ rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We need to free the already stored route here before returning */
|
/* We need to free the already stored route here before returning */
|
||||||
rte_free(new_stored);
|
rte_free(new_stored, table);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1534,7 +1581,7 @@ rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net
|
|||||||
/* If rejected by import limit, we need to pretend there is no route */
|
/* If rejected by import limit, we need to pretend there is no route */
|
||||||
if (req->preimport && (req->preimport(req, new, old) == 0))
|
if (req->preimport && (req->preimport(req, new, old) == 0))
|
||||||
{
|
{
|
||||||
rte_free(new_stored);
|
rte_free(new_stored, table);
|
||||||
new_stored = NULL;
|
new_stored = NULL;
|
||||||
new = NULL;
|
new = NULL;
|
||||||
}
|
}
|
||||||
@ -1661,10 +1708,10 @@ rte_recalculate(struct rtable_private *table, struct rt_import_hook *c, net *net
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (req->trace_routes & D_ROUTES)
|
if (req->trace_routes & D_ROUTES)
|
||||||
log(L_TRACE "%s > ignored %N %s->%s", req->name, net->n.addr, old ? "filtered" : "none", new ? "filtered" : "none");
|
log(L_TRACE "%s > ignored %N %s->%s", req->name, i->addr, old ? "filtered" : "none", new ? "filtered" : "none");
|
||||||
|
|
||||||
/* Propagate the route change */
|
/* Propagate the route change */
|
||||||
rte_announce(table, net, new_stored, old_stored,
|
rte_announce(table, i, net, new_stored, old_stored,
|
||||||
net->routes, old_best_stored);
|
net->routes, old_best_stored);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -1792,20 +1839,27 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RT_LOCKED(hook->table, tab)
|
RT_LOCKED(hook->table, tab)
|
||||||
{
|
{
|
||||||
|
struct netindex *i;
|
||||||
net *nn;
|
net *nn;
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
/* Use the actual struct network, not the dummy one */
|
/* Allocate the key structure */
|
||||||
nn = net_get(tab, n);
|
i = net_get_index(tab->netindex, n);
|
||||||
new->net = nn->n.addr;
|
nn = net_get(tab, i);
|
||||||
|
new->net = i->addr;
|
||||||
new->sender = hook;
|
new->sender = hook;
|
||||||
|
|
||||||
/* Set the stale cycle */
|
/* Set the stale cycle */
|
||||||
new->stale_cycle = hook->stale_set;
|
new->stale_cycle = hook->stale_set;
|
||||||
}
|
}
|
||||||
else if (!(nn = net_find(tab, n)))
|
else if (i = net_find_index(tab->netindex, n))
|
||||||
|
{
|
||||||
|
nn = net_find(tab, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
req->hook->stats.withdraws_ignored++;
|
req->hook->stats.withdraws_ignored++;
|
||||||
if (req->trace_routes & D_ROUTES)
|
if (req->trace_routes & D_ROUTES)
|
||||||
@ -1814,7 +1868,7 @@ rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rt
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Recalculate the best route */
|
/* Recalculate the best route */
|
||||||
if (rte_recalculate(tab, hook, nn, new, src))
|
if (rte_recalculate(tab, hook, i, nn, new, src))
|
||||||
ev_send(req->list, &hook->announce_event);
|
ev_send(req->list, &hook->announce_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1827,7 +1881,8 @@ rt_examine(rtable *tp, net_addr *a, struct channel *c, const struct filter *filt
|
|||||||
|
|
||||||
RT_LOCKED(tp, t)
|
RT_LOCKED(tp, t)
|
||||||
{
|
{
|
||||||
net *n = net_find(t, a);
|
const struct netindex *i = net_find_index(t->netindex, a);
|
||||||
|
net *n = i ? net_find(t, i) : NULL;
|
||||||
if (n)
|
if (n)
|
||||||
rt = RTE_COPY_VALID(n->routes);
|
rt = RTE_COPY_VALID(n->routes);
|
||||||
}
|
}
|
||||||
@ -2030,7 +2085,7 @@ rt_table_export_start_feed(struct rtable_private *tab, struct rt_table_export_ho
|
|||||||
case TE_ADDR_NONE:
|
case TE_ADDR_NONE:
|
||||||
case TE_ADDR_TRIE:
|
case TE_ADDR_TRIE:
|
||||||
case TE_ADDR_HOOK:
|
case TE_ADDR_HOOK:
|
||||||
FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib);
|
hook->feed_index = 0;
|
||||||
hook->h.event.hook = rt_feed_by_fib;
|
hook->h.event.hook = rt_feed_by_fib;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2130,8 +2185,6 @@ rt_table_export_stop_locked(struct rt_export_hook *hh)
|
|||||||
case TE_ADDR_NONE:
|
case TE_ADDR_NONE:
|
||||||
case TE_ADDR_HOOK:
|
case TE_ADDR_HOOK:
|
||||||
case TE_ADDR_TRIE:
|
case TE_ADDR_TRIE:
|
||||||
fit_get(&tab->fib, &hook->feed_fit);
|
|
||||||
break;
|
|
||||||
case TE_ADDR_EQUAL:
|
case TE_ADDR_EQUAL:
|
||||||
case TE_ADDR_FOR:
|
case TE_ADDR_FOR:
|
||||||
break;
|
break;
|
||||||
@ -2219,13 +2272,10 @@ rt_refresh_begin(struct rt_import_request *req)
|
|||||||
log(L_WARN "Route refresh flood in table %s (stale_set=%u, stale_pruned=%u)", hook->table->name, hook->stale_set, hook->stale_pruned);
|
log(L_WARN "Route refresh flood in table %s (stale_set=%u, stale_pruned=%u)", hook->table->name, hook->stale_set, hook->stale_pruned);
|
||||||
|
|
||||||
/* Forcibly set all old routes' stale cycle to zero. */
|
/* Forcibly set all old routes' stale cycle to zero. */
|
||||||
FIB_WALK(&tab->fib, net, n)
|
for (u32 i=0; i<tab->routes_block_size; i++)
|
||||||
{
|
for (struct rte_storage *e = tab->routes[i].routes; e; e = e->next)
|
||||||
for (struct rte_storage *e = n->routes; e; e = e->next)
|
|
||||||
if (e->rte.sender == req->hook)
|
if (e->rte.sender == req->hook)
|
||||||
e->stale_cycle = 0;
|
e->stale_cycle = 0;
|
||||||
}
|
|
||||||
FIB_WALK_END;
|
|
||||||
|
|
||||||
/* Smash the route refresh counter and zero everything. */
|
/* Smash the route refresh counter and zero everything. */
|
||||||
tab->rr_counter -= hook->stale_set - hook->stale_pruned;
|
tab->rr_counter -= hook->stale_set - hook->stale_pruned;
|
||||||
@ -2314,15 +2364,9 @@ rt_dump(rtable *tp)
|
|||||||
{
|
{
|
||||||
|
|
||||||
debug("Dump of routing table <%s>%s\n", t->name, t->deleted ? " (deleted)" : "");
|
debug("Dump of routing table <%s>%s\n", t->name, t->deleted ? " (deleted)" : "");
|
||||||
#ifdef DEBUGGING
|
for (u32 i=0; i<t->routes_block_size; i++)
|
||||||
fib_check(&t->fib);
|
for (struct rte_storage *e = t->routes[i].routes; e; e = e->next)
|
||||||
#endif
|
|
||||||
FIB_WALK(&t->fib, net, n)
|
|
||||||
{
|
|
||||||
for(struct rte_storage *e=n->routes; e; e=e->next)
|
|
||||||
rte_dump(e);
|
rte_dump(e);
|
||||||
}
|
|
||||||
FIB_WALK_END;
|
|
||||||
debug("\n");
|
debug("\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2749,14 +2793,13 @@ rt_setup(pool *pp, struct rtable_config *cf)
|
|||||||
if (t->id >= rtable_max_id)
|
if (t->id >= rtable_max_id)
|
||||||
rtable_max_id = t->id + 1;
|
rtable_max_id = t->id + 1;
|
||||||
|
|
||||||
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
|
t->netindex = rt_global_netindex_hash;
|
||||||
|
t->routes = mb_allocz(p, (t->routes_block_size = 128) * sizeof(net));
|
||||||
|
|
||||||
if (cf->trie_used)
|
if (cf->trie_used)
|
||||||
{
|
{
|
||||||
t->trie = f_new_trie(lp_new_default(p), 0);
|
t->trie = f_new_trie(lp_new_default(p), 0);
|
||||||
t->trie->ipv4 = net_val_match(t->addr_type, NB_IP4 | NB_VPN4 | NB_ROA4);
|
t->trie->ipv4 = net_val_match(t->addr_type, NB_IP4 | NB_VPN4 | NB_ROA4);
|
||||||
|
|
||||||
t->fib.init = net_init_with_trie;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init_list(&t->imports);
|
init_list(&t->imports);
|
||||||
@ -2819,6 +2862,25 @@ rt_init(void)
|
|||||||
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
|
||||||
rt_cork.run = (event) { .hook = rt_cork_release_hook };
|
rt_cork.run = (event) { .hook = rt_cork_release_hook };
|
||||||
idm_init(&rtable_idm, rt_table_pool, 256);
|
idm_init(&rtable_idm, rt_table_pool, 256);
|
||||||
|
rt_global_netindex_hash = netindex_hash_new(rt_table_pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool
|
||||||
|
rt_prune_net(struct rtable_private *tab, struct network *n)
|
||||||
|
{
|
||||||
|
for (struct rte_storage *e = n->routes; e; e = e->next)
|
||||||
|
{
|
||||||
|
struct rt_import_hook *s = e->rte.sender;
|
||||||
|
if ((s->import_state == TIS_FLUSHING) ||
|
||||||
|
(e->rte.stale_cycle < s->stale_valid) ||
|
||||||
|
(e->rte.stale_cycle > s->stale_set))
|
||||||
|
{
|
||||||
|
struct netindex *i = RTE_GET_NETINDEX(&e->rte);
|
||||||
|
rte_recalculate(tab, e->rte.sender, i, n, NULL, e->rte.src);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2839,16 +2901,12 @@ rt_init(void)
|
|||||||
static void
|
static void
|
||||||
rt_prune_table(struct rtable_private *tab)
|
rt_prune_table(struct rtable_private *tab)
|
||||||
{
|
{
|
||||||
struct fib_iterator *fit = &tab->prune_fit;
|
|
||||||
int limit = 2000;
|
int limit = 2000;
|
||||||
|
|
||||||
struct rt_import_hook *ih;
|
struct rt_import_hook *ih;
|
||||||
node *n, *x;
|
node *n, *x;
|
||||||
|
|
||||||
rt_trace(tab, D_STATES, "Pruning");
|
rt_trace(tab, D_STATES, "Pruning");
|
||||||
#ifdef DEBUGGING
|
|
||||||
fib_check(&tab->fib);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (tab->prune_state == 0)
|
if (tab->prune_state == 0)
|
||||||
return;
|
return;
|
||||||
@ -2865,7 +2923,7 @@ rt_prune_table(struct rtable_private *tab)
|
|||||||
rt_refresh_trace(tab, ih, "table prune after refresh begin");
|
rt_refresh_trace(tab, ih, "table prune after refresh begin");
|
||||||
}
|
}
|
||||||
|
|
||||||
FIB_ITERATE_INIT(fit, &tab->fib);
|
tab->prune_index = 0;
|
||||||
tab->prune_state = 2;
|
tab->prune_state = 2;
|
||||||
|
|
||||||
tab->gc_counter = 0;
|
tab->gc_counter = 0;
|
||||||
@ -2879,53 +2937,32 @@ rt_prune_table(struct rtable_private *tab)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
again:
|
for (; tab->prune_index < tab->routes_block_size; tab->prune_index++)
|
||||||
FIB_ITERATE_START(&tab->fib, fit, net, n)
|
|
||||||
{
|
{
|
||||||
rescan:
|
net *n = &tab->routes[tab->prune_index];
|
||||||
|
if (!n->routes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
while ((limit > 0) && rt_prune_net(tab, n))
|
||||||
|
limit--;
|
||||||
|
|
||||||
if (limit <= 0)
|
if (limit <= 0)
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(fit);
|
|
||||||
birdloop_flag(tab->loop, RTF_CLEANUP);
|
birdloop_flag(tab->loop, RTF_CLEANUP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct rte_storage *e=n->routes; e; e=e->next)
|
if (tab->trie_new && n->routes)
|
||||||
{
|
{
|
||||||
struct rt_import_hook *s = e->rte.sender;
|
const net_addr *a = n->routes->rte.net;
|
||||||
if ((s->import_state == TIS_FLUSHING) ||
|
trie_add_prefix(tab->trie_new, a, a->pxlen, a->pxlen);
|
||||||
(e->rte.stale_cycle < s->stale_valid) ||
|
|
||||||
(e->rte.stale_cycle > s->stale_set))
|
|
||||||
{
|
|
||||||
rte_recalculate(tab, e->rte.sender, n, NULL, e->rte.src);
|
|
||||||
limit--;
|
|
||||||
|
|
||||||
goto rescan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!n->routes && !n->first) /* Orphaned FIB entry */
|
|
||||||
{
|
|
||||||
FIB_ITERATE_PUT(fit);
|
|
||||||
fib_delete(&tab->fib, n);
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab->trie_new)
|
|
||||||
{
|
|
||||||
trie_add_prefix(tab->trie_new, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
|
|
||||||
limit--;
|
limit--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FIB_ITERATE_END;
|
|
||||||
|
|
||||||
rt_trace(tab, D_EVENTS, "Prune done, scheduling export timer");
|
rt_trace(tab, D_EVENTS, "Prune done, scheduling export timer");
|
||||||
rt_kick_export_settle(tab);
|
rt_kick_export_settle(tab);
|
||||||
|
|
||||||
#ifdef DEBUGGING
|
|
||||||
fib_check(&tab->fib);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* state change 2->0, 3->1 */
|
/* state change 2->0, 3->1 */
|
||||||
if (tab->prune_state &= 1)
|
if (tab->prune_state &= 1)
|
||||||
birdloop_flag(tab->loop, RTF_CLEANUP);
|
birdloop_flag(tab->loop, RTF_CLEANUP);
|
||||||
@ -2953,7 +2990,7 @@ again:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Schedule prefix trie pruning */
|
/* Schedule prefix trie pruning */
|
||||||
if (tab->trie && !tab->trie_old && (tab->trie->prefix_count > (2 * tab->fib.entries)))
|
if (tab->trie && !tab->trie_old && (tab->trie->prefix_count > (2 * tab->net_count)))
|
||||||
{
|
{
|
||||||
/* state change 0->1, 2->3 */
|
/* state change 0->1, 2->3 */
|
||||||
tab->prune_state |= 1;
|
tab->prune_state |= 1;
|
||||||
@ -3064,7 +3101,9 @@ rt_export_cleanup(struct rtable_private *tab)
|
|||||||
const net_addr *n = first->new ?
|
const net_addr *n = first->new ?
|
||||||
first->new->rte.net :
|
first->new->rte.net :
|
||||||
first->old->rte.net;
|
first->old->rte.net;
|
||||||
net *net = SKIP_BACK(struct network, n.addr, (net_addr (*)[0]) n);
|
struct netindex *i = NET_TO_INDEX(n);
|
||||||
|
ASSERT_DIE(i->index < tab->routes_block_size);
|
||||||
|
net *net = &tab->routes[i->index];
|
||||||
|
|
||||||
ASSERT_DIE(net->first == first);
|
ASSERT_DIE(net->first == first);
|
||||||
|
|
||||||
@ -3082,7 +3121,7 @@ rt_export_cleanup(struct rtable_private *tab)
|
|||||||
{
|
{
|
||||||
rt_rte_trace_in(D_ROUTES, first->old->rte.sender->req, &first->old->rte, "freed");
|
rt_rte_trace_in(D_ROUTES, first->old->rte.sender->req, &first->old->rte, "freed");
|
||||||
hmap_clear(&tab->id_map, first->old->rte.id);
|
hmap_clear(&tab->id_map, first->old->rte.id);
|
||||||
rte_free(first->old);
|
rte_free(first->old, tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOCAL_DEBUG
|
#ifdef LOCAL_DEBUG
|
||||||
@ -3224,7 +3263,7 @@ rt_unlock_trie(struct rtable_private *tab, struct f_trie *trie)
|
|||||||
tab->trie_old = NULL;
|
tab->trie_old = NULL;
|
||||||
|
|
||||||
/* Kick prefix trie pruning that was postponed */
|
/* Kick prefix trie pruning that was postponed */
|
||||||
if (tab->trie && (tab->trie->prefix_count > (2 * tab->fib.entries)))
|
if (tab->trie && (tab->trie->prefix_count > (2 * tab->net_count)))
|
||||||
{
|
{
|
||||||
tab->prune_trie = 1;
|
tab->prune_trie = 1;
|
||||||
rt_kick_prune_timer(tab);
|
rt_kick_prune_timer(tab);
|
||||||
@ -3507,7 +3546,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, ea_list *
|
|||||||
{
|
{
|
||||||
rb = RTE_COPY_VALID(nb->routes);
|
rb = RTE_COPY_VALID(nb->routes);
|
||||||
rta_clone(rb.attrs);
|
rta_clone(rb.attrs);
|
||||||
net_copy(&nau.n, nb->n.addr);
|
net_copy(&nau.n, nb->routes->rte.net);
|
||||||
rb.net = &nau.n;
|
rb.net = &nau.n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3545,9 +3584,10 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, ea_list *
|
|||||||
/* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
|
/* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
|
||||||
RT_LOCKED(tab_ip, tip)
|
RT_LOCKED(tab_ip, tip)
|
||||||
{
|
{
|
||||||
|
NH_LOCK(tip->netindex, nh);
|
||||||
TRIE_WALK(tip->trie, subnet, &dst)
|
TRIE_WALK(tip->trie, subnet, &dst)
|
||||||
{
|
{
|
||||||
net *nc = net_find_valid(tip, &subnet);
|
net *nc = net_find_valid(tip, nh, &subnet);
|
||||||
if (!nc)
|
if (!nc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -3624,10 +3664,10 @@ rt_flowspec_resolve_rte(rte *r, struct channel *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
rt_next_hop_update_net(struct rtable_private *tab, net *n)
|
rt_next_hop_update_net(struct rtable_private *tab, struct netindex *ni, net *n)
|
||||||
{
|
{
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
int is_flow = net_is_flow(n->n.addr);
|
int is_flow = net_val_match(tab->addr_type, NB_FLOW);
|
||||||
|
|
||||||
struct rte_storage *old_best = n->routes;
|
struct rte_storage *old_best = n->routes;
|
||||||
if (!old_best)
|
if (!old_best)
|
||||||
@ -3678,7 +3718,7 @@ rt_next_hop_update_net(struct rtable_private *tab, net *n)
|
|||||||
|
|
||||||
/* Something has changed inbetween, retry NHU. */
|
/* Something has changed inbetween, retry NHU. */
|
||||||
if (last_pending != n->last)
|
if (last_pending != n->last)
|
||||||
return rt_next_hop_update_net(tab, n);
|
return rt_next_hop_update_net(tab, ni, n);
|
||||||
|
|
||||||
/* Now we reconstruct the original linked list */
|
/* Now we reconstruct the original linked list */
|
||||||
struct rte_storage **nptr = &n->routes;
|
struct rte_storage **nptr = &n->routes;
|
||||||
@ -3688,7 +3728,7 @@ rt_next_hop_update_net(struct rtable_private *tab, net *n)
|
|||||||
|
|
||||||
struct rte_storage *put;
|
struct rte_storage *put;
|
||||||
if (updates[i].new.attrs)
|
if (updates[i].new.attrs)
|
||||||
put = updates[i].new_stored = rte_store(&updates[i].new, n, tab);
|
put = updates[i].new_stored = rte_store(&updates[i].new, ni, tab);
|
||||||
else
|
else
|
||||||
put = updates[i].old;
|
put = updates[i].old;
|
||||||
|
|
||||||
@ -3753,7 +3793,7 @@ rt_next_hop_update_net(struct rtable_private *tab, net *n)
|
|||||||
{ "autoupdated [+best]", "autoupdated [best]" }
|
{ "autoupdated [+best]", "autoupdated [best]" }
|
||||||
};
|
};
|
||||||
rt_rte_trace_in(D_ROUTES, updates[i].new.sender->req, &updates[i].new, best_indicator[nb][ob]);
|
rt_rte_trace_in(D_ROUTES, updates[i].new.sender->req, &updates[i].new, best_indicator[nb][ob]);
|
||||||
rte_announce(tab, n, updates[i].new_stored, updates[i].old, new, old_best);
|
rte_announce(tab, ni, n, updates[i].new_stored, updates[i].old, new, old_best);
|
||||||
|
|
||||||
total++;
|
total++;
|
||||||
}
|
}
|
||||||
@ -3802,13 +3842,12 @@ rt_next_hop_update(struct rtable_private *tab)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fib_iterator *fit = &tab->nhu_fit;
|
|
||||||
int max_feed = 32;
|
int max_feed = 32;
|
||||||
|
|
||||||
/* Initialize a new run */
|
/* Initialize a new run */
|
||||||
if (tab->nhu_state == NHU_SCHEDULED)
|
if (tab->nhu_state == NHU_SCHEDULED)
|
||||||
{
|
{
|
||||||
FIB_ITERATE_INIT(fit, &tab->fib);
|
tab->nhu_index = 0;
|
||||||
tab->nhu_state = NHU_RUNNING;
|
tab->nhu_state = NHU_RUNNING;
|
||||||
|
|
||||||
if (tab->flowspec_trie)
|
if (tab->flowspec_trie)
|
||||||
@ -3816,18 +3855,21 @@ rt_next_hop_update(struct rtable_private *tab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Walk the fib one net after another */
|
/* Walk the fib one net after another */
|
||||||
FIB_ITERATE_START(&tab->fib, fit, net, n)
|
for (; tab->nhu_index < tab->routes_block_size; tab->nhu_index++)
|
||||||
{
|
{
|
||||||
|
net *n = &tab->routes[tab->nhu_index];
|
||||||
|
if (!n->routes)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (max_feed <= 0)
|
if (max_feed <= 0)
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(fit);
|
|
||||||
birdloop_flag(tab->loop, RTF_NHU);
|
birdloop_flag(tab->loop, RTF_NHU);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TMP_SAVED
|
TMP_SAVED
|
||||||
max_feed -= rt_next_hop_update_net(tab, n);
|
max_feed -= rt_next_hop_update_net(tab, RTE_GET_NETINDEX(&n->routes->rte), n);
|
||||||
}
|
}
|
||||||
FIB_ITERATE_END;
|
|
||||||
|
|
||||||
/* Finished NHU, cleanup */
|
/* Finished NHU, cleanup */
|
||||||
rt_trace(tab, D_EVENTS, "NHU done, scheduling export timer");
|
rt_trace(tab, D_EVENTS, "NHU done, scheduling export timer");
|
||||||
@ -4204,7 +4246,6 @@ static void
|
|||||||
rt_feed_by_fib(void *data)
|
rt_feed_by_fib(void *data)
|
||||||
{
|
{
|
||||||
struct rt_table_export_hook *c = data;
|
struct rt_table_export_hook *c = data;
|
||||||
struct fib_iterator *fit = &c->feed_fit;
|
|
||||||
rt_feed_block block = {};
|
rt_feed_block block = {};
|
||||||
|
|
||||||
_Bool done = 1;
|
_Bool done = 1;
|
||||||
@ -4214,21 +4255,24 @@ rt_feed_by_fib(void *data)
|
|||||||
RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, exporter, c->table)), tab)
|
RT_LOCKED(RT_PUB(SKIP_BACK(struct rtable_private, exporter, c->table)), tab)
|
||||||
{
|
{
|
||||||
|
|
||||||
FIB_ITERATE_START(&tab->fib, fit, net, n)
|
for (; c->feed_index < tab->routes_block_size; c->feed_index++)
|
||||||
{
|
{
|
||||||
if (rt_prefilter_net(&c->h.req->prefilter, n->n.addr))
|
net *n = &tab->routes[c->feed_index];
|
||||||
|
if (!n->routes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const net_addr *a = n->routes->rte.net;
|
||||||
|
if (rt_prefilter_net(&c->h.req->prefilter, a))
|
||||||
{
|
{
|
||||||
if (!rt_prepare_feed(c, n, &block))
|
if (!rt_prepare_feed(c, n, &block))
|
||||||
{
|
{
|
||||||
FIB_ITERATE_PUT(fit);
|
|
||||||
done = 0;
|
done = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
req_trace(c->h.req, D_ROUTES, "Feeding %N rejected by prefilter", n->n.addr);
|
req_trace(c->h.req, D_ROUTES, "Feeding %N rejected by prefilter", a);
|
||||||
}
|
}
|
||||||
FIB_ITERATE_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_process_feed(c, &block);
|
rt_process_feed(c, &block);
|
||||||
@ -4257,7 +4301,8 @@ rt_feed_by_trie(void *data)
|
|||||||
if (!c->walk_last.type)
|
if (!c->walk_last.type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
net *n = net_find(tab, &c->walk_last);
|
const struct netindex *i = net_find_index(tab->netindex, &c->walk_last);
|
||||||
|
net *n = i ? net_find(tab, i) : NULL;
|
||||||
if (!n)
|
if (!n)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -4294,7 +4339,8 @@ rt_feed_equal(void *data)
|
|||||||
ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING);
|
ASSERT_DIE(atomic_load_explicit(&c->h.export_state, memory_order_relaxed) == TES_FEEDING);
|
||||||
ASSERT_DIE(c->h.req->prefilter.mode == TE_ADDR_EQUAL);
|
ASSERT_DIE(c->h.req->prefilter.mode == TE_ADDR_EQUAL);
|
||||||
|
|
||||||
if (n = net_find(tab, c->h.req->prefilter.addr))
|
const struct netindex *i = net_find_index(tab->netindex, c->h.req->prefilter.addr);
|
||||||
|
if (i && (n = net_find(tab, i)))
|
||||||
ASSERT_DIE(rt_prepare_feed(c, n, &block));
|
ASSERT_DIE(rt_prepare_feed(c, n, &block));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4603,11 +4649,11 @@ rt_update_hostentry(struct rtable_private *tab, struct hostentry *he)
|
|||||||
{
|
{
|
||||||
/* Recursive route should not depend on another recursive route */
|
/* Recursive route should not depend on another recursive route */
|
||||||
log(L_WARN "Next hop address %I resolvable through recursive route for %N",
|
log(L_WARN "Next hop address %I resolvable through recursive route for %N",
|
||||||
he->addr, n->n.addr);
|
he->addr, ee->rte.net);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxlen = n->n.addr->pxlen;
|
pxlen = e->rte.net->pxlen;
|
||||||
|
|
||||||
eattr *nhea = ea_find(a, &ea_gen_nexthop);
|
eattr *nhea = ea_find(a, &ea_gen_nexthop);
|
||||||
ASSERT_DIE(nhea);
|
ASSERT_DIE(nhea);
|
||||||
|
@ -369,7 +369,7 @@ rte_feed_obtain_valid(net *n, const rte **feed, uint count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct rte *
|
static struct rte *
|
||||||
krt_export_net(struct krt_proto *p, net *net)
|
krt_export_net(struct krt_proto *p, struct netindex *i, net *net)
|
||||||
{
|
{
|
||||||
/* FIXME: Here we are calling filters in table-locked context when exporting
|
/* FIXME: Here we are calling filters in table-locked context when exporting
|
||||||
* to kernel. Here BIRD can crash if the user requested ROA check in kernel
|
* to kernel. Here BIRD can crash if the user requested ROA check in kernel
|
||||||
@ -389,7 +389,7 @@ krt_export_net(struct krt_proto *p, net *net)
|
|||||||
|
|
||||||
const rte **feed = alloca(count * sizeof(rte *));
|
const rte **feed = alloca(count * sizeof(rte *));
|
||||||
rte_feed_obtain_valid(net, feed, count);
|
rte_feed_obtain_valid(net, feed, count);
|
||||||
return rt_export_merged(c, net->n.addr, feed, count, krt_filter_lp, 1);
|
return rt_export_merged(c, i->addr, feed, count, krt_filter_lp, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _Thread_local rte rt;
|
static _Thread_local rte rt;
|
||||||
@ -477,11 +477,12 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
|||||||
if (!p->ready)
|
if (!p->ready)
|
||||||
goto ignore;
|
goto ignore;
|
||||||
|
|
||||||
net *net = net_find(tab, e->net);
|
struct netindex *i = net_find_index(tab->netindex, e->net);
|
||||||
|
net *net = i ? net_find(tab, i) : NULL;
|
||||||
if (!net || !krt_is_installed(p, net))
|
if (!net || !krt_is_installed(p, net))
|
||||||
goto delete;
|
goto delete;
|
||||||
|
|
||||||
new = krt_export_net(p, net);
|
new = krt_export_net(p, i, net);
|
||||||
|
|
||||||
/* Rejected by filters */
|
/* Rejected by filters */
|
||||||
if (!new)
|
if (!new)
|
||||||
@ -542,22 +543,26 @@ krt_prune(struct krt_proto *p)
|
|||||||
{
|
{
|
||||||
|
|
||||||
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
|
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
|
||||||
FIB_WALK(&t->fib, net, n)
|
for (u32 i = 0; i < t->routes_block_size; i++)
|
||||||
{
|
{
|
||||||
|
net *n = &t->routes[i];
|
||||||
|
if (!n->routes)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->rte.id))
|
if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->rte.id))
|
||||||
{
|
{
|
||||||
rte *new = krt_export_net(p, n);
|
struct netindex *ni = RTE_GET_NETINDEX(&n->routes->rte);
|
||||||
|
rte *new = krt_export_net(p, ni, n);
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
krt_trace_in(p, new, "installing");
|
krt_trace_in(p, new, "installing");
|
||||||
krt_replace_rte(p, n->n.addr, new, NULL);
|
krt_replace_rte(p, new->net, new, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_flush(krt_filter_lp);
|
lp_flush(krt_filter_lp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
|
||||||
|
|
||||||
if (p->ready)
|
if (p->ready)
|
||||||
p->initialized = 1;
|
p->initialized = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user