diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/proto-hooks.c | 13 | ||||
-rw-r--r-- | nest/proto.c | 210 | ||||
-rw-r--r-- | nest/protocol.h | 22 | ||||
-rw-r--r-- | nest/route.h | 6 | ||||
-rw-r--r-- | nest/rt-table.c | 82 |
5 files changed, 179 insertions, 154 deletions
diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index 2582c48b..e80f87ea 100644 --- a/nest/proto-hooks.c +++ b/nest/proto-hooks.c @@ -90,7 +90,7 @@ void dump_attrs(rte *e) * @p: protocol instance * * The start() hook is called by the core when it wishes to start - * the instance. + * the instance. Multitable protocols should lock their tables here. * * Result: new protocol state */ @@ -110,6 +110,17 @@ int shutdown(struct proto *p) { DUMMY; } /** + * cleanup - request instance cleanup + * @p: protocol instance + * + * The cleanup() hook is called by the core when the protocol became + * hungry/down, i.e. all protocol ahooks and routes are flushed. + * Multitable protocols should unlock their tables here. + */ +void cleanup(struct proto *p) +{ DUMMY; } + +/** * get_status - get instance status * @p: protocol instance * @buf: buffer to be filled with the status string diff --git a/nest/proto.c b/nest/proto.c index 0fc72ce1..9a7f123e 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -112,8 +112,6 @@ proto_new(struct proto_config *c, unsigned size) p->disabled = c->disabled; p->proto = pr; p->table = c->table->table; - p->in_filter = c->in_filter; - p->out_filter = c->out_filter; p->hash_key = random_u32(); c->proto = p; return p; @@ -126,49 +124,102 @@ proto_init_instance(struct proto *p) p->pool = rp_new(proto_pool, p->proto->name); p->attn = ev_new(p->pool); p->attn->data = p; - rt_lock_table(p->table); + + if (! p->proto->multitable) + rt_lock_table(p->table); } +extern pool *rt_table_pool; /** * proto_add_announce_hook - connect protocol to a routing table * @p: protocol instance * @t: routing table to connect to + * @in: input filter + * @out: output filter + * @stats: per-table protocol statistics * * This function creates a connection between the protocol instance @p * and the routing table @t, making the protocol hear all changes in * the table. * + * The announce hook is linked in the protocol ahook list and, if the + * protocol accepts routes, also in the table ahook list. Announce + * hooks are allocated from the routing table resource pool, they are + * unlinked from the table ahook list after the protocol went down, + * (in proto_schedule_flush()) and they are automatically freed after the + * protocol is flushed (in proto_fell_down()). + * * Unless you want to listen to multiple routing tables (as the Pipe * protocol does), you needn't to worry about this function since the * connection to the protocol's primary routing table is initialized * automatically by the core code. */ struct announce_hook * -proto_add_announce_hook(struct proto *p, struct rtable *t) +proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in, + struct filter *out, struct proto_stats *stats) { struct announce_hook *h; - if (!p->rt_notify) - return NULL; DBG("Connecting protocol %s to table %s\n", p->name, t->name); PD(p, "Connected to table %s", t->name); - h = mb_alloc(p->pool, sizeof(struct announce_hook)); + + h = mb_allocz(rt_table_pool, sizeof(struct announce_hook)); h->table = t; h->proto = p; + h->in_filter = in; + h->out_filter = out; + h->stats = stats; + h->next = p->ahooks; p->ahooks = h; - add_tail(&t->hooks, &h->n); + + if (p->rt_notify) + add_tail(&t->hooks, &h->n); return h; } +/** + * proto_find_announce_hook - find announce hooks + * @p: protocol instance + * @t: routing table + * + * Returns pointer to announce hook or NULL + */ +struct announce_hook * +proto_find_announce_hook(struct proto *p, struct rtable *t) +{ + struct announce_hook *a; + + for (a = p->ahooks; a; a = a->next) + if (a->table == t) + return a; + + return NULL; +} + static void -proto_flush_hooks(struct proto *p) +proto_unlink_ahooks(struct proto *p) { struct announce_hook *h; - for(h=p->ahooks; h; h=h->next) - rem_node(&h->n); + if (p->rt_notify) + for(h=p->ahooks; h; h=h->next) + rem_node(&h->n); +} + +static void +proto_free_ahooks(struct proto *p) +{ + struct announce_hook *h, *hn; + + for(h = p->ahooks; h; h = hn) + { + hn = h->next; + mb_free(h); + } + p->ahooks = NULL; + p->main_ahook = NULL; } /** @@ -322,6 +373,8 @@ proto_init(struct proto_config *c) return q; } +int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */ + static int proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type) { @@ -336,23 +389,10 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config (proto_get_router_id(nc) != proto_get_router_id(oc))) return 0; - int import_changed = (type != RECONFIG_SOFT) && ! filter_same(nc->in_filter, oc->in_filter); - int export_changed = (type != RECONFIG_SOFT) && ! filter_same(nc->out_filter, oc->out_filter); - - /* We treat a change in preferences by reimporting routes */ - if (nc->preference != oc->preference) - import_changed = 1; - - /* If the protocol in not UP, it has no routes and we can ignore such changes */ - if (p->proto_state != PS_UP) - import_changed = export_changed = 0; - - /* Without this hook we cannot reload routes and have to restart the protocol */ - if (import_changed && ! p->reload_routes) - return 0; p->debug = nc->debug; p->mrtdump = nc->mrtdump; + proto_reconfig_type = type; /* Execute protocol specific reconfigure hook */ if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc))) @@ -362,14 +402,37 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config PD(p, "Reconfigured"); p->cf = nc; p->name = nc->name; - p->in_filter = nc->in_filter; - p->out_filter = nc->out_filter; p->preference = nc->preference; + + /* Multitable protocols handle rest in their reconfigure hooks */ + if (p->proto->multitable) + return 1; + + /* Update filters in the main announce hook */ + if (p->main_ahook) + { + p->main_ahook->in_filter = nc->in_filter; + p->main_ahook->out_filter = nc->out_filter; + } + + /* Update routes when filters changed. If the protocol in not UP, + it has no routes and we can ignore such changes */ + if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT)) + return 1; + + int import_changed = ! filter_same(nc->in_filter, oc->in_filter); + int export_changed = ! filter_same(nc->out_filter, oc->out_filter); + + /* We treat a change in preferences by reimporting routes */ + if (nc->preference != oc->preference) + import_changed = 1; + if (import_changed || export_changed) log(L_INFO "Reloading protocol %s", p->name); - if (import_changed && ! p->reload_routes(p)) + /* If import filter changed, call reload hook */ + if (import_changed && ! (p->reload_routes && p->reload_routes(p))) { /* Now, the protocol is reconfigured. But route reload failed and we have to do regular protocol restart. */ @@ -553,6 +616,7 @@ void protos_dump_all(void) { struct proto *p; + struct announce_hook *a; debug("Protocols:\n"); @@ -560,10 +624,14 @@ protos_dump_all(void) { debug(" protocol %s state %s/%s\n", p->name, p_states[p->proto_state], c_states[p->core_state]); - if (p->in_filter) - debug("\tInput filter: %s\n", filter_name(p->in_filter)); - if (p->out_filter != FILTER_REJECT) - debug("\tOutput filter: %s\n", filter_name(p->out_filter)); + for (a = p->ahooks; a; a = a->next) + { + debug("\tTABLE %s\n", a->table->name); + if (a->in_filter) + debug("\tInput filter: %s\n", filter_name(a->in_filter)); + if (a->out_filter != FILTER_REJECT) + debug("\tOutput filter: %s\n", filter_name(a->out_filter)); + } if (p->disabled) debug("\tDISABLED\n"); else if (p->proto->dump) @@ -647,7 +715,10 @@ proto_fell_down(struct proto *p) log(L_ERR "Protocol %s is down but still has %d routes", p->name, p->stats.imp_routes); bzero(&p->stats, sizeof(struct proto_stats)); - rt_unlock_table(p->table); + proto_free_ahooks(p); + + if (! p->proto->multitable) + rt_unlock_table(p->table); if (p->proto->cleanup) p->proto->cleanup(p); @@ -686,7 +757,7 @@ proto_feed_initial(void *P) return; DBG("Feeding protocol %s\n", p->name); - proto_add_announce_hook(p, p->table); + if_feed_baby(p); proto_feed_more(P); } @@ -701,7 +772,7 @@ proto_schedule_flush(struct proto *p) DBG("%s: Scheduling flush\n", p->name); p->core_state = FS_FLUSHING; proto_relink(p); - proto_flush_hooks(p); + proto_unlink_ahooks(p); ev_schedule(proto_flush_event); } @@ -716,6 +787,11 @@ proto_schedule_feed(struct proto *p, int initial) if (!initial) p->stats.exp_routes = 0; + /* Connect protocol to routing table */ + if (initial && !p->proto->multitable) + p->main_ahook = proto_add_announce_hook(p, p->table, + p->cf->in_filter, p->cf->out_filter, &p->stats); + proto_relink(p); p->attn->hook = initial ? proto_feed_initial : proto_feed_more; ev_schedule(p->attn); @@ -855,9 +931,8 @@ proto_state_name(struct proto *p) } static void -proto_do_show_stats(struct proto *p) +proto_show_stats(struct proto_stats *s) { - 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"); @@ -875,47 +950,17 @@ proto_do_show_stats(struct proto *p) s->exp_withdraws_received, s->exp_withdraws_accepted); } -#ifdef CONFIG_PIPE -static void -proto_do_show_pipe_stats(struct proto *p) +void +proto_show_basic_info(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, " Table: %s", p->table->name); + cli_msg(-1006, " Preference: %d", p->preference); + cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter)); + cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter)); - 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); + if (p->proto_state != PS_DOWN) + proto_show_stats(&p->stats); } -#endif void proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) @@ -943,22 +988,11 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) cli_msg(-1006, " Description: %s", p->cf->dsc); if (p->cf->router_id) cli_msg(-1006, " Router ID: %R", p->cf->router_id); - 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)); - - if (p->proto_state != PS_DOWN) - { -#ifdef CONFIG_PIPE - if (proto_is_pipe(p)) - proto_do_show_pipe_stats(p); - else -#endif - proto_do_show_stats(p); - } if (p->proto->show_proto_info) p->proto->show_proto_info(p); + else + proto_show_basic_info(p); cli_msg(-1006, ""); } diff --git a/nest/protocol.h b/nest/protocol.h index a83c4ffc..187b8712 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -39,6 +39,7 @@ struct protocol { char *template; /* Template for automatic generation of names */ int name_counter; /* Counter for automatic name generation */ int attr_class; /* Attribute class known to this protocol */ + int multitable; /* Protocol handles all announce hooks itself */ unsigned preference; /* Default protocol preference */ void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ @@ -193,8 +194,7 @@ struct proto { void (*rte_remove)(struct network *, struct rte *); struct rtable *table; /* Our primary routing table */ - struct filter *in_filter; /* Input filter */ - struct filter *out_filter; /* Output filter */ + struct announce_hook *main_ahook; /* Primary announcement hook */ struct announce_hook *ahooks; /* Announcement hooks for this protocol */ struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */ @@ -218,6 +218,9 @@ static inline void proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size) { memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); } + +void proto_show_basic_info(struct proto *p); + 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); @@ -352,18 +355,13 @@ struct announce_hook { node n; struct rtable *table; struct proto *proto; + struct filter *in_filter; /* Input filter */ + struct filter *out_filter; /* Output filter */ + struct proto_stats *stats; /* Per-table protocol statistics */ struct announce_hook *next; /* Next hook for the same protocol */ }; -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 - +struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *, struct filter *, struct filter *, struct proto_stats *); +struct announce_hook *proto_find_announce_hook(struct proto *p, struct rtable *t); #endif diff --git a/nest/route.h b/nest/route.h index e6712c64..fcb4f283 100644 --- a/nest/route.h +++ b/nest/route.h @@ -12,6 +12,7 @@ #include "lib/lists.h" #include "lib/resource.h" #include "lib/timer.h" +#include "nest/protocol.h" struct protocol; struct proto; @@ -179,7 +180,7 @@ struct hostentry { typedef struct rte { struct rte *next; net *net; /* Network this RTE belongs to */ - struct proto *sender; /* Protocol instance that sent the route to the routing table */ + struct announce_hook *sender; /* Announce hook used to send the route to the routing table */ struct rta *attrs; /* Attributes of this route */ byte flags; /* Flags (REF_...) */ byte pflags; /* Protocol-specific flags */ @@ -234,7 +235,8 @@ static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (n static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); } rte *rte_find(net *net, struct proto *p); rte *rte_get_temp(struct rta *); -void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new); +void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src); +static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); } void rte_discard(rtable *tab, rte *old); void rte_dump(rte *); void rte_free(rte *); diff --git a/nest/rt-table.c b/nest/rt-table.c index 377687de..3807ef8d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -184,24 +184,16 @@ 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 refeed) +do_rte_announce(struct announce_hook *ah, 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; + struct proto *p = ah->proto; + struct filter *filter = ah->out_filter; + struct proto_stats *stats = ah->stats; + rte *new0 = new; rte *old0 = old; int ok; -#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++; @@ -294,18 +286,18 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt rte_trace_out(D_ROUTES, p, old, "removed"); } if (!new) - p->rt_notify(p, a->table, net, NULL, old, NULL); + p->rt_notify(p, ah->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, a->table, net, new, old, tmpa); + p->rt_notify(p, ah->table, net, new, old, tmpa); t->next = NULL; } else - p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs); + p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs); if (new && new != new0) /* Discard temporary rte's */ rte_free(new); if (old && old != old0) @@ -375,7 +367,7 @@ rte_validate(rte *e) if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen)) { log(L_WARN "Ignoring bogus prefix %I/%d received via %s", - n->n.prefix, n->n.pxlen, e->sender->name); + n->n.prefix, n->n.pxlen, e->sender->proto->name); return 0; } @@ -383,7 +375,7 @@ rte_validate(rte *e) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { log(L_WARN "Ignoring bogus route %I/%d received via %s", - n->n.prefix, n->n.pxlen, e->sender->name); + n->n.prefix, n->n.pxlen, e->sender->proto->name); return 0; } @@ -423,18 +415,15 @@ 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) +rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct proto *src) { - struct proto_stats *stats = &p->stats; + struct proto *p = ah->proto; + struct rtable *table = ah->table; + struct proto_stats *stats = ah->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) { @@ -449,7 +438,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte * ignore it completely (there might be 'spurious withdraws', * see FIXME in do_rte_announce()) */ - if (old->sender != p) + if (old->sender->proto != p) { if (new) { @@ -613,6 +602,7 @@ rte_update_unlock(void) /** * rte_update - enter a new update to a routing table * @table: table to be updated + * @ah: pointer to table announce hook * @net: network node * @p: protocol submitting the update * @src: protocol originating the update @@ -652,28 +642,17 @@ rte_update_unlock(void) */ void -rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new) +rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src) { + struct proto *p = ah->proto; + struct proto_stats *stats = ah->stats; + struct filter *filter = ah->in_filter; 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) { - new->sender = p; - struct filter *filter = p->in_filter; - - /* Do not filter routes going through the pipe, - they are filtered in the export filter only. */ -#ifdef CONFIG_PIPE - if (proto_is_pipe(p)) - filter = FILTER_ACCEPT; -#endif + new->sender = ah; stats->imp_updates_received++; if (!rte_validate(new)) @@ -710,13 +689,13 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new else stats->imp_withdraws_received++; - rte_recalculate(table, net, p, src, new, tmpa); + rte_recalculate(ah, net, new, tmpa, src); rte_update_unlock(); return; drop: rte_free(new); - rte_recalculate(table, net, p, src, NULL, NULL); + rte_recalculate(ah, net, NULL, NULL, src); rte_update_unlock(); } @@ -739,7 +718,7 @@ void rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during garbage collection */ { rte_update_lock(); - rte_recalculate(t, old->net, old->sender, old->attrs->proto, NULL, NULL); + rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->proto); rte_update_unlock(); } @@ -912,8 +891,8 @@ again: ncnt++; rescan: for (e=n->routes; e; e=e->next, rcnt++) - if (e->sender->core_state != FS_HAPPY && - e->sender->core_state != FS_FEEDING) + if (e->sender->proto->core_state != FS_HAPPY && + e->sender->proto->core_state != FS_FEEDING) { rte_discard(tab, e); rdel++; @@ -1026,7 +1005,7 @@ rt_next_hop_update_net(rtable *tab, net *n) *k = new; rte_announce_i(tab, RA_ANY, n, new, e); - rte_trace_in(D_ROUTES, new->sender, new, "updated"); + rte_trace_in(D_ROUTES, new->sender->proto, new, "updated"); /* Call a pre-comparison hook */ /* Not really an efficient way to compute this */ @@ -1066,7 +1045,7 @@ rt_next_hop_update_net(rtable *tab, net *n) if (new != old_best) { rte_announce_i(tab, RA_OPTIMAL, n, new, old_best); - rte_trace_in(D_ROUTES, new->sender, new, "updated [best]"); + rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]"); } if (free_old_best) @@ -1693,6 +1672,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) { rte *e, *ee; byte ia[STD_ADDRESS_P_LENGTH+8]; + struct announce_hook *a; int ok; bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen); @@ -1722,8 +1702,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 ((a = proto_find_announce_hook(p1, d->table)) && ((a->out_filter == FILTER_REJECT) || + (a->out_filter && f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))) ok = 0; } } |