mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
KRT: Using obligatory export table when non-trivial filters are applied.
When the kernel filter is anything more sophisticated than FILTER_ACCEPT or FILTER_REJECT, we should ensure that the old route being sent to the kernel protocol is really what was sent there before. This fixes the old misbehavior when an unfiltered old route was used.
This commit is contained in:
parent
87fcc2d735
commit
a267d569ee
@ -70,6 +70,8 @@ void filters_dump_all(void);
|
||||
#define FILTER_REJECT ((struct filter *) 1)
|
||||
#define FILTER_UNDEF ((struct filter *) 2) /* Used in BGP */
|
||||
|
||||
#define TRIVIAL_FILTER(f) (((f) == FILTER_REJECT) || ((f) == FILTER_ACCEPT))
|
||||
|
||||
#define FF_SILENT 2 /* Silent filter execution */
|
||||
|
||||
/* Custom route attributes */
|
||||
|
@ -466,7 +466,7 @@ struct channel_class {
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct channel_class channel_bgp;
|
||||
extern struct channel_class channel_bgp, channel_krt;
|
||||
|
||||
struct channel_config {
|
||||
node n;
|
||||
|
@ -329,7 +329,7 @@ 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, const net_addr *n, rte *new, rte *old0, int refeed);
|
||||
int rte_update_out(struct channel *c, const net_addr *n, struct rte_src *src, rte *new, rte **old_exported, int refeed);
|
||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||
|
||||
|
||||
|
@ -330,6 +330,27 @@ rte_cow_rta(rte *r, linpool *lp)
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* rte_free - delete a &rte
|
||||
* @e: &rte to be deleted
|
||||
*
|
||||
* rte_free() deletes the given &rte from the routing table it's linked to.
|
||||
*/
|
||||
void
|
||||
rte_free(rte *e)
|
||||
{
|
||||
if (rta_is_cached(e->attrs))
|
||||
rta_free(e->attrs);
|
||||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rte_free_quick(rte *e)
|
||||
{
|
||||
rta_free(e->attrs);
|
||||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
static int /* Actually better or at least as good as */
|
||||
rte_better(rte *new, rte *old)
|
||||
{
|
||||
@ -483,9 +504,17 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
|
||||
}
|
||||
}
|
||||
|
||||
struct rte_src *src = old ? old->attrs->src : new->attrs->src;
|
||||
|
||||
/* Apply export table */
|
||||
if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
|
||||
return;
|
||||
struct rte *old_exported = NULL;
|
||||
if (c->out_table)
|
||||
{
|
||||
if (!rte_update_out(c, net->n.addr, src, new, &old_exported, refeed))
|
||||
return;
|
||||
}
|
||||
else if (c->out_filter == FILTER_ACCEPT)
|
||||
old_exported = old;
|
||||
|
||||
if (new)
|
||||
stats->exp_updates_accepted++;
|
||||
@ -515,6 +544,9 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
|
||||
}
|
||||
|
||||
p->rt_notify(p, c, net, new, old);
|
||||
|
||||
if (c->out_table && old_exported)
|
||||
rte_free_quick(old_exported);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -865,27 +897,6 @@ rte_validate(rte *e)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* rte_free - delete a &rte
|
||||
* @e: &rte to be deleted
|
||||
*
|
||||
* rte_free() deletes the given &rte from the routing table it's linked to.
|
||||
*/
|
||||
void
|
||||
rte_free(rte *e)
|
||||
{
|
||||
if (rta_is_cached(e->attrs))
|
||||
rta_free(e->attrs);
|
||||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rte_free_quick(rte *e)
|
||||
{
|
||||
rta_free(e->attrs);
|
||||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
static int
|
||||
rte_same(rte *x, rte *y)
|
||||
{
|
||||
@ -2366,17 +2377,15 @@ rt_prune_sync(rtable *t, int all)
|
||||
*/
|
||||
|
||||
int
|
||||
rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed)
|
||||
rte_update_out(struct channel *c, const net_addr *n, struct rte_src *src, rte *new, rte **old_exported, int refeed)
|
||||
{
|
||||
struct rtable *tab = c->out_table;
|
||||
struct rte_src *src;
|
||||
rte *old, **pos;
|
||||
net *net;
|
||||
|
||||
if (new)
|
||||
{
|
||||
net = net_get(tab, n);
|
||||
src = new->attrs->src;
|
||||
|
||||
if (!rta_is_cached(new->attrs))
|
||||
new->attrs = rta_lookup(new->attrs);
|
||||
@ -2384,7 +2393,6 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
|
||||
else
|
||||
{
|
||||
net = net_find(tab, n);
|
||||
src = old0->attrs->src;
|
||||
|
||||
if (!net)
|
||||
goto drop_withdraw;
|
||||
@ -2410,7 +2418,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
|
||||
|
||||
/* Remove the old rte */
|
||||
*pos = old->next;
|
||||
rte_free_quick(old);
|
||||
*old_exported = old;
|
||||
tab->rt_count--;
|
||||
|
||||
break;
|
||||
|
@ -33,6 +33,7 @@ CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTAR
|
||||
CF_KEYWORDS(INTERFACE, PREFERRED)
|
||||
|
||||
%type <i> kern_mp_limit
|
||||
%type <cc> kern_channel_start kern_proto_channel
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -53,9 +54,17 @@ kern_mp_limit:
|
||||
| LIMIT expr { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error("Merge paths limit must be in range 1-255"); }
|
||||
;
|
||||
|
||||
kern_channel_start: net_type
|
||||
{
|
||||
$$ = this_channel = channel_config_get(&channel_krt, net_label[$1], $1, this_proto);
|
||||
this_proto->net_type = $1;
|
||||
};
|
||||
|
||||
kern_proto_channel: kern_channel_start channel_opt_list channel_end;
|
||||
|
||||
kern_item:
|
||||
proto_item
|
||||
| proto_channel { this_proto->net_type = $1->net_type; }
|
||||
| kern_proto_channel
|
||||
| PERSIST bool { THIS_KRT->persist = $2; }
|
||||
| SCAN TIME expr {
|
||||
/* Scan time of 0 means scan on startup only */
|
||||
|
@ -1029,6 +1029,11 @@ krt_start(struct proto *P)
|
||||
default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
|
||||
}
|
||||
|
||||
/* If it is needed, setup out table automagically */
|
||||
if (!TRIVIAL_FILTER(p->p.main_channel->out_filter))
|
||||
channel_setup_out_table(p->p.main_channel);
|
||||
|
||||
|
||||
bmap_init(&p->sync_map, p->p.pool, 1024);
|
||||
bmap_init(&p->seen_map, p->p.pool, 1024);
|
||||
add_tail(&krt_proto_list, &p->krt_node);
|
||||
@ -1075,6 +1080,15 @@ krt_shutdown(struct proto *P)
|
||||
return PS_DOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
krt_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed UNUSED, int *export_changed)
|
||||
{
|
||||
if (!*export_changed)
|
||||
return 1;
|
||||
|
||||
return (TRIVIAL_FILTER(C->out_filter) == TRIVIAL_FILTER(CC->out_filter));
|
||||
}
|
||||
|
||||
static int
|
||||
krt_reconfigure(struct proto *p, struct proto_config *CF)
|
||||
{
|
||||
@ -1147,6 +1161,12 @@ krt_get_attr(const eattr *a, byte *buf, int buflen)
|
||||
#define MAYBE_MPLS 0
|
||||
#endif
|
||||
|
||||
struct channel_class channel_krt = {
|
||||
.channel_size = sizeof(struct channel),
|
||||
.config_size = sizeof(struct channel_config),
|
||||
.reconfigure = krt_channel_reconfigure,
|
||||
};
|
||||
|
||||
struct protocol proto_unix_kernel = {
|
||||
.name = "Kernel",
|
||||
.template = "kernel%d",
|
||||
|
Loading…
Reference in New Issue
Block a user