summaryrefslogtreecommitdiffstats
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/a-path.c17
-rw-r--r--nest/attrs.h3
-rw-r--r--nest/config.Y6
-rw-r--r--nest/proto.c5
-rw-r--r--nest/protocol.h8
-rw-r--r--nest/rt-attr.c2
-rw-r--r--nest/rt-table.c104
7 files changed, 99 insertions, 46 deletions
diff --git a/nest/a-path.c b/nest/a-path.c
index 5aacf8f..c804619 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -13,6 +13,7 @@
#include "lib/resource.h"
#include "lib/unaligned.h"
#include "lib/string.h"
+#include "filter/filter.h"
/* Global AS4 support, shared by all BGP instances.
@@ -188,6 +189,12 @@ int
as_path_getlen(struct adata *path)
{
int bs = bgp_as4_support ? 4 : 2;
+ return as_path_getlen_int(path, bs);
+}
+
+int
+as_path_getlen_int(struct adata *path, int bs)
+{
int res = 0;
u8 *p = path->data;
u8 *q = p+path->length;
@@ -206,7 +213,7 @@ as_path_getlen(struct adata *path)
}
int
-as_path_get_first(struct adata *path, u32 *orig_as)
+as_path_get_last(struct adata *path, u32 *orig_as)
{
int bs = bgp_as4_support ? 4 : 2;
int found = 0;
@@ -222,8 +229,7 @@ as_path_get_first(struct adata *path, u32 *orig_as)
case AS_PATH_SET:
if (len = *p++)
{
- found = 1;
- res = get_as(p);
+ found = 0;
p += bs * len;
}
break;
@@ -239,12 +245,13 @@ as_path_get_first(struct adata *path, u32 *orig_as)
}
}
- *orig_as = res;
+ if (found)
+ *orig_as = res;
return found;
}
int
-as_path_get_last(struct adata *path, u32 *last_as)
+as_path_get_first(struct adata *path, u32 *last_as)
{
u8 *p = path->data;
diff --git a/nest/attrs.h b/nest/attrs.h
index b838ce9..16fb35a 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -9,6 +9,8 @@
#ifndef _BIRD_ATTRS_H_
#define _BIRD_ATTRS_H_
+#include <stdint.h>
+
/* a-path.c */
#define AS_PATH_SET 1 /* Types of path segments */
@@ -28,6 +30,7 @@ int as_path_convert_to_old(struct adata *path, byte *dst, int *new_used);
int as_path_convert_to_new(struct adata *path, byte *dst, int req_as);
void as_path_format(struct adata *path, byte *buf, unsigned int size);
int as_path_getlen(struct adata *path);
+int as_path_getlen_int(struct adata *path, int bs);
int as_path_get_first(struct adata *path, u32 *orig_as);
int as_path_get_last(struct adata *path, u32 *last_as);
int as_path_is_member(struct adata *path, u32 as);
diff --git a/nest/config.Y b/nest/config.Y
index dc31224..4721112 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -44,7 +44,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
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)
+CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -132,7 +132,7 @@ proto_name:
proto_item:
/* EMPTY */
| PREFERENCE expr {
- if ($2 < 0 || $2 > 255) cf_error("Invalid preference");
+ if ($2 < 0 || $2 > 0xFFFF) cf_error("Invalid preference");
this_proto->preference = $2;
}
| DISABLED bool { this_proto->disabled = $2; }
@@ -140,6 +140,7 @@ proto_item:
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
| TABLE rtable { this_proto->table = $2; }
+ | ROUTER ID idval { this_proto->router_id = $3; }
;
imexport:
@@ -293,6 +294,7 @@ password_item_params:
;
+
/* Core commands */
CF_CLI_HELP(SHOW, ..., [[Show status information]])
diff --git a/nest/proto.c b/nest/proto.c
index 2af077b..7bb1286 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -313,6 +313,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
&& nc->preference == oc->preference
&& nc->disabled == oc->disabled
&& nc->table->table == oc->table->table
+ && proto_get_router_id(nc) == proto_get_router_id(oc)
&& ((type == RECONFIG_SOFT) || filter_same(nc->in_filter, oc->in_filter))
&& ((type == RECONFIG_SOFT) || filter_same(nc->out_filter, oc->out_filter))
&& p->proto_state != PS_DOWN)
@@ -515,7 +516,9 @@ static void
proto_fell_down(struct proto *p)
{
DBG("Protocol %s down\n", p->name);
- ASSERT(p->stats.imp_routes == 0);
+
+ if (p->stats.imp_routes != 0)
+ log(L_ERR "Protocol %s is down but still has %d routes", p->name, p->stats.imp_routes);
bzero(&p->stats, sizeof(struct proto_stats));
rt_unlock_table(p->table);
diff --git a/nest/protocol.h b/nest/protocol.h
index 0f9d59d..484df84 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -12,6 +12,7 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/timer.h"
+#include "conf/conf.h"
struct iface;
struct ifa;
@@ -81,6 +82,7 @@ struct proto_config {
struct proto *proto; /* Instance we've created */
char *name;
unsigned debug, preference, disabled; /* Generic parameters */
+ u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
@@ -192,6 +194,12 @@ struct proto *proto_get_named(struct symbol *, struct protocol *);
void proto_xxable(char *, int);
void proto_debug(char *, unsigned int);
+static inline u32
+proto_get_router_id(struct proto_config *pc)
+{
+ return pc->router_id ? pc->router_id : pc->global->router_id;
+}
+
extern list active_proto_list;
/*
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index de63198..9d78ce0 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -74,7 +74,7 @@ ea__find(ea_list *e, unsigned id)
if (e->flags & EALF_BISECT)
{
l = 0;
- r = e->count + 1;
+ r = e->count - 1;
while (l <= r)
{
m = (l+r) / 2;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index fb2feac..87bf0dc 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -427,57 +427,87 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte
rte_announce(table, RA_ANY, net, new, old, tmpa);
- if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */
+
+ if (new && rte_better(new, old_best))
{
+ /* 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_announce(table, RA_OPTIMAL, net, new, old_best, tmpa);
new->next = net->routes;
net->routes = new;
}
- else
+ else if (old == old_best)
{
- if (old == old_best) /* It has _replaced_ the old optimal route */
+ /* The second case - the old best route disappeared, we add the
+ new route (if we have any) to the list (we don't care about
+ position) and then we elect the new optimal route and relink
+ that route at the first position and announce it. New optimal
+ route might be NULL if there is no more routes */
+
+ /* Add the new route to the list */
+ if (new)
{
- r = new; /* Find new optimal route and announce it */
- for(s=net->routes; s; s=s->next)
- if (rte_better(s, r))
- r = s;
- rte_announce(table, RA_OPTIMAL, net, r, old_best, tmpa);
- if (r) /* Re-link the new optimal route */
+ rte_trace_in(D_ROUTES, p, new, "added");
+ new->next = net->routes;
+ net->routes = new;
+ }
+
+ /* Find new optimal route */
+ r = NULL;
+ for (s=net->routes; s; s=s->next)
+ if (rte_better(s, r))
+ r = s;
+
+ /* Announce optimal route */
+ rte_announce(table, RA_OPTIMAL, net, r, old_best, tmpa);
+
+ /* And relink it (if there is any) */
+ if (r)
+ {
+ k = &net->routes;
+ while (s = *k)
{
- k = &net->routes;
- while (s = *k)
+ if (s == r)
{
- if (s == r)
- {
- *k = r->next;
- break;
- }
- k = &s->next;
+ *k = r->next;
+ break;
}
- r->next = net->routes;
- net->routes = r;
+ k = &s->next;
}
- else if (table->gc_counter++ >= table->config->gc_max_ops &&
- table->gc_time + table->config->gc_min_time <= now)
- ev_schedule(table->gc_event);
- }
- if (new) /* Link in the new non-optimal route */
- {
- new->next = old_best->next;
- old_best->next = new;
- rte_trace_in(D_ROUTES, p, new, "added");
- }
- else if (old && (p->debug & D_ROUTES))
- {
- if (old != old_best)
- rte_trace_in(D_ROUTES, p, old, "removed");
- else if (net->routes)
- rte_trace_in(D_ROUTES, p, old, "removed [replaced]");
- else
- rte_trace_in(D_ROUTES, p, old, "removed [sole]");
+ r->next = net->routes;
+ net->routes = r;
}
+ else if (table->gc_counter++ >= table->config->gc_max_ops &&
+ table->gc_time + table->config->gc_min_time <= now)
+ ev_schedule(table->gc_event);
+ }
+ else if (new)
+ {
+ /* The third case - the new route is not better than the old
+ best route (therefore old_best != NULL) and the old best
+ route was not removed (therefore old_best == net->routes).
+ We just link the new route after the old best route. */
+
+ ASSERT(net->routes != NULL);
+ new->next = net->routes->next;
+ net->routes->next = new;
+ rte_trace_in(D_ROUTES, p, new, "added");
}
+ else if (old && (p->debug & D_ROUTES))
+ {
+ /* Not really a case - the list of routes is correct, we just
+ log the route removal */
+
+ if (old != old_best)
+ rte_trace_in(D_ROUTES, p, old, "removed");
+ else if (net->routes)
+ rte_trace_in(D_ROUTES, p, old, "removed [replaced]");
+ else
+ rte_trace_in(D_ROUTES, p, old, "removed [sole]");
+ }
+
if (old)
{
if (p->rte_remove)