diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index c30b1070..3d19e3fe 100644 --- a/nest/proto-hooks.c +++ b/nest/proto-hooks.c @@ -178,13 +178,14 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a) /** * rt_notify - notify instance about routing table change * @p: protocol instance + * @table: a routing table * @net: a network entry * @new: new route for the network * @old: old route for the network * @attrs: extended attributes associated with the @new entry * * The rt_notify() hook is called to inform the protocol instance about - * changes in the routing table it's connected to, that is a route @old + * changes in the connected routing table @table, that is a route @old * belonging to network @net being replaced by a new route @new with * extended attributes @attrs. Either @new or @old or both can be %NULL * if the corresponding route doesn't exist. diff --git a/nest/proto.c b/nest/proto.c index a7e4e0c9..57c2aa13 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -133,11 +133,6 @@ proto_init_instance(struct proto *p) p->attn = ev_new(p->pool); p->attn->data = p; rt_lock_table(p->table); - -#ifdef CONFIG_PIPE - if (proto_is_pipe(p)) - rt_lock_table(pipe_get_peer_table(p)); -#endif } /** diff --git a/nest/protocol.h b/nest/protocol.h index 876427ab..82f3766f 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -16,6 +16,7 @@ struct iface; struct ifa; +struct rtable; struct rte; struct neighbor; struct rta; @@ -162,7 +163,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 network *net, struct rte *new, struct rte *old, struct ea_list *attrs); + void (*rt_notify)(struct proto *, struct rtable *table, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs); void (*neigh_notify)(struct neighbor *neigh); struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); @@ -339,13 +340,7 @@ struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); */ #ifdef CONFIG_PIPE - -static inline int proto_is_pipe(struct proto *p) -{ return p->proto == &proto_pipe; } - -struct rtable *pipe_get_peer_table(struct proto *p); -struct proto_stats *pipe_get_peer_stats(struct proto *p); - +#include "proto/pipe/pipe.h" #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index c9e421e9..72a1cb0e 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -161,6 +161,7 @@ static inline void do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) { struct proto *p = a->proto; + struct filter *filter = p->out_filter; struct proto_stats *stats = &p->stats; rte *new0 = new; rte *old0 = old; @@ -168,6 +169,15 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, int fast_exit_hack = 0; +#ifdef CONFIG_PIPE + /* The secondary direction of the pipe */ + if (proto_is_pipe(p) && (p->table != a->table)) + { + filter = p->in_filter; + stats = pipe_get_peer_stats(p); + } +#endif + if (new) { stats->exp_updates_received++; @@ -186,8 +196,8 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, } else if (ok) rte_trace_out(D_FILTERS, p, new, "forced accept by protocol"); - else if (p->out_filter == FILTER_REJECT || - p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) + else if (filter == FILTER_REJECT || + filter && f_run(filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) { stats->exp_updates_filtered++; drop_reason = "filtered out"; @@ -230,13 +240,13 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, if (old && !refeed) { - if (p->out_filter == FILTER_REJECT) + if (filter == FILTER_REJECT) old = NULL; else { ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL; ok = p->import_control ? p->import_control(p, &old, &tmpb, rte_update_pool) : 0; - if (ok < 0 || (!ok && p->out_filter && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) + if (ok < 0 || (!ok && filter && f_run(filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) { if (old != old0) rte_free(old); @@ -271,18 +281,18 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, rte_trace_out(D_ROUTES, p, old, "removed"); } if (!new) - p->rt_notify(p, net, NULL, old, NULL); + p->rt_notify(p, a->table, net, NULL, old, NULL); else if (tmpa) { ea_list *t = tmpa; while (t->next) t = t->next; t->next = new->attrs->eattrs; - p->rt_notify(p, net, new, old, tmpa); + p->rt_notify(p, a->table, net, new, old, tmpa); t->next = NULL; } else - p->rt_notify(p, net, new, old, new->attrs->eattrs); + p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs); if (new && new != new0) /* Discard temporary rte's */ rte_free(new); if (old && old != old0) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 4cfabf18..96679870 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -772,7 +772,7 @@ bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck) } void -bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old UNUSED, ea_list *attrs) +bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs) { struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_bucket *buck; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 7f574ed4..1a291952 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -179,7 +179,7 @@ byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned att struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory); int bgp_get_attr(struct eattr *e, byte *buf, int buflen); int bgp_rte_better(struct rte *, struct rte *); -void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *); +void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); void bgp_attr_init(struct bgp_proto *); unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index d2ceab25..26a05d95 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -78,7 +78,7 @@ static int ospf_reload_routes(struct proto *p); -static void ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ea_list * attrs); +static void ospf_rt_notify(struct proto *p, struct rtable *table UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs); static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a); static int ospf_rte_better(struct rte *new, struct rte *old); static int ospf_rte_same(struct rte *new, struct rte *old); @@ -484,8 +484,7 @@ ospf_shutdown(struct proto *p) } static void -ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, - ea_list * attrs) +ospf_rt_notify(struct proto *p, rtable *tbl UNUSED, net * n, rte * new, rte * old UNUSED, ea_list * attrs) { struct proto_ospf *po = (struct proto_ospf *) p; diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 879135d1..943d3a0e 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -31,9 +31,12 @@ #include "pipe.h" static void -pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs) +pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs) { + struct pipe_proto *p = (struct pipe_proto *) P; + rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */ struct proto *src; + net *nn; rte *e; rta a; @@ -85,30 +88,12 @@ pipe_send(struct pipe_proto *p, rtable *src_table, rtable *dest, net *n, rte *ne src_table->pipe_busy = 0; } -static void -pipe_rt_notify_pri(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs) -{ - struct pipe_proto *p = (struct pipe_proto *) P; - - DBG("PIPE %c> %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); - pipe_send(p, p->p.table, p->peer, net, new, old, attrs); -} - -static void -pipe_rt_notify_sec(struct proto *P, net *net, rte *new, rte *old, ea_list *attrs) -{ - struct pipe_proto *p = ((struct pipe_proto *) P)->phantom; - - DBG("PIPE %c< %I/%d\n", (new ? '+' : '-'), net->n.prefix, net->n.pxlen); - pipe_send(p, p->peer, p->p.table, net, new, old, attrs); -} - static int pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED) { struct proto *pp = (*ee)->sender; - if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p) + if (pp == P) return -1; /* Avoid local loops automatically */ return 0; } @@ -130,49 +115,16 @@ static int pipe_start(struct proto *P) { struct pipe_proto *p = (struct pipe_proto *) P; - struct pipe_proto *ph; struct announce_hook *a; - /* - * Create a phantom protocol which will represent the remote - * end of the pipe (we need to do this in order to get different - * filters and announce functions and it unfortunately involves - * a couple of magic trickery). - * - * The phantom protocol is used ONLY in announce hooks and - * therefore in do_rte_announce() function. - */ - ph = mb_alloc(P->pool, sizeof(struct pipe_proto)); - memcpy(ph, p, sizeof(struct pipe_proto)); - p->phantom = ph; - ph->phantom = p; - ph->p.accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; - ph->p.rt_notify = pipe_rt_notify_sec; - ph->p.proto_state = PS_UP; - ph->p.core_state = ph->p.core_goal = FS_HAPPY; + /* Clean up the secondary stats */ + bzero(&p->peer_stats, sizeof(struct proto_stats)); - /* - * Routes should be filtered in the do_rte_announce() (export - * filter for protocols). Reverse direction is handled by putting - * specified import filter to out_filter field of the phantom - * protocol. - * - * in_filter fields are not important, there is an exception in - * rte_update() to ignore it for pipes. We cannot just set - * P->in_filter to FILTER_ACCEPT, because that would break other - * things (reconfiguration, show-protocols command). - */ - ph->p.in_filter = FILTER_ACCEPT; - ph->p.out_filter = P->in_filter; + /* Lock the peer table, unlock is handled in proto_fell_down() */ + rt_lock_table(p->peer); - /* - * Connect the phantom protocol to the peer routing table, but - * keep it in the list of connections of the primary protocol, - * so that it gets disconnected at the right time and we also - * get all routes from both sides during the feeding phase. - */ + /* Connect the protocol also to the peer routing table. */ a = proto_add_announce_hook(P, p->peer); - a->proto = &ph->p; return PS_UP; } @@ -187,9 +139,10 @@ pipe_init(struct proto_config *C) p->peer = c->peer->table; p->mode = c->mode; P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; - P->rt_notify = pipe_rt_notify_pri; + P->rt_notify = pipe_rt_notify; P->import_control = pipe_import_control; P->reload_routes = pipe_reload_routes; + return P; } @@ -222,24 +175,9 @@ pipe_reconfigure(struct proto *P, struct proto_config *new) if ((o->peer->table != n->peer->table) || (o->mode != n->mode)) return 0; - /* Update also the filter in the phantom protocol */ - p->phantom->p.out_filter = new->in_filter; return 1; } -struct rtable * -pipe_get_peer_table(struct proto *P) -{ - struct pipe_proto *p = (struct pipe_proto *) P; - return p->peer; -} - -struct proto_stats * -pipe_get_peer_stats(struct proto *P) -{ - struct pipe_proto *p = (struct pipe_proto *) P; - return &p->phantom->p.stats; -} struct protocol proto_pipe = { name: "Pipe", diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h index 368ba41b..fbd21291 100644 --- a/proto/pipe/pipe.h +++ b/proto/pipe/pipe.h @@ -21,8 +21,20 @@ struct pipe_config { struct pipe_proto { struct proto p; struct rtable *peer; + struct proto_stats peer_stats; /* Statistics for the direction peer->primary */ int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */ - struct pipe_proto *phantom; }; + +extern struct protocol proto_pipe; + +static inline int proto_is_pipe(struct proto *p) +{ return p->proto == &proto_pipe; } + +static inline struct rtable * pipe_get_peer_table(struct proto *P) +{ return ((struct pipe_proto *) P)->peer; } + +static inline struct proto_stats * pipe_get_peer_stats(struct proto *P) +{ return &((struct pipe_proto *) P)->peer_stats; } + #endif diff --git a/proto/rip/rip.c b/proto/rip/rip.c index f9a160e6..d69d6432 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -864,7 +864,8 @@ rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) * own), so store it into our data structures. */ static void -rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs) +rip_rt_notify(struct proto *p, struct rtable *table UNUSED, struct network *net, + struct rte *new, struct rte *old, struct ea_list *attrs) { CHK_MAGIC; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 488447b7..6d94cada 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -742,7 +742,8 @@ krt_scan(timer *t UNUSED) */ static void -krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED) +krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, + rte *new, rte *old, struct ea_list *attrs UNUSED) { struct krt_proto *p = (struct krt_proto *) P;