#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 */
#endif
};
-extern struct channel_class channel_bgp;
+extern struct channel_class channel_bgp, channel_krt;
struct channel_config {
node n;
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);
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)
{
}
}
+ 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++;
}
p->rt_notify(p, c, net, new, old);
+
+ if (c->out_table && old_exported)
+ rte_free_quick(old_exported);
}
static void
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)
{
*/
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);
else
{
net = net_find(tab, n);
- src = old0->attrs->src;
if (!net)
goto drop_withdraw;
/* Remove the old rte */
*pos = old->next;
- rte_free_quick(old);
+ *old_exported = old;
tab->rt_count--;
break;
CF_KEYWORDS(INTERFACE, PREFERRED)
%type <i> kern_mp_limit
+%type <cc> kern_channel_start kern_proto_channel
CF_GRAMMAR
| 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 */
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);
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)
{
#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",