diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/bgp.c | 2 | ||||
-rw-r--r-- | proto/pipe/pipe.c | 189 | ||||
-rw-r--r-- | proto/pipe/pipe.h | 9 | ||||
-rw-r--r-- | proto/static/static.c | 3 |
4 files changed, 153 insertions, 50 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 4d3c32fb..4dd4b7be 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1125,6 +1125,8 @@ bgp_show_proto_info(struct proto *P) struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_conn *c = p->conn; + proto_show_basic_info(P); + cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p)); cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface); cli_msg(-1006, " Neighbor AS: %u", p->remote_as); diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index fe8618b6..36b06d43 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -16,6 +16,17 @@ * * To avoid pipe loops, Pipe keeps a `being updated' flag in each routing * table. + * + * A pipe has two announce hooks, the first connected to the main + * table, the second connected to the peer table. When a new route is + * announced on the main table, it gets checked by an export filter in + * ahook 1, and, after that, it is announced to the peer table via + * rte_update(), an import filter in ahook 2 is called. When a new + * route is announced in the peer table, an export filter in ahook2 + * and an import filter in ahook 1 are used. Oviously, there is no + * need in filtering the same route twice, so both import filters + * are set to accept, while user configured 'import' and 'export' + * filters are used as export filters in ahooks 2 and 1. */ #undef LOCAL_DEBUG @@ -24,6 +35,7 @@ #include "nest/iface.h" #include "nest/protocol.h" #include "nest/route.h" +#include "nest/cli.h" #include "conf/conf.h" #include "filter/filter.h" #include "lib/string.h" @@ -34,7 +46,8 @@ static void 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 announce_hook *ah = (src_table == P->table) ? p->peer_ahook : P->main_ahook; + rtable *dst_table = ah->table; struct proto *src; net *nn; @@ -44,13 +57,14 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e if (!new && !old) return; - if (dest->pipe_busy) + if (dst_table->pipe_busy) { log(L_ERR "Pipe loop detected when sending %I/%d to table %s", - n->n.prefix, n->n.pxlen, dest->name); + n->n.prefix, n->n.pxlen, dst_table->name); return; } - nn = net_get(dest, n->n.prefix, n->n.pxlen); + + nn = net_get(dst_table, n->n.prefix, n->n.pxlen); if (new) { memcpy(&a, new->attrs, sizeof(rta)); @@ -85,14 +99,14 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e } src_table->pipe_busy = 1; - rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e); + rte_update2(ah, nn, e, (p->mode == PIPE_OPAQUE) ? &p->p : src); src_table->pipe_busy = 0; } static int pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED) { - struct proto *pp = (*ee)->sender; + struct proto *pp = (*ee)->sender->proto; if (pp == P) return -1; /* Avoid local loops automatically */ @@ -112,20 +126,39 @@ pipe_reload_routes(struct proto *P) return 1; } +static struct proto * +pipe_init(struct proto_config *C) +{ + struct pipe_config *c = (struct pipe_config *) C; + struct proto *P = proto_new(C, sizeof(struct pipe_proto)); + struct pipe_proto *p = (struct pipe_proto *) P; + + p->mode = c->mode; + p->peer_table = c->peer->table; + P->accept_ra_types = (p->mode == PIPE_OPAQUE) ? RA_OPTIMAL : RA_ANY; + P->rt_notify = pipe_rt_notify; + P->import_control = pipe_import_control; + P->reload_routes = pipe_reload_routes; + + return P; +} + static int pipe_start(struct proto *P) { struct pipe_proto *p = (struct pipe_proto *) P; - struct announce_hook *a; - /* Clean up the secondary stats */ - bzero(&p->peer_stats, sizeof(struct proto_stats)); + /* Lock both tables, unlock is handled in pipe_cleanup() */ + rt_lock_table(P->table); + rt_lock_table(p->peer_table); - /* Lock the peer table, unlock is handled in pipe_cleanup() */ - rt_lock_table(p->peer); + /* Going directly to PS_UP - prepare for feeding, + connect the protocol to both routing tables */ - /* Connect the protocol also to the peer routing table. */ - a = proto_add_announce_hook(P, p->peer); + P->main_ahook = proto_add_announce_hook(P, P->table, + FILTER_ACCEPT, P->cf->out_filter, &P->stats); + p->peer_ahook = proto_add_announce_hook(P, p->peer_table, + FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats); return PS_UP; } @@ -134,24 +167,15 @@ static void pipe_cleanup(struct proto *P) { struct pipe_proto *p = (struct pipe_proto *) P; - rt_unlock_table(p->peer); -} -static struct proto * -pipe_init(struct proto_config *C) -{ - struct pipe_config *c = (struct pipe_config *) C; - struct proto *P = proto_new(C, sizeof(struct pipe_proto)); - struct pipe_proto *p = (struct pipe_proto *) P; + bzero(&P->stats, sizeof(struct proto_stats)); + bzero(&p->peer_stats, sizeof(struct proto_stats)); - 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; - P->import_control = pipe_import_control; - P->reload_routes = pipe_reload_routes; + P->main_ahook = NULL; + p->peer_ahook = NULL; - return P; + rt_unlock_table(P->table); + rt_unlock_table(p->peer_table); } static void @@ -165,16 +189,34 @@ pipe_postconfig(struct proto_config *C) cf_error("Primary table and peer table must be different"); } +extern int proto_reconfig_type; + static int pipe_reconfigure(struct proto *P, struct proto_config *new) { - // struct pipe_proto *p = (struct pipe_proto *) P; - struct pipe_config *o = (struct pipe_config *) P->cf; - struct pipe_config *n = (struct pipe_config *) new; + struct pipe_proto *p = (struct pipe_proto *)P; + struct proto_config *old = P->cf; + struct pipe_config *oc = (struct pipe_config *) old; + struct pipe_config *nc = (struct pipe_config *) new; - if ((o->peer->table != n->peer->table) || (o->mode != n->mode)) + if ((oc->peer->table != nc->peer->table) || (oc->mode != nc->mode)) return 0; + /* Update output filters in ahooks */ + if (P->main_ahook) + P->main_ahook->out_filter = new->out_filter; + + if (p->peer_ahook) + p->peer_ahook->out_filter = new->in_filter; + + if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT)) + return 1; + + if ((new->preference != old->preference) + || ! filter_same(new->in_filter, old->in_filter) + || ! filter_same(new->out_filter, old->out_filter)) + proto_request_feeding(P); + return 1; } @@ -190,19 +232,80 @@ pipe_get_status(struct proto *P, byte *buf) { struct pipe_proto *p = (struct pipe_proto *) P; - bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name); + bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer_table->name); +} + +static void +pipe_show_stats(struct pipe_proto *p) +{ + struct proto_stats *s1 = &p->p.stats; + struct proto_stats *s2 = &p->peer_stats; + + /* + * Pipe stats (as anything related to pipes) are a bit tricky. There + * are two sets of stats - s1 for ahook to the primary routing and + * s2 for the ahook to the secondary routing table. The user point + * of view is that routes going from the primary routing table to + * the secondary routing table are 'exported', while routes going in + * the other direction are 'imported'. + * + * Each route going through a pipe is, technically, first exported + * to the pipe and then imported from that pipe and such operations + * are counted in one set of stats according to the direction of the + * route propagation. Filtering is done just in the first part + * (export). Therefore, we compose stats for one directon for one + * user direction from both import and export stats, skipping + * immediate and irrelevant steps (exp_updates_accepted, + * imp_updates_received, imp_updates_filtered, ...). + * + * Rule of thumb is that stats s1 have the correct 'polarity' + * (imp/exp), while stats s2 have switched 'polarity'. + */ + + cli_msg(-1006, " Routes: %u imported, %u exported", + s1->imp_routes, s2->imp_routes); + cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); + cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", + s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid, + s2->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + s2->exp_withdraws_received, s1->imp_withdraws_invalid, + s1->imp_withdraws_ignored, s1->imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u", + s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid, + s1->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u", + s1->exp_withdraws_received, s2->imp_withdraws_invalid, + s2->imp_withdraws_ignored, s2->imp_withdraws_accepted); +} + +static void +pipe_show_proto_info(struct proto *P) +{ + struct pipe_proto *p = (struct pipe_proto *) P; + + // cli_msg(-1006, " Table: %s", P->table->name); + // cli_msg(-1006, " Peer table: %s", p->peer_table->name); + cli_msg(-1006, " Preference: %d", P->preference); + cli_msg(-1006, " Input filter: %s", filter_name(P->cf->in_filter)); + cli_msg(-1006, " Output filter: %s", filter_name(P->cf->out_filter)); + + if (P->proto_state != PS_DOWN) + pipe_show_stats(p); } struct protocol proto_pipe = { - name: "Pipe", - template: "pipe%d", - preference: DEF_PREF_PIPE, - postconfig: pipe_postconfig, - init: pipe_init, - start: pipe_start, - cleanup: pipe_cleanup, - reconfigure: pipe_reconfigure, - copy_config: pipe_copy_config, - get_status: pipe_get_status, + name: "Pipe", + template: "pipe%d", + multitable: 1, + preference: DEF_PREF_PIPE, + postconfig: pipe_postconfig, + init: pipe_init, + start: pipe_start, + cleanup: pipe_cleanup, + reconfigure: pipe_reconfigure, + copy_config: pipe_copy_config, + get_status: pipe_get_status, + show_proto_info: pipe_show_proto_info }; diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h index fbd21291..50b31698 100644 --- a/proto/pipe/pipe.h +++ b/proto/pipe/pipe.h @@ -20,7 +20,8 @@ struct pipe_config { struct pipe_proto { struct proto p; - struct rtable *peer; + struct rtable *peer_table; + struct announce_hook *peer_ahook; /* Announce hook for direction peer->primary */ struct proto_stats peer_stats; /* Statistics for the direction peer->primary */ int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */ }; @@ -31,10 +32,4 @@ 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/static/static.c b/proto/static/static.c index aaa9bfad..6a027f50 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -224,6 +224,9 @@ static_start(struct proto *p) if (cf->igp_table) rt_lock_table(cf->igp_table->table); + /* We have to go UP before routes could be installed */ + proto_notify_state(p, PS_UP); + WALK_LIST(r, cf->other_routes) static_add(p, cf, r); return PS_UP; |