diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/a-path.c | 4 | ||||
-rw-r--r-- | nest/cli.c | 4 | ||||
-rw-r--r-- | nest/cli.h | 9 | ||||
-rw-r--r-- | nest/config.Y | 46 | ||||
-rw-r--r-- | nest/iface.c | 9 | ||||
-rw-r--r-- | nest/iface.h | 4 | ||||
-rw-r--r-- | nest/locks.c | 3 | ||||
-rw-r--r-- | nest/neighbor.c | 23 | ||||
-rw-r--r-- | nest/proto-hooks.c | 3 | ||||
-rw-r--r-- | nest/proto.c | 354 | ||||
-rw-r--r-- | nest/protocol.h | 42 | ||||
-rw-r--r-- | nest/rt-attr.c | 2 | ||||
-rw-r--r-- | nest/rt-dev.c | 7 | ||||
-rw-r--r-- | nest/rt-table.c | 135 |
14 files changed, 385 insertions, 260 deletions
diff --git a/nest/a-path.c b/nest/a-path.c index 396d4632..058b4344 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) { @@ -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; @@ -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 f9e88d59..792012e7 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) @@ -59,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT) %type <s> optsym %type <ra> r_args %type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport -%type <t> proto_patt +%type <ps> 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, [<name>], [[Show routing protocols]]) -{ proto_show($3, 0); } ; +CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]]) +{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ; -CF_CLI(SHOW PROTOCOLS ALL, optsym, [<name>], [[Show routing protocol details]]) -{ proto_show($4, 1); } ; +CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]]) +{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; optsym: SYM @@ -459,34 +459,42 @@ echo_size: ; CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) -{ proto_xxable($2, XX_DISABLE); } ; +{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]) -{ proto_xxable($2, XX_ENABLE); } ; +{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]]) -{ proto_xxable($2, XX_RESTART); } ; +{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]]) -{ proto_xxable($2, XX_RELOAD); } ; +{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ; CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]]) -{ proto_xxable($3, XX_RELOAD_IN); } ; +{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ; CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]]) -{ proto_xxable($3, XX_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, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]]) -{ proto_debug($2, 0, $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, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) -{ proto_debug($2, 1, $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 { $$ = $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/iface.c b/nest/iface.c index 5e88b21b..82dead35 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 b7c3c19c..873734d8 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 *); @@ -106,6 +107,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/locks.c b/nest/locks.c index 1cdbbc99..7044d6a9 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/neighbor.c b/nest/neighbor.c index a44667f5..25b98dbd 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-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 870edddd..78fca99c 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; @@ -57,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) { @@ -119,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; @@ -583,6 +576,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); } @@ -741,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) { @@ -749,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); @@ -781,10 +787,75 @@ proto_state_name(struct proto *p) } static void -proto_do_show(struct proto *p, int verbose) +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); +} + +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); @@ -806,21 +877,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, ""); @@ -828,25 +890,140 @@ 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) { - WALK_PROTO_LIST(p) - proto_do_show(p, verbose); - WALK_PROTO_LIST_END; + 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) + { + 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), + int restricted, unsigned int arg) +{ + if (restricted && cli_access_restricted()) + return; + + 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) { @@ -875,112 +1052,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 5a69b33b..d94873e4 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; @@ -129,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) */ @@ -162,7 +162,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); @@ -194,21 +194,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), int restricted, 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) @@ -334,4 +343,13 @@ struct announce_hook { struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); +/* + * Some pipe-specific nest hacks + */ + +#ifdef CONFIG_PIPE +#include "proto/pipe/pipe.h" +#endif + + #endif diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 9d78ce07..94b105d7 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; i<ad->length; i++) diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b86015df..bb8eb8ee 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 413675c9..1860b1a1 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -158,37 +158,42 @@ 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 refeed) { struct proto *p = a->proto; + struct filter *filter = p->out_filter; + struct proto_stats *stats = &p->stats; rte *new0 = new; rte *old0 = old; int ok; 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) { - 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++; - 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) { - p->stats.exp_updates_rejected++; + stats->exp_updates_rejected++; drop_reason = "rejected by protocol"; } 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)) { - p->stats.exp_updates_filtered++; + stats->exp_updates_filtered++; drop_reason = "filtered out"; } if (drop_reason) @@ -200,7 +205,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. */ @@ -229,13 +234,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); @@ -249,16 +254,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) { @@ -270,18 +275,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) @@ -318,10 +323,9 @@ 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); if (type == RA_OPTIMAL) { @@ -335,7 +339,7 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) { 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); } } @@ -351,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; } @@ -416,10 +402,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 +440,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 +454,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 +624,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) @@ -642,20 +640,20 @@ 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 - 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 +665,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 +677,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(); @@ -995,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(); } @@ -1167,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) { @@ -1180,8 +1175,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; } } |