Commit c0adf7e9 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Better support for multitable protocols.

The nest-protocol interaction is changed to better handle multitable
protocols. Multitable protocols now declare that by 'multitable' field,
which tells nest that a protocol handles things related to proto-rtable
interaction (table locking, announce hook adding, reconfiguration of
filters) itself.

Filters and stats are moved to announce hooks, a protocol could have
different filters and stats to different tables.

The patch is based on one from Alexander V. Chernikov, thanks.
parent 46c1a583
...@@ -90,7 +90,7 @@ void dump_attrs(rte *e) ...@@ -90,7 +90,7 @@ void dump_attrs(rte *e)
* @p: protocol instance * @p: protocol instance
* *
* The start() hook is called by the core when it wishes to start * 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 * Result: new protocol state
*/ */
...@@ -109,6 +109,17 @@ int start(struct proto *p) ...@@ -109,6 +109,17 @@ int start(struct proto *p)
int shutdown(struct proto *p) int shutdown(struct proto *p)
{ DUMMY; } { 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 * get_status - get instance status
* @p: protocol instance * @p: protocol instance
......
...@@ -112,8 +112,6 @@ proto_new(struct proto_config *c, unsigned size) ...@@ -112,8 +112,6 @@ proto_new(struct proto_config *c, unsigned size)
p->disabled = c->disabled; p->disabled = c->disabled;
p->proto = pr; p->proto = pr;
p->table = c->table->table; p->table = c->table->table;
p->in_filter = c->in_filter;
p->out_filter = c->out_filter;
p->hash_key = random_u32(); p->hash_key = random_u32();
c->proto = p; c->proto = p;
return p; return p;
...@@ -126,49 +124,102 @@ proto_init_instance(struct proto *p) ...@@ -126,49 +124,102 @@ proto_init_instance(struct proto *p)
p->pool = rp_new(proto_pool, p->proto->name); p->pool = rp_new(proto_pool, p->proto->name);
p->attn = ev_new(p->pool); p->attn = ev_new(p->pool);
p->attn->data = p; p->attn->data = p;
if (! p->proto->multitable)
rt_lock_table(p->table); rt_lock_table(p->table);
} }
extern pool *rt_table_pool;
/** /**
* proto_add_announce_hook - connect protocol to a routing table * proto_add_announce_hook - connect protocol to a routing table
* @p: protocol instance * @p: protocol instance
* @t: routing table to connect to * @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 * This function creates a connection between the protocol instance @p
* and the routing table @t, making the protocol hear all changes in * and the routing table @t, making the protocol hear all changes in
* the table. * 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 * Unless you want to listen to multiple routing tables (as the Pipe
* protocol does), you needn't to worry about this function since the * protocol does), you needn't to worry about this function since the
* connection to the protocol's primary routing table is initialized * connection to the protocol's primary routing table is initialized
* automatically by the core code. * automatically by the core code.
*/ */
struct announce_hook * 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; struct announce_hook *h;
if (!p->rt_notify)
return NULL;
DBG("Connecting protocol %s to table %s\n", p->name, t->name); DBG("Connecting protocol %s to table %s\n", p->name, t->name);
PD(p, "Connected to table %s", 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->table = t;
h->proto = p; h->proto = p;
h->in_filter = in;
h->out_filter = out;
h->stats = stats;
h->next = p->ahooks; h->next = p->ahooks;
p->ahooks = h; p->ahooks = h;
if (p->rt_notify)
add_tail(&t->hooks, &h->n); add_tail(&t->hooks, &h->n);
return h; 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 static void
proto_flush_hooks(struct proto *p) proto_unlink_ahooks(struct proto *p)
{ {
struct announce_hook *h; struct announce_hook *h;
if (p->rt_notify)
for(h=p->ahooks; h; h=h->next) for(h=p->ahooks; h; h=h->next)
rem_node(&h->n); 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->ahooks = NULL;
p->main_ahook = NULL;
} }
/** /**
...@@ -322,6 +373,8 @@ proto_init(struct proto_config *c) ...@@ -322,6 +373,8 @@ proto_init(struct proto_config *c)
return q; return q;
} }
int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hook */
static int static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type) 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 ...@@ -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))) (proto_get_router_id(nc) != proto_get_router_id(oc)))
return 0; 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->debug = nc->debug;
p->mrtdump = nc->mrtdump; p->mrtdump = nc->mrtdump;
proto_reconfig_type = type;
/* Execute protocol specific reconfigure hook */ /* Execute protocol specific reconfigure hook */
if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc))) 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 ...@@ -362,14 +402,37 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
PD(p, "Reconfigured"); PD(p, "Reconfigured");
p->cf = nc; p->cf = nc;
p->name = nc->name; p->name = nc->name;
p->in_filter = nc->in_filter;
p->out_filter = nc->out_filter;
p->preference = nc->preference; 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) if (import_changed || export_changed)
log(L_INFO "Reloading protocol %s", p->name); 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 /* Now, the protocol is reconfigured. But route reload failed
and we have to do regular protocol restart. */ and we have to do regular protocol restart. */
...@@ -553,6 +616,7 @@ void ...@@ -553,6 +616,7 @@ void
protos_dump_all(void) protos_dump_all(void)
{ {
struct proto *p; struct proto *p;
struct announce_hook *a;
debug("Protocols:\n"); debug("Protocols:\n");
...@@ -560,10 +624,14 @@ protos_dump_all(void) ...@@ -560,10 +624,14 @@ protos_dump_all(void)
{ {
debug(" protocol %s state %s/%s\n", p->name, debug(" protocol %s state %s/%s\n", p->name,
p_states[p->proto_state], c_states[p->core_state]); p_states[p->proto_state], c_states[p->core_state]);
if (p->in_filter) for (a = p->ahooks; a; a = a->next)
debug("\tInput filter: %s\n", filter_name(p->in_filter)); {
if (p->out_filter != FILTER_REJECT) debug("\tTABLE %s\n", a->table->name);
debug("\tOutput filter: %s\n", filter_name(p->out_filter)); 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) if (p->disabled)
debug("\tDISABLED\n"); debug("\tDISABLED\n");
else if (p->proto->dump) else if (p->proto->dump)
...@@ -647,6 +715,9 @@ proto_fell_down(struct proto *p) ...@@ -647,6 +715,9 @@ proto_fell_down(struct proto *p)
log(L_ERR "Protocol %s is down but still has %d routes", p->name, p->stats.imp_routes); 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)); bzero(&p->stats, sizeof(struct proto_stats));
proto_free_ahooks(p);
if (! p->proto->multitable)
rt_unlock_table(p->table); rt_unlock_table(p->table);
if (p->proto->cleanup) if (p->proto->cleanup)
...@@ -686,7 +757,7 @@ proto_feed_initial(void *P) ...@@ -686,7 +757,7 @@ proto_feed_initial(void *P)
return; return;
DBG("Feeding protocol %s\n", p->name); DBG("Feeding protocol %s\n", p->name);
proto_add_announce_hook(p, p->table);
if_feed_baby(p); if_feed_baby(p);
proto_feed_more(P); proto_feed_more(P);
} }
...@@ -701,7 +772,7 @@ proto_schedule_flush(struct proto *p) ...@@ -701,7 +772,7 @@ proto_schedule_flush(struct proto *p)
DBG("%s: Scheduling flush\n", p->name); DBG("%s: Scheduling flush\n", p->name);
p->core_state = FS_FLUSHING; p->core_state = FS_FLUSHING;
proto_relink(p); proto_relink(p);
proto_flush_hooks(p); proto_unlink_ahooks(p);
ev_schedule(proto_flush_event); ev_schedule(proto_flush_event);
} }
...@@ -716,6 +787,11 @@ proto_schedule_feed(struct proto *p, int initial) ...@@ -716,6 +787,11 @@ proto_schedule_feed(struct proto *p, int initial)
if (!initial) if (!initial)
p->stats.exp_routes = 0; 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); proto_relink(p);
p->attn->hook = initial ? proto_feed_initial : proto_feed_more; p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
ev_schedule(p->attn); ev_schedule(p->attn);
...@@ -855,9 +931,8 @@ proto_state_name(struct proto *p) ...@@ -855,9 +931,8 @@ proto_state_name(struct proto *p)
} }
static void 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", cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
s->imp_routes, s->exp_routes, s->pref_routes); s->imp_routes, s->exp_routes, s->pref_routes);
cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
...@@ -875,47 +950,17 @@ proto_do_show_stats(struct proto *p) ...@@ -875,47 +950,17 @@ proto_do_show_stats(struct proto *p)
s->exp_withdraws_received, s->exp_withdraws_accepted); s->exp_withdraws_received, s->exp_withdraws_accepted);
} }
#ifdef CONFIG_PIPE void
static void proto_show_basic_info(struct proto *p)
proto_do_show_pipe_stats(struct proto *p)
{ {
struct proto_stats *s1 = &p->stats; // cli_msg(-1006, " Table: %s", p->table->name);
struct proto_stats *s2 = pipe_get_peer_stats(p); 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));
* 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", if (p->proto_state != PS_DOWN)
s2->imp_routes, s1->imp_routes); proto_show_stats(&p->stats);
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);
} }
#endif
void void
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) 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) ...@@ -943,22 +988,11 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
cli_msg(-1006, " Description: %s", p->cf->dsc); cli_msg(-1006, " Description: %s", p->cf->dsc);
if (p->cf->router_id) if (p->cf->router_id)
cli_msg(-1006, " Router ID: %R", 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) if (p->proto->show_proto_info)
p->proto->show_proto_info(p); p->proto->show_proto_info(p);
else
proto_show_basic_info(p);
cli_msg(-1006, ""); cli_msg(-1006, "");
} }
......
...@@ -39,6 +39,7 @@ struct protocol { ...@@ -39,6 +39,7 @@ struct protocol {
char *template; /* Template for automatic generation of names */ char *template; /* Template for automatic generation of names */
int name_counter; /* Counter for automatic name generation */ int name_counter; /* Counter for automatic name generation */
int attr_class; /* Attribute class known to this protocol */ int attr_class; /* Attribute class known to this protocol */
int multitable; /* Protocol handles all announce hooks itself */
unsigned preference; /* Default protocol preference */ unsigned preference; /* Default protocol preference */
void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */
...@@ -193,8 +194,7 @@ struct proto { ...@@ -193,8 +194,7 @@ struct proto {
void (*rte_remove)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *);
struct rtable *table; /* Our primary routing table */ struct rtable *table; /* Our primary routing table */
struct filter *in_filter; /* Input filter */ struct announce_hook *main_ahook; /* Primary announcement hook */
struct filter *out_filter; /* Output filter */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */ struct announce_hook *ahooks; /* Announcement hooks for this protocol */
struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */ struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */
...@@ -218,6 +218,9 @@ static inline void ...@@ -218,6 +218,9 @@ static inline void
proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size) proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size)
{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); } { 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_show(struct proto *, unsigned int, int);
void proto_cmd_disable(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_enable(struct proto *, unsigned int, int);
...@@ -352,18 +355,13 @@ struct announce_hook { ...@@ -352,18 +355,13 @@ struct announce_hook {
node n; node n;
struct rtable *table; struct rtable *table;
struct proto *proto; 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 *next; /* Next hook for the same protocol */
}; };
struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); 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);
/*
* Some pipe-specific nest hacks
*/
#ifdef CONFIG_PIPE
#include "proto/pipe/pipe.h"
#endif
#endif #endif
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/timer.h" #include "lib/timer.h"
#include "nest/protocol.h"
struct protocol; struct protocol;
struct proto; struct proto;
...@@ -179,7 +180,7 @@ struct hostentry { ...@@ -179,7 +180,7 @@ struct hostentry {
typedef struct rte { typedef struct rte {
struct rte *next; struct rte *next;
net *net; /* Network this RTE belongs to */ 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 */ struct rta *attrs; /* Attributes of this route */
byte flags; /* Flags (REF_...) */ byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */ byte pflags; /* Protocol-specific flags */
...@@ -234,7 +235,8 @@ static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (n ...@@ -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); } 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_find(net *net, struct proto *p);
rte *rte_get_temp(struct rta *); 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_discard(rtable *tab, rte *old);
void rte_dump(rte *); void rte_dump(rte *);
void rte_free(rte *); void rte_free(rte *);
......
...@@ -184,24 +184,16 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) ...@@ -184,24 +184,16 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
} }
static inline void 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 proto *p = ah->proto;
struct filter *filter = p->out_filter; struct filter *filter = ah->out_filter;
struct proto_stats *stats = &p->stats; struct proto_stats *stats = ah->stats;
rte *new0 = new; rte *new0 = new;
rte *old0 = old; rte *old0 = old;
int ok; 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) if (new)
{ {
stats->exp_updates_received++; stats->exp_updates_received++;
...@@ -294,18 +286,18 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt ...@@ -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"); rte_trace_out(D_ROUTES, p, old, "removed");
} }
if (!new) 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) else if (tmpa)
{ {
ea_list *t = tmpa; ea_list *t = tmpa;
while (t->next) while (t->next)
t = t->next; t = t->next;
t->next = new->attrs->eattrs; 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; t->next = NULL;
} }
else 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 */ if (new && new != new0) /* Discard temporary rte's */
rte_free(new); rte_free(new);
if (old && old != old0) if (old && old != old0)
...@@ -375,7 +367,7 @@ rte_validate(rte *e) ...@@ -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)) 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", 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; return 0;
} }
...@@ -383,7 +375,7 @@ rte_validate(rte *e) ...@@ -383,7 +375,7 @@ rte_validate(rte *e)
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{ {
log(L_WARN "Ignoring bogus route %I/%d received via %s", 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; return 0;
} }
...@@ -423,18 +415,15 @@ rte_same(rte *x, rte *y) ...@@ -423,18 +415,15 @@ rte_same(rte *x, rte *y)
} }
static void 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_best = net->routes;
rte *old = NULL; rte *old = NULL;
rte **k, *r, *s; 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 */ k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k) while (old = *k)
{ {
...@@ -449,7 +438,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte ...@@ -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', * ignore it completely (there might be 'spurious withdraws',
* see FIXME in do_rte_announce()) * see FIXME in do_rte_announce())
*/ */
if (old->sender != p) if (old->sender->proto != p)
{ {
if (new) if (new)
{ {
...@@ -613,6 +602,7 @@ rte_update_unlock(void) ...@@ -613,6 +602,7 @@ rte_update_unlock(void)
/** /**
* rte_update - enter a new update to a routing table