Bird-users
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
November 2011
- 20 participants
- 26 discussions
27 Nov '11
---
nest/proto.c | 147 +++++++++++++++++++++++++++++++----------------------
nest/protocol.h | 16 ++----
nest/route.h | 3 +
nest/rt-table.c | 64 +++++++++--------------
proto/pipe/pipe.c | 119 +++++++++++++++++++++++++++++++++++++++++-
proto/pipe/pipe.h | 7 +--
6 files changed, 238 insertions(+), 118 deletions(-)
diff --git a/nest/proto.c b/nest/proto.c
index d55c348..451db2c 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -19,6 +19,9 @@
#include "nest/iface.h"
#include "nest/cli.h"
#include "filter/filter.h"
+#ifdef CONFIG_PIPE
+#include "proto/pipe/pipe.h"
+#endif
pool *proto_pool;
@@ -112,8 +115,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;
@@ -142,6 +143,8 @@ proto_init_instance(struct proto *p)
* 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.
+ *
+ * Returns pointer to announce hook or NULL
*/
struct announce_hook *
proto_add_announce_hook(struct proto *p, struct rtable *t)
@@ -152,7 +155,7 @@ proto_add_announce_hook(struct proto *p, struct rtable *t)
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(p->pool, sizeof(struct announce_hook));
h->table = t;
h->proto = p;
h->next = p->ahooks;
@@ -161,6 +164,25 @@ proto_add_announce_hook(struct proto *p, struct rtable *t)
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)
{
@@ -324,6 +346,8 @@ proto_init(struct proto_config *c)
static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
{
+ struct announce_hook *a;
+
/* If the protocol is DOWN, we just restart it */
if (p->proto_state == PS_DOWN)
return 0;
@@ -353,6 +377,19 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
p->debug = nc->debug;
p->mrtdump = nc->mrtdump;
+ /*
+ * Set import/export filters if protocol is connected to the route table.
+ * We need to to this before protocol-specific reconfigure hook due to
+ * possible filter manipulations in pipe-like protocols.
+ * If no connection to master table is available, skip this step.
+ * In this case filters are assigned in proto_feed_initial
+ */
+ if (a = p->thook)
+ {
+ a->in_filter = nc->in_filter;
+ a->out_filter = nc->out_filter;
+ }
+
/* Execute protocol specific reconfigure hook */
if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
return 0;
@@ -361,8 +398,6 @@ 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;
if (import_changed || export_changed)
@@ -552,6 +587,7 @@ void
protos_dump_all(void)
{
struct proto *p;
+ struct announce_hook *a;
debug("Protocols:\n");
@@ -559,10 +595,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)
@@ -680,12 +720,30 @@ static void
proto_feed_initial(void *P)
{
struct proto *p = P;
+ struct announce_hook *a;
if (p->core_state != FS_FEEDING)
return;
DBG("Feeding protocol %s\n", p->name);
- proto_add_announce_hook(p, p->table);
+ if (a = proto_add_announce_hook(p, p->table))
+ {
+ /* Set master table */
+ p->thook = a;
+ /* Set filters */
+ a->in_filter = p->cf->in_filter;
+ a->out_filter = p->cf->out_filter;
+ /* Set pointer to stats */
+ a->stats = &p->stats;
+ }
+
+ /*
+ * Call reconfigure hook to permit possible filter changes.
+ * Old config is the same as new so no problems should arise
+ */
+ if (p->proto->reconfigure)
+ p->proto->reconfigure(p, p->cf);
+
if_feed_baby(p);
proto_feed_more(P);
}
@@ -854,9 +912,8 @@ proto_state_name(struct proto *p)
}
static void
-proto_do_show_stats(struct proto *p)
+proto_do_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");
@@ -874,52 +931,11 @@ 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)
-{
- 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);
-}
-#endif
-
void
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
{
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
+ struct announce_hook *a;
/* First protocol - show header */
if (!cnt)
@@ -943,17 +959,26 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
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)
+ for (a = p->ahooks; a; a = a->next)
{
+ cli_msg(-1006, " Table: %s", a->table->name);
+ cli_msg(-1006, " Input filter: %s", filter_name(a->in_filter));
+ cli_msg(-1006, " Output filter: %s", filter_name(a->out_filter));
+
+ if (p->proto_state != PS_DOWN)
+ {
#ifdef CONFIG_PIPE
- if (proto_is_pipe(p))
- proto_do_show_pipe_stats(p);
- else
+ /* XXX: This block should be removed */
+ if (proto_is_pipe(p))
+ {
+ if (a == p->thook)
+ pipe_show_stats(p);
+ }
+ else
#endif
- proto_do_show_stats(p);
+ proto_do_show_stats(a->stats);
+ }
}
if (p->proto->show_proto_info)
diff --git a/nest/protocol.h b/nest/protocol.h
index a7518c2..09ccd9c 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -190,8 +190,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 *thook; /* Announcement hook for the master table */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */
@@ -349,18 +348,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_find_announce_hook(struct proto *p, struct rtable *t);
#endif
diff --git a/nest/route.h b/nest/route.h
index a4c0154..03703c6 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -218,6 +218,7 @@ typedef struct rte {
#define RA_ANY 2 /* Announcement of any route change */
struct config;
+struct announce_hook;
void rt_init(void);
void rt_preconfig(struct config *);
@@ -230,6 +231,8 @@ static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (ne
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);
+#define rte_update(tab, net, p, src, new) do_rte_update(tab, (p)->thook, net, p, src, new)
+void do_rte_update(rtable *tab, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new);
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 e20d2f6..0c0a042 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -187,21 +187,12 @@ static inline void
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;
+ struct filter *filter = a->out_filter;
+ struct proto_stats *stats = a->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++;
@@ -423,18 +414,14 @@ 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(rtable *table, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa)
{
- struct proto_stats *stats = &p->stats;
+ struct proto_stats *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
-
+ stats = a ? a->stats : &p->stats;
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
@@ -607,8 +594,9 @@ rte_update_unlock(void)
}
/**
- * rte_update - enter a new update to a routing table
+ * do_rte_update - enter a new update to a routing table
* @table: table to be updated
+ * @a: pointer to table announce hook
* @net: network node
* @p: protocol submitting the update
* @src: protocol originating the update
@@ -648,28 +636,27 @@ rte_update_unlock(void)
*/
void
-rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
+do_rte_update(rtable *table, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new)
{
ea_list *tmpa = NULL;
- struct proto_stats *stats = &p->stats;
+ struct proto_stats *stats;
+ struct filter *filter;
-#ifdef CONFIG_PIPE
- if (proto_is_pipe(p) && (p->table == table))
- stats = pipe_get_peer_stats(p);
-#endif
+ if (a)
+ {
+ stats = a->stats;
+ filter = a->in_filter;
+ }
+ else
+ {
+ stats = &p->stats;
+ filter = p->cf->in_filter;
+ }
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
stats->imp_updates_received++;
if (!rte_validate(new))
@@ -706,13 +693,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(table, a, net, p, src, new, tmpa);
rte_update_unlock();
return;
drop:
rte_free(new);
- rte_recalculate(table, net, p, src, NULL, NULL);
+ rte_recalculate(table, a, net, p, src, NULL, NULL);
rte_update_unlock();
}
@@ -735,7 +722,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(t, old->sender->thook, old->net, old->sender, old->attrs->proto, NULL, NULL);
rte_update_unlock();
}
@@ -1680,6 +1667,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);
@@ -1709,8 +1697,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;
}
}
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 420c5a9..2f1b519 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -24,6 +24,7 @@
#include "nest/iface.h"
#include "nest/protocol.h"
#include "nest/route.h"
+#include "nest/cli.h"
#include "conf/conf.h"
#include "filter/filter.h"
#include "lib/string.h"
@@ -34,8 +35,10 @@ static void
pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
{
struct pipe_proto *p = (struct pipe_proto *) P;
- rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */
+ rtable *dest;
struct proto *src;
+ struct announce_hook *h;
+ struct proto_stats *stats, *old_stats;
net *nn;
rte *e;
@@ -44,6 +47,19 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
if (!new && !old)
return;
+ if (src_table == P->table)
+ {
+ dest = p->peer;
+ h = p->a;
+ stats = &P->stats;
+ }
+ else
+ {
+ dest = P->table;
+ h = P->thook;
+ stats = &p->peer_stats;
+ }
+
if (dest->pipe_busy)
{
log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
@@ -85,7 +101,14 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
}
src_table->pipe_busy = 1;
- rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
+ /*
+ * FIXME: Trick with stats pointer is needed to produce
+ * valid numbers on protocol shutdown.
+ */
+ old_stats = h->stats;
+ h->stats = stats;
+ do_rte_update(dest, h, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
+ h->stats = old_stats;
src_table->pipe_busy = 0;
}
@@ -126,6 +149,10 @@ pipe_start(struct proto *P)
/* Connect the protocol also to the peer routing table. */
a = proto_add_announce_hook(P, p->peer);
+ p->a = a;
+
+ /* Set up filters and stats */
+ a->stats = &p->peer_stats;
return PS_UP;
}
@@ -168,16 +195,101 @@ pipe_postconfig(struct proto_config *C)
static int
pipe_reconfigure(struct proto *P, struct proto_config *new)
{
- // struct pipe_proto *p = (struct pipe_proto *) P;
+ struct announce_hook *a, *pa;
+ struct pipe_proto *p = (struct pipe_proto *)P;
struct pipe_config *o = (struct pipe_config *) P->cf;
struct pipe_config *n = (struct pipe_config *) new;
if ((o->peer->table != n->peer->table) || (o->mode != n->mode))
return 0;
+ /*
+ * reconfigure can be called in any protocol status
+ */
+ if (!((a = P->thook) && (pa = p->a)))
+ return 1;
+
+ /* Update filters */
+ /*
+ * Export filter remains as is and import filter moves to
+ * peer table
+ *
+ * /------\ /------\
+ * | | --- (OUT)(1) (OUT)(3) --- | |
+ * | MAIN | | PIPE | | PEER |
+ * | | ---- (IN)(2) (IN)(4) --- | |
+ * \------/ \------/
+ *
+ * When new route is announced on MAIN table it gets checked by
+ * export filter (1), and, after that, it is announced to peer table
+ * via rte_update. import filter (4) is called. When new route is
+ * annouced in PEER table (3) and (2) are used. Oviously, there is
+ * no need in filtering the same route twice, so (4) and (2) filters
+ * should be set to pass all routes.
+ *
+ * User can configure (1) and (2) filters so we move filter (2) to
+ * (3) and set (2) and (4) to FILTER_ACCEPT
+ *
+ * This is the right place to do it since
+ * 1) configure hook is called exactly before initial feeding
+ * 2) it is (now) called exactly after setting new filters in proto_reconfigure
+ */
+
+ /*
+ * Check for changed filters:
+ * Import and export filters are checked in proto_reconfigure by
+ * comparing old/new configurations so no additional checks are
+ * required here
+ */
+
+ pa->out_filter = a->in_filter;
+ a->in_filter = FILTER_ACCEPT;
+ pa->in_filter = FILTER_ACCEPT;
+
return 1;
}
+void
+pipe_show_stats(struct proto *P)
+{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+ struct proto_stats *s1 = &P->stats;
+ struct proto_stats *s2 = &p->peer_stats;
+
+ /*
+ * Pipe stats (as anything related to pipes) are a bit tricky. There
+ * are two sets of stats - s1 for routes going from the primary
+ * routing table to the secondary routing table ('exported' from the
+ * user point of view) and s2 for routes going in the other
+ * direction ('imported' from the user point of view).
+ *
+ * Each route going through a pipe is, technically, first exported
+ * to the pipe and then imported from that pipe and such operations
+ * are counted in one set of stats according to the direction of the
+ * route propagation. Filtering is done just in the first part
+ * (export). Therefore, we compose stats for one directon for one
+ * user direction from both import and export stats, skipping
+ * immediate and irrelevant steps (exp_updates_accepted,
+ * imp_updates_received, imp_updates_filtered, ...)
+ */
+
+ cli_msg(-1006, " Routes: %u imported, %u exported",
+ s2->imp_routes, s1->imp_routes);
+ cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
+ cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
+ s2->exp_updates_received, s2->exp_updates_rejected + s2->imp_updates_invalid,
+ s2->exp_updates_filtered, s2->imp_updates_ignored, s2->imp_updates_accepted);
+ cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
+ s2->exp_withdraws_received, s2->imp_withdraws_invalid,
+ s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
+ cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u",
+ s1->exp_updates_received, s1->exp_updates_rejected + s1->imp_updates_invalid,
+ s1->exp_updates_filtered, s1->imp_updates_ignored, s1->imp_updates_accepted);
+ cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u",
+ s1->exp_withdraws_received, s1->imp_withdraws_invalid,
+ s1->imp_withdraws_ignored, s1->imp_withdraws_accepted);
+}
+
static void
pipe_copy_config(struct proto_config *dest, struct proto_config *src)
{
@@ -194,6 +306,7 @@ pipe_get_status(struct proto *P, byte *buf)
}
+
struct protocol proto_pipe = {
name: "Pipe",
template: "pipe%d",
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index fbd2129..6eb5b03 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -22,6 +22,7 @@ struct pipe_proto {
struct proto p;
struct rtable *peer;
struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
+ struct announce_hook *a; /* Announce hook for the peer table */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
};
@@ -31,10 +32,6 @@ extern struct protocol proto_pipe;
static inline int proto_is_pipe(struct proto *p)
{ return p->proto == &proto_pipe; }
-static inline struct rtable * pipe_get_peer_table(struct proto *P)
-{ return ((struct pipe_proto *) P)->peer; }
-
-static inline struct proto_stats * pipe_get_peer_stats(struct proto *P)
-{ return &((struct pipe_proto *) P)->peer_stats; }
+void pipe_show_stats(struct proto *P);
#endif
--
1.7.3.2
--------------090506030508010702020103--
1
0
25 Nov '11
---
nest/proto.c | 132 ++++++++++++++++++++++++++++++++++++++++-------------
nest/protocol.h | 16 ++----
nest/route.h | 3 +
nest/rt-table.c | 64 ++++++++++---------------
proto/pipe/pipe.c | 68 ++++++++++++++++++++++++++-
proto/pipe/pipe.h | 7 +--
6 files changed, 201 insertions(+), 89 deletions(-)
diff --git a/nest/proto.c b/nest/proto.c
index d55c348..3d7684c 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -19,6 +19,9 @@
#include "nest/iface.h"
#include "nest/cli.h"
#include "filter/filter.h"
+#ifdef CONFIG_PIPE
+#include "proto/pipe/pipe.h"
+#endif
pool *proto_pool;
@@ -112,8 +115,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;
@@ -142,6 +143,8 @@ proto_init_instance(struct proto *p)
* 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.
+ *
+ * Returns pointer to announce hook or NULL
*/
struct announce_hook *
proto_add_announce_hook(struct proto *p, struct rtable *t)
@@ -152,7 +155,7 @@ proto_add_announce_hook(struct proto *p, struct rtable *t)
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(p->pool, sizeof(struct announce_hook));
h->table = t;
h->proto = p;
h->next = p->ahooks;
@@ -161,6 +164,25 @@ proto_add_announce_hook(struct proto *p, struct rtable *t)
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)
{
@@ -324,6 +346,8 @@ proto_init(struct proto_config *c)
static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
{
+ struct announce_hook *a;
+
/* If the protocol is DOWN, we just restart it */
if (p->proto_state == PS_DOWN)
return 0;
@@ -353,6 +377,19 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
p->debug = nc->debug;
p->mrtdump = nc->mrtdump;
+ /*
+ * Set import/export filters if protocol is connected to the route table.
+ * We need to to this before protocol-specific reconfigure hook due to
+ * possible filter manipulations in pipe-like protocols.
+ * If no connection to master table is available, skip this step.
+ * In this case filters are assigned in proto_feed_initial
+ */
+ if (a = p->thook)
+ {
+ a->in_filter = nc->in_filter;
+ a->out_filter = nc->out_filter;
+ }
+
/* Execute protocol specific reconfigure hook */
if (! (p->proto->reconfigure && p->proto->reconfigure(p, nc)))
return 0;
@@ -361,8 +398,6 @@ 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;
if (import_changed || export_changed)
@@ -552,6 +587,7 @@ void
protos_dump_all(void)
{
struct proto *p;
+ struct announce_hook *a;
debug("Protocols:\n");
@@ -559,10 +595,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)
@@ -680,12 +720,30 @@ static void
proto_feed_initial(void *P)
{
struct proto *p = P;
+ struct announce_hook *a;
if (p->core_state != FS_FEEDING)
return;
DBG("Feeding protocol %s\n", p->name);
- proto_add_announce_hook(p, p->table);
+ if (a = proto_add_announce_hook(p, p->table))
+ {
+ /* Set master table */
+ p->thook = a;
+ /* Set filters */
+ a->in_filter = p->cf->in_filter;
+ a->out_filter = p->cf->out_filter;
+ /* Set pointer to stats */
+ a->stats = &p->stats;
+ }
+
+ /*
+ * Call reconfigure hook to permit possible filter changes.
+ * Old config is the same as new so no problems should arise
+ */
+ if (p->proto->reconfigure)
+ p->proto->reconfigure(p, p->cf);
+
if_feed_baby(p);
proto_feed_more(P);
}
@@ -854,9 +912,8 @@ proto_state_name(struct proto *p)
}
static void
-proto_do_show_stats(struct proto *p)
+proto_do_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,11 +932,12 @@ proto_do_show_stats(struct proto *p)
}
#ifdef CONFIG_PIPE
-static void
-proto_do_show_pipe_stats(struct proto *p)
+void
+pipe_do_show_stats(struct proto *P)
{
- struct proto_stats *s1 = &p->stats;
- struct proto_stats *s2 = pipe_get_peer_stats(p);
+ struct pipe_proto *p = (struct pipe_proto *) P;
+ struct proto_stats *s1 = &P->stats;
+ struct proto_stats *s2 = &p->peer_stats;
/*
* Pipe stats (as anything related to pipes) are a bit tricky. There
@@ -899,20 +957,20 @@ proto_do_show_pipe_stats(struct proto *p)
*/
cli_msg(-1006, " Routes: %u imported, %u exported",
- s2->imp_routes, s1->imp_routes);
+ s1->imp_routes, s2->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);
+ s2->exp_updates_received, s2->exp_updates_rejected + s1->imp_updates_invalid,
+ s2->exp_updates_filtered, s1->imp_updates_ignored, s1->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);
+ s2->exp_withdraws_received, s1->imp_withdraws_invalid,
+ s1->imp_withdraws_ignored, s1->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);
+ s1->exp_updates_received, s1->exp_updates_rejected + s2->imp_updates_invalid,
+ s1->exp_updates_filtered, s2->imp_updates_ignored, s2->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);
+ s1->exp_withdraws_received, s2->imp_withdraws_invalid,
+ s2->imp_withdraws_ignored, s2->imp_withdraws_accepted);
}
#endif
@@ -920,6 +978,7 @@ void
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
{
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
+ struct announce_hook *a;
/* First protocol - show header */
if (!cnt)
@@ -943,17 +1002,26 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
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)
+ for (a = p->ahooks; a; a = a->next)
{
+ cli_msg(-1006, " Table: %s", a->table->name);
+ cli_msg(-1006, " Input filter: %s", filter_name(a->in_filter));
+ cli_msg(-1006, " Output filter: %s", filter_name(a->out_filter));
+
+ if (p->proto_state != PS_DOWN)
+ {
#ifdef CONFIG_PIPE
- if (proto_is_pipe(p))
- proto_do_show_pipe_stats(p);
- else
+ /* XXX: This block should be removed */
+ if (proto_is_pipe(p))
+ {
+ if (a == p->thook)
+ pipe_do_show_stats(p);
+ }
+ else
#endif
- proto_do_show_stats(p);
+ proto_do_show_stats(a->stats);
+ }
}
if (p->proto->show_proto_info)
diff --git a/nest/protocol.h b/nest/protocol.h
index a7518c2..09ccd9c 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -190,8 +190,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 *thook; /* Announcement hook for the master table */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */
@@ -349,18 +348,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_find_announce_hook(struct proto *p, struct rtable *t);
#endif
diff --git a/nest/route.h b/nest/route.h
index a4c0154..ff09178 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -218,6 +218,7 @@ typedef struct rte {
#define RA_ANY 2 /* Announcement of any route change */
struct config;
+struct announce_hook;
void rt_init(void);
void rt_preconfig(struct config *);
@@ -230,6 +231,8 @@ static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (ne
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);
+#define rte_update(tab, net, p, src, new) rte_do_update(tab, (p)->thook, net, p, src, new)
+void rte_do_update(rtable *tab, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new);
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 e20d2f6..53578c0 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -187,21 +187,12 @@ static inline void
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;
+ struct filter *filter = a->out_filter;
+ struct proto_stats *stats = a->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++;
@@ -423,18 +414,14 @@ 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(rtable *table, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa)
{
- struct proto_stats *stats = &p->stats;
+ struct proto_stats *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
-
+ stats = a ? a->stats : &p->stats;
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
@@ -607,8 +594,9 @@ rte_update_unlock(void)
}
/**
- * rte_update - enter a new update to a routing table
+ * rte_do_update - enter a new update to a routing table
* @table: table to be updated
+ * @a: pointer to table announce hook
* @net: network node
* @p: protocol submitting the update
* @src: protocol originating the update
@@ -648,28 +636,27 @@ rte_update_unlock(void)
*/
void
-rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
+rte_do_update(rtable *table, struct announce_hook *a, net *net, struct proto *p, struct proto *src, rte *new)
{
ea_list *tmpa = NULL;
- struct proto_stats *stats = &p->stats;
+ struct proto_stats *stats;
+ struct filter *filter;
-#ifdef CONFIG_PIPE
- if (proto_is_pipe(p) && (p->table == table))
- stats = pipe_get_peer_stats(p);
-#endif
+ if (a)
+ {
+ stats = a->stats;
+ filter = a->in_filter;
+ }
+ else
+ {
+ stats = &p->stats;
+ filter = p->cf->in_filter;
+ }
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
stats->imp_updates_received++;
if (!rte_validate(new))
@@ -706,13 +693,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(table, a, net, p, src, new, tmpa);
rte_update_unlock();
return;
drop:
rte_free(new);
- rte_recalculate(table, net, p, src, NULL, NULL);
+ rte_recalculate(table, a, net, p, src, NULL, NULL);
rte_update_unlock();
}
@@ -735,7 +722,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(t, old->sender->thook, old->net, old->sender, old->attrs->proto, NULL, NULL);
rte_update_unlock();
}
@@ -1680,6 +1667,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);
@@ -1709,8 +1697,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;
}
}
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 420c5a9..869ddb8 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -24,6 +24,7 @@
#include "nest/iface.h"
#include "nest/protocol.h"
#include "nest/route.h"
+#include "nest/cli.h"
#include "conf/conf.h"
#include "filter/filter.h"
#include "lib/string.h"
@@ -34,8 +35,9 @@ static void
pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs)
{
struct pipe_proto *p = (struct pipe_proto *) P;
- rtable *dest = (src_table == P->table) ? p->peer : P->table; /* The other side of the pipe */
+ rtable *dest;
struct proto *src;
+ struct announce_hook *h;
net *nn;
rte *e;
@@ -44,6 +46,17 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
if (!new && !old)
return;
+ if (src_table == P->table)
+ {
+ dest = p->peer;
+ h = p->a;
+ }
+ else
+ {
+ dest = P->table;
+ h = P->thook;
+ }
+
if (dest->pipe_busy)
{
log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
@@ -85,7 +98,7 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
}
src_table->pipe_busy = 1;
- rte_update(dest, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
+ rte_do_update(dest, h, nn, &p->p, (p->mode == PIPE_OPAQUE) ? &p->p : src, e);
src_table->pipe_busy = 0;
}
@@ -126,6 +139,10 @@ pipe_start(struct proto *P)
/* Connect the protocol also to the peer routing table. */
a = proto_add_announce_hook(P, p->peer);
+ p->a = a;
+
+ /* Set up filters and stats */
+ a->stats = &p->peer_stats;
return PS_UP;
}
@@ -168,13 +185,57 @@ pipe_postconfig(struct proto_config *C)
static int
pipe_reconfigure(struct proto *P, struct proto_config *new)
{
- // struct pipe_proto *p = (struct pipe_proto *) P;
+ struct announce_hook *a, *pa;
+ struct pipe_proto *p = (struct pipe_proto *)P;
struct pipe_config *o = (struct pipe_config *) P->cf;
struct pipe_config *n = (struct pipe_config *) new;
if ((o->peer->table != n->peer->table) || (o->mode != n->mode))
return 0;
+ /*
+ * reconfigure can be called in any protocol status
+ */
+ if (!((a = P->thook) && (pa = p->a)))
+ return 1;
+
+ /* Update filters */
+ /*
+ * Export filter remains as is and import filter moves to
+ * peer table
+ *
+ * /------\ /------\
+ * | | --- (OUT)(1) (OUT)(3) --- | |
+ * | MAIN | | PIPE | | PEER |
+ * | | ---- (IN)(2) (IN)(4) --- | |
+ * \------/ \------/
+ *
+ * When new route is announced on MAIN table it gets checked by
+ * export filter (1), and, after that, it is announced to peer table
+ * via rte_update. import filter (4) is called. When new route is
+ * annouced in PEER table (3) and (2) are used. Oviously, there is
+ * no need in filtering the same route twice, so (4) and (2) filters
+ * should be set to pass all routes.
+ *
+ * User can configure (1) and (2) filters so we move filter (2) to
+ * (3) and set (2) and (4) to FILTER_ACCEPT
+ *
+ * This is the right place to do it since
+ * 1) configure hook is called exactly before initial feeding
+ * 2) it is (now) called exactly after setting new filters in proto_reconfigure
+ */
+
+ /*
+ * Check for changed filters:
+ * Import and export filters are checked in proto_reconfigure by
+ * comparing old/new configurations so no additional checks are
+ * required here
+ */
+
+ pa->out_filter = a->in_filter;
+ a->in_filter = FILTER_ACCEPT;
+ pa->in_filter = FILTER_ACCEPT;
+
return 1;
}
@@ -194,6 +255,7 @@ pipe_get_status(struct proto *P, byte *buf)
}
+
struct protocol proto_pipe = {
name: "Pipe",
template: "pipe%d",
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index fbd2129..69df612 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -22,6 +22,7 @@ struct pipe_proto {
struct proto p;
struct rtable *peer;
struct proto_stats peer_stats; /* Statistics for the direction peer->primary */
+ struct announce_hook *a; /* Announce hook for the peer table */
int mode; /* PIPE_OPAQUE or PIPE_TRANSPARENT */
};
@@ -31,10 +32,6 @@ extern struct protocol proto_pipe;
static inline int proto_is_pipe(struct proto *p)
{ return p->proto == &proto_pipe; }
-static inline struct rtable * pipe_get_peer_table(struct proto *P)
-{ return ((struct pipe_proto *) P)->peer; }
-
-static inline struct proto_stats * pipe_get_peer_stats(struct proto *P)
-{ return &((struct pipe_proto *) P)->peer_stats; }
+void pipe_do_show_stats(struct proto *P);
#endif
--
1.7.3.2
--------------070306020804010102050307--
1
0
Hi list,
Is it just me, or is something totally broken in scan function of
kernel protocol?
# ping -i 0.01 -c 2500 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.019 ms
(...)
64 bytes from 127.0.0.1: icmp_seq=1149 ttl=64 time=0.018 ms
64 bytes from 127.0.0.1: icmp_seq=1150 ttl=64 time=0.018 ms
64 bytes from 127.0.0.1: icmp_seq=1151 ttl=64 time=176.896 ms
64 bytes from 127.0.0.1: icmp_seq=1152 ttl=64 time=204.953 ms
64 bytes from 127.0.0.1: icmp_seq=1153 ttl=64 time=0.027 ms
64 bytes from 127.0.0.1: icmp_seq=1154 ttl=64 time=0.026 ms
(...)
64 bytes from 127.0.0.1: icmp_seq=2499 ttl=64 time=0.019 ms
--- 127.0.0.1 ping statistics ---
2500 packets transmitted, 2500 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.007/0.187/204.953/5.495 ms
This generates quite a lot of funny things, among them being SIP
breakage, freezes in games, hair-pulling in my person - whole network
freezes for the scan-time.
Does this happen only on my system?
Bird 1.3.4+FIB, 8-STABLE current as of 2 hours ago.
Pawel.
6
11
Yo!
Ran into an issue where I couldn't use a function with 32 bit AS numbers. Made the following changes and got it working:
bash-4.1# diff conf/confbase.Y ../bird-1.3.2/conf/confbase.Y
30c30
< check_u32(unsigned val)
---
> check_u16(unsigned val)
32,33c32,33
< if (val > 0xFFFFFFFF)
< cf_error("Value %d out of range (0-4294967295)", val);
---
> if (val > 0xFFFF)
> cf_error("Value %d out of range (0-65535)", val);
bash-4.1# diff filter/config.Y ../bird-1.3.2/filter/config.Y
307c307
< term { $$ = f_eval_int($1); check_u32($$); }
---
> term { $$ = f_eval_int($1); check_u16($$); }
420c420
< check_u32($2->a2.i); check_u32($4->a2.i);
---
> check_u16($2->a2.i); check_u16($4->a2.i);
Feel free to use it :)
//Rasmus
2
1
22 Nov '11
---
doc/bird.sgml | 17 +++++-
nest/config.Y | 26 ++++++++-
nest/proto-hooks.c | 11 ++++
nest/proto.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++--
nest/protocol.h | 40 ++++++++++++-
nest/rt-table.c | 84 ++++++++++++++++++++++++--
proto/bgp/bgp.c | 33 +++++++---
proto/bgp/bgp.h | 1 -
proto/bgp/config.Y | 9 +++-
proto/bgp/packets.c | 3 -
10 files changed, 361 insertions(+), 29 deletions(-)
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 7f53f02..ef9901d 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -415,6 +415,20 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
<tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
works in the direction from the routing table to the protocol. Default: <cf/none/.
+ <tag>import limit <m/number/ exceed warn | block | restart | disable</tag>
+ Specify limit action to be taken when import routes limit is hit. Warn action
+ does nothing more than printing error log message. Block action ignores
+ new routes (and converts route updates to withdraws) coming from protocol.
+ Restart action shuts protocol down (and core immediately restarts it).
+ Disable action takes protocol down and restrict automatic protocol restart
+ until protocol is explicitly enabled from CLI.
+ Default: <cf/none/.
+
+ <tag>export limit <m/number/ exceed warn | block | disable</tag>
+ Specify limit action to be taken when export routes limit is hit.
+ Actions are the same as in <cf>import</cf> keyword except <cf/restart/.
+ Default: <cf/none/.
+
<tag>description "<m/text/"</tag> This is an optional
description of the protocol. It is displayed as a part of the
output of 'show route all' command.
@@ -1271,7 +1285,8 @@ for each neighbor using the following configuration parameters:
<tag>route limit <m/number/</tag> The maximal number of routes
that may be imported from the protocol. If the route limit is
- exceeded, the connection is closed with error. Default: no limit.
+ exceeded, the connection is closed with error. Limit is currently implemented as
+ <cf/import limit number exceed restart/. Default: no limit.
<tag>disable after error <m/switch/</tag> When an error is encountered (either
locally or by the other side), disable the instance automatically
diff --git a/nest/config.Y b/nest/config.Y
index a6baf4e..aa08661 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -43,6 +43,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
+CF_KEYWORDS(EXCEED, LIMIT, WARN, BLOCK, RESTART, DISABLE)
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, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
@@ -59,7 +60,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULT
%type <r> rtable
%type <s> optsym
%type <ra> r_args
-%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport limit_action
%type <ps> proto_patt proto_patt2
CF_GRAMMAR
@@ -153,6 +154,22 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
+ | IMPORT LIMIT expr EXCEED limit_action {
+ if (!this_proto->in_limit)
+ this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
+ this_proto->in_limit->direction = PL_IMPORT;
+ this_proto->in_limit->limit = $3;
+ this_proto->in_limit->action = $5;
+ }
+ | EXPORT LIMIT expr EXCEED limit_action {
+ if (!this_proto->out_limit)
+ this_proto->out_limit = cfg_allocz(sizeof(struct proto_limit));
+ this_proto->out_limit->direction = PL_EXPORT;
+ this_proto->out_limit->limit = $3;
+ this_proto->out_limit->action = $5;
+ if ($5 == PL_ACTION_RESTART)
+ cf_error("RESTART action can't be used in export limiter. Use DISABLE action instead");
+ }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
@@ -165,6 +182,13 @@ imexport:
| NONE { $$ = FILTER_REJECT; }
;
+limit_action:
+ WARN { $$ = PL_ACTION_WARN; }
+ | BLOCK { $$ = PL_ACTION_BLOCK; }
+ | RESTART { $$ = PL_ACTION_RESTART; }
+ | DISABLE { $$ = PL_ACTION_DISABLE; }
+ ;
+
rtable:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table name expected");
diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c
index f026192..c901e9d 100644
--- a/nest/proto-hooks.c
+++ b/nest/proto-hooks.c
@@ -205,6 +205,17 @@ void rt_notify(struct proto *p, net *net, rte *new, rte *old, ea_list *attrs)
{ DUMMY; }
/**
+ * limit_notify - notify instance about limit hit
+ * @p: protocol instance
+ * @l: linit structure
+ * @table: table where route limit occurs
+ *
+ * Function should return 0 unless it shuts protocol down
+ */
+int limit_notify(struct proto *, struct proto_limit *l, struct rtable *table)
+{ DUMMY; }
+
+/**
* neigh_notify - notify instance about neighbor status change
* @neigh: a neighbor cache entry
*
diff --git a/nest/proto.c b/nest/proto.c
index d55c348..56ca6af 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -33,6 +33,10 @@ static list initial_proto_list;
static list flush_proto_list;
static struct proto *initial_device_proto;
+/* protocol limiting variables */
+static struct rate_limit rl_rt_limit;
+static event *proto_shut_event;
+
static event *proto_flush_event;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
@@ -41,6 +45,8 @@ static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
static void proto_flush_all(void *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
+static char *proto_limit_name(struct proto_limit *l);
+static void proto_shutdown_abusers(void *unused UNUSED);
static void
proto_enqueue(list *l, struct proto *p)
@@ -114,6 +120,8 @@ 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->in_limit = c->in_limit;
+ p->out_limit = c->out_limit;
p->hash_key = random_u32();
c->proto = p;
return p;
@@ -363,6 +371,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
p->name = nc->name;
p->in_filter = nc->in_filter;
p->out_filter = nc->out_filter;
+ p->in_limit = nc->in_limit;
+ p->out_limit = nc->out_limit;
p->preference = nc->preference;
if (import_changed || export_changed)
@@ -457,7 +467,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
PD(p, "Unconfigured");
p->cf_new = NULL;
}
- p->reconfiguring = 1;
+ p->flags |= PFLAG_RECONFIGURING;
config_add_obstacle(old);
proto_rethink_goal(p);
}
@@ -490,7 +500,7 @@ proto_rethink_goal(struct proto *p)
{
struct protocol *q;
- if (p->reconfiguring && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
+ if (PROTO_IS_RECONFIGURING(p) && p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
{
struct proto_config *nc = p->cf_new;
DBG("%s has shut down for reconfiguration\n", p->name);
@@ -504,7 +514,7 @@ proto_rethink_goal(struct proto *p)
}
/* Determine what state we want to reach */
- if (p->disabled || p->reconfiguring)
+ if (p->disabled || PROTO_IS_RECONFIGURING(p))
{
p->core_goal = FS_HUNGRY;
if (p->core_state == FS_HUNGRY && p->proto_state == PS_DOWN)
@@ -525,6 +535,8 @@ proto_rethink_goal(struct proto *p)
DBG("Kicking %s up\n", p->name);
PD(p, "Starting");
proto_init_instance(p);
+ /* Zeroing limit flags */
+ p->flags &= ~PLIMIT_FLAGS;
proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
}
}
@@ -635,6 +647,8 @@ protos_build(void)
proto_pool = rp_new(&root_pool, "Protocols");
proto_flush_event = ev_new(proto_pool);
proto_flush_event->hook = proto_flush_all;
+ proto_shut_event = ev_new(proto_pool);
+ proto_shut_event->hook = proto_shutdown_abusers;
}
static void
@@ -715,6 +729,20 @@ proto_schedule_feed(struct proto *p, int initial)
if (!initial)
p->stats.exp_routes = 0;
+ /*
+ * Remove export limit if set.
+ * We assume something is changed (protocol limit or filter or
+ * other host announces) so refeeding protocol will not cause
+ * export limit to hit again.
+ */
+ p->flags &= ~(PFLAG_ELIMIT|PFLAG_ELIMIT_BLOCK);
+#ifdef CONFIG_PIPE
+ /* feedind is requested for every pipe hook e.g. both ends */
+ if (proto_is_pipe(p))
+ {
+ p->flags &= ~(PFLAG_ILIMIT|PFLAG_ILIMIT_BLOCK);
+ }
+#endif
proto_relink(p);
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
ev_schedule(p->attn);
@@ -749,6 +777,80 @@ proto_request_feeding(struct proto *p)
proto_schedule_feed(p, 0);
}
+static void
+proto_shutdown_abusers(void *unused UNUSED)
+{
+ struct proto *p, *p_next;
+ int disable;
+
+ WALK_LIST_DELSAFE(p, p_next, active_proto_list)
+ {
+ if (!(p->flags & (PFLAG_RESTART|PFLAG_DISABLE)))
+ continue;
+
+ disable = (p->flags & PFLAG_DISABLE) ? 1 : 0;
+
+ p->disabled = 1;
+ proto_rethink_goal(p);
+ if (!disable)
+ {
+ p->disabled = 0;
+ proto_rethink_goal(p);
+ }
+ }
+}
+
+/**
+ * proto_notify_limit: notify protocol instance about limit hit and take appropriate action
+ * @p: given protocol
+ * @l: limit being hit
+ *
+ * If limit hook exists it is called and returned value is examined.
+ * If non-zero value returned, processing stops. Overwise action is taken
+ * depending on l->action configured in limit instance. Non-zero value should be
+ * used for proper protocol shutdown only. Setting one of PFLAG_ILIMIT|PFLAG_ELIMIT is required
+ * if protocol is not going down.
+ *
+ * Returns 1 if processing must be stopped, 0 overwise.
+ */
+int
+proto_notify_limit(struct proto *p, struct proto_limit *l, struct rtable *table)
+{
+ int ret = 1, flag;
+
+ log_rl(&rl_rt_limit, L_ERR "Protocol %s hits route %s limit (%d), action: %s", p->name,
+ (l->direction == PL_IMPORT) ? "import" : "export", l->limit, proto_limit_name(l));
+
+ flag = (l->direction == PL_IMPORT) ? PFLAG_ILIMIT : PFLAG_ELIMIT;
+
+ /* Skip multiple filter hit invocations */
+ if ((l->action != PL_ACTION_WARN) && (p->flags & flag))
+ return 1;
+
+ p->flags |= flag;
+
+ if (p->limit_notify && (p->limit_notify(p, l, table)))
+ return 1;
+
+ switch (l->action)
+ {
+ case PL_ACTION_WARN:
+ ret = 0;
+ break;
+ case PL_ACTION_BLOCK:
+ p->flags |= (l->direction == PL_IMPORT) ? PFLAG_ILIMIT_BLOCK : PFLAG_ELIMIT_BLOCK;
+ break;
+ case PL_ACTION_RESTART:
+ case PL_ACTION_DISABLE:
+ /* Schedule instance shutdown */
+ p->flags |= (l->action == PL_ACTION_DISABLE) ? PFLAG_DISABLE : PFLAG_RESTART;
+ ev_schedule(proto_shut_event);
+ break;
+ }
+
+ return ret;
+}
+
/**
* proto_notify_state - notify core about protocol state change
* @p: protocol the state of which has changed
@@ -853,6 +955,19 @@ proto_state_name(struct proto *p)
#undef P
}
+static char *
+proto_limit_name(struct proto_limit *l)
+{
+ switch (l->action)
+ {
+ case PL_ACTION_WARN: return "WARN";
+ case PL_ACTION_BLOCK: return "BLOCK";
+ case PL_ACTION_RESTART: return "RESTART";
+ case PL_ACTION_DISABLE: return "DISABLE";
+ }
+ return "unknown";
+}
+
static void
proto_do_show_stats(struct proto *p)
{
@@ -919,7 +1034,8 @@ proto_do_show_pipe_stats(struct proto *p)
void
proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
{
- byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
+ byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE], lbuf[25];
+ struct proto_limit *l;
/* First protocol - show header */
if (!cnt)
@@ -928,12 +1044,16 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
buf[0] = 0;
if (p->proto->get_status)
p->proto->get_status(p, buf);
+ if (p->flags & (PFLAG_ILIMIT|PFLAG_ELIMIT))
+ bsnprintf(lbuf, sizeof(lbuf), "%s/%s", proto_state_name(p), "LI");
+ else
+ strcpy(lbuf, proto_state_name(p));
tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
p->name,
p->proto->name,
p->table->name,
- proto_state_name(p),
+ lbuf,
tbuf,
buf);
if (verbose)
@@ -945,6 +1065,20 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
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->in_limit)
+ {
+ l = p->in_limit;
+ cli_msg(-1006, " Import limit: %4d, action: %7s%s", l->limit,
+ proto_limit_name(l), (p->flags & PFLAG_ILIMIT) ? " [ LIMIT HIT ]" : "");
+ } else if (p->flags & PFLAG_ILIMIT)
+ cli_msg(-1006, " Old Import limit: [HIT][reload/restart required]");
+ if (p->out_limit)
+ {
+ l = p->out_limit;
+ cli_msg(-1006, " Export limit: %4d, action: %7s%s", l->limit,
+ proto_limit_name(l), (p->flags & PFLAG_ELIMIT) ? " [ LIMIT HIT ]" : "");
+ } else if (p->flags & PFLAG_ELIMIT)
+ cli_msg(-1006, " Old export limit: [HIT][reload/restart required]");
if (p->proto_state != PS_DOWN)
{
@@ -1013,6 +1147,8 @@ proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
void
proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
{
+ u32 flags;
+
if (p->disabled)
{
cli_msg(-8, "%s: already disabled", p->name);
@@ -1027,13 +1163,31 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
/* re-importing routes */
if (dir != CMD_RELOAD_OUT)
+ {
+ /*
+ * Removing limit hit flags should be safe because:
+ * current (and planned) limiting actions block
+ * new route import only. Route withdrawal is not blocked.
+ * At this moment core has a small (possibly zero) subset of
+ * routes which are announced by protocol. Same route announce
+ * from the same protocol are ignored by core so we can safely
+ * re-import all routes.
+ */
+ flags = p->flags & (PFLAG_ILIMIT|PFLAG_ILIMIT_BLOCK);
+ p->flags &= ~flags;
if (! (p->reload_routes && p->reload_routes(p)))
{
cli_msg(-8006, "%s: reload failed", p->name);
+ /* reload failed, adding removed flags back */
+ p->flags |= flags;
return;
}
+ }
- /* re-exporting routes */
+ /*
+ * re-exporting routes.
+ * Export limit flags are dispatched in proto_request_feeding()
+ */
if (dir != CMD_RELOAD_IN)
proto_request_feeding(p);
diff --git a/nest/protocol.h b/nest/protocol.h
index a7518c2..82b20cb 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -68,6 +68,25 @@ void protos_dump_all(void);
#define GA_FULL 2 /* Result = both name and value */
/*
+ * Protocol limits
+ */
+#define PL_IMPORT 1 /* Import limit*/
+#define PL_EXPORT 2 /* Export limit */
+
+#define PL_ACTION_WARN 1 /* Issue log warning */
+#define PL_ACTION_BLOCK 2 /* Block new routes */
+#define PL_ACTION_RESTART 4 /* Force protocol restart */
+#define PL_ACTION_DISABLE 5 /* Shutdown and disable protocol */
+
+struct proto_limit {
+ int direction; /* PL_IMPORT|PL_EXPORT */
+ int limit; /* maximum prefix number */
+ int action; /* action to take */
+};
+
+int proto_notify_limit(struct proto *p, struct proto_limit *l, struct rtable *table);
+
+/*
* Known protocols
*/
@@ -92,12 +111,15 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
+ struct proto_limit *in_limit; /* Limit for importing routes from protocol */
+ struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
/* Protocol-specific data follow... */
};
+
/* Protocol statistics */
struct proto_stats {
/* Import - from protocol to core */
@@ -141,7 +163,7 @@ struct proto {
unsigned proto_state; /* Protocol state machine (see below) */
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 flags; /* Various protocol flags */
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 */
@@ -154,6 +176,7 @@ struct proto {
* if_notify Notify protocol about interface state changes.
* ifa_notify Notify protocol about interface address changes.
* rt_notify Notify protocol about routing table updates.
+ * limit_notify Notify protocol about import/export limit hit.
* neigh_notify Notify protocol about neighbor cache events.
* make_tmp_attrs Construct ea_list from private attrs stored in rte.
* store_tmp_attrs Store private attrs back to the rte.
@@ -169,6 +192,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 rtable *table, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs);
+ int (*limit_notify)(struct proto *, struct proto_limit *l, struct rtable *table);
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);
@@ -192,6 +216,8 @@ struct proto {
struct rtable *table; /* Our primary routing table */
struct filter *in_filter; /* Input filter */
struct filter *out_filter; /* Output filter */
+ struct proto_limit *in_limit; /* Limit for importing routes from protocol */
+ struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */
@@ -200,6 +226,18 @@ struct proto {
/* Hic sunt protocol-specific data */
};
+#define PFLAG_RECONFIGURING 0x01 /* We're shutting down due to reconfiguration */
+#define PFLAG_ILIMIT 0x02 /* Import route limit reached */
+#define PFLAG_ELIMIT 0x04 /* Export route limit reached */
+#define PFLAG_ILIMIT_BLOCK 0x08 /* Block route imports */
+#define PFLAG_ELIMIT_BLOCK 0x10 /* Block route exports */
+#define PFLAG_RESTART 0x20 /* Protocol needs restart */
+#define PFLAG_DISABLE 0x40 /* Protocol needs disabling */
+
+#define PLIMIT_FLAGS (PFLAG_ILIMIT|PFLAG_ELIMIT|PFLAG_ILIMIT_BLOCK|PFLAG_ELIMIT_BLOCK|PFLAG_DISABLE)
+
+#define PROTO_IS_RECONFIGURING(x) ((x)->flags & PFLAG_RECONFIGURING)
+
struct proto_spec {
void *ptr;
int patt;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index e20d2f6..92fb245 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -183,25 +183,44 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
rte_trace(p, e, '<', msg);
}
-static inline void
+/**
+ * do_rte_announce - announce new rte to protocol
+ * @a: pointer to announce hook
+ * @type: announce type (RA_ANY or RA_OPTIMAL)
+ * @net: pointer to announced network
+ * @new: new rte or NULL
+ * @old: previous rte or NULL
+ * @tmpa: new rte attributes (possibly modified by filter)
+ * @refeed: are we refeeding protocol
+ *
+ * Returns 1 if feeding can continue, 0 overwise
+ *
+ */
+static inline int
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_limit *l = p->out_limit;
struct proto_stats *stats = &p->stats;
rte *new0 = new;
rte *old0 = old;
- int ok;
+ int ok, check_limit = 1;
#ifdef CONFIG_PIPE
/* The secondary direction of the pipe */
if (proto_is_pipe(p) && (p->table != a->table))
{
filter = p->in_filter;
+ l = p->in_limit;
stats = pipe_get_peer_stats(p);
}
#endif
+ /* Check if we're called on non-default protocol table */
+ if ((!proto_is_pipe(p)) && (p->table != a->table))
+ check_limit = 0;
+
if (new)
{
stats->exp_updates_received++;
@@ -270,7 +289,35 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
/* FIXME - This is broken because of incorrect 'old' value (see above) */
if (!new && !old)
- return;
+ return 1;
+
+ /*
+ * XXX: there is (currently) no way to determine if rte was announced to the protocol,
+ * especially in case of route limiting active. As a result if block flag is set we're
+ * 1) ignoring new routes
+ * 2) convert updates to withdrawals
+ *
+ */
+ if (new && (p->flags & PFLAG_ELIMIT_BLOCK) && check_limit)
+ {
+ if (new != new0)
+ rte_free(new);
+ /* New route announce, simply ignore */
+ if (!old)
+ return 0;
+ /* Route update, change to withdraw */
+ new = NULL;
+ }
+
+ /* Check route limits for new routes */
+ if (new && l && !old && check_limit && (stats->exp_routes + 1 > l->limit) && (proto_notify_limit(p, l, a->table) == 1))
+ {
+ /* free allocated data and return */
+ if (new != new0)
+ rte_free(new);
+
+ return 0;
+ }
if (new)
stats->exp_updates_accepted++;
@@ -310,6 +357,8 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
rte_free(new);
if (old && old != old0)
rte_free(old);
+
+ return 1;
}
/**
@@ -426,13 +475,21 @@ 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;
+ struct proto_limit *l;
rte *old_best = net->routes;
rte *old = NULL;
rte **k, *r, *s;
+ int check_limit = 1;
#ifdef CONFIG_PIPE
if (proto_is_pipe(p) && (p->table == table))
stats = pipe_get_peer_stats(p);
+ /* Check if we're called on non-default protocol table */
+ if ((!proto_is_pipe(p)) && (p->table != table))
+ check_limit = 0;
+#else
+ if (p->table != a->table)
+ check_limit = 0;
#endif
k = &net->routes; /* Find and remove original route from the same protocol */
@@ -486,6 +543,17 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
return;
}
+ /* Check limit for imported routes */
+ if (new && !old && check_limit)
+ {
+ if (p->flags & PFLAG_ILIMIT_BLOCK)
+ return;
+
+ if ((l = p->in_limit) && (!proto_is_pipe(p)) &&
+ (stats->imp_routes + 1 > l->limit) && (proto_notify_limit(p, l, table) == 1))
+ return;
+ }
+
if (new)
stats->imp_updates_accepted++;
else
@@ -1207,16 +1275,19 @@ rt_commit(struct config *new, struct config *old)
DBG("\tdone\n");
}
-static inline void
+static inline int
do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
{
struct proto *q = e->attrs->proto;
+ int res;
ea_list *tmpa;
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, p->refeeding);
+ res = do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding);
rte_update_unlock();
+
+ return res;
}
/**
@@ -1263,8 +1334,9 @@ again:
{
if (p->core_state != FS_FEEDING)
return 1; /* In the meantime, the protocol fell down. */
- do_feed_baby(p, RA_OPTIMAL, h, n, e);
max_feed--;
+ if (do_feed_baby(p, RA_OPTIMAL, h, n, e) == 0)
+ break;
}
if (p->accept_ra_types == RA_ANY)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 675342d..0c5516b 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -542,19 +542,33 @@ bgp_active(struct bgp_proto *p)
bgp_start_timer(conn->connect_retry_timer, delay);
}
-int
-bgp_apply_limits(struct bgp_proto *p)
+static int
+bgp_limit_notify(struct proto *P, struct proto_limit *l, struct rtable *table)
{
- if (p->cf->route_limit && (p->p.stats.imp_routes > p->cf->route_limit))
+ struct bgp_proto *p = (struct bgp_proto *) P;
+ int subcode;
+ if ((l->direction != PL_IMPORT) && (l->action != PL_ACTION_DISABLE))
+ return 0;
+
+ switch (l->action)
{
- log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
+ case PL_ACTION_RESTART:
+ case PL_ACTION_DISABLE:
+ if (l->action == PL_ACTION_DISABLE)
+ P->disabled = 1;
+ log(L_WARN "%s: Route limit exceeded, shutting down", P->name);
bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
bgp_update_startup_delay(p);
- bgp_stop(p, 1); // Errcode 6, 1 - max number of prefixes reached
- return -1;
+ /*
+ * Send 6,2 (Administrative Shutdown) for export limit
+ * Send 6,1 (Maximum Number of Prefixes Reached) overwise
+ */
+ subcode = (P->disabled && (l->direction == PL_EXPORT)) ? 2 : 1;
+ bgp_stop(p, subcode);
+ return 1;
+ default:
+ return 0;
}
-
- return 0;
}
@@ -866,7 +880,7 @@ bgp_shutdown(struct proto *P)
BGP_TRACE(D_EVENTS, "Shutdown requested");
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
- if (P->reconfiguring)
+ if (P->flags & PFLAG_RECONFIGURING)
{
if (P->cf_new)
subcode = 6; // Errcode 6, 6 - other configuration change
@@ -907,6 +921,7 @@ bgp_init(struct proto_config *C)
P->rte_better = bgp_rte_better;
P->import_control = bgp_import_control;
P->neigh_notify = bgp_neigh_notify;
+ P->limit_notify = bgp_limit_notify;
P->reload_routes = bgp_reload_routes;
p->cf = c;
p->local_as = c->local_as;
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 437ba33..f271ef3 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -150,7 +150,6 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn);
void bgp_conn_enter_close_state(struct bgp_conn *conn);
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
-int bgp_apply_limits(struct bgp_proto *p);
void bgp_stop(struct bgp_proto *p, unsigned subcode);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 03c233d..de3b254 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -94,7 +94,14 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
- | bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
+ | bgp_proto ROUTE LIMIT expr ';' {
+ if (!this_proto->in_limit)
+ this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
+ struct proto_limit *l = this_proto->in_limit;
+ l->direction = PL_IMPORT;
+ l->limit = $4;
+ l->action = PL_ACTION_RESTART;
+ }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index c3a8673..8eb6483 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -883,9 +883,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
-
- if (bgp_apply_limits(p) < 0)
- goto done;
}
done:
--
1.7.3.2
--------------010908080505070307040008--
1
0
Hi Bird user group
We are currently trying to configure bird as a route reflector and I would
like to know if there is multiprocol BGP support. We have some L2VPN
services based on Juniper routers and I was wondering how bird handles
these type of VPN BGP routes.
Any advice would be greatly appreciated and congratulation for this great
piece of software
2
2
On 21.11.2011 16:07, Ondrej Zajicek wrote:
> On Mon, Nov 14, 2011 at 04:40:25PM +0400, Alexander V. Chernikov wrote:
>> Hello list!
>>
>> At the moment bird has route limits implemented for BGP only (route
>> limit XXX).
>>
> ...
>>
>> This patch introduces general limiting functionality for any protocol.
>>
>> Import/export limits can be configured with the following actions:
>> * warn (prints warning message)
>> * block (blocks new import/exports from/to the protocol)
>> * shutdown (restart the protocol, import only)
>> * disable (shutdown and disable protocol)
>>
>> If any protocol limit is hit and block action is taken, protocol can be
>> returned to 'normal' state by using reload [in|out] protocol (or
>> restaring it).
>
> There are several problems, esp. with 'block' action in export limit. Primary
> cause is that BIRD does not remember which route was sent to a peer,
> instead it reruns filter to know that. This get broken when 'block' is
> active, because it is not possible to know whether given route was
> blocked or not. For example, if export is blocked, then a new route arrives,
> it is blocked, but if later the route is updated, it is treated as an update
> (and not as a new route) and propagated, therefore limit is exceeded
> ('old' value in do_rte_announce is not NULL).
Understood. Okay, we can possibly do the following:
implement per-table counter which will be incremented with every
rte_announce. current counter value will be saved inside rte.
Even u32 should not overflow (over 8k times of full-view gets announced)
however using u64 is much better.
This should not introduce significant performance penalty (but this will
harden possible future multithreading a bit).
When protocol state changes to blocked we can save current counter value.
After that, if we're re-announcing such rte we can check if old rte
counter value is less than block counter value.
>
> Not sure if there is a way how to fix it. One possible way is when
> protocol is blocked then convert any later updates to withdraws (instead
> just block new routes). Don't know how exactly the block/withdraw
> behaves in Junipers and Ciscos. Note also that we have to count routes
> blocked by this as exported in exp_routes, otherwise it would be
> inconsistent and would drift away (when genuine withdraw is announced,
> it is unknown whether the withdrawed route is 'older' route (propagated
> before the block) or 'later' route (propagated after the block).
>
> Another possibility is just do not allow block in export filter.
>
> Another related problem is that exp_routes statistics became unreliable
> when 'configure soft' is used, export filter is changed and protocol
> is not reloaded. This is probably a reason why BGP limits were originally
> implemented for import only.
IMHO export limit main usage pattern is IGP. BGP export limit can be
forbidden (however the original problem with 'configure soft' remains).
>
> Some minor comments later:
>
>> From f9c8c639593aa98723397a640f8d899b85c39fb7 Mon Sep 17 00:00:00 2001
>> From: Alexander V. Chernikov<melifaro(a)ipfw.ru>
>> Date: Mon, 14 Nov 2011 15:33:27 +0000
>> Subject: [PATCH 1/1] * Implement general protocol limiting
>>
>> ---
>> doc/bird.sgml | 16 +++++-
>> nest/config.Y | 32 +++++++++
>> nest/proto.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++--
>> nest/protocol.h | 42 ++++++++++++-
>> nest/rt-table.c | 49 ++++++++++++++-
>> proto/bgp/bgp.c | 28 +++++---
>> proto/bgp/bgp.h | 1 -
>> proto/bgp/config.Y | 9 +++-
>> proto/bgp/packets.c | 3 -
>> 9 files changed, 329 insertions(+), 26 deletions(-)
>>
>> diff --git a/doc/bird.sgml b/doc/bird.sgml
>> index 7f53f02..4060f05 100644
>> --- a/doc/bird.sgml
>> +++ b/doc/bird.sgml
>> @@ -415,6 +415,19 @@ to zero to disable it. An empty<cf><m/switch/</cf> is equivalent to<cf/on/
>> <tag>export<m/filter/</tag> This is similar to the<cf>import</cf> keyword, except that it
>> works in the direction from the routing table to the protocol. Default:<cf/none/.
>>
>> + <tag>import limit<m/number/ exceed warn | block | shutdown | disable</tag>
>
> It would be much better to rename 'shutdown' to 'restart'.
>
>> + | IMPORT LIMIT expr {
>> + if ((!strcmp(this_proto->protocol->name, "Device")) ||
>> + (!strcmp(this_proto->protocol->name, "Static")))
>> + cf_error("%s protocol does not support import limits", this_proto->protocol->name);
>
> Why not? Altough it probably does not make much sense, i see no need to
> create an exception. And even if so, strcmp() is a crazy way to check
> protocol class.
>
>> + if (!this_proto->in_limit)
>> + this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
>> + this_limit = this_proto->in_limit;
>> + this_limit->direction = PL_IMPORT;
>> + this_limit->limit = $3;
>> + }
>> + EXCEED limit_action
>> + | EXPORT LIMIT expr {
>> + if (!this_proto->out_limit)
>> + this_proto->out_limit = cfg_allocz(sizeof(struct proto_limit));
>> + this_limit = this_proto->out_limit;
>> + this_limit->direction = PL_EXPORT;
>> + this_limit->limit = $3;
>> + }
>> + EXCEED limit_action
>
> This seems unnecessary complicated, what about just (without global
> variable this_limit and with return value of limit_action):
>
> | IMPORT LIMIT expr EXCEED limit_action {
> ...
> xxx->limit = $3
> xxx->action = $5
> // and check for valid action w.r.t. direction
> }
>
>> SYM {
>> if ($1->class != SYM_TABLE) cf_error("Table name expected");
>> diff --git a/nest/proto.c b/nest/proto.c
>> index d55c348..f022dc2 100644
>> --- a/nest/proto.c
>> +++ b/nest/proto.c
>> @@ -33,6 +33,11 @@ static list initial_proto_list;
>> static list flush_proto_list;
>> static struct proto *initial_device_proto;
>>
>> +/* protocol limiting variables */
>> +static struct rate_limit rl_rt_limit;
>> +static event *proto_shut_event;
>> +static list abuse_proto_list;
>
>> - if (p->reconfiguring&& p->core_state == FS_HUNGRY&& p->proto_state == PS_DOWN)
>> + if ((p->flags& PFLAG_RECONFIGURING)&& p->core_state == FS_HUNGRY&& p->proto_state == PS_DOWN)
>
> It would be nice to use some inline function to check for reconfiguring flag.
>
>> + /* Remove from pre-shutdown list if exists */
>> + WALK_LIST_DELSAFE(ap, ap_next, abuse_proto_list)
>> + {
>> + if ((ap = SKIP_BACK(struct proto, shutdown_node, ap)) != p)
>> + continue;
>> + rem_node(&ap->shutdown_node);
>> + break;
>> + }
>
> This seems a bit crazy to me - what about just use some flag to mark a proto
> in abuse_proto_list and then call rem_node base on that?
>
> Personally, i would remove the whole abuse_proto_list. Disabling or restarting
> protocols because of limit breaching seems to be too unfrequent event
> that just walking active_proto_list and acting based on flags seems OK and
> keeps the code simpler.
>
>> +#define PL_HANDLED 1 /* Limit action is handled by the protocol hook */
>> +#define PL_DEFAULT 2 /* Core has to execute default action */
>
> Perhaps just keep the callback return boolean, like the reconfigure hook?
>
>> +#define PL_ACTION_WARN 1 /* Issue log warning */
>> +#define PL_ACTION_BLOCK 2 /* Block new routes */
>> +#define PL_ACTION_CLEAR 3 /* Clear exported routes */
>
> Some unimplemented feature?
>
>
>> @@ -188,20 +188,26 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
>> {
>> struct proto *p = a->proto;
>> struct filter *filter = p->out_filter;
>> + struct proto_limit *l = p->out_limit;
>> struct proto_stats *stats =&p->stats;
>> rte *new0 = new;
>> rte *old0 = old;
>> - int ok;
>> + int ok, wrong_table = 0;
>>
>> #ifdef CONFIG_PIPE
>> /* The secondary direction of the pipe */
>> if (proto_is_pipe(p)&& (p->table != a->table))
>> {
>> filter = p->in_filter;
>> + l = p->in_limit;
>> stats = pipe_get_peer_stats(p);
>> }
>> #endif
>>
>> + /* Check if we're called on non-default protocol table */
>> + if ((!proto_is_pipe(p))&& (p->table != a->table))
>> + wrong_table = 1;
>> +
>
> Some unimplemented thing?
>
>> if (new)
>> {
>> stats->exp_updates_received++;
>> @@ -272,6 +278,22 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
>> if (!new&& !old)
>> return;
>>
>> + /* Check if we can export new route / exceed export limit */
>> + if (new&& l&& !old)
>> + {
>> + if (p->flags& PFLAG_ELIMIT_BLOCK)
>> + return;
>> +
>> + if ((l = p->out_limit)&& (p->stats.exp_routes + 1> l->limit)&& (proto_notify_limit(p, l, a->table) == 1))
>> + {
>
> 'l' and 'stats' is already set above to be consistent with pipe, that should be used here?
>
>> + /* free allocated data and return */
>> + if (new != new0)
>> + rte_free(new);
>> +
>> + return;
>> + }
>> + }
>> +
>> if (new)
>> stats->exp_updates_accepted++;
>> else
>> @@ -426,6 +448,7 @@ 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;
>> + struct proto_limit *l;
>> rte *old_best = net->routes;
>> rte *old = NULL;
>> rte **k, *r, *s;
>> @@ -486,6 +509,16 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
>> return;
>> }
>>
>> + /* Check limit for imported routes */
>> + if (new&& !old)
>> + {
>> + if (p->flags& PFLAG_ILIMIT_BLOCK)
>> + return;
>> +
>> + if ((l = p->in_limit)&& (p->stats.imp_routes + 1> l->limit)&& (proto_notify_limit(p, l, table) == 1))
>> + return;
>> + }
>
> Ignore this check in case of pipe?
>
>> +
>> if (new)
>> stats->imp_updates_accepted++;
>> else
>> @@ -1233,7 +1266,11 @@ rt_feed_baby(struct proto *p)
>> {
>> struct announce_hook *h;
>> struct fib_iterator *fit;
>> - int max_feed = 256;
>> + struct proto_limit *l = p->out_limit;
>> + int max_feed = 256, need_check, do_check;
>
> Isn't code here in rt_feed_baby() unnecessary?
> do_feed_baby() is called and do_rte_announce() is called,
> where limits are already handled. Perhaps just some check
> if block is reached to skip rest of feeding?
>
> Also pipes seems not to be handled properly here.
>
>> + /* Do we need to filter route updates? */
>> + need_check = (!(p->flags& PFLAG_ELIMIT_BLOCK)&& l) ? 1 : 0;
>>
>> if (!p->feed_ahook) /* Need to initialize first */
>> {
>> @@ -1248,6 +1285,8 @@ rt_feed_baby(struct proto *p)
>>
>> again:
>> h = p->feed_ahook;
>> + /* Do limit check for base protocol table only */
>> + do_check = ((p->table == h->table)&& need_check)? 1 : 0;
>> FIB_ITERATE_START(&h->table->fib, fit, fn)
>> {
>> net *n = (net *) fn;
>> @@ -1263,6 +1302,12 @@ again:
>> {
>> if (p->core_state != FS_FEEDING)
>> return 1; /* In the meantime, the protocol fell down. */
>> + if (do_check&& (p->stats.exp_routes + 1> l->limit))
>> + if (proto_notify_limit(p, l, h->table))
>> + {
>> + /* limit action forbids new exports, end feed */
>> + break;
>> + }
>> do_feed_baby(p, RA_OPTIMAL, h, n, e);
>> max_feed--;
>> }
>> diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
>> index 675342d..483a2d0 100644
>> --- a/proto/bgp/bgp.c
>> +++ b/proto/bgp/bgp.c
>> @@ -542,19 +542,27 @@ bgp_active(struct bgp_proto *p)
>> bgp_start_timer(conn->connect_retry_timer, delay);
>> }
>>
>> -int
>> -bgp_apply_limits(struct bgp_proto *p)
>> +static int
>> +bgp_limit_notify(struct proto *P, struct proto_limit *l, struct rtable *table)
>> {
>> - if (p->cf->route_limit&& (p->p.stats.imp_routes> p->cf->route_limit))
>> + struct bgp_proto *p = (struct bgp_proto *) P;
>> + if (l->direction != PL_IMPORT)
>> + return PL_DEFAULT;
>
> Perhaps there should be proper error code even for import limit?
>
>> @@ -1141,9 +1150,6 @@ bgp_show_proto_info(struct proto *P)
>> p->rs_client ? " route-server" : "",
>> p->as4_session ? " AS4" : "");
>> cli_msg(-1006, " Source address: %I", p->source_addr);
>> - if (p->cf->route_limit)
>> - cli_msg(-1006, " Route limit: %d/%d",
>> - p->p.stats.imp_routes, p->cf->route_limit);
>
> Perhaps this should be kept compatible until next major release?
>
>
> BTW, which of your addresses should i use when sending/replying e-mail
> to you? Or keep both ones?
>
1
0
Hello,
what is a right way to delete all extended communities ?
bgp_ext_community.delete( [ (*,*,*) ] );
raises a syntax error.
Thanks in advance!
--
MINO-RIPE
3
4
Hello,
patch adds 'show bgp summary' command in bird 1.3.4.
We're running bird in production environment (an IXP), and the such command
makes diagnostic output more usual and simplifies development of looking
glasses (we do not need to parse 'show protocols all' output).
--
MINO-RIPE
2
2
Hello.
In my test configuration of bird i want to announce two prefixes:
11.11.11.0/24 and 12.12.12.0/24.
But i do not understand how.
vlan3001 11.11.11.1/28 (direct connected)
vlan3002 11.11.11.17/28 (direct connected)
vlan3003 11.11.11.65/26 (direct connected)
bird.conf
#v+
protocol static static_bgp {
route 11.11.11.128/25 via 11.11.11.66;
route 12.12.12.0/24 via 11.11.11.66;
}
protocol direct { interface "*"; }
#v-
This configration announce as is - two times /28, one /26 and one /25 of
11.11.11.0/24 prefix.
How to aggregate this in one /24 prefix in this sample?
--
damkol(a)gmail.com
3
7