mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Merged export moved after out_table
This commit is contained in:
parent
ef95b3c7c8
commit
a89cf0525a
@ -230,7 +230,7 @@ struct proto {
|
||||
|
||||
int (*rte_recalculate)(struct rtable *, struct network *, struct rte_storage *, struct rte_storage *, struct rte_storage *);
|
||||
int (*rte_better)(struct rte_storage *, struct rte_storage *);
|
||||
int (*rte_mergable)(struct rte_storage *, struct rte_storage *);
|
||||
int (*rte_mergable)(struct rte, struct rte);
|
||||
struct rta *(*rte_modify)(struct rte_storage *, struct linpool *);
|
||||
void (*rte_insert)(struct network *, struct rte_storage *);
|
||||
void (*rte_remove)(struct network *, struct rte_storage *);
|
||||
@ -491,7 +491,7 @@ struct channel_config {
|
||||
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
|
||||
u16 preference; /* Default route preference */
|
||||
u32 debug; /* Debugging flags (D_*) */
|
||||
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
|
||||
u8 merge_limit; /* Maximal number of nexthops for merging */
|
||||
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
|
||||
u8 rpki_reload; /* RPKI changes trigger channel reload */
|
||||
};
|
||||
@ -523,7 +523,7 @@ struct channel {
|
||||
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
|
||||
u16 preference; /* Default route preference */
|
||||
u32 debug; /* Debugging flags (D_*) */
|
||||
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
|
||||
u8 merge_limit; /* Maximal number of nexthops for merging */
|
||||
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
|
||||
u8 disabled;
|
||||
u8 stale; /* Used in reconfiguration */
|
||||
|
19
nest/route.h
19
nest/route.h
@ -231,6 +231,8 @@ typedef struct rte {
|
||||
struct rta *attrs; /* Attributes of this route */
|
||||
const net_addr *net; /* Network this RTE belongs to */
|
||||
struct rte_src *src; /* Route source that created the route */
|
||||
byte flags; /* Flags (REF_...) */
|
||||
byte pflags; /* Protocol-specific flags */
|
||||
} rte;
|
||||
|
||||
struct rte_storage {
|
||||
@ -251,6 +253,7 @@ struct rte_storage {
|
||||
#define REF_STALE 4 /* Route is stale in a refresh cycle */
|
||||
#define REF_DISCARD 8 /* Route is scheduled for discard */
|
||||
#define REF_MODIFY 16 /* Route is scheduled for modify */
|
||||
#define REF_E_MERGED 32 /* Route has been merged on export */
|
||||
|
||||
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
|
||||
static inline int rte_is_valid(const struct rte_storage *r) { return r && !(r->flags & REF_FILTERED); }
|
||||
@ -288,7 +291,6 @@ struct rte_export {
|
||||
#define RA_OPTIMAL 1 /* Announcement of optimal route change */
|
||||
#define RA_ACCEPTED 2 /* Announcement of first accepted route */
|
||||
#define RA_ANY 3 /* Announcement of any route change */
|
||||
#define RA_MERGED 4 /* Announcement of optimal route merged with next ones */
|
||||
|
||||
/* Return value of preexport() callback */
|
||||
#define RIC_ACCEPT 1 /* Accepted by protocol */
|
||||
@ -348,7 +350,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
|
||||
void *net_route(rtable *tab, const net_addr *n);
|
||||
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
|
||||
struct rte_storage *rte_find(net *net, struct rte_src *src);
|
||||
_Bool rt_export_merged(struct channel *c, net *net, rte *best, linpool *pool, int silent);
|
||||
rte rte_get_merged(net *n, linpool *p, u32 limit);
|
||||
void rt_refresh_begin(rtable *t, struct channel *c);
|
||||
void rt_refresh_end(rtable *t, struct channel *c);
|
||||
void rt_modify_stale(rtable *t, struct channel *c);
|
||||
@ -358,7 +360,15 @@ void rte_free(struct rte_storage *);
|
||||
struct rte_storage *rte_store(const rte *, net *n);
|
||||
void rte_copy_metadata(struct rte_storage *dest, struct rte_storage *src);
|
||||
static inline rte rte_copy(const struct rte_storage *r)
|
||||
{ return (rte) { .attrs = r->attrs, .net = r->net->n.addr, .src = r->src }; }
|
||||
{
|
||||
return r ? (rte) {
|
||||
.attrs = r->attrs,
|
||||
.net = r->net->n.addr,
|
||||
.src = r->src,
|
||||
.flags = r->flags,
|
||||
.pflags = r->pflags
|
||||
} : (rte) {};
|
||||
}
|
||||
void rt_dump(rtable *);
|
||||
void rt_dump_all(void);
|
||||
int rt_feed_channel(struct channel *c);
|
||||
@ -367,10 +377,9 @@ void rt_feed_channel_abort(struct channel *c);
|
||||
int rt_reload_channel(struct channel *c);
|
||||
void rt_reload_channel_abort(struct channel *c);
|
||||
void rt_prune_sync(rtable *t, int all);
|
||||
int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed);
|
||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||
void rt_out_sync_start(struct channel *c);
|
||||
_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e);
|
||||
_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e, linpool *p);
|
||||
void rt_out_sync_finish(struct channel *c);
|
||||
void rt_out_flush(struct channel *c);
|
||||
|
||||
|
@ -133,25 +133,26 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||
|
||||
if (d->export_mode == RSEM_EXPORTED)
|
||||
{
|
||||
if (!bmap_test(&ec->export_map, er->id))
|
||||
if (ec->merge_limit > 1)
|
||||
{
|
||||
pass = 1;
|
||||
e = rte_get_merged(n, c->show_pool, ec->merge_limit);
|
||||
if (!e.attrs)
|
||||
goto skip;
|
||||
}
|
||||
else if (!bmap_test(&ec->export_map, er->id))
|
||||
goto skip;
|
||||
|
||||
|
||||
// if (ec->ra_mode != RA_ANY)
|
||||
// pass = 1;
|
||||
}
|
||||
else if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
|
||||
{
|
||||
/* Special case for merged export */
|
||||
pass = 1;
|
||||
if (!rt_export_merged(ec, n, &e, c->show_pool, 1))
|
||||
goto skip;
|
||||
}
|
||||
else if (d->export_mode)
|
||||
{
|
||||
struct proto *ep = ec->proto;
|
||||
int ic = ep->preexport ? ep->preexport(ec, &e) : 0;
|
||||
|
||||
if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
|
||||
if (ec->ra_mode == RA_OPTIMAL)
|
||||
pass = 1;
|
||||
|
||||
if (ic < 0)
|
||||
@ -230,7 +231,15 @@ rt_show_cont(struct cli *c)
|
||||
|
||||
if (!d->table_open)
|
||||
{
|
||||
FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib);
|
||||
if (d->export_mode == RSEM_EXPORTED &&
|
||||
d->tab->export_channel &&
|
||||
d->tab->export_channel->out_table)
|
||||
fib = &d->tab->export_channel->out_table->fib;
|
||||
else
|
||||
fib = &d->tab->table->fib;
|
||||
|
||||
FIB_ITERATE_INIT(&d->fit, fib);
|
||||
|
||||
d->table_open = 1;
|
||||
d->table_counter++;
|
||||
d->kernel = rt_show_get_kernel(d);
|
||||
@ -410,10 +419,12 @@ rt_show(struct rt_show_data *d)
|
||||
d->tab = tab;
|
||||
d->kernel = rt_show_get_kernel(d);
|
||||
|
||||
struct rtable *rt = (d->export_mode == RSEM_EXPORTED) ? tab->export_channel->out_table : tab->table;
|
||||
|
||||
if (d->show_for)
|
||||
n = net_route(tab->table, d->addr);
|
||||
n = net_route(rt, d->addr);
|
||||
else
|
||||
n = net_find(tab->table, d->addr);
|
||||
n = net_find(rt, d->addr);
|
||||
|
||||
if (n)
|
||||
rt_show_net(this_cli, n, d);
|
||||
|
302
nest/rt-table.c
302
nest/rt-table.c
@ -68,13 +68,15 @@ static linpool *rte_update_pool;
|
||||
|
||||
list routing_tables;
|
||||
|
||||
struct rte_export_internal;
|
||||
|
||||
static void rt_free_hostcache(rtable *tab);
|
||||
static void rt_notify_hostcache(rtable *tab, net *net);
|
||||
static void rt_update_hostcache(rtable *tab);
|
||||
static void rt_next_hop_update(rtable *tab);
|
||||
static inline void rt_prune_table(rtable *tab);
|
||||
static inline void rt_schedule_notify(rtable *tab);
|
||||
|
||||
static int rte_update_out(struct channel *c, struct rte_export_internal *e);
|
||||
|
||||
/* Like fib_route(), but skips empty net entries */
|
||||
static inline void *
|
||||
@ -392,20 +394,20 @@ rte_better(struct rte_storage *new, struct rte_storage *old)
|
||||
}
|
||||
|
||||
static int
|
||||
rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
rte_mergable(struct rte pri, struct rte sec)
|
||||
{
|
||||
int (*mergable)(struct rte_storage *, struct rte_storage *);
|
||||
int (*mergable)(struct rte, struct rte);
|
||||
|
||||
if (!rte_is_valid(pri) || !rte_is_valid(sec))
|
||||
ASSERT_DIE(pri.attrs);
|
||||
ASSERT_DIE(sec.attrs);
|
||||
|
||||
if (pri.attrs->pref != sec.attrs->pref)
|
||||
return 0;
|
||||
|
||||
if (pri->attrs->pref != sec->attrs->pref)
|
||||
if (pri.src->proto->proto != sec.src->proto->proto)
|
||||
return 0;
|
||||
|
||||
if (pri->src->proto->proto != sec->src->proto->proto)
|
||||
return 0;
|
||||
|
||||
if (mergable = pri->src->proto->rte_mergable)
|
||||
if (mergable = pri.src->proto->rte_mergable)
|
||||
return mergable(pri, sec);
|
||||
|
||||
return 0;
|
||||
@ -617,93 +619,33 @@ nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max)
|
||||
return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool);
|
||||
}
|
||||
|
||||
_Bool
|
||||
rt_export_merged(struct channel *c, net *net, rte *best, linpool *pool, int silent)
|
||||
rte
|
||||
rte_get_merged(net *net, linpool *pool, uint limit)
|
||||
{
|
||||
// struct proto *p = c->proto;
|
||||
if (!net->routes || !(net->routes->flags & REF_E_MERGED))
|
||||
return (rte) {};
|
||||
|
||||
struct nexthop *nhs = NULL;
|
||||
struct rte_storage *best0 = net->routes;
|
||||
struct rte e = rte_copy(net->routes);
|
||||
|
||||
if (!rte_is_valid(best0))
|
||||
return 0;
|
||||
|
||||
*best = rte_copy(best0);
|
||||
if (export_filter_(c, best, best0->id, pool, silent) >= EFR_FILTER_REJECT)
|
||||
/* Best route doesn't pass the filter */
|
||||
return 0;
|
||||
|
||||
if (!rte_is_reachable(best))
|
||||
/* Unreachable routes can't be merged */
|
||||
return 1;
|
||||
|
||||
for (struct rte_storage *rt0 = best0->next; rt0; rt0 = rt0->next)
|
||||
for (struct rte_storage *rt0 = net->routes->next; rt0; rt0 = rt0->next)
|
||||
{
|
||||
if (!rte_mergable(best0, rt0))
|
||||
if (!(rt0->flags & REF_E_MERGED))
|
||||
continue;
|
||||
|
||||
struct rte tmp = rte_copy(rt0);
|
||||
if (export_filter_(c, &tmp, rt0->id, pool, 1) >= EFR_FILTER_REJECT)
|
||||
continue;
|
||||
|
||||
if (!rte_is_reachable(&tmp))
|
||||
continue;
|
||||
|
||||
nhs = nexthop_merge_rta(nhs, tmp.attrs, pool, c->merge_limit);
|
||||
nhs = nexthop_merge_rta(nhs, rte_copy(rt0).attrs, pool, limit);
|
||||
}
|
||||
|
||||
if (nhs)
|
||||
{
|
||||
nhs = nexthop_merge_rta(nhs, best->attrs, pool, c->merge_limit);
|
||||
|
||||
nhs = nexthop_merge_rta(nhs, e.attrs, pool, limit);
|
||||
if (nhs->next)
|
||||
best->attrs = rta_cow(best->attrs, pool);
|
||||
e.attrs = rta_cow(e.attrs, pool);
|
||||
|
||||
nexthop_link(best->attrs, nhs);
|
||||
nexthop_link(e.attrs, nhs);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
USE_RESULT static _Bool
|
||||
rt_notify_merged(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
/* We assume that all rte arguments are either NULL or rte_is_valid() */
|
||||
|
||||
/* This check should be done by the caller */
|
||||
if (!e->new_best && !e->old_best)
|
||||
return 0;
|
||||
|
||||
/* Check whether the change is relevant to the merged route */
|
||||
if ((e->new_best == e->old_best) &&
|
||||
(e->new != e->old) &&
|
||||
!rte_mergable(e->new_best, e->new) &&
|
||||
!rte_mergable(e->old_best, e->old))
|
||||
return 0;
|
||||
|
||||
if (e->new_best)
|
||||
c->stats.exp_updates_received++;
|
||||
else
|
||||
c->stats.exp_withdraws_received++;
|
||||
|
||||
struct rte_export *ep = &e->pub;
|
||||
|
||||
/* Prepare new merged route */
|
||||
if (e->new_best)
|
||||
{
|
||||
ep->new_id = e->new_best->id;
|
||||
if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0))
|
||||
ep->new.attrs = NULL;
|
||||
}
|
||||
|
||||
/* Check old merged route */
|
||||
if (e->old_best && bmap_test(&c->export_map, e->old_best->id))
|
||||
{
|
||||
ep->old_id = e->old_best->id;
|
||||
ep->old = rte_copy(e->old_best);
|
||||
}
|
||||
|
||||
return RTE_EXPORT_IS_OK(ep);
|
||||
return e;
|
||||
}
|
||||
|
||||
static struct rte_export *
|
||||
@ -729,10 +671,6 @@ rte_export_obtain(struct channel *c, struct rte_export_internal *e)
|
||||
accepted = rt_notify_accepted(c, e);
|
||||
break;
|
||||
|
||||
case RA_MERGED:
|
||||
accepted = rt_notify_merged(c, e);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Strange channel route announcement mode");
|
||||
}
|
||||
@ -774,7 +712,7 @@ rte_export_store(struct channel *c, struct rte_export_internal *e)
|
||||
/* Apply export table */
|
||||
if (c->out_table)
|
||||
{
|
||||
if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->pub.new_id, e->refeed))
|
||||
if (!rte_update_out(c, e))
|
||||
return 0;
|
||||
}
|
||||
else if (c->out_filter != FILTER_ACCEPT)
|
||||
@ -938,7 +876,7 @@ rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct r
|
||||
.new = new, .old = old,
|
||||
.new_best = new_best, .old_best = old_best,
|
||||
};
|
||||
|
||||
|
||||
rte_export(c, &rei);
|
||||
}
|
||||
}
|
||||
@ -2477,106 +2415,164 @@ rt_prune_sync(rtable *t, int all)
|
||||
* Export table
|
||||
*/
|
||||
|
||||
int
|
||||
rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed)
|
||||
static int
|
||||
rte_update_out(struct channel *c, struct rte_export_internal *e)
|
||||
{
|
||||
struct rtable *tab = c->out_table;
|
||||
struct rte_storage **pos;
|
||||
net *net;
|
||||
|
||||
rte *new = &e->pub.new;
|
||||
rte *old = &e->pub.old;
|
||||
|
||||
_Bool new_is_best = (e->new == e->new_best);
|
||||
_Bool old_is_best = (e->old == e->old_best);
|
||||
_Bool merging = c->merge_limit > 1;
|
||||
|
||||
if (new->attrs)
|
||||
{
|
||||
net = net_get(tab, new->net);
|
||||
|
||||
if (!rta_is_cached(new->attrs))
|
||||
new->attrs = rta_lookup(new->attrs);
|
||||
}
|
||||
else
|
||||
{
|
||||
net = net_find(tab, old->net);
|
||||
|
||||
if (!net)
|
||||
goto drop_withdraw;
|
||||
net = net_get(tab, new->net);
|
||||
}
|
||||
else if (!(net = net_find(tab, old->net)))
|
||||
return 0;
|
||||
|
||||
/* Find the old rte */
|
||||
/* Find the old rte if exists */
|
||||
for (pos = &net->routes; *pos; pos = &(*pos)->next)
|
||||
if ((c->ra_mode != RA_ANY) || ((*pos)->src == old->src))
|
||||
{
|
||||
if (new && rte_same(*pos, new, 0))
|
||||
{
|
||||
/* REF_STALE / REF_DISCARD not used in export table */
|
||||
/*
|
||||
if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
|
||||
{
|
||||
old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
goto drop_update;
|
||||
}
|
||||
|
||||
/* Keep the old rte */
|
||||
*old_stored = *pos;
|
||||
*old = rte_copy(*pos);
|
||||
|
||||
/* Remove the old rte from the list */
|
||||
*pos = (*pos)->next;
|
||||
tab->rt_count--;
|
||||
|
||||
if ((c->ra_mode != RA_ANY) || ((*pos)->src == new->src))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new->attrs)
|
||||
/* Found exactly the same route, no update needed */
|
||||
if ((*pos) && new->attrs && rte_same(*pos, new, 0))
|
||||
return 0;
|
||||
|
||||
/* Are the new/old routes mergable with the old_best? */
|
||||
struct rte_storage *best_stored =
|
||||
(!merging || net->routes && (net->routes->flags & REF_E_MERGED))
|
||||
? net->routes : NULL;
|
||||
|
||||
_Bool best_changed = new_is_best || old_is_best;
|
||||
|
||||
_Bool new_mergable_with_best_stored =
|
||||
!best_changed &&
|
||||
new->attrs && best_stored &&
|
||||
rte_mergable(rte_copy(best_stored), *new);
|
||||
|
||||
_Bool gen_old = merging ?
|
||||
best_changed ||
|
||||
(*pos) && ((*pos)->flags & REF_E_MERGED) ||
|
||||
new_mergable_with_best_stored
|
||||
: 0;
|
||||
|
||||
if (gen_old)
|
||||
/* Reconstruct the old merged rte completely. It's gonna change */
|
||||
*old = rte_get_merged(net, rte_update_pool, c->merge_limit);
|
||||
else if (!merging && *pos)
|
||||
/* A plain old route */
|
||||
*old = rte_copy(*pos);
|
||||
|
||||
/* Keep the old_stored but remove it from the list */
|
||||
tab->rt_count--;
|
||||
e->old_stored = *pos;
|
||||
if (*pos)
|
||||
*pos = (*pos)->next;
|
||||
|
||||
/* Idempotent withdraw */
|
||||
if (!e->old_stored && !new->attrs)
|
||||
return 0;
|
||||
|
||||
/* Best route must be inserted to the beginning */
|
||||
if (merging)
|
||||
{
|
||||
if (!*old_stored)
|
||||
goto drop_withdraw;
|
||||
if (new_is_best)
|
||||
pos = &net->routes;
|
||||
else if (old_is_best && (c->ra_mode == RA_ANY))
|
||||
{
|
||||
/* We have to find the new best route and put it first */
|
||||
for (pos = &net->routes; *pos; pos = &(*pos)->next)
|
||||
if ((c->ra_mode != RA_ANY) || ((*pos)->src == e->new_best->src))
|
||||
break;
|
||||
|
||||
return 1;
|
||||
if (best_stored = *pos)
|
||||
{
|
||||
*pos = best_stored->next;
|
||||
best_stored->next = net->routes;
|
||||
net->routes = best_stored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the new rte */
|
||||
if (new->attrs)
|
||||
{
|
||||
struct rte_storage *es = rte_store(new, net);
|
||||
es->sender = c;
|
||||
es->lastmod = current_time();
|
||||
es->id = e->new->id;
|
||||
es->next = *pos;
|
||||
*pos = es;
|
||||
tab->rt_count++;
|
||||
|
||||
if (new_is_best)
|
||||
best_stored = es;
|
||||
else if (!best_changed && new_mergable_with_best_stored)
|
||||
es->flags |= REF_E_MERGED;
|
||||
}
|
||||
|
||||
if (merging)
|
||||
{
|
||||
if (best_stored)
|
||||
best_stored->flags |= REF_E_MERGED;
|
||||
|
||||
ASSERT_DIE(best_stored == net->routes);
|
||||
|
||||
/* Recalculate REF_E_MERGED for other routes */
|
||||
if (best_changed && net->routes)
|
||||
for (struct rte_storage *rt0 = best_stored ? net->routes->next : net->routes; rt0; rt0 = rt0->next)
|
||||
if (best_stored && rte_mergable(rte_copy(best_stored), rte_copy(rt0)))
|
||||
rt0->flags |= REF_E_MERGED;
|
||||
else
|
||||
rt0->flags &= ~REF_E_MERGED;
|
||||
|
||||
if (!gen_old)
|
||||
/* Not mergable before nor after, no update generated at all. */
|
||||
return 0;
|
||||
|
||||
*new = rte_get_merged(net, rte_update_pool, c->merge_limit);
|
||||
}
|
||||
|
||||
/* Insert the new rte */
|
||||
struct rte_storage *e = rte_store(new, net);
|
||||
e->sender = c;
|
||||
e->lastmod = current_time();
|
||||
e->id = id;
|
||||
e->next = *pos;
|
||||
*pos = e;
|
||||
tab->rt_count++;
|
||||
return 1;
|
||||
|
||||
drop_update:
|
||||
return refeed;
|
||||
|
||||
drop_withdraw:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rt_out_sync_start(struct channel *c)
|
||||
{
|
||||
ASSERT_DIE(c->out_table);
|
||||
ASSERT_DIE(c->ra_mode != RA_ANY);
|
||||
ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1));
|
||||
bmap_reset(&c->out_seen_map, 1024);
|
||||
}
|
||||
|
||||
_Bool
|
||||
rt_out_sync_mark(struct channel *c, struct rte_export *e)
|
||||
rt_out_sync_mark(struct channel *c, struct rte_export *e, linpool *p)
|
||||
{
|
||||
ASSERT_DIE(c->out_table);
|
||||
ASSERT_DIE(c->ra_mode != RA_ANY);
|
||||
ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1));
|
||||
|
||||
net *n = net_find(c->out_table, e->old.net);
|
||||
if (!n || !n->routes)
|
||||
return 1;
|
||||
|
||||
e->new = rte_copy(n->routes);
|
||||
e->new_id = n->routes->id;
|
||||
|
||||
if (bmap_test(&c->out_seen_map, n->routes->id))
|
||||
return 0;
|
||||
|
||||
if (c->merge_limit > 1)
|
||||
e->new = rte_get_merged(n, p, c->merge_limit);
|
||||
else
|
||||
e->new = rte_copy(n->routes);
|
||||
|
||||
bmap_set(&c->out_seen_map, n->routes->id);
|
||||
return 1;
|
||||
}
|
||||
@ -2585,7 +2581,7 @@ void
|
||||
rt_out_sync_finish(struct channel *c)
|
||||
{
|
||||
ASSERT_DIE(c->out_table);
|
||||
ASSERT_DIE(c->ra_mode != RA_ANY);
|
||||
ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1));
|
||||
|
||||
FIB_WALK(&c->out_table->fib, net, n)
|
||||
{
|
||||
@ -2594,12 +2590,14 @@ rt_out_sync_finish(struct channel *c)
|
||||
|
||||
if (!bmap_test(&c->out_seen_map, n->routes->id))
|
||||
{
|
||||
rte_update_lock();
|
||||
struct rte_export ex = {
|
||||
.new_id = n->routes->id,
|
||||
.new = rte_copy(n->routes),
|
||||
.new = ((c->merge_limit > 1) ? rte_get_merged(n, rte_update_pool, c->merge_limit) : rte_copy(n->routes)),
|
||||
};
|
||||
|
||||
c->proto->rt_notify(c, &ex);
|
||||
rte_update_unlock();
|
||||
}
|
||||
}
|
||||
FIB_WALK_END;
|
||||
@ -2610,19 +2608,21 @@ void
|
||||
rt_out_flush(struct channel *c)
|
||||
{
|
||||
ASSERT_DIE(c->out_table);
|
||||
ASSERT_DIE(c->ra_mode != RA_ANY);
|
||||
ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1));
|
||||
|
||||
FIB_WALK(&c->out_table->fib, net, n)
|
||||
{
|
||||
if (!n->routes)
|
||||
continue;
|
||||
|
||||
rte_update_lock();
|
||||
struct rte_export ex = {
|
||||
.old_id = n->routes->id,
|
||||
.old = rte_copy(n->routes),
|
||||
.old = ((c->merge_limit > 1) ? rte_get_merged(n, rte_update_pool, c->merge_limit) : rte_copy(n->routes)),
|
||||
};
|
||||
|
||||
c->proto->rt_notify(c, &ex);
|
||||
rte_update_unlock();
|
||||
}
|
||||
FIB_WALK_END;
|
||||
}
|
||||
|
@ -1869,19 +1869,27 @@ bgp_rt_notify(struct channel *C, struct rte_export *e)
|
||||
|
||||
|
||||
static inline u32
|
||||
bgp_get_neighbor(struct rte_storage *r)
|
||||
bgp_get_neighbor(const struct rte r)
|
||||
{
|
||||
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
|
||||
eattr *e = ea_find(r.attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
|
||||
u32 as;
|
||||
|
||||
if (e && as_path_get_first_regular(e->u.ptr, &as))
|
||||
return as;
|
||||
|
||||
/* If AS_PATH is not defined, we treat rte as locally originated */
|
||||
struct bgp_proto *p = (void *) r->src->proto;
|
||||
struct bgp_proto *p = (void *) r.src->proto;
|
||||
return p->cf->confederation ?: p->local_as;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rte_stale_get(rta *r)
|
||||
{
|
||||
/* If staleness is unknown, compute and cache it */
|
||||
eattr *a = ea_find(r->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
|
||||
return (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE));
|
||||
}
|
||||
|
||||
static inline int
|
||||
rte_stale(struct rte_storage *r)
|
||||
{
|
||||
@ -1891,9 +1899,7 @@ rte_stale(struct rte_storage *r)
|
||||
if (r->pflags & BGP_REF_NOT_STALE)
|
||||
return 0;
|
||||
|
||||
/* If staleness is unknown, compute and cache it */
|
||||
eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
|
||||
if (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE))
|
||||
if (rte_stale_get(r->attrs))
|
||||
{
|
||||
r->pflags |= BGP_REF_STALE;
|
||||
return 1;
|
||||
@ -1990,7 +1996,7 @@ bgp_rte_better(struct rte_storage *new, struct rte_storage *old)
|
||||
* probably not a big issue.
|
||||
*/
|
||||
if (new_bgp->cf->med_metric || old_bgp->cf->med_metric ||
|
||||
(bgp_get_neighbor(new) == bgp_get_neighbor(old)))
|
||||
(bgp_get_neighbor(rte_copy(new)) == bgp_get_neighbor(rte_copy(old))))
|
||||
{
|
||||
x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
|
||||
y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
|
||||
@ -2049,9 +2055,8 @@ bgp_rte_better(struct rte_storage *new, struct rte_storage *old)
|
||||
return ipa_compare(new_bgp->remote_ip, old_bgp->remote_ip) < 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
static int
|
||||
bgp_rte_mergable_internal(struct rte *pri, struct rte *sec)
|
||||
{
|
||||
struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->src->proto;
|
||||
struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->src->proto;
|
||||
@ -2059,14 +2064,17 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
u32 p, s;
|
||||
|
||||
/* Skip suppressed routes (see bgp_rte_recalculate()) */
|
||||
/* LLGR draft - depreference stale routes */
|
||||
if (pri->pflags != sec->pflags)
|
||||
if ((pri->pflags ^ sec->pflags) & BGP_REF_SUPPRESSED)
|
||||
return 0;
|
||||
|
||||
/* RFC 4271 9.1.2.1. Route resolvability test */
|
||||
if (rta_resolvable(pri->attrs) != rta_resolvable(sec->attrs))
|
||||
return 0;
|
||||
|
||||
/* LLGR draft - depreference stale routes */
|
||||
if (rte_stale_get(pri->attrs) != rte_stale_get(sec->attrs))
|
||||
return 0;
|
||||
|
||||
/* Start with local preferences */
|
||||
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
|
||||
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
|
||||
@ -2100,7 +2108,7 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
|
||||
/* RFC 4271 9.1.2.2. c) Compare MED's */
|
||||
if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric ||
|
||||
(bgp_get_neighbor(pri) == bgp_get_neighbor(sec)))
|
||||
(bgp_get_neighbor(*pri) == bgp_get_neighbor(*sec)))
|
||||
{
|
||||
x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
|
||||
y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
|
||||
@ -2125,11 +2133,17 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
bgp_rte_mergable(struct rte pri, struct rte sec)
|
||||
{
|
||||
return bgp_rte_mergable_internal(&pri, &sec);
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
same_group(struct rte_storage *r, u32 lpref, u32 lasn)
|
||||
{
|
||||
return (r->attrs->pref == lpref) && (bgp_get_neighbor(r) == lasn);
|
||||
return (r->attrs->pref == lpref) && (bgp_get_neighbor(rte_copy(r)) == lasn);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -2145,7 +2159,7 @@ bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte
|
||||
struct rte_storage *r, *s;
|
||||
struct rte_storage *key = new ? new : old;
|
||||
u32 lpref = key->attrs->pref;
|
||||
u32 lasn = bgp_get_neighbor(key);
|
||||
u32 lasn = bgp_get_neighbor(rte_copy(key));
|
||||
int old_suppressed = old ? !!(old->pflags & BGP_REF_SUPPRESSED) : 0;
|
||||
|
||||
/*
|
||||
@ -2224,13 +2238,13 @@ bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte
|
||||
return 0;
|
||||
|
||||
/* Found if new is mergable with best-in-group */
|
||||
if (new && (new != r) && bgp_rte_mergable(r, new))
|
||||
if (new && (new != r) && bgp_rte_mergable(rte_copy(r), rte_copy(new)))
|
||||
new->pflags &= ~BGP_REF_SUPPRESSED;
|
||||
|
||||
/* Found all existing routes mergable with best-in-group */
|
||||
for (s=net->routes; rte_is_valid(s); s=s->next)
|
||||
if (use_deterministic_med(s) && same_group(s, lpref, lasn))
|
||||
if ((s != r) && bgp_rte_mergable(r, s))
|
||||
if ((s != r) && bgp_rte_mergable(rte_copy(r), rte_copy(s)))
|
||||
s->pflags &= ~BGP_REF_SUPPRESSED;
|
||||
|
||||
/* Found best-in-group */
|
||||
|
@ -583,7 +583,7 @@ void bgp_free_prefix_table(struct bgp_channel *c);
|
||||
void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
|
||||
|
||||
int bgp_rte_better(struct rte_storage *, struct rte_storage *);
|
||||
int bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec);
|
||||
int bgp_rte_mergable(struct rte pri, struct rte sec);
|
||||
int bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte_storage *old, struct rte_storage *old_best);
|
||||
struct rta *bgp_rte_modify_stale(struct rte_storage *r, struct linpool *pool);
|
||||
void bgp_rt_notify(struct channel *C, struct rte_export *e);
|
||||
|
@ -410,10 +410,10 @@ static_rte_better(struct rte_storage *new, struct rte_storage *old)
|
||||
}
|
||||
|
||||
static int
|
||||
static_rte_mergable(struct rte_storage *pri, struct rte_storage *sec)
|
||||
static_rte_mergable(struct rte pri, struct rte sec)
|
||||
{
|
||||
u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
u32 a = ea_get_int(pri.attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
u32 b = ea_get_int(sec.attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
|
||||
return a == b;
|
||||
}
|
||||
|
||||
|
@ -68,12 +68,14 @@
|
||||
*/
|
||||
|
||||
pool *krt_pool;
|
||||
static linpool *krt_filter_lp;
|
||||
static list krt_proto_list;
|
||||
|
||||
void
|
||||
krt_io_init(void)
|
||||
{
|
||||
krt_pool = rp_new(&root_pool, "Kernel Syncer");
|
||||
krt_filter_lp = lp_new_default(krt_pool);
|
||||
init_list(&krt_proto_list);
|
||||
krt_sys_io_init();
|
||||
}
|
||||
@ -558,7 +560,6 @@ krt_same_dest(rte *k, rte *e)
|
||||
void
|
||||
krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
||||
{
|
||||
|
||||
struct rte_export ex = {
|
||||
.old = *e,
|
||||
};
|
||||
@ -587,7 +588,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
|
||||
if (!p->ready)
|
||||
goto ignore;
|
||||
|
||||
if (!rt_out_sync_mark(p->p.main_channel, &ex))
|
||||
if (!rt_out_sync_mark(p->p.main_channel, &ex, krt_filter_lp))
|
||||
goto aseen;
|
||||
|
||||
if (!ex.new.attrs)
|
||||
@ -622,6 +623,7 @@ delete:
|
||||
goto done;
|
||||
|
||||
done:
|
||||
lp_flush(krt_filter_lp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -896,7 +898,7 @@ krt_postconfig(struct proto_config *CF)
|
||||
|
||||
if (cf->merge_paths)
|
||||
{
|
||||
cc->ra_mode = RA_MERGED;
|
||||
cc->ra_mode = RA_ANY;
|
||||
cc->merge_limit = cf->merge_paths;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user