Bird-users
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- 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
- 23 participants
- 3719 discussions
Hello list!
There are some patches enabling bird to act as VPNv4 and (partly) as
VPNv6 RR.
Release is based on 1.3.4 git version.
VPNv6 is supported over IPv4 BGP sessions only and does not support pure
IPv6 nexthops.
Example RR configuration:
http://bird.mpls.in/projects/mpls-bird/wiki/Bird_rr
Download: http://bird.mpls.in/distfiles/bird/bird-20111202.tar.gz
Do configure with --enable-mpls switch
(FreeBSD example)
./configure --prefix=/usr/local --mandir=/usr/local/man
--infodir=/usr/local/info/ --build=amd64-portbld-freebsd8.2 --enable-mpls
FreeBSD users can edit net/bird-devel port, change its version to
20111202 and call 'make makesum'
Please note, this is BETA quality software and testing MUST be done
before real-world usage.
Feedback is highly appreciated.
4
11
Hello list!
At the moment bird has route limits implemented for BGP only (route
limit XXX).
This seems to be not enough in various BGP+IGP configurations.
Vendors implement the following approaches:
Cisco:
* warning-only (OSPF, redistribute maximum-prefix) - print warning message
* withdraw (OSPF, redistribute maximum-prefix) - Prevents additional
redistribution when the number of routes defined by the maximum argument
have been redistributed.
* clear (IS-IS) - clears all redistributed prefixes
See
http://www.cisco.com/en/US/docs/ios/12_0s/feature/guide/fsoredis.htmlfor
more information
Juniper:
* log-only (general, maximum-prefixes) - print warning message only
* withdraw (general, maximum-prefixes) - any additional routes are rejected
* clear (OSPF, ISIS, prefix-export-limit) - clear database from all
extrnal routes
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).
3
7
Hi!
We have a test setup with Debian Linux server running Bird. This
server also acts as PPPoE server. We have OSPF running between Bird
and Cisco router. But Bird is not advertising PPP peer's IP address to
that Cisco router. Any hints? Here is our config file:
# This pseudo-protocol watches all interface up/down events.
protocol device {
import all;
scan time 10; # Scan interfaces every 10 seconds
}
# This pseudo-protocol performs synchronization between BIRD's routing
# tables and the kernel. If your kernel supports multiple routing
tables
# (as Linux 2.2.x does), you can run multiple instances of the kernel
# protocol and synchronize different kernel tables with different BIRD
tables.
protocol kernel {
# learn; # Learn all alien routes from the
kernel
persist; # Don't remove routes on bird shutdown
scan time 20; # Scan kernel routing table every 20
seconds
import all; # Default is import all
export all; # Default is export none
# kernel table 5; # Kernel table to synchronize with
(default: main)
}
protocol ospf one {
export all;
rfc1583compat yes;
debug all;
tick 1;
area 0 {
interface "eth1.20" {
cost 10;
dead count 4;
rx buffer large;
authentication cryptographic;
password "***";
};
};
};
Thanks in advance!
--
Timur Irmatov, xmpp:irmatov@jabber.ru
3
8
Hello list!
This patch implements RFC 4271 MED comparison.
This patch may introduce significant performance penalty (unfortunately
I haven't got any real numbers at the moment).
However, this comparison is absolutely necessary at least for RR setups.
rte_better cost has changed from O(1) to O(n) (should not affect
performance much)
rte_recalculate can execute 2-3 times slower in worst case (this can
consume more resources when preferred BGP neighbor goes down)
Deterministic med can be made as optional global BGP config switch
(which will be done in next patch version). Keeping this switch off with
patched bird should not introduce much performance penalty.
Please consider this patch as beta.
Comments/reviews are welcome.
3
5
---
doc/bird.sgml | 17 +++++-
nest/config.Y | 28 ++++++++-
nest/proto-hooks.c | 12 ++++
nest/proto.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++--
nest/protocol.h | 45 ++++++++++++-
nest/rt-table.c | 132 +++++++++++++++++++++++++++++---------
proto/bgp/bgp.c | 37 ++++++++---
proto/bgp/bgp.h | 1 -
proto/bgp/config.Y | 9 ++-
proto/bgp/packets.c | 3 -
proto/pipe/pipe.c | 11 +++
proto/pipe/pipe.h | 3 +
12 files changed, 419 insertions(+), 57 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..0f2a8a8 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,24 @@ 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;
+ if (($5 == PL_ACTION_RESTART) && (config_is_pipe(this_proto)))
+ cf_error("RESTART action can't be used in pipes. Use DISABLE action instead");
+ }
+ | 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 +184,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..92bdf01 100644
--- a/nest/proto-hooks.c
+++ b/nest/proto-hooks.c
@@ -205,6 +205,18 @@ 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
+ * @a: announce hook
+ * @l: linit structure
+ * @table: table where route limit occurs
+ *
+ * Function should return 0 unless it shuts protocol down
+ */
+int limit_notify(struct proto *, struct announce_hook *, 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 451db2c..3b261a2 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -36,6 +36,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" };
@@ -44,6 +48,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)
@@ -388,6 +394,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
{
a->in_filter = nc->in_filter;
a->out_filter = nc->out_filter;
+ a->in_limit = nc->in_limit;
+ a->out_limit = nc->out_limit;
}
/* Execute protocol specific reconfigure hook */
@@ -492,7 +500,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);
}
@@ -525,7 +533,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);
@@ -539,7 +547,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)
@@ -560,6 +568,8 @@ proto_rethink_goal(struct proto *p)
DBG("Kicking %s up\n", p->name);
PD(p, "Starting");
proto_init_instance(p);
+ /* Zeroing limit-related flags */
+ p->flags &= ~PLIMIT_FLAGS;
proto_notify_state(p, (q->start ? q->start(p) : PS_UP));
}
}
@@ -675,6 +685,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
@@ -733,6 +745,9 @@ proto_feed_initial(void *P)
/* Set filters */
a->in_filter = p->cf->in_filter;
a->out_filter = p->cf->out_filter;
+ /* Set limits */
+ a->in_limit = p->cf->in_limit;
+ a->out_limit = p->cf->out_limit;
/* Set pointer to stats */
a->stats = &p->stats;
}
@@ -773,6 +788,13 @@ 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.
+ */
+ proto_clear_limits(p, PFLAG_ELIMIT|PFLAG_ELIMIT_BLOCK);
proto_relink(p);
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
ev_schedule(p->attn);
@@ -808,6 +830,100 @@ proto_request_feeding(struct proto *p)
}
/**
+ * proto_clear_limits - clear limiting flags in protocol instance
+ * @p: given protocol
+ * @flags: flags to clear
+ *
+ */
+void proto_clear_limits(struct proto *p, u32 flags)
+{
+ struct announce_hook *a;
+
+ p->flags &= ~flags;
+
+ for (a = p->ahooks; a; a = a->next)
+ a->flags &= ~flags;
+}
+
+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
+ * @a: announce hook
+ * @l: limit being hit
+ * @table: table where limititng occurs
+ *
+ * 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 announce_hook *a, 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 (a)
+ a->flags |= flag;
+
+ if (p->limit_notify && (p->limit_notify(p, a, 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
* @ps: the new status
@@ -911,6 +1027,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_stats *s)
{
@@ -934,7 +1063,8 @@ proto_do_show_stats(struct proto_stats *s)
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;
struct announce_hook *a;
/* First protocol - show header */
@@ -944,12 +1074,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)
@@ -965,6 +1099,18 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
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 (l = a->in_limit)
+ {
+ cli_msg(-1006, " Import limit: %4d, action: %7s%s", l->limit,
+ proto_limit_name(l), (a->flags & PFLAG_ILIMIT) ? " [ LIMIT HIT ]" : "");
+ } else if (a->flags & PFLAG_ILIMIT)
+ cli_msg(-1006, " Old Import limit: [HIT][reload/restart required]");
+ if (l = a->out_limit)
+ {
+ cli_msg(-1006, " Export limit: %4d, action: %7s%s", l->limit,
+ proto_limit_name(l), (a->flags & PFLAG_ELIMIT) ? " [ LIMIT HIT ]" : "");
+ } else if (a->flags & PFLAG_ELIMIT)
+ cli_msg(-1006, " Old export limit: [HIT][reload/restart required]");
if (p->proto_state != PS_DOWN)
{
@@ -1038,6 +1184,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);
@@ -1052,13 +1200,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 09ccd9c..91bb07b 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -28,6 +28,7 @@ struct event;
struct ea_list;
struct eattr;
struct symbol;
+struct announce_hook;
/*
* Routing Protocol
@@ -68,6 +69,26 @@ 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 announce_hook *a, struct proto_limit *l, struct rtable *table);
+void proto_clear_limits(struct proto *p, u32 flags);
+
+/*
* Known protocols
*/
@@ -92,12 +113,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 +165,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 +178,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 +194,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 announce_hook *a, 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);
@@ -199,6 +225,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;
@@ -346,12 +384,15 @@ extern struct proto_config *cf_dev_proto;
struct announce_hook {
node n;
+ struct announce_hook *next; /* Next hook for the same protocol */
struct rtable *table;
struct proto *proto;
+ u32 flags; /* General flags */
struct filter *in_filter; /* Input filter */
struct filter *out_filter; /* Output filter */
+ struct proto_limit *in_limit; /* Input limit */
+ struct proto_limit *out_limit; /* Output limit */
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 *);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 0c0a042..c5752bc 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -161,34 +161,49 @@ rte_better(rte *new, rte *old)
}
static void
-rte_trace(struct proto *p, rte *e, int dir, char *msg)
+rte_trace(struct proto *p, struct rtable *t, rte *e, int dir, char *msg)
{
byte via[STD_ADDRESS_P_LENGTH+32];
rt_format_via(e, via);
- log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, via);
+ log(L_TRACE "%s %c [%s] %s %I/%d %s", p->name, dir, t->name, msg, e->net->n.prefix, e->net->n.pxlen, via);
}
static inline void
-rte_trace_in(unsigned int flag, struct proto *p, rte *e, char *msg)
+rte_trace_in(unsigned int flag, struct proto *p, struct rtable *t, rte *e, char *msg)
{
if (p->debug & flag)
- rte_trace(p, e, '>', msg);
+ rte_trace(p, t, e, '>', msg);
}
static inline void
-rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
+rte_trace_out(unsigned int flag, struct proto *p, struct rtable *t, rte *e, char *msg)
{
if (p->debug & flag)
- rte_trace(p, e, '<', msg);
+ rte_trace(p, t, 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 = a->out_filter;
struct proto_stats *stats = a->stats;
+ struct proto_limit *l = a->out_limit;
+ struct rtable *table = a->table;
rte *new0 = new;
rte *old0 = old;
int ok;
@@ -204,7 +219,7 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
drop_reason = "rejected by protocol";
}
else if (ok)
- rte_trace_out(D_FILTERS, p, new, "forced accept by protocol");
+ rte_trace_out(D_FILTERS, p, table, new, "forced accept by protocol");
else if ((filter == FILTER_REJECT) ||
(filter && f_run(filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
{
@@ -213,7 +228,7 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
}
if (drop_reason)
{
- rte_trace_out(D_FILTERS, p, new, drop_reason);
+ rte_trace_out(D_FILTERS, p, table, new, drop_reason);
if (new != new0)
rte_free(new);
new = NULL;
@@ -261,7 +276,38 @@ 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))
+ {
+ rte_trace_out(D_FILTERS, p, table, new, "ignored [outbound limit hit]");
+ if (new != new0)
+ rte_free(new);
+ /* New route announce, simply ignore */
+ if (!old)
+ return 0;
+ rte_trace_out(D_FILTERS, p, table, new, "converted to withdraw [outbound limit hit]");
+ /* Route update, change to withdraw */
+ new = NULL;
+ }
+
+ /* Check route limits for new routes */
+ if (new && l && !old && (stats->exp_routes + 1 > l->limit) && (proto_notify_limit(p, a, l, table) == 1))
+ {
+ rte_trace_out(D_FILTERS, p, table, new, "ignored [outbound limit hit]");
+ /* free allocated data and return */
+ if (new != new0)
+ rte_free(new);
+
+ return 0;
+ }
if (new)
stats->exp_updates_accepted++;
@@ -278,29 +324,31 @@ do_rte_announce(struct announce_hook *a, int type UNUSED, net *net, rte *new, rt
if (p->debug & D_ROUTES)
{
if (new && old)
- rte_trace_out(D_ROUTES, p, new, "replaced");
+ rte_trace_out(D_ROUTES, p, table, new, "replaced");
else if (new)
- rte_trace_out(D_ROUTES, p, new, "added");
+ rte_trace_out(D_ROUTES, p, table, new, "added");
else if (old)
- rte_trace_out(D_ROUTES, p, old, "removed");
+ rte_trace_out(D_ROUTES, p, table, old, "removed");
}
if (!new)
- p->rt_notify(p, a->table, net, NULL, old, NULL);
+ p->rt_notify(p, table, net, NULL, old, NULL);
else if (tmpa)
{
ea_list *t = tmpa;
while (t->next)
t = t->next;
t->next = new->attrs->eattrs;
- p->rt_notify(p, a->table, net, new, old, tmpa);
+ p->rt_notify(p, table, net, new, old, tmpa);
t->next = NULL;
}
else
- p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs);
+ p->rt_notify(p, table, net, new, old, new->attrs->eattrs);
if (new && new != new0) /* Discard temporary rte's */
rte_free(new);
if (old && old != old0)
rte_free(old);
+
+ return 1;
}
/**
@@ -417,11 +465,13 @@ static void
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;
+ struct proto_limit *l;
rte *old_best = net->routes;
rte *old = NULL;
rte **k, *r, *s;
stats = a ? a->stats : &p->stats;
+ l = a ? a->in_limit : p->cf->in_limit;
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
@@ -451,7 +501,7 @@ rte_recalculate(rtable *table, struct announce_hook *a, net *net, struct proto *
{
/* No changes, ignore the new route */
stats->imp_updates_ignored++;
- rte_trace_in(D_ROUTES, p, new, "ignored");
+ rte_trace_in(D_ROUTES, p, table, new, "ignored");
rte_free_quick(new);
#ifdef CONFIG_RIP
/* lastmod is used internally by RIP as the last time
@@ -473,6 +523,22 @@ rte_recalculate(rtable *table, struct announce_hook *a, net *net, struct proto *
return;
}
+ /* Check limit for imported routes */
+ if (new && !old)
+ {
+ if (p->flags & PFLAG_ILIMIT_BLOCK)
+ {
+ rte_trace_in(D_FILTERS, p, table, new, "ignored [inbound limit in action]");
+ return;
+ }
+
+ if (l && (stats->imp_routes + 1 > l->limit) && (proto_notify_limit(p, a, l, table) == 1))
+ {
+ rte_trace_in(D_FILTERS, p, table, new, "ignored [inbound limit hit]");
+ return;
+ }
+ }
+
if (new)
stats->imp_updates_accepted++;
else
@@ -490,7 +556,7 @@ rte_recalculate(rtable *table, struct announce_hook *a, net *net, struct proto *
/* The first case - the new route is cleary optimal, we link it
at the first position and announce it */
- rte_trace_in(D_ROUTES, p, new, "added [best]");
+ rte_trace_in(D_ROUTES, p, table, new, "added [best]");
rte_announce(table, RA_OPTIMAL, net, new, old_best, tmpa);
new->next = net->routes;
net->routes = new;
@@ -506,7 +572,7 @@ rte_recalculate(rtable *table, struct announce_hook *a, net *net, struct proto *
/* Add the new route to the list */
if (new)
{
- rte_trace_in(D_ROUTES, p, new, "added");
+ rte_trace_in(D_ROUTES, p, table, new, "added");
new->next = net->routes;
net->routes = new;
}
@@ -550,18 +616,18 @@ rte_recalculate(rtable *table, struct announce_hook *a, net *net, struct proto *
ASSERT(net->routes != NULL);
new->next = net->routes->next;
net->routes->next = new;
- rte_trace_in(D_ROUTES, p, new, "added");
+ rte_trace_in(D_ROUTES, p, table, new, "added");
}
/* Log the route removal */
if (!new && old && (p->debug & D_ROUTES))
{
if (old != old_best)
- rte_trace_in(D_ROUTES, p, old, "removed");
+ rte_trace_in(D_ROUTES, p, table, old, "removed");
else if (net->routes)
- rte_trace_in(D_ROUTES, p, old, "removed [replaced]");
+ rte_trace_in(D_ROUTES, p, table, old, "removed [replaced]");
else
- rte_trace_in(D_ROUTES, p, old, "removed [sole]");
+ rte_trace_in(D_ROUTES, p, table, old, "removed [sole]");
}
if (old)
@@ -661,14 +727,14 @@ do_rte_update(rtable *table, struct announce_hook *a, net *net, struct proto *p,
stats->imp_updates_received++;
if (!rte_validate(new))
{
- rte_trace_in(D_FILTERS, p, new, "invalid");
+ rte_trace_in(D_FILTERS, p, table, new, "invalid");
stats->imp_updates_invalid++;
goto drop;
}
if (filter == FILTER_REJECT)
{
stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, p, new, "filtered out");
+ rte_trace_in(D_FILTERS, p, table, new, "filtered out");
goto drop;
}
if (src->make_tmp_attrs)
@@ -680,7 +746,7 @@ do_rte_update(rtable *table, struct announce_hook *a, net *net, struct proto *p,
if (fr > F_ACCEPT)
{
stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, p, new, "filtered out");
+ rte_trace_in(D_FILTERS, p, table, new, "filtered out");
goto drop;
}
if (tmpa != old_tmpa && src->store_tmp_attrs)
@@ -1012,7 +1078,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
*k = new;
rte_announce_i(tab, RA_ANY, n, new, e);
- rte_trace_in(D_ROUTES, new->sender, new, "updated");
+ rte_trace_in(D_ROUTES, new->sender, tab, new, "updated");
if (e != old_best)
rte_free_quick(e);
@@ -1040,7 +1106,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
if (new != old_best)
{
rte_announce_i(tab, RA_OPTIMAL, n, new, old_best);
- rte_trace_in(D_ROUTES, new->sender, new, "updated [best]");
+ rte_trace_in(D_ROUTES, new->sender, tab, new, "updated [best]");
}
if (free_old_best)
@@ -1194,16 +1260,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;
}
/**
@@ -1250,8 +1319,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..88e9667 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 announce_hook *a, 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);
- 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;
+ 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);
+ /*
+ * 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 (PROTO_IS_RECONFIGURING(P))
{
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:
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 2f1b519..6b13a53 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -130,7 +130,9 @@ pipe_reload_routes(struct proto *P)
* together, both directions are reloaded during refeed and 'reload
* out' command works like 'reload' command. For symmetry, we also
* request refeed when 'reload in' command is used.
+ * We have to remove import limit here, too
*/
+ proto_clear_limits(P, PFLAG_ILIMIT|PFLAG_ILIMIT_BLOCK|PFLAG_ELIMIT|PFLAG_ELIMIT_BLOCK);
proto_request_feeding(P);
return 1;
}
@@ -246,6 +248,15 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
a->in_filter = FILTER_ACCEPT;
pa->in_filter = FILTER_ACCEPT;
+ /*
+ * Update limits
+ * Note that import/export limit can have different functionality
+ * (for example, RESTART action can't be used in export filter)
+ * so this trick may impose some usage limitation.
+ */
+ pa->out_limit = a->in_limit;
+ a->in_limit = NULL;
+
return 1;
}
diff --git a/proto/pipe/pipe.h b/proto/pipe/pipe.h
index 6eb5b03..6f2bad5 100644
--- a/proto/pipe/pipe.h
+++ b/proto/pipe/pipe.h
@@ -32,6 +32,9 @@ extern struct protocol proto_pipe;
static inline int proto_is_pipe(struct proto *p)
{ return p->proto == &proto_pipe; }
+static inline int config_is_pipe(struct proto_config *c)
+{ return c->protocol == &proto_pipe; }
+
void pipe_show_stats(struct proto *P);
#endif
--
1.7.3.2
--------------070507000102070502090107--
1
0
---
filter/f-util.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/filter/f-util.c b/filter/f-util.c
index 9f2eb6b..eef09da 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -61,6 +61,6 @@ filter_name(struct filter *filter)
return "ACCEPT";
else if (filter == FILTER_REJECT)
return "REJECT";
- else
- return filter->name;
+
+ return (filter->name ? filter->name : "UNNAMED");
}
--
1.7.3.2
--------------090506030508010702020103
Content-Type: text/plain;
name="yandex-Implement-per-table-protocol-hooks-in-core.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename*0="yandex-Implement-per-table-protocol-hooks-in-core.patch"
1
0
---
filter/f-util.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/filter/f-util.c b/filter/f-util.c
index 9f2eb6b..eef09da 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -61,6 +61,6 @@ filter_name(struct filter *filter)
return "ACCEPT";
else if (filter == FILTER_REJECT)
return "REJECT";
- else
- return filter->name;
+
+ return (filter->name ? filter->name : "UNNAMED");
}
--
1.7.3.2
--------------070507000102070502090107
Content-Type: text/plain;
name="0003-Implement-general-protocol-limits-v3.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="0003-Implement-general-protocol-limits-v3.patch"
1
0
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
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
--------------070507000102070502090107
Content-Type: text/plain;
name="0002-Fix-BGP-filters-naming.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="0002-Fix-BGP-filters-naming.patch"
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