diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/a-path.c | 17 | ||||
-rw-r--r-- | nest/attrs.h | 3 | ||||
-rw-r--r-- | nest/config.Y | 6 | ||||
-rw-r--r-- | nest/proto.c | 5 | ||||
-rw-r--r-- | nest/protocol.h | 8 | ||||
-rw-r--r-- | nest/rt-attr.c | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 104 |
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) |