diff --git a/nest/protocol.h b/nest/protocol.h index df31d95b..a6bf79f7 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -210,7 +210,7 @@ struct proto { void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); - void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old); + void (*rt_notify)(struct channel *, struct rte_export *); void (*neigh_notify)(struct neighbor *neigh); int (*preexport)(struct proto *, struct rte **rt, struct linpool *pool); void (*reload_routes)(struct channel *); diff --git a/nest/route.h b/nest/route.h index 688d26ff..892a1dee 100644 --- a/nest/route.h +++ b/nest/route.h @@ -223,6 +223,16 @@ typedef struct rte { btime lastmod; /* Last modified */ } rte; +/* Route export structure. Protocols get this structure as an information about + * new routes on the channel. */ +struct rte_export { + net *net; /* Network information */ + struct rte_src *new_src; /* New route src (NULL for withdraw) */ + rte *new; /* New route (NULL for withdraw) */ + struct rte_src *old_src; /* Old route src */ + rte *old; /* Old route */ +}; + #define REF_COW 1 /* Copy this rte on write */ #define REF_FILTERED 2 /* Route is rejected by import filter */ #define REF_STALE 4 /* Route is stale in a refresh cycle */ diff --git a/nest/rt-table.c b/nest/rt-table.c index f8a7990c..51f0a84c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -543,7 +543,15 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) rte_trace_out(D_ROUTES, p, old, "removed"); } - p->rt_notify(p, c, net, new, old); + struct rte_export export = { + .net = net, + .new_src = new ? new->attrs->src : NULL, + .new = new, + .old_src = old ? old->attrs->src : NULL, + .old = old, + }; + + p->rt_notify(c, &export); if (c->out_table && old_exported) rte_free_quick(old_exported); diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 9dc0d17e..0cc633fa 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -2121,38 +2121,32 @@ babel_preexport(struct proto *P, struct rte **new, struct linpool *pool UNUSED) * so store it into our data structures. */ static void -babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, - struct rte *new, struct rte *old UNUSED) +babel_rt_notify(struct channel *c, struct rte_export *export) { - struct babel_proto *p = (void *) P; + struct babel_proto *p = (void *) c->proto; struct babel_entry *e; - if (new) + if (export->new) { /* Update */ - uint rt_seqno; - uint rt_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, 0); + uint rt_metric = ea_get_int(export->new->attrs->eattrs, EA_BABEL_METRIC, 0); + uint rt_seqno = ea_get_int(export->new->attrs->eattrs, EA_BABEL_SEQNO, p->update_seqno); u64 rt_router_id; - if (new->attrs->src->proto == P) - { - rt_seqno = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data; - memcpy(&rt_router_id, ea_find(new->attrs->eattrs, EA_BABEL_ROUTER_ID)->u.ptr->data, sizeof(u64)); - } + eattr *ea; + if (ea = ea_find(export->new->attrs->eattrs, EA_BABEL_ROUTER_ID)) + memcpy(&rt_router_id, ea->u.ptr->data, sizeof(u64)); else - { - rt_seqno = p->router_id; - rt_router_id = p->router_id; - } + rt_router_id = p->router_id; if (rt_metric > BABEL_INFINITY) { log(L_WARN "%s: Invalid babel_metric value %u for route %N", - p->p.name, rt_metric, net->n.addr); + p->p.name, rt_metric, export->net->n.addr); rt_metric = BABEL_INFINITY; } - e = babel_get_entry(p, net->n.addr); + e = babel_get_entry(p, export->net->n.addr); /* Activate triggered updates */ if ((e->valid != BABEL_ENTRY_VALID) || @@ -2170,7 +2164,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, else { /* Withdraw */ - e = babel_find_entry(p, net->n.addr); + e = babel_find_entry(p, export->net->n.addr); if (!e || e->valid != BABEL_ENTRY_VALID) return; diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 59a82f95..281b9889 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1802,31 +1802,31 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at } void -bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) +bgp_rt_notify(struct channel *C, struct rte_export *e) { - struct bgp_proto *p = (void *) P; + struct bgp_proto *p = (void *) C->proto; struct bgp_channel *c = (void *) C; struct bgp_bucket *buck; struct bgp_prefix *px; u32 path; - if (new) + if (e->new) { - struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2); + struct ea_list *attrs = bgp_update_attrs(p, c, e->new, e->new->attrs->eattrs, bgp_linpool2); /* If attributes are invalid, we fail back to withdraw */ buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c); - path = new->attrs->src->global_id; + path = e->new_src->global_id; lp_flush(bgp_linpool2); } else { buck = bgp_get_withdraw_bucket(c); - path = old->attrs->src->global_id; + path = e->old_src->global_id; } - px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0); + px = bgp_get_prefix(c, e->net->n.addr, c->add_path_tx ? path : 0); add_tail(&buck->prefixes, &px->buck_node); bgp_schedule_packet(p->conn, c, PKT_UPDATE); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index baa6cf32..ef01296d 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -583,7 +583,7 @@ int bgp_rte_better(struct rte *, struct rte *); int bgp_rte_mergable(rte *pri, rte *sec); int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool); -void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); +void bgp_rt_notify(struct channel *C, struct rte_export *e); int bgp_preexport(struct proto *, struct rte **, struct linpool *); int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); void bgp_get_route_info(struct rte *, byte *buf); diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index c8ec730a..3822e4c0 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1303,9 +1303,9 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa) } void -ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED) +ospf_rt_notify(struct channel *ch, struct rte_export *e) { - struct ospf_proto *p = (struct ospf_proto *) P; + struct ospf_proto *p = (struct ospf_proto *) ch->proto; struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */ ort *nf; @@ -1320,9 +1320,9 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if ((p->areano == 1) && oa_is_nssa(HEAD(p->area_list))) oa = HEAD(p->area_list); - if (!new) + if (!e->new) { - nf = fib_find(&p->rtf, n->n.addr); + nf = fib_find(&p->rtf, e->net->n.addr); if (!nf || !nf->external_rte) return; @@ -1340,7 +1340,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte ASSERT(p->asbr); /* Get route attributes */ - rta *a = new->attrs; + rta *a = e->new->attrs; eattr *m1a = ea_find(a->eattrs, EA_OSPF_METRIC1); eattr *m2a = ea_find(a->eattrs, EA_OSPF_METRIC2); uint m1 = m1a ? m1a->u.data : 0; @@ -1349,14 +1349,14 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if (m1 > LSINFINITY) { log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N", - p->p.name, m1, n->n.addr); + p->p.name, m1, e->net->n.addr); m1 = LSINFINITY; } if (m2 > LSINFINITY) { log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N", - p->p.name, m2, n->n.addr); + p->p.name, m2, e->net->n.addr); m2 = LSINFINITY; } @@ -1380,12 +1380,12 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if (ipa_zero(fwd)) { log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N", - p->p.name, n->n.addr); + p->p.name, e->net->n.addr); return; } } - nf = fib_get(&p->rtf, n->n.addr); + nf = fib_get(&p->rtf, e->net->n.addr); ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe); nf->external_rte = 1; } diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 535d1f1b..9df70027 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -200,7 +200,7 @@ void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 d void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn); void ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa); -void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old); +void ospf_rt_notify(struct channel *ch, struct rte_export *e); void ospf_update_topology(struct ospf_proto *p); struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type); diff --git a/proto/perf/perf.c b/proto/perf/perf.c index ec2a9014..452821b8 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -204,9 +204,9 @@ perf_loop(void *data) } static void -perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED) +perf_rt_notify(struct channel *c, struct rte_export *e UNUSED) { - struct perf_proto *p = (struct perf_proto *) P; + struct perf_proto *p = (struct perf_proto *) c->proto; p->exp++; return; } diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index d935d16b..e5b27717 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -48,50 +48,44 @@ #include "pipe.h" static void -pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old) +pipe_rt_notify(struct channel *src_ch, struct rte_export *export) { - struct pipe_proto *p = (void *) P; + struct pipe_proto *p = (void *) src_ch->proto; struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri; - struct rte_src *src; - rte e0 = {}, *e = &e0; - rta *a; - - if (!new && !old) + if (!export->new && !export->old) return; if (dst->table->pipe_busy) { log(L_ERR "Pipe loop detected when sending %N to table %s", - n->n.addr, dst->table->name); + export->net->n.addr, dst->table->name); return; } - if (new) + if (export->new) { - a = alloca(rta_size(new->attrs)); - memcpy(a, new->attrs, rta_size(new->attrs)); + rta *a = alloca(rta_size(export->new->attrs)); + memcpy(a, export->new->attrs, rta_size(export->new->attrs)); a->cached = 0; + a->uc = 0; a->hostentry = NULL; - e->attrs = rta_lookup(a); - e->pflags = 0; + rte e0 = { + .attrs = rta_lookup(a), + }; - src = a->src; + src_ch->table->pipe_busy = 1; + rte_update(dst, export->net->n.addr, &e0); + src_ch->table->pipe_busy = 0; } else { - e = NULL; - src = old->attrs->src; + src_ch->table->pipe_busy = 1; + rte_withdraw(dst, export->net->n.addr, export->old_src); + src_ch->table->pipe_busy = 0; } - - src_ch->table->pipe_busy = 1; - if (e) - rte_update(dst, n->n.addr, e); - else - rte_withdraw(dst, n->n.addr, src); - src_ch->table->pipe_busy = 0; } static int diff --git a/proto/radv/radv.c b/proto/radv/radv.c index b4235917..042d3769 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -406,17 +406,17 @@ radv_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED) } static void -radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED) +radv_rt_notify(struct channel *ch, struct rte_export *e) { - struct radv_proto *p = (struct radv_proto *) P; - struct radv_config *cf = (struct radv_config *) (P->cf); + struct radv_proto *p = (struct radv_proto *) ch->proto; + struct radv_config *cf = (struct radv_config *) (ch->proto->cf); struct radv_route *rt; eattr *ea; - if (radv_net_match_trigger(cf, n)) + if (radv_net_match_trigger(cf, e->net)) { u8 old_active = p->active; - p->active = !!new; + p->active = !!e->new; if (p->active == old_active) return; @@ -440,15 +440,15 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte * And yes, we exclude the trigger route on purpose. */ - if (new) + if (e->new) { /* Update */ - ea = ea_find(new->attrs->eattrs, EA_RA_PREFERENCE); + ea = ea_find(e->new->attrs->eattrs, EA_RA_PREFERENCE); uint preference = ea ? ea->u.data : RA_PREF_MEDIUM; uint preference_set = !!ea; - ea = ea_find(new->attrs->eattrs, EA_RA_LIFETIME); + ea = ea_find(e->new->attrs->eattrs, EA_RA_LIFETIME); uint lifetime = ea ? ea->u.data : 0; uint lifetime_set = !!ea; @@ -457,14 +457,14 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte (preference != RA_PREF_HIGH)) { log(L_WARN "%s: Invalid ra_preference value %u on route %N", - p->p.name, preference, n->n.addr); + p->p.name, preference, e->net->n.addr); preference = RA_PREF_MEDIUM; preference_set = 1; lifetime = 0; lifetime_set = 1; } - rt = fib_get(&p->routes, n->n.addr); + rt = fib_get(&p->routes, e->net->n.addr); /* Ignore update if nothing changed */ if (rt->valid && @@ -487,7 +487,7 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte else { /* Withdraw */ - rt = fib_find(&p->routes, n->n.addr); + rt = fib_find(&p->routes, e->net->n.addr); if (!rt || !rt->valid) return; diff --git a/proto/rip/rip.c b/proto/rip/rip.c index f56fb6c4..5ac8a106 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -309,31 +309,31 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from) * it into our data structures. */ static void -rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new, - struct rte *old UNUSED) +rip_rt_notify(struct channel *ch, struct rte_export *e) { - struct rip_proto *p = (struct rip_proto *) P; + struct rip_proto *p = (struct rip_proto *) ch->proto; struct rip_entry *en; int old_metric; - if (new) + if (e->new) { /* Update */ - u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0); - u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1); - struct iface *rt_from = (struct iface *) ea_get_int(new->attrs->eattrs, EA_RIP_FROM, 0); + rta *a = e->new->attrs; + u32 rt_tag = ea_get_int(a->eattrs, EA_RIP_TAG, 0); + u32 rt_metric = ea_get_int(a->eattrs, EA_RIP_METRIC, 1); + struct iface *rt_from = (struct iface *) ea_get_int(a->eattrs, EA_RIP_FROM, 0); if (rt_metric > p->infinity) { log(L_WARN "%s: Invalid rip_metric value %u for route %N", - p->p.name, rt_metric, net->n.addr); + p->p.name, rt_metric, e->net->n.addr); rt_metric = p->infinity; } if (rt_tag > 0xffff) { log(L_WARN "%s: Invalid rip_tag value %u for route %N", - p->p.name, rt_tag, net->n.addr); + p->p.name, rt_tag, e->net->n.addr); rt_metric = p->infinity; rt_tag = 0; } @@ -345,7 +345,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s * collection. */ - en = fib_get(&p->rtable, net->n.addr); + en = fib_get(&p->rtable, e->net->n.addr); old_metric = en->valid ? en->metric : -1; @@ -353,13 +353,13 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s en->metric = rt_metric; en->tag = rt_tag; en->from = rt_from; - en->iface = new->attrs->nh.iface; - en->next_hop = new->attrs->nh.gw; + en->iface = a->nh.iface; + en->next_hop = a->nh.gw; } else { /* Withdraw */ - en = fib_find(&p->rtable, net->n.addr); + en = fib_find(&p->rtable, e->net->n.addr); if (!en || en->valid != RIP_ENTRY_VALID) return; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 7e89a590..16b3d2e1 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -889,10 +889,9 @@ krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED) } static void -krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net, - rte *new, rte *old) +krt_rt_notify(struct channel *ch, struct rte_export *e) { - struct krt_proto *p = (struct krt_proto *) P; + struct krt_proto *p = (struct krt_proto *) ch->proto; if (config->shutdown) return; @@ -904,13 +903,13 @@ krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net, * but if we processed the update as usual, we would send withdraw to the * kernel, which would remove the new imported route instead. */ - rte *best = net->routes; - if (!new && best && (best->attrs->src->proto == P)) + rte *best = e->net->routes; + if (!e->new && best && (best->attrs->src->proto == ch->proto)) return; #endif if (p->initialized) /* Before first scan we don't touch the routes */ - krt_replace_rte(p, net, new, old); + krt_replace_rte(p, e->net, e->new, e->old); } static void