From e04555c04545278cfe3aeae85d707b1d78e5abeb Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 17 Nov 2009 15:45:05 +0100 Subject: Implement description field of protocol. --- nest/config.Y | 3 ++- nest/proto.c | 3 +++ nest/protocol.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index 4721112..f287943 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -44,7 +44,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) 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) +CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -141,6 +141,7 @@ proto_item: | EXPORT imexport { this_proto->out_filter = $2; } | TABLE rtable { this_proto->table = $2; } | ROUTER ID idval { this_proto->router_id = $3; } + | DESCRIPTION dsc { this_proto->dsc = $2; } ; imexport: diff --git a/nest/proto.c b/nest/proto.c index 7bb1286..c05db76 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -307,6 +307,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty if (sym && sym->class == SYM_PROTO && !new->shutdown) { /* Found match, let's check if we can smoothly switch to new configuration */ + /* No need to check description */ nc = sym->def; if (!force_reconfig && nc->protocol == oc->protocol @@ -702,6 +703,8 @@ proto_do_show(struct proto *p, int verbose) buf); if (verbose) { + if (p->cf->dsc) + cli_msg(-1006, " Description: %s", p->cf->dsc); cli_msg(-1006, " Preference: %d", p->preference); cli_msg(-1006, " Input filter: %s", filter_name(p->in_filter)); cli_msg(-1006, " Output filter: %s", filter_name(p->out_filter)); diff --git a/nest/protocol.h b/nest/protocol.h index 484df84..807b579 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -81,6 +81,7 @@ struct proto_config { struct protocol *protocol; /* Protocol */ struct proto *proto; /* Instance we've created */ char *name; + char *dsc; unsigned debug, preference, disabled; /* Generic parameters */ u32 router_id; /* Protocol specific router ID */ struct rtable_config *table; /* Table we're attached to */ -- cgit v1.2.3 From 3f9b7bfe9ff050430a5886b22a5ab11b5f253048 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 18 Nov 2009 20:32:36 +0100 Subject: Implements option that controls IPv6 BGP next hops when lladdr is missing. --- nest/config.Y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index f287943..3d6f154 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -141,7 +141,7 @@ proto_item: | EXPORT imexport { this_proto->out_filter = $2; } | TABLE rtable { this_proto->table = $2; } | ROUTER ID idval { this_proto->router_id = $3; } - | DESCRIPTION dsc { this_proto->dsc = $2; } + | DESCRIPTION TEXT { this_proto->dsc = $2; } ; imexport: -- cgit v1.2.3 From 069bfcb53cef012c063a27e5af93d620be2917bd Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 24 Nov 2009 17:15:20 +0100 Subject: Fixes serious bug in core related to route filtering. If protocol announces a route, route is accepted by import filter to routing table, and later it announces replacement of that route that is rejected by import filter, old route remains in routing table. --- nest/rt-table.c | 1 + 1 file changed, 1 insertion(+) (limited to 'nest') diff --git a/nest/rt-table.c b/nest/rt-table.c index 87bf0dc..dda0e56 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -636,6 +636,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new drop: rte_free(new); + rte_recalculate(table, net, p, src, NULL, NULL); rte_update_unlock(); } -- cgit v1.2.3 From bf47fe4b2e40ccfcfe6af2d86548d06cdf9739c5 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 26 Nov 2009 20:47:59 +0100 Subject: Implements BGP route refresh. --- nest/config.Y | 7 ++++++ nest/proto.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++------ nest/protocol.h | 9 ++++++++ nest/rt-table.c | 14 ++++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index 3d6f154..dde20c5 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -45,6 +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, REFEED) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -442,6 +443,12 @@ CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]] { proto_xxable($2, 1); } ; CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]]) { proto_xxable($2, 2); } ; +CF_CLI(RELOAD, proto_patt, | \"\" | all, [[Reload protocol]]) +{ proto_xxable($2, 3); } ; +CF_CLI(REFEED, proto_patt, | \"\" | all, [[Refeed protocol BROKEN]]) +{ proto_xxable($2, 4); } ; + + CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging]]) CF_CLI(DEBUG, proto_patt debug_mask, ( | | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]]) diff --git a/nest/proto.c b/nest/proto.c index c05db76..c531d86 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -73,6 +73,10 @@ proto_relink(struct proto *p) rem_node(&p->n); switch (p->core_state) { + case FS_HUNGRY: + l = &inactive_proto_list; + break; + case FS_FEEDING: case FS_HAPPY: l = &active_proto_list; break; @@ -80,7 +84,7 @@ proto_relink(struct proto *p) l = &flush_proto_list; break; default: - l = &inactive_proto_list; + ASSERT(0); } proto_enqueue(l, p); } @@ -549,7 +553,7 @@ proto_feed_more(void *P) } static void -proto_feed(void *P) +proto_feed_initial(void *P) { struct proto *p = P; @@ -577,15 +581,44 @@ proto_schedule_flush(struct proto *p) } static void -proto_schedule_feed(struct proto *p) +proto_schedule_feed(struct proto *p, int initial) { DBG("%s: Scheduling meal\n", p->name); p->core_state = FS_FEEDING; proto_relink(p); - p->attn->hook = proto_feed; + p->attn->hook = initial ? proto_feed_initial : proto_feed_more; ev_schedule(p->attn); } +/** + * proto_request_feeding - request feeding routes to the protocol + * @p: given protocol + * + * Sometimes it is needed to send again all routes to the + * protocol. This is called feeding and can be requested by this + * function. This would cause protocol core state transition + * to FS_FEEDING (during feeding) and when completed, it will + * switch back to FS_HAPPY. This function can be called even + * when feeding is already running, in that case it is restarted. + */ +void +proto_request_feeding(struct proto *p) +{ + ASSERT(p->proto_state == PS_UP); + + /* If we are already feeding, we want to restart it */ + if (p->core_state == FS_FEEDING) + { + /* Unless feeding is in initial state */ + if (p->attn->hook == proto_feed_initial) + return; + + rt_feed_baby_abort(p); + } + + proto_schedule_feed(p, 0); +} + /** * proto_notify_state - notify core about protocol state change * @p: protocol the state of which has changed @@ -635,7 +668,7 @@ proto_notify_state(struct proto *p, unsigned ps) case PS_UP: ASSERT(ops == PS_DOWN || ops == PS_START); ASSERT(cs == FS_HUNGRY); - proto_schedule_feed(p); + proto_schedule_feed(p, 1); break; case PS_STOP: if ((cs = FS_FEEDING) || (cs == FS_HAPPY)) @@ -798,6 +831,7 @@ proto_xxable(char *pattern, int xx) { cli_msg(-9, "%s: disabled", p->name); p->disabled = 1; + proto_rethink_goal(p); } break; case 1: @@ -807,6 +841,7 @@ proto_xxable(char *pattern, int xx) { cli_msg(-11, "%s: enabled", p->name); p->disabled = 0; + proto_rethink_goal(p); } break; case 2: @@ -817,13 +852,33 @@ proto_xxable(char *pattern, int xx) p->disabled = 1; proto_rethink_goal(p); p->disabled = 0; + proto_rethink_goal(p); cli_msg(-12, "%s: restarted", p->name); } break; + case 3: + // FIXME change msg number + if (p->disabled) + cli_msg(-8, "%s: already disabled", p->name); + else if (p->reload_routes && p->reload_routes(p)) + cli_msg(-12, "%s: reloading", p->name); + else + cli_msg(-12, "%s: reload failed", p->name); + break; + case 4: + // FIXME change msg number + if (p->disabled) + cli_msg(-8, "%s: already disabled", p->name); + else + { + proto_request_feeding(p); + cli_msg(-12, "%s: reexport failed", p->name); + } + break; + default: ASSERT(0); } - proto_rethink_goal(p); } WALK_PROTO_LIST_END; if (!cnt) diff --git a/nest/protocol.h b/nest/protocol.h index 807b579..66e6c43 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -152,6 +152,9 @@ struct proto { * It can construct a new rte, add private attributes and * decide whether the route shall be imported: 1=yes, -1=no, * 0=process it through the import filter set by the user. + * reload_routes Request protocol to reload all its routes to the core + * (using rte_update()). Returns: 0=reload cannot be done, + * 1= reload is scheduled and will happen (asynchronously). */ void (*if_notify)(struct proto *, unsigned flags, struct iface *i); @@ -161,6 +164,7 @@ struct proto { struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool); void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs); int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool); + int (*reload_routes)(struct proto *); /* * Routing entry hooks (called only for rte's belonging to this protocol): @@ -190,6 +194,7 @@ struct proto { 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); struct proto *proto_get_named(struct symbol *, struct protocol *); void proto_xxable(char *, int); @@ -271,6 +276,10 @@ void proto_notify_state(struct proto *p, unsigned state); * HUNGRY/DOWN --> HUNGRY/START --> HUNGRY/UP --> * FEEDING/UP --> HAPPY/UP --> FLUSHING/STOP|DOWN --> * HUNGRY/STOP|DOWN --> HUNGRY/DOWN + * + * Sometimes, protocol might switch from HAPPY/UP to FEEDING/UP + * if it wants to refeed the routes (for example BGP does so + * as a result of received ROUTE-REFRESH request). */ #define FS_HUNGRY 0 diff --git a/nest/rt-table.c b/nest/rt-table.c index dda0e56..e0cd797 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -199,6 +199,14 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else p->stats.exp_withdraws_received++; + /* This is a tricky part - we don't know whether route 'old' was + exported to protocol 'p' or was filtered by the export filter. + We try tu run the export filter to know this to have a correct + value in 'old' argument of rt_update (and proper filter value) + + FIXME - this is broken because 'configure soft' may change + filters but keep routes */ + if (old) { if (p->out_filter == FILTER_REJECT) @@ -216,6 +224,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, } } + /* FIXME - This is broken because of incorrect 'old' value (see above) */ if (!new && !old) return; @@ -1122,6 +1131,11 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) ok = 0; else if (!ic && d->export_mode > 1) { + /* FIXME - this shows what should be exported according + to current filters, but not what was really exported. + '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) ok = 0; -- cgit v1.2.3 From e8b29bdc8dc34d4a0358458907a5d8ac29011d28 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Dec 2009 14:33:34 +0100 Subject: Fixes one missing log message. --- nest/rt-table.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'nest') diff --git a/nest/rt-table.c b/nest/rt-table.c index e0cd797..186a2dc 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -504,11 +504,10 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte net->routes->next = new; rte_trace_in(D_ROUTES, p, new, "added"); } - else if (old && (p->debug & D_ROUTES)) - { - /* Not really a case - the list of routes is correct, we just - log the route removal */ + /* Log the route removal */ + if (!new && old && (p->debug & D_ROUTES)) + { if (old != old_best) rte_trace_in(D_ROUTES, p, old, "removed"); else if (net->routes) -- cgit v1.2.3 From 11787b8473ae1685d43dad809592fabc64eb8f46 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Dec 2009 17:26:16 +0100 Subject: Fixes some problems in pipes. For transparent pipes, loop detection works correctly now. Pipes are now more symmetric - in both directions filtering is done in do_rte_announce(). --- nest/rt-table.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'nest') diff --git a/nest/rt-table.c b/nest/rt-table.c index 186a2dc..a8d0fee 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -403,6 +403,26 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte { if (old->attrs->proto == src) { + /* If there is the same route in the routing table but from + * a different sender, then there are two paths from the + * source protocol to this routing table through transparent + * pipes, which is not allowed. + * + * We log that and ignore the route. If it is withdraw, we + * ignore it completely (there might be 'spurious withdraws', + * see FIXME in do_rte_announce()) + */ + if (old->sender != p) + { + if (new) + { + log(L_ERR "Pipe collision detected when sending %I/%d to table %s", + net->n.prefix, net->n.pxlen, table->name); + rte_free_quick(new); + } + return; + } + if (new && rte_same(old, new)) { /* No changes, ignore the new route */ @@ -597,11 +617,12 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new new->sender = p; struct filter *filter = p->in_filter; - /* Do not filter routes going to the secondary side of the pipe, - that should only go through export filter. - FIXME Make a better check whether p is really a pipe. */ - if (p->table != table) + /* Do not filter routes going through the pipe, + they are filtered in the export filter only. */ +#ifdef CONFIG_PIPE + if (p->proto == &proto_pipe) filter = FILTER_ACCEPT; +#endif p->stats.imp_updates_received++; if (!rte_validate(new)) -- cgit v1.2.3 From 11361a101517c2c87e3d35d2c63cacb3ddb97724 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Dec 2009 22:19:47 +0100 Subject: Implements route re-feed. This can be used to re-feed routes to protocol after soft change in export filters. --- nest/proto.c | 1 + nest/protocol.h | 1 + nest/rt-table.c | 36 ++++++++++++++++++++++++------------ 3 files changed, 26 insertions(+), 12 deletions(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index c531d86..bdac4bf 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -585,6 +585,7 @@ proto_schedule_feed(struct proto *p, int initial) { DBG("%s: Scheduling meal\n", p->name); p->core_state = FS_FEEDING; + p->refeeding = !initial; proto_relink(p); p->attn->hook = initial ? proto_feed_initial : proto_feed_more; ev_schedule(p->attn); diff --git a/nest/protocol.h b/nest/protocol.h index 66e6c43..e1adc52 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -134,6 +134,7 @@ struct proto { unsigned core_state; /* Core state machine (see below) */ unsigned core_goal; /* State we want to reach (see below) */ unsigned reconfiguring; /* We're shutting down due to reconfiguration */ + unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */ u32 hash_key; /* Random key used for hashing of neighbors */ bird_clock_t last_state_change; /* Time of last state transition */ char *last_state_name_announced; /* Last state name we've announced to the user */ diff --git a/nest/rt-table.c b/nest/rt-table.c index a8d0fee..8efc0a6 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) +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; rte *new0 = new; @@ -199,15 +199,27 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else p->stats.exp_withdraws_received++; - /* This is a tricky part - we don't know whether route 'old' was - exported to protocol 'p' or was filtered by the export filter. - We try tu run the export filter to know this to have a correct - value in 'old' argument of rt_update (and proper filter value) - - FIXME - this is broken because 'configure soft' may change - filters but keep routes */ - - if (old) + /* + * This is a tricky part - we don't know whether route 'old' was + * exported to protocol 'p' or was filtered by the export filter. + * We try tu run the export filter to know this to have a correct + * value in 'old' argument of rt_update (and proper filter value) + * + * FIXME - this is broken because 'configure soft' may change + * filters but keep routes. Refeed is expected to be called after + * change of the filters and with old == new, therefore we do not + * even try to run the filter on an old route, This may lead to + * 'spurious withdraws' but ensure that there are no 'missing + * withdraws'. + * + * This is not completely safe as there is a window between + * reconfiguration and the end of refeed - if a newly filtered + * route disappears during this period, proper withdraw is not + * sent (because old would be also filtered) and the route is + * not refeeded (because it disappeared before that). + */ + + if (old && !refeed) { if (p->out_filter == FILTER_REJECT) old = NULL; @@ -313,7 +325,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); + do_rte_announce(a, type, net, new, old, tmpa, class, 0); } } @@ -973,7 +985,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, NULL, tmpa, ipa_classify(n->n.prefix)); + do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding); rte_update_unlock(); } -- cgit v1.2.3 From a421ec33cb9029899122d0ab63bab0fa268348d2 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Dec 2009 22:22:40 +0100 Subject: Fixes silly bug. --- nest/proto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nest') diff --git a/nest/proto.c b/nest/proto.c index bdac4bf..b23011d 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -649,7 +649,7 @@ proto_notify_state(struct proto *p, unsigned ps) switch (ps) { case PS_DOWN: - if ((cs = FS_FEEDING) || (cs == FS_HAPPY)) + if ((cs == FS_FEEDING) || (cs == FS_HAPPY)) proto_schedule_flush(p); neigh_prune(); // FIXME convert neighbors to resource? @@ -672,7 +672,7 @@ proto_notify_state(struct proto *p, unsigned ps) proto_schedule_feed(p, 1); break; case PS_STOP: - if ((cs = FS_FEEDING) || (cs == FS_HAPPY)) + if ((cs == FS_FEEDING) || (cs == FS_HAPPY)) proto_schedule_flush(p); break; default: -- cgit v1.2.3 From 8a7fb8858fa87bce6f2f15ee2bbb77704b5fff4e Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 14 Dec 2009 01:32:37 +0100 Subject: Finishes 'route reload' feature. --- nest/config.Y | 18 +++++++++--------- nest/proto.c | 48 ++++++++++++++++++++++++++++++------------------ nest/protocol.h | 7 +++++++ nest/rt-table.c | 12 +++++++++++- 4 files changed, 57 insertions(+), 28 deletions(-) (limited to 'nest') diff --git a/nest/config.Y b/nest/config.Y index dde20c5..dbb10ad 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, REFEED) +CF_KEYWORDS(RELOAD, IN, OUT) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -438,17 +438,17 @@ echo_size: ; CF_CLI(DISABLE, proto_patt, | \"\" | all, [[Disable protocol]]) -{ proto_xxable($2, 0); } ; +{ proto_xxable($2, XX_DISABLE); } ; CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]]) -{ proto_xxable($2, 1); } ; +{ proto_xxable($2, XX_ENABLE); } ; CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]]) -{ proto_xxable($2, 2); } ; +{ proto_xxable($2, XX_RESTART); } ; CF_CLI(RELOAD, proto_patt, | \"\" | all, [[Reload protocol]]) -{ proto_xxable($2, 3); } ; -CF_CLI(REFEED, proto_patt, | \"\" | all, [[Refeed protocol BROKEN]]) -{ proto_xxable($2, 4); } ; - - +{ proto_xxable($2, XX_RELOAD); } ; +CF_CLI(RELOAD IN, proto_patt, | \"\" | all, [[Reload protocol (just imported routes)]]) +{ proto_xxable($3, XX_RELOAD_IN); } ; +CF_CLI(RELOAD OUT, proto_patt, | \"\" | all, [[Reload protocol (just exported routes)]]) +{ proto_xxable($3, XX_RELOAD_OUT); } ; CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging]]) CF_CLI(DEBUG, proto_patt debug_mask, ( | | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging]]) diff --git a/nest/proto.c b/nest/proto.c index b23011d..4f352a6 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -586,6 +586,11 @@ proto_schedule_feed(struct proto *p, int initial) DBG("%s: Scheduling meal\n", p->name); p->core_state = FS_FEEDING; p->refeeding = !initial; + + /* Hack: reset exp_routes during refeed, and do not decrease it later */ + if (!initial) + p->stats.exp_routes = 0; + proto_relink(p); p->attn->hook = initial ? proto_feed_initial : proto_feed_more; ev_schedule(p->attn); @@ -825,7 +830,7 @@ proto_xxable(char *pattern, int xx) cnt++; switch (xx) { - case 0: + case XX_DISABLE: if (p->disabled) cli_msg(-8, "%s: already disabled", p->name); else @@ -835,7 +840,8 @@ proto_xxable(char *pattern, int xx) proto_rethink_goal(p); } break; - case 1: + + case XX_ENABLE: if (!p->disabled) cli_msg(-10, "%s: already enabled", p->name); else @@ -845,7 +851,8 @@ proto_xxable(char *pattern, int xx) proto_rethink_goal(p); } break; - case 2: + + case XX_RESTART: if (p->disabled) cli_msg(-8, "%s: already disabled", p->name); else @@ -857,24 +864,29 @@ proto_xxable(char *pattern, int xx) cli_msg(-12, "%s: restarted", p->name); } break; - case 3: - // FIXME change msg number - if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else if (p->reload_routes && p->reload_routes(p)) - cli_msg(-12, "%s: reloading", p->name); - else - cli_msg(-12, "%s: reload failed", p->name); - break; - case 4: - // FIXME change msg number + + case XX_RELOAD: + case XX_RELOAD_IN: + case XX_RELOAD_OUT: if (p->disabled) - cli_msg(-8, "%s: already disabled", p->name); - else { - proto_request_feeding(p); - cli_msg(-12, "%s: reexport failed", p->name); + cli_msg(-8, "%s: already disabled", p->name); + break; } + + /* 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: diff --git a/nest/protocol.h b/nest/protocol.h index e1adc52..21a1c1b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -201,6 +201,13 @@ struct proto *proto_get_named(struct symbol *, struct protocol *); void proto_xxable(char *, int); void proto_debug(char *, 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 + static inline u32 proto_get_router_id(struct proto_config *pc) { diff --git a/nest/rt-table.c b/nest/rt-table.c index 8efc0a6..df2834a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -165,6 +165,8 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, rte *old0 = old; int ok; + int fast_exit_hack = 0; + if (new) { p->stats.exp_updates_received++; @@ -174,6 +176,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, { 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) { @@ -199,6 +202,11 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else p->stats.exp_withdraws_received++; + /* Hack: This is here to prevent 'spurious withdraws' + for loopback addresses during reload. */ + if (fast_exit_hack) + return; + /* * This is a tricky part - we don't know whether route 'old' was * exported to protocol 'p' or was filtered by the export filter. @@ -245,9 +253,11 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else p->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++; - if (old) + if (old && !refeed) p->stats.exp_routes--; if (p->debug & D_ROUTES) -- cgit v1.2.3