diff --git a/filter/filter.h b/filter/filter.h index 9d997efb..890b869d 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -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 */ diff --git a/nest/protocol.h b/nest/protocol.h index 7806b9c0..df31d95b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -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; diff --git a/nest/route.h b/nest/route.h index 43ad858f..688d26ff 100644 --- a/nest/route.h +++ b/nest/route.h @@ -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); diff --git a/nest/rt-table.c b/nest/rt-table.c index b527a6b7..f8a7990c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -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; diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 95b54d65..623cbd92 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -33,6 +33,7 @@ CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTAR CF_KEYWORDS(INTERFACE, PREFERRED) %type kern_mp_limit +%type 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 */ diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 8fdc67f4..7e89a590 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -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",