From c83876265eeae3591bfe90375503728e633cb807 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 11 Feb 2010 22:27:06 +0100 Subject: Fixes a tricky bug in the pipe protocol. When uncofiguring the pipe and the peer table, the peer table was unlocked when pipe protocol state changed to down/flushing and not to down/hungry. This leads to the removal of the peer table before the routes from the pipe were flushed. The fix leads to adding some pipe-specific hacks to the nest, but this seems inevitable. --- nest/proto.c | 11 +++++++++++ nest/protocol.h | 14 ++++++++++++++ nest/rt-table.c | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index 870eddd..c6b7e63 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -133,6 +133,11 @@ 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 } /** @@ -583,6 +588,12 @@ proto_fell_down(struct proto *p) bzero(&p->stats, sizeof(struct proto_stats)); rt_unlock_table(p->table); + +#ifdef CONFIG_PIPE + if (proto_is_pipe(p)) + rt_unlock_table(pipe_get_peer_table(p)); +#endif + proto_rethink_goal(p); } diff --git a/nest/protocol.h b/nest/protocol.h index 5a69b33..99d8dc8 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -334,4 +334,18 @@ struct announce_hook { struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); +/* + * Some pipe-specific nest hacks + */ + +#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); + +#endif + + #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index 413675c..fee5718 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -642,7 +642,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new /* Do not filter routes going through the pipe, they are filtered in the export filter only. */ #ifdef CONFIG_PIPE - if (p->proto == &proto_pipe) + if (proto_is_pipe(p)) filter = FILTER_ACCEPT; #endif -- cgit v1.2.3 From 9db74169be76f658df2207d1ec99eac48fa36f5f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 13 Feb 2010 10:44:46 +0100 Subject: Fixes protocol statistics for pipes. --- nest/proto.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++----------- nest/protocol.h | 1 + nest/rt-table.c | 53 +++++++++++++++++++++++-------------- 3 files changed, 101 insertions(+), 35 deletions(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index c6b7e63..a7e4e0c 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -791,6 +791,67 @@ proto_state_name(struct proto *p) #undef P } +static void +proto_do_show_stats(struct proto *p) +{ + struct proto_stats *s = &p->stats; + cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", + s->imp_routes, s->exp_routes, s->pref_routes); + cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); + cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", + s->imp_updates_received, s->imp_updates_invalid, + s->imp_updates_filtered, s->imp_updates_ignored, + s->imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + s->imp_withdraws_received, s->imp_withdraws_invalid, + s->imp_withdraws_ignored, s->imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", + s->exp_updates_received, s->exp_updates_rejected, + s->exp_updates_filtered, s->exp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", + s->exp_withdraws_received, s->exp_withdraws_accepted); +} + +static void +proto_do_show_pipe_stats(struct proto *p) +{ + struct proto_stats *s1 = &p->stats; + struct proto_stats *s2 = pipe_get_peer_stats(p); + + /* + * Pipe stats (as anything related to pipes) are a bit tricky. There + * are two sets of stats - s1 for routes going from the primary + * routing table to the secondary routing table ('exported' from the + * user point of view) and s2 for routes going in the other + * direction ('imported' from the user point of view). + * + * 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, ...) + */ + + cli_msg(-1006, " Routes: %u imported, %u exported", + s2->imp_routes, s1->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 + s2->imp_updates_invalid, + s2->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + s2->exp_withdraws_received, s2->imp_withdraws_invalid, + s2->imp_withdraws_ignored, s2->imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u", + s1->exp_updates_received, s1->exp_updates_rejected + s1->imp_updates_invalid, + s1->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u", + s1->exp_withdraws_received, s1->imp_withdraws_invalid, + s1->imp_withdraws_ignored, s1->imp_withdraws_accepted); +} + static void proto_do_show(struct proto *p, int verbose) { @@ -817,21 +878,12 @@ proto_do_show(struct proto *p, int verbose) if (p->proto_state != PS_DOWN) { - cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", - p->stats.imp_routes, p->stats.exp_routes, p->stats.pref_routes); - cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); - cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", - p->stats.imp_updates_received, p->stats.imp_updates_invalid, - p->stats.imp_updates_filtered, p->stats.imp_updates_ignored, - p->stats.imp_updates_accepted); - cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", - p->stats.imp_withdraws_received, p->stats.imp_withdraws_invalid, - p->stats.imp_withdraws_ignored, p->stats.imp_withdraws_accepted); - cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", - p->stats.exp_updates_received, p->stats.exp_updates_rejected, - p->stats.exp_updates_filtered, p->stats.exp_updates_accepted); - cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", - p->stats.exp_withdraws_received, p->stats.exp_withdraws_accepted); +#ifdef CONFIG_PIPE + if (proto_is_pipe(p)) + proto_do_show_pipe_stats(p); + else +#endif + proto_do_show_stats(p); } cli_msg(-1006, ""); diff --git a/nest/protocol.h b/nest/protocol.h index 99d8dc8..876427a 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -344,6 +344,7 @@ 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); #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index fee5718..c9e421e 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 proto_stats *stats = &p->stats; rte *new0 = new; rte *old0 = old; int ok; @@ -169,18 +170,18 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, if (new) { - p->stats.exp_updates_received++; + stats->exp_updates_received++; char *drop_reason = NULL; if ((class & IADDR_SCOPE_MASK) < p->min_scope) { - p->stats.exp_updates_rejected++; + stats->exp_updates_rejected++; drop_reason = "out of scope"; fast_exit_hack = 1; } else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) { - p->stats.exp_updates_rejected++; + stats->exp_updates_rejected++; drop_reason = "rejected by protocol"; } else if (ok) @@ -188,7 +189,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, 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) { - p->stats.exp_updates_filtered++; + stats->exp_updates_filtered++; drop_reason = "filtered out"; } if (drop_reason) @@ -200,7 +201,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, } } else - p->stats.exp_withdraws_received++; + stats->exp_withdraws_received++; /* Hack: This is here to prevent 'spurious withdraws' for loopback addresses during reload. */ @@ -249,16 +250,16 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, return; if (new) - p->stats.exp_updates_accepted++; + stats->exp_updates_accepted++; else - p->stats.exp_withdraws_accepted++; + stats->exp_withdraws_accepted++; /* Hack: We do not decrease exp_routes during refeed, we instead reset exp_routes at the start of refeed. */ if (new) - p->stats.exp_routes++; + stats->exp_routes++; if (old && !refeed) - p->stats.exp_routes--; + stats->exp_routes--; if (p->debug & D_ROUTES) { @@ -416,10 +417,16 @@ rte_same(rte *x, rte *y) static void rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa) { + struct proto_stats *stats = &p->stats; rte *old_best = net->routes; rte *old = NULL; rte **k, *r, *s; +#ifdef CONFIG_PIPE + if (proto_is_pipe(p) && (p->table == table)) + stats = pipe_get_peer_stats(p); +#endif + k = &net->routes; /* Find and remove original route from the same protocol */ while (old = *k) { @@ -448,7 +455,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte if (new && rte_same(old, new)) { /* No changes, ignore the new route */ - p->stats.imp_updates_ignored++; + stats->imp_updates_ignored++; rte_trace_in(D_ROUTES, p, new, "ignored"); rte_free_quick(new); old->lastmod = now; @@ -462,19 +469,19 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte if (!old && !new) { - p->stats.imp_withdraws_ignored++; + stats->imp_withdraws_ignored++; return; } if (new) - p->stats.imp_updates_accepted++; + stats->imp_updates_accepted++; else - p->stats.imp_withdraws_accepted++; + stats->imp_withdraws_accepted++; if (new) - p->stats.imp_routes++; + stats->imp_routes++; if (old) - p->stats.imp_routes--; + stats->imp_routes--; rte_announce(table, RA_ANY, net, new, old, tmpa); @@ -632,6 +639,12 @@ void rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new) { ea_list *tmpa = NULL; + struct proto_stats *stats = &p->stats; + +#ifdef CONFIG_PIPE + if (proto_is_pipe(p) && (p->table == table)) + stats = pipe_get_peer_stats(p); +#endif rte_update_lock(); if (new) @@ -646,16 +659,16 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new filter = FILTER_ACCEPT; #endif - p->stats.imp_updates_received++; + stats->imp_updates_received++; if (!rte_validate(new)) { rte_trace_in(D_FILTERS, p, new, "invalid"); - p->stats.imp_updates_invalid++; + stats->imp_updates_invalid++; goto drop; } if (filter == FILTER_REJECT) { - p->stats.imp_updates_filtered++; + stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -667,7 +680,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); if (fr > F_ACCEPT) { - p->stats.imp_updates_filtered++; + stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -679,7 +692,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new new->flags |= REF_COW; } else - p->stats.imp_withdraws_received++; + stats->imp_withdraws_received++; rte_recalculate(table, net, p, src, new, tmpa); rte_update_unlock(); -- cgit v1.2.3 From dca75fd7c207f0bfc627cb6b74a484da3b27e05f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 13 Feb 2010 12:26:26 +0100 Subject: Removes phantom protocol from the pipe design. It seems that by adding one pipe-specific exception to route announcement code and by adding one argument to rt_notify() callback i could completely eliminate the need for the phantom protocol instance and therefore make the code more straightforward. It will also fix some minor bugs (like ignoring debug flag changes from the command line). --- nest/proto-hooks.c | 3 ++- nest/proto.c | 5 ----- nest/protocol.h | 11 +++-------- nest/rt-table.c | 24 +++++++++++++++++------- 4 files changed, 22 insertions(+), 21 deletions(-) (limited to 'nest') diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index c30b107..3d19e3f 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 a7e4e0c..57c2aa1 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 876427a..82f3766 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 c9e421e..72a1cb0 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) -- cgit v1.2.3 From e304fd4bcf5813b581a39078a25a5cf6916b9f29 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 20 Feb 2010 00:03:31 +0100 Subject: Implements pattern match for 'show protocols' command. And generally consolidates protocol commands. --- nest/config.Y | 41 +++++---- nest/proto.c | 254 ++++++++++++++++++++++++++++---------------------------- nest/protocol.h | 31 ++++--- 3 files changed, 170 insertions(+), 156 deletions(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index 11f0a9b..8dc8c71 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -59,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT) %type optsym %type r_args %type echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport -%type proto_patt +%type proto_patt proto_patt2 CF_GRAMMAR @@ -324,11 +324,11 @@ CF_CLI_HELP(SHOW, ..., [[Show status information]]) CF_CLI(SHOW STATUS,,, [[Show router status]]) { cmd_show_status(); } ; -CF_CLI(SHOW PROTOCOLS, optsym, [], [[Show routing protocols]]) -{ proto_show($3, 0); } ; +CF_CLI(SHOW PROTOCOLS, proto_patt2, [ | \"\"], [[Show routing protocols]]) +{ proto_apply_cmd($3, proto_cmd_show, 0); } ; -CF_CLI(SHOW PROTOCOLS ALL, optsym, [], [[Show routing protocol details]]) -{ proto_show($4, 1); } ; +CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show routing protocol details]]) +{ proto_apply_cmd($4, proto_cmd_show, 1); } ; optsym: SYM @@ -459,34 +459,39 @@ echo_size: ; CF_CLI(DISABLE, proto_patt, | \"\" | all, [[Disable protocol]]) -{ proto_xxable($2, XX_DISABLE); } ; +{ proto_apply_cmd($2, proto_cmd_disable, 0); } ; CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]]) -{ proto_xxable($2, XX_ENABLE); } ; +{ proto_apply_cmd($2, proto_cmd_enable, 0); } ; CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]]) -{ proto_xxable($2, XX_RESTART); } ; +{ proto_apply_cmd($2, proto_cmd_restart, 0); } ; CF_CLI(RELOAD, proto_patt, | \"\" | all, [[Reload protocol]]) -{ proto_xxable($2, XX_RELOAD); } ; +{ proto_apply_cmd($2, proto_cmd_reload, CMD_RELOAD); } ; CF_CLI(RELOAD IN, proto_patt, | \"\" | all, [[Reload protocol (just imported routes)]]) -{ proto_xxable($3, XX_RELOAD_IN); } ; +{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_IN); } ; CF_CLI(RELOAD OUT, proto_patt, | \"\" | all, [[Reload protocol (just exported routes)]]) -{ proto_xxable($3, XX_RELOAD_OUT); } ; +{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_OUT); } ; CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]]) CF_CLI(DEBUG, proto_patt debug_mask, ( | | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging via BIRD logs]]) -{ proto_debug($2, 0, $3); } - ; +{ proto_apply_cmd($2, proto_cmd_debug, $3); } ; CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]]) CF_CLI(MRTDUMP, proto_patt mrtdump_mask, ( | | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) -{ proto_debug($2, 1, $3); } - ; +{ proto_apply_cmd($2, proto_cmd_mrtdump, $3); } ; proto_patt: - SYM { $$ = $1->name; } - | ALL { $$ = "*"; } - | TEXT + SYM { $$.ptr = $1; $$.patt = 0; } + | ALL { $$.ptr = NULL; $$.patt = 1; } + | TEXT { $$.ptr = $1; $$.patt = 1; } ; +proto_patt2: + SYM { $$.ptr = $1; $$.patt = 0; } + | { $$.ptr = NULL; $$.patt = 1; } + | TEXT { $$.ptr = $1; $$.patt = 1; } + ; + + CF_CODE CF_END diff --git a/nest/proto.c b/nest/proto.c index 57c2aa1..7c4d32d 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -25,12 +25,6 @@ static pool *proto_pool; static list protocol_list; static list proto_list; -#define WALK_PROTO_LIST(p) do { \ - node *nn; \ - WALK_LIST(nn, proto_list) { \ - struct proto *p = SKIP_BACK(struct proto, glob_node, nn); -#define WALK_PROTO_LIST_END } } while(0) - #define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0) list active_proto_list; @@ -847,11 +841,15 @@ proto_do_show_pipe_stats(struct proto *p) s1->imp_withdraws_ignored, s1->imp_withdraws_accepted); } -static void -proto_do_show(struct proto *p, int verbose) +void +proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) { byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE]; + /* First protocol - show header */ + if (!cnt) + cli_msg(-2002, "name proto table state since info"); + buf[0] = 0; if (p->proto->get_status) p->proto->get_status(p, buf); @@ -886,25 +884,136 @@ proto_do_show(struct proto *p, int verbose) } void -proto_show(struct symbol *s, int verbose) +proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) { - if (s && s->class != SYM_PROTO) + if (p->disabled) { - cli_msg(9002, "%s is not a protocol", s->name); + cli_msg(-8, "%s: already disabled", p->name); return; } - cli_msg(-2002, "name proto table state since info"); - if (s) - proto_do_show(((struct proto_config *)s->def)->proto, verbose); - else + + log(L_INFO "Disabling protocol %s", p->name); + p->disabled = 1; + proto_rethink_goal(p); + cli_msg(-9, "%s: disabled", p->name); +} + +void +proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +{ + if (!p->disabled) + { + cli_msg(-10, "%s: already enabled", p->name); + return; + } + + log(L_INFO "Enabling protocol %s", p->name); + p->disabled = 0; + proto_rethink_goal(p); + cli_msg(-11, "%s: enabled", p->name); +} + +void +proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +{ + if (p->disabled) + { + cli_msg(-8, "%s: already disabled", p->name); + return; + } + + log(L_INFO "Restarting protocol %s", p->name); + p->disabled = 1; + proto_rethink_goal(p); + p->disabled = 0; + proto_rethink_goal(p); + cli_msg(-12, "%s: restarted", p->name); +} + +void +proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED) +{ + if (p->disabled) + { + cli_msg(-8, "%s: already disabled", p->name); + return; + } + + /* If the protocol in not UP, it has no routes */ + if (p->proto_state != PS_UP) + return; + + log(L_INFO "Reloading protocol %s", p->name); + + /* re-importing routes */ + if (dir != CMD_RELOAD_OUT) + if (! (p->reload_routes && p->reload_routes(p))) + { + cli_msg(-8006, "%s: reload failed", p->name); + return; + } + + /* re-exporting routes */ + if (dir != CMD_RELOAD_IN) + proto_request_feeding(p); + + cli_msg(-15, "%s: reloading", p->name); +} + +void +proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED) +{ + p->debug = mask; +} + +void +proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED) +{ + p->mrtdump = mask; +} + +static void +proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +{ + if (s->class != SYM_PROTO) { - WALK_PROTO_LIST(p) - proto_do_show(p, verbose); - WALK_PROTO_LIST_END; + cli_msg(9002, "%s is not a protocol", s->name); + return; } + + cmd(((struct proto_config *)s->def)->proto, arg, 0); cli_msg(0, ""); } +static void +proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +{ + int cnt = 0; + + node *nn; + WALK_LIST(nn, proto_list) + { + struct proto *p = SKIP_BACK(struct proto, glob_node, nn); + + if (!patt || patmatch(patt, p->name)) + cmd(p, arg, cnt++); + } + + if (!cnt) + cli_msg(8003, "No protocols match"); + else + cli_msg(0, ""); +} + +void +proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +{ + if (ps.patt) + proto_apply_cmd_patt(ps.ptr, cmd, arg); + else + proto_apply_cmd_symbol(ps.ptr, cmd, arg); +} + struct proto * proto_get_named(struct symbol *sym, struct protocol *pr) { @@ -933,112 +1042,3 @@ proto_get_named(struct symbol *sym, struct protocol *pr) } return p; } - -void -proto_xxable(char *pattern, int xx) -{ - int cnt = 0; - WALK_PROTO_LIST(p) - if (patmatch(pattern, p->name)) - { - cnt++; - switch (xx) - { - case XX_DISABLE: - if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else - { - log(L_INFO "Disabling protocol %s", p->name); - p->disabled = 1; - proto_rethink_goal(p); - cli_msg(-9, "%s: disabled", p->name); - } - break; - - case XX_ENABLE: - if (!p->disabled) - cli_msg(-10, "%s: already enabled", p->name); - else - { - log(L_INFO "Enabling protocol %s", p->name); - p->disabled = 0; - proto_rethink_goal(p); - cli_msg(-11, "%s: enabled", p->name); - } - break; - - case XX_RESTART: - if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else - { - log(L_INFO "Restarting protocol %s", p->name); - p->disabled = 1; - proto_rethink_goal(p); - p->disabled = 0; - proto_rethink_goal(p); - cli_msg(-12, "%s: restarted", p->name); - } - break; - - case XX_RELOAD: - case XX_RELOAD_IN: - case XX_RELOAD_OUT: - if (p->disabled) - { - cli_msg(-8, "%s: already disabled", p->name); - break; - } - - /* If the protocol in not UP, it has no routes */ - if (p->proto_state != PS_UP) - break; - - log(L_INFO "Reloading protocol %s", p->name); - - /* re-importing routes */ - if (xx != XX_RELOAD_OUT) - if (! (p->reload_routes && p->reload_routes(p))) - { - cli_msg(-8006, "%s: reload failed", p->name); - break; - } - - /* re-exporting routes */ - if (xx != XX_RELOAD_IN) - proto_request_feeding(p); - - cli_msg(-15, "%s: reloading", p->name); - break; - - default: - ASSERT(0); - } - } - WALK_PROTO_LIST_END; - if (!cnt) - cli_msg(8003, "No protocols match"); - else - cli_msg(0, ""); -} - -void -proto_debug(char *pattern, int which, unsigned int mask) -{ - int cnt = 0; - WALK_PROTO_LIST(p) - if (patmatch(pattern, p->name)) - { - cnt++; - if (which == 0) - p->debug = mask; - else - p->mrtdump = mask; - } - WALK_PROTO_LIST_END; - if (!cnt) - cli_msg(8003, "No protocols match"); - else - cli_msg(0, ""); -} diff --git a/nest/protocol.h b/nest/protocol.h index 82f3766..d652c4f 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -195,21 +195,30 @@ struct proto { /* Hic sunt protocol-specific data */ }; +struct proto_spec { + void *ptr; + int patt; +}; + + void *proto_new(struct proto_config *, unsigned size); void *proto_config_new(struct protocol *, unsigned size); - void proto_request_feeding(struct proto *p); -void proto_show(struct symbol *, int); + +void proto_cmd_show(struct proto *, unsigned int, int); +void proto_cmd_disable(struct proto *, unsigned int, int); +void proto_cmd_enable(struct proto *, unsigned int, int); +void proto_cmd_restart(struct proto *, unsigned int, int); +void proto_cmd_reload(struct proto *, unsigned int, int); +void proto_cmd_debug(struct proto *, unsigned int, int); +void proto_cmd_mrtdump(struct proto *, unsigned int, int); + +void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg); struct proto *proto_get_named(struct symbol *, struct protocol *); -void proto_xxable(char *, int); -void proto_debug(char *, int, unsigned int); - -#define XX_DISABLE 0 -#define XX_ENABLE 1 -#define XX_RESTART 2 -#define XX_RELOAD 3 -#define XX_RELOAD_IN 4 -#define XX_RELOAD_OUT 5 + +#define CMD_RELOAD 0 +#define CMD_RELOAD_IN 1 +#define CMD_RELOAD_OUT 2 static inline u32 proto_get_router_id(struct proto_config *pc) -- cgit v1.2.3 From e0a45fb42163a6bfdeeee44bd0a6a7461552e10f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 21 Feb 2010 09:57:26 +0100 Subject: Restricted read-only CLI. Also adds support for executing commands using birdc . --- nest/cli.h | 9 +++++++++ nest/config.Y | 25 ++++++++++++++----------- nest/proto.c | 6 +++++- nest/protocol.h | 2 +- 4 files changed, 29 insertions(+), 13 deletions(-) (limited to 'nest') diff --git a/nest/cli.h b/nest/cli.h index f816ef1..57414a2 100644 --- a/nest/cli.h +++ b/nest/cli.h @@ -33,6 +33,7 @@ typedef struct cli { void (*cleanup)(struct cli *c); void *rover; /* Private to continuation routine */ int last_reply; + int restricted; /* CLI is restricted to read-only commands */ struct linpool *parser_pool; /* Pool used during parsing */ byte *ring_buf; /* Ring buffer for asynchronous messages */ byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */ @@ -60,6 +61,14 @@ void cli_kick(cli *); void cli_written(cli *); void cli_echo(unsigned int class, byte *msg); +static inline int cli_access_restricted(void) +{ + if (this_cli && this_cli->restricted) + return (cli_printf(this_cli, 8007, "Access denied"), 1); + else + return 0; +} + /* Functions provided by sysdep layer */ void cli_write_trigger(cli *); diff --git a/nest/config.Y b/nest/config.Y index 8dc8c71..5a89505 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -45,7 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION) -CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES) +CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -325,10 +325,10 @@ CF_CLI(SHOW STATUS,,, [[Show router status]]) { cmd_show_status(); } ; CF_CLI(SHOW PROTOCOLS, proto_patt2, [ | \"\"], [[Show routing protocols]]) -{ proto_apply_cmd($3, proto_cmd_show, 0); } ; +{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ; CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show routing protocol details]]) -{ proto_apply_cmd($4, proto_cmd_show, 1); } ; +{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; optsym: SYM @@ -459,25 +459,28 @@ echo_size: ; CF_CLI(DISABLE, proto_patt, | \"\" | all, [[Disable protocol]]) -{ proto_apply_cmd($2, proto_cmd_disable, 0); } ; +{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]]) -{ proto_apply_cmd($2, proto_cmd_enable, 0); } ; +{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]]) -{ proto_apply_cmd($2, proto_cmd_restart, 0); } ; +{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; CF_CLI(RELOAD, proto_patt, | \"\" | all, [[Reload protocol]]) -{ proto_apply_cmd($2, proto_cmd_reload, CMD_RELOAD); } ; +{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ; CF_CLI(RELOAD IN, proto_patt, | \"\" | all, [[Reload protocol (just imported routes)]]) -{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_IN); } ; +{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ; CF_CLI(RELOAD OUT, proto_patt, | \"\" | all, [[Reload protocol (just exported routes)]]) -{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_OUT); } ; +{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ; CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]]) CF_CLI(DEBUG, proto_patt debug_mask, ( | | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging via BIRD logs]]) -{ proto_apply_cmd($2, proto_cmd_debug, $3); } ; +{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ; CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]]) CF_CLI(MRTDUMP, proto_patt mrtdump_mask, ( | | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) -{ proto_apply_cmd($2, proto_cmd_mrtdump, $3); } ; +{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ; + +CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]]) +{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; proto_patt: SYM { $$.ptr = $1; $$.patt = 0; } diff --git a/nest/proto.c b/nest/proto.c index 7c4d32d..e9cf3df 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1006,8 +1006,12 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int) } void -proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), + int restricted, unsigned int arg) { + if (restricted && cli_access_restricted()) + return; + if (ps.patt) proto_apply_cmd_patt(ps.ptr, cmd, arg); else diff --git a/nest/protocol.h b/nest/protocol.h index d652c4f..99356a3 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -213,7 +213,7 @@ void proto_cmd_reload(struct proto *, unsigned int, int); void proto_cmd_debug(struct proto *, unsigned int, int); void proto_cmd_mrtdump(struct proto *, unsigned int, int); -void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg); +void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg); struct proto *proto_get_named(struct symbol *, struct protocol *); #define CMD_RELOAD 0 -- cgit v1.2.3 From e81b440f6878605edd19ed62441648ac71260881 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 21 Feb 2010 14:34:53 +0100 Subject: Fix configure to enable warnings and fix most of them. --- nest/a-path.c | 4 ++-- nest/cli.c | 4 ++-- nest/locks.c | 3 ++- nest/proto.c | 2 +- nest/rt-table.c | 12 ++++++------ 5 files changed, 13 insertions(+), 12 deletions(-) (limited to 'nest') diff --git a/nest/a-path.c b/nest/a-path.c index 396d463..058b434 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -385,7 +385,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) struct pm_pos pos[2048 + 1]; int plen = parse_path(path, pos); int l, h, i, nh, nl; - u32 val; + u32 val = 0; /* l and h are bound of interval of positions where are marked states */ @@ -417,7 +417,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) goto step; case PM_QUESTION: step: - nh = -1; + nh = nl = -1; for (i = h; i >= l; i--) if (pos[i].mark) { diff --git a/nest/cli.c b/nest/cli.c index ace97be..4d2b8fd 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -357,8 +357,8 @@ cli_echo(unsigned int class, byte *msg) free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1); else free = c->ring_read - c->ring_write - 1; - if (len > free || - free < c->log_threshold && class < (unsigned) L_INFO[0]) + if ((len > free) || + (free < c->log_threshold && class < (unsigned) L_INFO[0])) { c->ring_overflow++; continue; diff --git a/nest/locks.c b/nest/locks.c index 1cdbbc9..7044d6a 100644 --- a/nest/locks.c +++ b/nest/locks.c @@ -97,7 +97,8 @@ static struct resclass olock_class = { "ObjLock", sizeof(struct object_lock), olock_free, - olock_dump + olock_dump, + NULL }; /** diff --git a/nest/proto.c b/nest/proto.c index e9cf3df..4883705 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -51,7 +51,7 @@ proto_enqueue(list *l, struct proto *p) static void proto_relink(struct proto *p) { - list *l; + list *l = NULL; if (p->debug & D_STATES) { diff --git a/nest/rt-table.c b/nest/rt-table.c index 72a1cb0..41ecf64 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,7 +158,7 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) } 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) +do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) { struct proto *p = a->proto; struct filter *filter = p->out_filter; @@ -196,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 (filter == FILTER_REJECT || - filter && f_run(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"; @@ -329,7 +329,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, * the protocol gets called. */ static void -rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) +rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list *tmpa) { struct announce_hook *a; int class = ipa_classify(net->n.prefix); @@ -1203,8 +1203,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) 'configure soft' command may change the export filter and do not update routes */ - if (p1->out_filter == FILTER_REJECT || - p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) + if ((p1->out_filter == FILTER_REJECT) || + (p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) ok = 0; } } -- cgit v1.2.3 From ff2857b03db854f99902766ad842aaa5fa29ec3c Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 26 Feb 2010 10:55:58 +0100 Subject: Many changes in (mainly) kernel syncers. - BSD kernel syncer is now self-conscious and can learn alien routes - important bugfix in BSD kernel syncer (crash after protocol restart) - many minor changes and bugfixes in kernel syncers and neighbor cache - direct protocol does not generate host and link local routes - min_scope check is removed, all routes have SCOPE_UNIVERSE by default - also fixes some remaining compiler warnings --- nest/iface.h | 1 + nest/neighbor.c | 23 +++++++++++++++++------ nest/proto.c | 1 - nest/protocol.h | 1 - nest/rt-dev.c | 7 +++++-- nest/rt-table.c | 52 ++++++++++++---------------------------------------- 6 files changed, 35 insertions(+), 50 deletions(-) (limited to 'nest') diff --git a/nest/iface.h b/nest/iface.h index a982c17..02129ac 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -97,6 +97,7 @@ typedef struct neighbor { } neighbor; #define NEF_STICKY 1 +#define NEF_ONLINK 2 neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags); neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); diff --git a/nest/neighbor.c b/nest/neighbor.c index a44667f..25b98db 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -112,12 +112,12 @@ neighbor * neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) { neighbor *n; - int class, scope = SCOPE_HOST; + int class, scope = -1; ; unsigned int h = neigh_hash(p, a); struct iface *i; WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ - if (n->proto == p && ipa_equal(*a, n->addr)) + if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface))) return n; class = ipa_classify(*a); @@ -129,7 +129,12 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) return NULL; /* Bad scope or a somecast */ if (ifa) - scope = if_connected(a, ifa); + { + scope = if_connected(a, ifa); + + if ((scope < 0) && (flags & NEF_ONLINK)) + scope = class & IADDR_SCOPE_MASK; + } else WALK_LIST(i, iface_list) if ((scope = if_connected(a, i)) >= 0) @@ -138,22 +143,28 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) break; } - if (!ifa && !(flags & NEF_STICKY)) + /* scope < 0 means i don't know neighbor */ + /* scope >= 0 implies ifa != NULL */ + + if ((scope < 0) && !(flags & NEF_STICKY)) return NULL; n = sl_alloc(neigh_slab); n->addr = *a; - n->iface = ifa; - if (ifa) + if (scope >= 0) { add_tail(&neigh_hash_table[h], &n->n); add_tail(&ifa->neighbors, &n->if_n); } else { + /* sticky flag does not work for link-local neighbors; + fortunately, we don't use this combination */ add_tail(&sticky_neigh_list, &n->n); + ifa = NULL; scope = 0; } + n->iface = ifa; n->proto = p; n->data = NULL; n->aux = 0; diff --git a/nest/proto.c b/nest/proto.c index 4883705..db6bf9b 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -113,7 +113,6 @@ proto_new(struct proto_config *c, unsigned size) p->table = c->table->table; p->in_filter = c->in_filter; p->out_filter = c->out_filter; - p->min_scope = SCOPE_SITE; p->hash_key = random_u32(); c->proto = p; return p; diff --git a/nest/protocol.h b/nest/protocol.h index 99356a3..d94873e 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -130,7 +130,6 @@ struct proto { u32 debug; /* Debugging flags */ u32 mrtdump; /* MRTDump flags */ unsigned preference; /* Default route preference */ - int min_scope; /* Minimal route scope accepted */ unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */ unsigned disabled; /* Manually disabled */ unsigned proto_state; /* Protocol state machine (see below) */ diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b86015d..bb8eb8e 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -33,6 +33,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) !iface_patt_find(&P->iface_list, ad->iface)) /* Empty list is automagically treated as "*" */ return; + + if (ad->scope <= SCOPE_LINK) + return; + if (c & IF_CHANGE_DOWN) { net *n; @@ -56,7 +60,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) bzero(&A, sizeof(A)); A.proto = p; A.source = RTS_DEVICE; - A.scope = ad->scope; + A.scope = SCOPE_UNIVERSE; A.cast = RTC_UNICAST; A.dest = RTD_DEVICE; A.iface = ad->iface; @@ -76,7 +80,6 @@ dev_init(struct proto_config *c) struct proto *p = proto_new(c, sizeof(struct proto)); p->ifa_notify = dev_ifa_notify; - p->min_scope = SCOPE_HOST; return p; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 41ecf64..1860b1a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,7 +158,7 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) } static inline void -do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed) +do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rte *old, ea_list *tmpa, int refeed) { struct proto *p = a->proto; struct filter *filter = p->out_filter; @@ -183,13 +183,7 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt stats->exp_updates_received++; char *drop_reason = NULL; - if ((class & IADDR_SCOPE_MASK) < p->min_scope) - { - stats->exp_updates_rejected++; - drop_reason = "out of scope"; - fast_exit_hack = 1; - } - else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) + if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) { stats->exp_updates_rejected++; drop_reason = "rejected by protocol"; @@ -332,7 +326,6 @@ static void rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list *tmpa) { struct announce_hook *a; - int class = ipa_classify(net->n.prefix); if (type == RA_OPTIMAL) { @@ -346,7 +339,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list * { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); if (a->proto->accept_ra_types == type) - do_rte_announce(a, type, net, new, old, tmpa, class, 0); + do_rte_announce(a, type, net, new, old, tmpa, 0); } } @@ -362,33 +355,15 @@ rte_validate(rte *e) n->n.prefix, n->n.pxlen, e->sender->name); return 0; } - if (n->n.pxlen) + + c = ipa_classify_net(n->n.prefix); + if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { - c = ipa_classify(n->n.prefix); - if (c < 0 || !(c & IADDR_HOST)) - { - if (!ipa_nonzero(n->n.prefix)) - { - /* Various default routes */ -#ifdef IPV6 - if (n->n.pxlen == 96) -#else - if (n->n.pxlen <= 1) -#endif - return 1; - } - log(L_WARN "Ignoring bogus route %I/%d received via %s", - n->n.prefix, n->n.pxlen, e->sender->name); - return 0; - } - if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope) - { - log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s", - ip_scope_text(c & IADDR_SCOPE_MASK), - n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name); - return 0; - } + log(L_WARN "Ignoring bogus route %I/%d received via %s", + n->n.prefix, n->n.pxlen, e->sender->name); + return 0; } + return 1; } @@ -1018,7 +993,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) rte_update_lock(); tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; - do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding); + do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding); rte_update_unlock(); } @@ -1190,11 +1165,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (p2 && p2 != p0) ok = 0; if (ok && d->export_mode) { - int class = ipa_classify(n->n.prefix); int ic; - if ((class & IADDR_SCOPE_MASK) < p1->min_scope) - ok = 0; - else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) + if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) ok = 0; else if (!ic && d->export_mode > 1) { -- cgit v1.2.3 From 212ff335828fbe28311fcbae6154cf2495a44d0e Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 26 Feb 2010 13:55:22 +0100 Subject: Fixes signedness in format route attributes. --- nest/rt-attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nest') diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 9d78ce0..94b105d 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -400,7 +400,7 @@ ea_format(eattr *e, byte *buf) switch (e->type & EAF_TYPE_MASK) { case EAF_TYPE_INT: - bsprintf(buf, "%d", e->u.data); + bsprintf(buf, "%u", e->u.data); break; case EAF_TYPE_OPAQUE: for(i=0; ilength; i++) -- cgit v1.2.3 From 53434e44a95fe9334f4bdf5e0da987929addffb1 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 27 Feb 2010 16:00:07 +0100 Subject: Better flushing of interfaces. When device protocol goes down, interfaces should be flushed asynchronously (in the same way like routes from protocols are flushed), when protocol goes to DOWN/HUNGRY. This fixes the problem with static routes staying in kernel routing table after BIRD shutdown. --- nest/iface.c | 9 +++++++++ nest/iface.h | 3 ++- nest/proto.c | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'nest') diff --git a/nest/iface.c b/nest/iface.c index 5e88b21..82dead3 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -336,6 +336,15 @@ if_end_update(void) } } +void +if_flush_ifaces(struct proto *p) +{ + if (p->debug & D_EVENTS) + log(L_TRACE "%s: Flushing interfaces", p->name); + if_start_update(); + if_end_update(); +} + /** * if_feed_baby - advertise interfaces to a new protocol * @p: protocol to feed diff --git a/nest/iface.h b/nest/iface.h index 02129ac..8fc2567 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -75,8 +75,9 @@ struct iface *if_update(struct iface *); struct ifa *ifa_update(struct ifa *); void ifa_delete(struct ifa *); void if_start_update(void); -void if_end_update(void); void if_end_partial_update(struct iface *); +void if_end_update(void); +void if_flush_ifaces(struct proto *p); void if_feed_baby(struct proto *); struct iface *if_find_by_index(unsigned); struct iface *if_find_by_name(char *); diff --git a/nest/proto.c b/nest/proto.c index db6bf9b..78fca99 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -740,6 +740,8 @@ proto_notify_state(struct proto *p, unsigned ps) } } +extern struct protocol proto_unix_iface; + static void proto_flush_all(void *unused UNUSED) { @@ -748,6 +750,11 @@ proto_flush_all(void *unused UNUSED) rt_prune_all(); while ((p = HEAD(flush_proto_list))->n.next) { + /* This will flush interfaces in the same manner + like rt_prune_all() flushes routes */ + if (p->proto == &proto_unix_iface) + if_flush_ifaces(p); + DBG("Flushing protocol %s\n", p->name); p->core_state = FS_HUNGRY; proto_relink(p); -- cgit v1.2.3