summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/a-path.c4
-rw-r--r--nest/cli.c4
-rw-r--r--nest/cli.h9
-rw-r--r--nest/config.Y46
-rw-r--r--nest/iface.c9
-rw-r--r--nest/iface.h4
-rw-r--r--nest/locks.c3
-rw-r--r--nest/neighbor.c23
-rw-r--r--nest/proto-hooks.c3
-rw-r--r--nest/proto.c354
-rw-r--r--nest/protocol.h42
-rw-r--r--nest/rt-attr.c2
-rw-r--r--nest/rt-dev.c7
-rw-r--r--nest/rt-table.c135
14 files changed, 385 insertions, 260 deletions
diff --git a/nest/a-path.c b/nest/a-path.c
index 396d463..058b434 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -385,7 +385,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
struct pm_pos pos[2048 + 1];
int plen = parse_path(path, pos);
int l, h, i, nh, nl;
- u32 val;
+ u32 val = 0;
/* l and h are bound of interval of positions where
are marked states */
@@ -417,7 +417,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
goto step;
case PM_QUESTION:
step:
- nh = -1;
+ nh = nl = -1;
for (i = h; i >= l; i--)
if (pos[i].mark)
{
diff --git a/nest/cli.c b/nest/cli.c
index ace97be..4d2b8fd 100644
--- a/nest/cli.c
+++ b/nest/cli.c
@@ -357,8 +357,8 @@ cli_echo(unsigned int class, byte *msg)
free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1);
else
free = c->ring_read - c->ring_write - 1;
- if (len > free ||
- free < c->log_threshold && class < (unsigned) L_INFO[0])
+ if ((len > free) ||
+ (free < c->log_threshold && class < (unsigned) L_INFO[0]))
{
c->ring_overflow++;
continue;
diff --git a/nest/cli.h b/nest/cli.h
index f816ef1..57414a2 100644
--- a/nest/cli.h
+++ b/nest/cli.h
@@ -33,6 +33,7 @@ typedef struct cli {
void (*cleanup)(struct cli *c);
void *rover; /* Private to continuation routine */
int last_reply;
+ int restricted; /* CLI is restricted to read-only commands */
struct linpool *parser_pool; /* Pool used during parsing */
byte *ring_buf; /* Ring buffer for asynchronous messages */
byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */
@@ -60,6 +61,14 @@ void cli_kick(cli *);
void cli_written(cli *);
void cli_echo(unsigned int class, byte *msg);
+static inline int cli_access_restricted(void)
+{
+ if (this_cli && this_cli->restricted)
+ return (cli_printf(this_cli, 8007, "Access denied"), 1);
+ else
+ return 0;
+}
+
/* Functions provided by sysdep layer */
void cli_write_trigger(cli *);
diff --git a/nest/config.Y b/nest/config.Y
index f9e88d5..792012e 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -45,7 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
-CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES)
+CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -59,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT)
%type <s> optsym
%type <ra> r_args
%type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
-%type <t> proto_patt
+%type <ps> proto_patt proto_patt2
CF_GRAMMAR
@@ -324,11 +324,11 @@ CF_CLI_HELP(SHOW, ..., [[Show status information]])
CF_CLI(SHOW STATUS,,, [[Show router status]])
{ cmd_show_status(); } ;
-CF_CLI(SHOW PROTOCOLS, optsym, [<name>], [[Show routing protocols]])
-{ proto_show($3, 0); } ;
+CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
+{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
-CF_CLI(SHOW PROTOCOLS ALL, optsym, [<name>], [[Show routing protocol details]])
-{ proto_show($4, 1); } ;
+CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
+{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
optsym:
SYM
@@ -459,34 +459,42 @@ echo_size:
;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]])
-{ proto_xxable($2, XX_DISABLE); } ;
+{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]])
-{ proto_xxable($2, XX_ENABLE); } ;
+{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
-{ proto_xxable($2, XX_RESTART); } ;
+{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
-{ proto_xxable($2, XX_RELOAD); } ;
+{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
-{ proto_xxable($3, XX_RELOAD_IN); } ;
+{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
-{ proto_xxable($3, XX_RELOAD_OUT); } ;
+{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]])
-{ proto_debug($2, 0, $3); }
- ;
+{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
-{ proto_debug($2, 1, $3); }
- ;
+{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
+
+CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
+{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
proto_patt:
- SYM { $$ = $1->name; }
- | ALL { $$ = "*"; }
- | TEXT
+ SYM { $$.ptr = $1; $$.patt = 0; }
+ | ALL { $$.ptr = NULL; $$.patt = 1; }
+ | TEXT { $$.ptr = $1; $$.patt = 1; }
;
+proto_patt2:
+ SYM { $$.ptr = $1; $$.patt = 0; }
+ | { $$.ptr = NULL; $$.patt = 1; }
+ | TEXT { $$.ptr = $1; $$.patt = 1; }
+ ;
+
+
CF_CODE
CF_END
diff --git a/nest/iface.c b/nest/iface.c
index 5e88b21..82dead3 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -336,6 +336,15 @@ if_end_update(void)
}
}
+void
+if_flush_ifaces(struct proto *p)
+{
+ if (p->debug & D_EVENTS)
+ log(L_TRACE "%s: Flushing interfaces", p->name);
+ if_start_update();
+ if_end_update();
+}
+
/**
* if_feed_baby - advertise interfaces to a new protocol
* @p: protocol to feed
diff --git a/nest/iface.h b/nest/iface.h
index b7c3c19..873734d 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -75,8 +75,9 @@ struct iface *if_update(struct iface *);
struct ifa *ifa_update(struct ifa *);
void ifa_delete(struct ifa *);
void if_start_update(void);
-void if_end_update(void);
void if_end_partial_update(struct iface *);
+void if_end_update(void);
+void if_flush_ifaces(struct proto *p);
void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned);
struct iface *if_find_by_name(char *);
@@ -106,6 +107,7 @@ typedef struct neighbor {
} neighbor;
#define NEF_STICKY 1
+#define NEF_ONLINK 2
neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags);
neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);
diff --git a/nest/locks.c b/nest/locks.c
index 1cdbbc9..7044d6a 100644
--- a/nest/locks.c
+++ b/nest/locks.c
@@ -97,7 +97,8 @@ static struct resclass olock_class = {
"ObjLock",
sizeof(struct object_lock),
olock_free,
- olock_dump
+ olock_dump,
+ NULL
};
/**
diff --git a/nest/neighbor.c b/nest/neighbor.c
index a44667f..25b98db 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -112,12 +112,12 @@ neighbor *
neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
{
neighbor *n;
- int class, scope = SCOPE_HOST;
+ int class, scope = -1; ;
unsigned int h = neigh_hash(p, a);
struct iface *i;
WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */
- if (n->proto == p && ipa_equal(*a, n->addr))
+ if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface)))
return n;
class = ipa_classify(*a);
@@ -129,7 +129,12 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
return NULL; /* Bad scope or a somecast */
if (ifa)
- scope = if_connected(a, ifa);
+ {
+ scope = if_connected(a, ifa);
+
+ if ((scope < 0) && (flags & NEF_ONLINK))
+ scope = class & IADDR_SCOPE_MASK;
+ }
else
WALK_LIST(i, iface_list)
if ((scope = if_connected(a, i)) >= 0)
@@ -138,22 +143,28 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
break;
}
- if (!ifa && !(flags & NEF_STICKY))
+ /* scope < 0 means i don't know neighbor */
+ /* scope >= 0 implies ifa != NULL */
+
+ if ((scope < 0) && !(flags & NEF_STICKY))
return NULL;
n = sl_alloc(neigh_slab);
n->addr = *a;
- n->iface = ifa;
- if (ifa)
+ if (scope >= 0)
{
add_tail(&neigh_hash_table[h], &n->n);
add_tail(&ifa->neighbors, &n->if_n);
}
else
{
+ /* sticky flag does not work for link-local neighbors;
+ fortunately, we don't use this combination */
add_tail(&sticky_neigh_list, &n->n);
+ ifa = NULL;
scope = 0;
}
+ n->iface = ifa;
n->proto = p;
n->data = NULL;
n->aux = 0;
diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c
index c30b107..3d19e3f 100644
--- a/nest/proto-hooks.c
+++ b/nest/proto-hooks.c
@@ -178,13 +178,14 @@ void ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
/**
* rt_notify - notify instance about routing table change
* @p: protocol instance
+ * @table: a routing table
* @net: a network entry
* @new: new route for the network
* @old: old route for the network
* @attrs: extended attributes associated with the @new entry
*
* The rt_notify() hook is called to inform the protocol instance about
- * changes in the routing table it's connected to, that is a route @old
+ * changes in the connected routing table @table, that is a route @old
* belonging to network @net being replaced by a new route @new with
* extended attributes @attrs. Either @new or @old or both can be %NULL
* if the corresponding route doesn't exist.
diff --git a/nest/proto.c b/nest/proto.c
index 870eddd..78fca99 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -25,12 +25,6 @@ static pool *proto_pool;
static list protocol_list;
static list proto_list;
-#define WALK_PROTO_LIST(p) do { \
- node *nn; \
- WALK_LIST(nn, proto_list) { \
- struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
-#define WALK_PROTO_LIST_END } } while(0)
-
#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
list active_proto_list;
@@ -57,7 +51,7 @@ proto_enqueue(list *l, struct proto *p)
static void
proto_relink(struct proto *p)
{
- list *l;
+ list *l = NULL;
if (p->debug & D_STATES)
{
@@ -119,7 +113,6 @@ proto_new(struct proto_config *c, unsigned size)
p->table = c->table->table;
p->in_filter = c->in_filter;
p->out_filter = c->out_filter;
- p->min_scope = SCOPE_SITE;
p->hash_key = random_u32();
c->proto = p;
return p;
@@ -583,6 +576,12 @@ proto_fell_down(struct proto *p)
bzero(&p->stats, sizeof(struct proto_stats));
rt_unlock_table(p->table);
+
+#ifdef CONFIG_PIPE
+ if (proto_is_pipe(p))
+ rt_unlock_table(pipe_get_peer_table(p));
+#endif
+
proto_rethink_goal(p);
}
@@ -741,6 +740,8 @@ proto_notify_state(struct proto *p, unsigned ps)
}
}
+extern struct protocol proto_unix_iface;
+
static void
proto_flush_all(void *unused UNUSED)
{
@@ -749,6 +750,11 @@ proto_flush_all(void *unused UNUSED)
rt_prune_all();
while ((p = HEAD(flush_proto_list))->n.next)
{
+ /* This will flush interfaces in the same manner
+ like rt_prune_all() flushes routes */
+ if (p->proto == &proto_unix_iface)
+ if_flush_ifaces(p);
+
DBG("Flushing protocol %s\n", p->name);
p->core_state = FS_HUNGRY;
proto_relink(p);
@@ -781,10 +787,75 @@ proto_state_name(struct proto *p)
}
static void
-proto_do_show(struct proto *p, int verbose)
+proto_do_show_stats(struct proto *p)
+{
+ 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");
+ cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
+ s->imp_updates_received, s->imp_updates_invalid,
+ s->imp_updates_filtered, s->imp_updates_ignored,
+ s->imp_updates_accepted);
+ cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
+ s->imp_withdraws_received, s->imp_withdraws_invalid,
+ s->imp_withdraws_ignored, s->imp_withdraws_accepted);
+ cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u",
+ s->exp_updates_received, s->exp_updates_rejected,
+ s->exp_updates_filtered, s->exp_updates_accepted);
+ cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u",
+ s->exp_withdraws_received, s->exp_withdraws_accepted);
+}
+
+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);
+}
+
+void
+proto_cmd_show(struct proto *p, unsigned int verbose, int cnt)
{
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
+ /* First protocol - show header */
+ if (!cnt)
+ cli_msg(-2002, "name proto table state since info");
+
buf[0] = 0;
if (p->proto->get_status)
p->proto->get_status(p, buf);
@@ -806,21 +877,12 @@ proto_do_show(struct proto *p, int verbose)
if (p->proto_state != PS_DOWN)
{
- cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred",
- p->stats.imp_routes, p->stats.exp_routes, p->stats.pref_routes);
- cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted");
- cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u",
- p->stats.imp_updates_received, p->stats.imp_updates_invalid,
- p->stats.imp_updates_filtered, p->stats.imp_updates_ignored,
- p->stats.imp_updates_accepted);
- cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u",
- p->stats.imp_withdraws_received, p->stats.imp_withdraws_invalid,
- p->stats.imp_withdraws_ignored, p->stats.imp_withdraws_accepted);
- cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u",
- p->stats.exp_updates_received, p->stats.exp_updates_rejected,
- p->stats.exp_updates_filtered, p->stats.exp_updates_accepted);
- cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u",
- p->stats.exp_withdraws_received, p->stats.exp_withdraws_accepted);
+#ifdef CONFIG_PIPE
+ if (proto_is_pipe(p))
+ proto_do_show_pipe_stats(p);
+ else
+#endif
+ proto_do_show_stats(p);
}
cli_msg(-1006, "");
@@ -828,25 +890,140 @@ proto_do_show(struct proto *p, int verbose)
}
void
-proto_show(struct symbol *s, int verbose)
+proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
{
- if (s && s->class != SYM_PROTO)
+ if (p->disabled)
{
- cli_msg(9002, "%s is not a protocol", s->name);
+ cli_msg(-8, "%s: already disabled", p->name);
return;
}
- cli_msg(-2002, "name proto table state since info");
- if (s)
- proto_do_show(((struct proto_config *)s->def)->proto, verbose);
- else
+
+ log(L_INFO "Disabling protocol %s", p->name);
+ p->disabled = 1;
+ proto_rethink_goal(p);
+ cli_msg(-9, "%s: disabled", p->name);
+}
+
+void
+proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
+{
+ if (!p->disabled)
+ {
+ cli_msg(-10, "%s: already enabled", p->name);
+ return;
+ }
+
+ log(L_INFO "Enabling protocol %s", p->name);
+ p->disabled = 0;
+ proto_rethink_goal(p);
+ cli_msg(-11, "%s: enabled", p->name);
+}
+
+void
+proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
+{
+ if (p->disabled)
+ {
+ cli_msg(-8, "%s: already disabled", p->name);
+ return;
+ }
+
+ log(L_INFO "Restarting protocol %s", p->name);
+ p->disabled = 1;
+ proto_rethink_goal(p);
+ p->disabled = 0;
+ proto_rethink_goal(p);
+ cli_msg(-12, "%s: restarted", p->name);
+}
+
+void
+proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
+{
+ if (p->disabled)
{
- WALK_PROTO_LIST(p)
- proto_do_show(p, verbose);
- WALK_PROTO_LIST_END;
+ cli_msg(-8, "%s: already disabled", p->name);
+ return;
}
+
+ /* If the protocol in not UP, it has no routes */
+ if (p->proto_state != PS_UP)
+ return;
+
+ log(L_INFO "Reloading protocol %s", p->name);
+
+ /* re-importing routes */
+ if (dir != CMD_RELOAD_OUT)
+ if (! (p->reload_routes && p->reload_routes(p)))
+ {
+ cli_msg(-8006, "%s: reload failed", p->name);
+ return;
+ }
+
+ /* re-exporting routes */
+ if (dir != CMD_RELOAD_IN)
+ proto_request_feeding(p);
+
+ cli_msg(-15, "%s: reloading", p->name);
+}
+
+void
+proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED)
+{
+ p->debug = mask;
+}
+
+void
+proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED)
+{
+ p->mrtdump = mask;
+}
+
+static void
+proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
+{
+ if (s->class != SYM_PROTO)
+ {
+ cli_msg(9002, "%s is not a protocol", s->name);
+ return;
+ }
+
+ cmd(((struct proto_config *)s->def)->proto, arg, 0);
cli_msg(0, "");
}
+static void
+proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
+{
+ int cnt = 0;
+
+ node *nn;
+ WALK_LIST(nn, proto_list)
+ {
+ struct proto *p = SKIP_BACK(struct proto, glob_node, nn);
+
+ if (!patt || patmatch(patt, p->name))
+ cmd(p, arg, cnt++);
+ }
+
+ if (!cnt)
+ cli_msg(8003, "No protocols match");
+ else
+ cli_msg(0, "");
+}
+
+void
+proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int),
+ int restricted, unsigned int arg)
+{
+ if (restricted && cli_access_restricted())
+ return;
+
+ if (ps.patt)
+ proto_apply_cmd_patt(ps.ptr, cmd, arg);
+ else
+ proto_apply_cmd_symbol(ps.ptr, cmd, arg);
+}
+
struct proto *
proto_get_named(struct symbol *sym, struct protocol *pr)
{
@@ -875,112 +1052,3 @@ proto_get_named(struct symbol *sym, struct protocol *pr)
}
return p;
}
-
-void
-proto_xxable(char *pattern, int xx)
-{
- int cnt = 0;
- WALK_PROTO_LIST(p)
- if (patmatch(pattern, p->name))
- {
- cnt++;
- switch (xx)
- {
- case XX_DISABLE:
- if (p->disabled)
- cli_msg(-8, "%s: already disabled", p->name);
- else
- {
- log(L_INFO "Disabling protocol %s", p->name);
- p->disabled = 1;
- proto_rethink_goal(p);
- cli_msg(-9, "%s: disabled", p->name);
- }
- break;
-
- case XX_ENABLE:
- if (!p->disabled)
- cli_msg(-10, "%s: already enabled", p->name);
- else
- {
- log(L_INFO "Enabling protocol %s", p->name);
- p->disabled = 0;
- proto_rethink_goal(p);
- cli_msg(-11, "%s: enabled", p->name);
- }
- break;
-
- case XX_RESTART:
- if (p->disabled)
- cli_msg(-8, "%s: already disabled", p->name);
- else
- {
- log(L_INFO "Restarting protocol %s", p->name);
- p->disabled = 1;
- proto_rethink_goal(p);
- p->disabled = 0;
- proto_rethink_goal(p);
- cli_msg(-12, "%s: restarted", p->name);
- }
- break;
-
- case XX_RELOAD:
- case XX_RELOAD_IN:
- case XX_RELOAD_OUT:
- if (p->disabled)
- {
- cli_msg(-8, "%s: already disabled", p->name);
- break;
- }
-
- /* If the protocol in not UP, it has no routes */
- if (p->proto_state != PS_UP)
- break;
-
- log(L_INFO "Reloading protocol %s", p->name);
-
- /* re-importing routes */
- if (xx != XX_RELOAD_OUT)
- if (! (p->reload_routes && p->reload_routes(p)))
- {
- cli_msg(-8006, "%s: reload failed", p->name);
- break;
- }
-
- /* re-exporting routes */
- if (xx != XX_RELOAD_IN)
- proto_request_feeding(p);
-
- cli_msg(-15, "%s: reloading", p->name);
- break;
-
- default:
- ASSERT(0);
- }
- }
- WALK_PROTO_LIST_END;
- if (!cnt)
- cli_msg(8003, "No protocols match");
- else
- cli_msg(0, "");
-}
-
-void
-proto_debug(char *pattern, int which, unsigned int mask)
-{
- int cnt = 0;
- WALK_PROTO_LIST(p)
- if (patmatch(pattern, p->name))
- {
- cnt++;
- if (which == 0)
- p->debug = mask;
- else
- p->mrtdump = mask;
- }
- WALK_PROTO_LIST_END;
- if (!cnt)
- cli_msg(8003, "No protocols match");
- else
- cli_msg(0, "");
-}
diff --git a/nest/protocol.h b/nest/protocol.h
index 5a69b33..d94873e 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -16,6 +16,7 @@
struct iface;
struct ifa;
+struct rtable;
struct rte;
struct neighbor;
struct rta;
@@ -129,7 +130,6 @@ struct proto {
u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */
- int min_scope; /* Minimal route scope accepted */
unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
unsigned disabled; /* Manually disabled */
unsigned proto_state; /* Protocol state machine (see below) */
@@ -162,7 +162,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 network *net, struct rte *new, struct rte *old, struct ea_list *attrs);
+ void (*rt_notify)(struct proto *, struct rtable *table, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs);
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);
@@ -194,21 +194,30 @@ struct proto {
/* Hic sunt protocol-specific data */
};
+struct proto_spec {
+ void *ptr;
+ int patt;
+};
+
+
void *proto_new(struct proto_config *, unsigned size);
void *proto_config_new(struct protocol *, unsigned size);
-
void proto_request_feeding(struct proto *p);
-void proto_show(struct symbol *, int);
+
+void proto_cmd_show(struct proto *, unsigned int, int);
+void proto_cmd_disable(struct proto *, unsigned int, int);
+void proto_cmd_enable(struct proto *, unsigned int, int);
+void proto_cmd_restart(struct proto *, unsigned int, int);
+void proto_cmd_reload(struct proto *, unsigned int, int);
+void proto_cmd_debug(struct proto *, unsigned int, int);
+void proto_cmd_mrtdump(struct proto *, unsigned int, int);
+
+void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg);
struct proto *proto_get_named(struct symbol *, struct protocol *);
-void proto_xxable(char *, int);
-void proto_debug(char *, int, unsigned int);
-#define XX_DISABLE 0
-#define XX_ENABLE 1
-#define XX_RESTART 2
-#define XX_RELOAD 3
-#define XX_RELOAD_IN 4
-#define XX_RELOAD_OUT 5
+#define CMD_RELOAD 0
+#define CMD_RELOAD_IN 1
+#define CMD_RELOAD_OUT 2
static inline u32
proto_get_router_id(struct proto_config *pc)
@@ -334,4 +343,13 @@ struct announce_hook {
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
+
+
#endif
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 9d78ce0..94b105d 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -400,7 +400,7 @@ ea_format(eattr *e, byte *buf)
switch (e->type & EAF_TYPE_MASK)
{
case EAF_TYPE_INT:
- bsprintf(buf, "%d", e->u.data);
+ bsprintf(buf, "%u", e->u.data);
break;
case EAF_TYPE_OPAQUE:
for(i=0; i<ad->length; i++)
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index b86015d..bb8eb8e 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -33,6 +33,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
!iface_patt_find(&P->iface_list, ad->iface))
/* Empty list is automagically treated as "*" */
return;
+
+ if (ad->scope <= SCOPE_LINK)
+ return;
+
if (c & IF_CHANGE_DOWN)
{
net *n;
@@ -56,7 +60,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
bzero(&A, sizeof(A));
A.proto = p;
A.source = RTS_DEVICE;
- A.scope = ad->scope;
+ A.scope = SCOPE_UNIVERSE;
A.cast = RTC_UNICAST;
A.dest = RTD_DEVICE;
A.iface = ad->iface;
@@ -76,7 +80,6 @@ dev_init(struct proto_config *c)
struct proto *p = proto_new(c, sizeof(struct proto));
p->ifa_notify = dev_ifa_notify;
- p->min_scope = SCOPE_HOST;
return p;
}
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 413675c..1860b1a 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -158,37 +158,42 @@ rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg)
}
static inline void
-do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class, int refeed)
+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;
rte *new0 = new;
rte *old0 = old;
int ok;
int fast_exit_hack = 0;
+#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)
{
- p->stats.exp_updates_received++;
+ stats->exp_updates_received++;
char *drop_reason = NULL;
- if ((class & IADDR_SCOPE_MASK) < p->min_scope)
- {
- p->stats.exp_updates_rejected++;
- drop_reason = "out of scope";
- fast_exit_hack = 1;
- }
- else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0)
+ if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0)
{
- p->stats.exp_updates_rejected++;
+ stats->exp_updates_rejected++;
drop_reason = "rejected by protocol";
}
else if (ok)
rte_trace_out(D_FILTERS, p, new, "forced accept by protocol");
- else if (p->out_filter == FILTER_REJECT ||
- p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)
+ else if ((filter == FILTER_REJECT) ||
+ (filter && f_run(filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
{
- p->stats.exp_updates_filtered++;
+ stats->exp_updates_filtered++;
drop_reason = "filtered out";
}
if (drop_reason)
@@ -200,7 +205,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
}
}
else
- p->stats.exp_withdraws_received++;
+ stats->exp_withdraws_received++;
/* Hack: This is here to prevent 'spurious withdraws'
for loopback addresses during reload. */
@@ -229,13 +234,13 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
if (old && !refeed)
{
- if (p->out_filter == FILTER_REJECT)
+ if (filter == FILTER_REJECT)
old = NULL;
else
{
ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL;
ok = p->import_control ? p->import_control(p, &old, &tmpb, rte_update_pool) : 0;
- if (ok < 0 || (!ok && p->out_filter && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
+ if (ok < 0 || (!ok && filter && f_run(filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
{
if (old != old0)
rte_free(old);
@@ -249,16 +254,16 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
return;
if (new)
- p->stats.exp_updates_accepted++;
+ stats->exp_updates_accepted++;
else
- p->stats.exp_withdraws_accepted++;
+ stats->exp_withdraws_accepted++;
/* Hack: We do not decrease exp_routes during refeed, we instead
reset exp_routes at the start of refeed. */
if (new)
- p->stats.exp_routes++;
+ stats->exp_routes++;
if (old && !refeed)
- p->stats.exp_routes--;
+ stats->exp_routes--;
if (p->debug & D_ROUTES)
{
@@ -270,18 +275,18 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
rte_trace_out(D_ROUTES, p, old, "removed");
}
if (!new)
- p->rt_notify(p, net, NULL, old, NULL);
+ p->rt_notify(p, a->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, net, new, old, tmpa);
+ p->rt_notify(p, a->table, net, new, old, tmpa);
t->next = NULL;
}
else
- p->rt_notify(p, net, new, old, new->attrs->eattrs);
+ p->rt_notify(p, a->table, net, new, old, new->attrs->eattrs);
if (new && new != new0) /* Discard temporary rte's */
rte_free(new);
if (old && old != old0)
@@ -318,10 +323,9 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old,
* the protocol gets called.
*/
static void
-rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa)
+rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, ea_list *tmpa)
{
struct announce_hook *a;
- int class = ipa_classify(net->n.prefix);
if (type == RA_OPTIMAL)
{
@@ -335,7 +339,7 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa)
{
ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
if (a->proto->accept_ra_types == type)
- do_rte_announce(a, type, net, new, old, tmpa, class, 0);
+ do_rte_announce(a, type, net, new, old, tmpa, 0);
}
}
@@ -351,33 +355,15 @@ rte_validate(rte *e)
n->n.prefix, n->n.pxlen, e->sender->name);
return 0;
}
- if (n->n.pxlen)
+
+ c = ipa_classify_net(n->n.prefix);
+ if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{
- c = ipa_classify(n->n.prefix);
- if (c < 0 || !(c & IADDR_HOST))
- {
- if (!ipa_nonzero(n->n.prefix))
- {
- /* Various default routes */
-#ifdef IPV6
- if (n->n.pxlen == 96)
-#else
- if (n->n.pxlen <= 1)
-#endif
- return 1;
- }
- log(L_WARN "Ignoring bogus route %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->sender->name);
- return 0;
- }
- if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope)
- {
- log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s",
- ip_scope_text(c & IADDR_SCOPE_MASK),
- n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name);
- return 0;
- }
+ log(L_WARN "Ignoring bogus route %I/%d received via %s",
+ n->n.prefix, n->n.pxlen, e->sender->name);
+ return 0;
}
+
return 1;
}
@@ -416,10 +402,16 @@ 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)
{
+ struct proto_stats *stats = &p->stats;
rte *old_best = net->routes;
rte *old = NULL;
rte **k, *r, *s;
+#ifdef CONFIG_PIPE
+ if (proto_is_pipe(p) && (p->table == table))
+ stats = pipe_get_peer_stats(p);
+#endif
+
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
@@ -448,7 +440,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
if (new && rte_same(old, new))
{
/* No changes, ignore the new route */
- p->stats.imp_updates_ignored++;
+ stats->imp_updates_ignored++;
rte_trace_in(D_ROUTES, p, new, "ignored");
rte_free_quick(new);
old->lastmod = now;
@@ -462,19 +454,19 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
if (!old && !new)
{
- p->stats.imp_withdraws_ignored++;
+ stats->imp_withdraws_ignored++;
return;
}
if (new)
- p->stats.imp_updates_accepted++;
+ stats->imp_updates_accepted++;
else
- p->stats.imp_withdraws_accepted++;
+ stats->imp_withdraws_accepted++;
if (new)
- p->stats.imp_routes++;
+ stats->imp_routes++;
if (old)
- p->stats.imp_routes--;
+ stats->imp_routes--;
rte_announce(table, RA_ANY, net, new, old, tmpa);
@@ -632,6 +624,12 @@ void
rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
{
ea_list *tmpa = NULL;
+ struct proto_stats *stats = &p->stats;
+
+#ifdef CONFIG_PIPE
+ if (proto_is_pipe(p) && (p->table == table))
+ stats = pipe_get_peer_stats(p);
+#endif
rte_update_lock();
if (new)
@@ -642,20 +640,20 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
/* Do not filter routes going through the pipe,
they are filtered in the export filter only. */
#ifdef CONFIG_PIPE
- if (p->proto == &proto_pipe)
+ if (proto_is_pipe(p))
filter = FILTER_ACCEPT;
#endif
- p->stats.imp_updates_received++;
+ stats->imp_updates_received++;
if (!rte_validate(new))
{
rte_trace_in(D_FILTERS, p, new, "invalid");
- p->stats.imp_updates_invalid++;
+ stats->imp_updates_invalid++;
goto drop;
}
if (filter == FILTER_REJECT)
{
- p->stats.imp_updates_filtered++;
+ stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
@@ -667,7 +665,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0);
if (fr > F_ACCEPT)
{
- p->stats.imp_updates_filtered++;
+ stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
@@ -679,7 +677,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
new->flags |= REF_COW;
}
else
- p->stats.imp_withdraws_received++;
+ stats->imp_withdraws_received++;
rte_recalculate(table, net, p, src, new, tmpa);
rte_update_unlock();
@@ -995,7 +993,7 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
rte_update_lock();
tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
- do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, ipa_classify(n->n.prefix), p->refeeding);
+ do_rte_announce(h, type, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding);
rte_update_unlock();
}
@@ -1167,11 +1165,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
if (p2 && p2 != p0) ok = 0;
if (ok && d->export_mode)
{
- int class = ipa_classify(n->n.prefix);
int ic;
- if ((class & IADDR_SCOPE_MASK) < p1->min_scope)
- ok = 0;
- else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0)
+ if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0)
ok = 0;
else if (!ic && d->export_mode > 1)
{
@@ -1180,8 +1175,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 ((p1->out_filter == FILTER_REJECT) ||
+ (p1->out_filter && f_run(p1->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
ok = 0;
}
}