From cf98be7b6743e45dde9e0458664cc0762bf08867 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 10 Nov 2012 14:26:13 +0100 Subject: [PATCH 1/9] Allows rejected routes to be kept and examined. When 'import keep rejected' protocol option is activated, routes rejected by the import filter are kept in the routing table, but they are hidden and not propagated to other protocols. It is possible to examine them using 'show route rejected'. --- doc/bird.sgml | 22 +++++++-- nest/config.Y | 9 +++- nest/proto.c | 20 +++++--- nest/protocol.h | 5 +- nest/route.h | 10 +++- nest/rt-table.c | 113 ++++++++++++++++++++++++++++++++-------------- proto/bgp/attrs.c | 2 +- proto/bgp/bgp.c | 2 +- sysdep/unix/krt.c | 4 +- 9 files changed, 135 insertions(+), 52 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 24bc3026..e5550590 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -459,6 +459,14 @@ to zero to disable it. An empty is equivalent to import keep rejected + Usually, if an import filter rejects a route, the route is + forgotten. When this option is active, rejected routes are + kept in the routing table, but they are hidden and not + propagated to other protocols. But it is possible to show them + using import limit Specify an import route limit (a maximum number of routes imported from the protocol) and optionally the action to be @@ -467,8 +475,11 @@ to zero to disable it. An empty is equivalent to export limit Specify an export route limit, works similarly to @@ -661,6 +672,9 @@ This argument can be omitted if there exists only a single instance.

You can also select just routes added by a specific protocol. protocol . +

If BIRD is configured to keep rejected routes (see The rdnss local + rdnss local Use only local (interface-specific) RDNSS definitions for this interface. Otherwise, both global and local definitions are used. Could also be used to disable RDNSS for given interface if no local definitons are specified. Default: no. - dnssl local + dnssl local Use only local DNSSL definitions for this interface. See diff --git a/nest/config.Y b/nest/config.Y index a75dd0c3..93402d90 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -44,7 +44,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(LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE) +CF_KEYWORDS(LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, REJECTED) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) @@ -187,6 +187,7 @@ proto_item: | EXPORT imexport { this_proto->out_filter = $2; } | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; } | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; } + | IMPORT KEEP REJECTED bool { this_proto->in_keep_rejected = $4; } | TABLE rtable { this_proto->table = $2; } | ROUTER ID idval { this_proto->router_id = $3; } | DESCRIPTION TEXT { this_proto->dsc = $2; } @@ -405,7 +406,7 @@ CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]]) { if_show_summary(); } ; CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]]) -CF_CLI(SHOW ROUTE, r_args, [[[|for |for ] [table ] [filter |where ] [all] [primary] [(export|preexport)

] [protocol

] [stats|count]]], [[Show routing table]]) +CF_CLI(SHOW ROUTE, r_args, [[[|for |for ] [table ] [filter |where ] [all] [primary] [rejected] [(export|preexport)

] [protocol

] [stats|count]]], [[Show routing table]]) { rt_show($3); } ; r_args: @@ -451,6 +452,10 @@ r_args: $$ = $1; $$->primary_only = 1; } + | r_args REJECTED { + $$ = $1; + $$->rejected = 1; + } | r_args export_or_preexport SYM { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; diff --git a/nest/proto.c b/nest/proto.c index 53d3f1a2..2fb0e796 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -414,6 +414,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config p->main_ahook->out_filter = nc->out_filter; p->main_ahook->in_limit = nc->in_limit; p->main_ahook->out_limit = nc->out_limit; + p->main_ahook->in_keep_rejected = nc->in_keep_rejected; } /* Update routes when filters changed. If the protocol in not UP, @@ -719,8 +720,9 @@ proto_fell_down(struct proto *p) { DBG("Protocol %s down\n", p->name); - if (p->stats.imp_routes != 0) - log(L_ERR "Protocol %s is down but still has %d routes", p->name, p->stats.imp_routes); + u32 all_routes = p->stats.imp_routes + p->stats.rej_routes; + if (all_routes != 0) + log(L_ERR "Protocol %s is down but still has %d routes", p->name, all_routes); bzero(&p->stats, sizeof(struct proto_stats)); proto_free_ahooks(p); @@ -796,6 +798,7 @@ proto_schedule_feed(struct proto *p, int initial) p->main_ahook->out_filter = p->cf->out_filter; p->main_ahook->in_limit = p->cf->in_limit; p->main_ahook->out_limit = p->cf->out_limit; + p->main_ahook->in_keep_rejected = p->cf->in_keep_rejected; proto_reset_limit(p->main_ahook->in_limit); proto_reset_limit(p->main_ahook->out_limit); } @@ -1093,10 +1096,15 @@ proto_state_name(struct proto *p) } static void -proto_show_stats(struct proto_stats *s) +proto_show_stats(struct proto_stats *s, int in_keep_rejected) { - cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", - s->imp_routes, s->exp_routes, s->pref_routes); + if (in_keep_rejected) + cli_msg(-1006, " Routes: %u imported, %u rejected, %u exported, %u preferred", + s->imp_routes, s->rej_routes, s->exp_routes, s->pref_routes); + else + 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, @@ -1134,7 +1142,7 @@ proto_show_basic_info(struct proto *p) proto_show_limit(p->cf->out_limit, "Export limit:"); if (p->proto_state != PS_DOWN) - proto_show_stats(&p->stats); + proto_show_stats(&p->stats, p->cf->in_keep_rejected); } void diff --git a/nest/protocol.h b/nest/protocol.h index 11fcb164..b10016d7 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -91,6 +91,7 @@ struct proto_config { int class; /* SYM_PROTO or SYM_TEMPLATE */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ unsigned preference, disabled; /* Generic parameters */ + int in_keep_rejected; /* Routes rejected in import filter are kept */ u32 router_id; /* Protocol specific router ID */ struct rtable_config *table; /* Table we're attached to */ struct filter *in_filter, *out_filter; /* Attached filters */ @@ -106,7 +107,8 @@ struct proto_config { struct proto_stats { /* Import - from protocol to core */ u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ - u32 pref_routes; /* Number of routes that are preferred, sum over all routing table */ + u32 rej_routes; /* Number of routes rejected in import filter but kept in the routing table */ + u32 pref_routes; /* Number of routes that are preferred, sum over all routing tables */ u32 imp_updates_received; /* Number of route updates received */ u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ u32 imp_updates_filtered; /* Number of route updates rejected by filters */ @@ -410,6 +412,7 @@ struct announce_hook { 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 */ + int in_keep_rejected; /* Routes rejected in import filter are kept */ }; struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats); diff --git a/nest/route.h b/nest/route.h index 524e69b3..3c10fc55 100644 --- a/nest/route.h +++ b/nest/route.h @@ -221,6 +221,14 @@ typedef struct rte { } rte; #define REF_COW 1 /* Copy this rte on write */ +#define REF_REJECTED 2 /* Route is rejected by import filter */ + +/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ +static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_REJECTED); } + +/* Route just has REF_REJECTED flag */ +static inline int rte_is_rejected(rte *r) { return !!(r->flags & REF_REJECTED); } + /* Types of route announcement, also used as flags */ #define RA_OPTIMAL 1 /* Announcement of optimal route change */ @@ -263,7 +271,7 @@ struct rt_show_data { struct fib_iterator fit; struct proto *show_protocol; struct proto *export_protocol; - int export_mode, primary_only; + int export_mode, primary_only, rejected; struct config *running_on_config; int net_counter, rt_counter, show_counter; int stats, show_for; diff --git a/nest/rt-table.c b/nest/rt-table.c index 118f4c25..421a05ea 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -69,7 +69,7 @@ net_route(rtable *tab, ip_addr a, int len) { a0 = ipa_and(a, ipa_mkmask(len)); n = fib_find(&tab->fib, &a0, len); - if (n && n->routes) + if (n && rte_is_valid(n->routes)) return n; len--; } @@ -139,8 +139,11 @@ rte_better(rte *new, rte *old) { int (*better)(rte *, rte *); - if (!old) + if (!rte_is_valid(old)) return 1; + if (!rte_is_valid(new)) + return 0; + if (new->pref > old->pref) return 1; if (new->pref < old->pref) @@ -399,9 +402,13 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol rte *old_free = NULL; rte *r; - /* Used to track whether we met old_changed position. If it is NULL - it was the first and met it implicitly before current best route. */ - int old_meet = (old_changed && !before_old) ? 1 : 0; + /* Used to track whether we met old_changed position. If before_old is NULL + old_changed was the first and we met it implicitly before current best route. */ + int old_meet = old_changed && !before_old; + + /* Note that before_old is either NULL or valid (not rejected) route. + If old_changed is valid, before_old have to be too. If old changed route + was not valid, caller must use NULL for both old_changed and before_old. */ if (new_changed) stats->exp_updates_received++; @@ -409,7 +416,7 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol stats->exp_withdraws_received++; /* First, find the new_best route - first accepted by filters */ - for (r=net->routes; r; r=r->next) + for (r=net->routes; rte_is_valid(r); r=r->next) { if (new_best = export_filter(ah, r, &new_free, &tmpa, 0)) break; @@ -428,7 +435,8 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol if (feed) { if (feed == 2) /* refeed */ - old_best = new_best ? new_best : net->routes; + old_best = new_best ? new_best : + (rte_is_valid(net->routes) ? net->routes : NULL); else old_best = NULL; @@ -477,7 +485,7 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol } /* Fourth case */ - for (r=r->next; r; r=r->next) + for (r=r->next; rte_is_valid(r); r=r->next) { if (old_best = export_filter(ah, r, &old_free, NULL, 1)) goto found; @@ -531,7 +539,14 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol static void rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *before_old, ea_list *tmpa) { - struct announce_hook *a; + if (!rte_is_valid(old)) + old = before_old = NULL; + + if (!rte_is_valid(new)) + new = NULL; + + if (!old && !new) + return; if (type == RA_OPTIMAL) { @@ -544,6 +559,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *befo rt_notify_hostcache(tab, net); } + struct announce_hook *a; WALK_LIST(a, tab->hooks) { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); @@ -650,8 +666,13 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str if (new && rte_same(old, new)) { /* No changes, ignore the new route */ - stats->imp_updates_ignored++; - rte_trace_in(D_ROUTES, p, new, "ignored"); + + if (!rte_is_rejected(new)) + { + stats->imp_updates_ignored++; + rte_trace_in(D_ROUTES, p, new, "ignored"); + } + rte_free_quick(new); #ifdef CONFIG_RIP /* lastmod is used internally by RIP as the last time @@ -680,8 +701,10 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str struct proto_limit *l = ah->in_limit; if (l && !old && new) { - if (stats->imp_routes >= l->limit) - proto_notify_limit(ah, l, stats->imp_routes); + u32 all_routes = stats->imp_routes + stats->rej_routes; + + if (all_routes >= l->limit) + proto_notify_limit(ah, l, all_routes); if (l->state == PLS_BLOCKED) { @@ -692,15 +715,15 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str } } - if (new) + if (new && !rte_is_rejected(new)) stats->imp_updates_accepted++; else stats->imp_withdraws_accepted++; if (new) - stats->imp_routes++; + rte_is_rejected(new) ? stats->rej_routes++ : stats->imp_routes++; if (old) - stats->imp_routes--; + rte_is_rejected(old) ? stats->rej_routes-- : stats->imp_routes--; if (table->config->sorted) { @@ -900,27 +923,41 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src) stats->imp_updates_invalid++; goto drop; } + if (filter == FILTER_REJECT) { stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); - goto drop; + + if (! ah->in_keep_rejected) + goto drop; + + /* new is a private copy, i could modify it */ + new->flags |= REF_REJECTED; } - if (src->make_tmp_attrs) - tmpa = src->make_tmp_attrs(new, rte_update_pool); - if (filter) + else { - ea_list *old_tmpa = tmpa; - int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); - if (fr > F_ACCEPT) + if (src->make_tmp_attrs) + tmpa = src->make_tmp_attrs(new, rte_update_pool); + if (filter && (filter != FILTER_REJECT)) { - stats->imp_updates_filtered++; - rte_trace_in(D_FILTERS, p, new, "filtered out"); - goto drop; + ea_list *old_tmpa = tmpa; + int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); + if (fr > F_ACCEPT) + { + stats->imp_updates_filtered++; + rte_trace_in(D_FILTERS, p, new, "filtered out"); + + if (! ah->in_keep_rejected) + goto drop; + + new->flags |= REF_REJECTED; + } + if (tmpa != old_tmpa && src->store_tmp_attrs) + src->store_tmp_attrs(new, tmpa); } - if (tmpa != old_tmpa && src->store_tmp_attrs) - src->store_tmp_attrs(new, tmpa); } + if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */ new->attrs = rta_lookup(new->attrs); new->flags |= REF_COW; @@ -1553,9 +1590,11 @@ again: return 0; } + /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */ + if ((p->accept_ra_types == RA_OPTIMAL) || (p->accept_ra_types == RA_ACCEPTED)) - if (e) + if (rte_is_valid(e)) { if (p->core_state != FS_FEEDING) return 1; /* In the meantime, the protocol fell down. */ @@ -1564,7 +1603,7 @@ again: } if (p->accept_ra_types == RA_ANY) - for(e = n->routes; e != NULL; e = e->next) + for(e = n->routes; rte_is_valid(e); e = e->next) { if (p->core_state != FS_FEEDING) return 1; /* In the meantime, the protocol fell down. */ @@ -1817,7 +1856,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH); if (n) { - rta *a = n->routes->attrs; + rte *e = n->routes; + rta *a = e->attrs; pxlen = n->n.pxlen; if (a->hostentry) @@ -1850,7 +1890,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) } he->src = rta_clone(a); - he->igp_metric = rt_get_igp_metric(n->routes); + he->igp_metric = rt_get_igp_metric(e); } done: @@ -1980,14 +2020,19 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) int ok; bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen); - if (n->routes) - d->net_counter++; + for(e=n->routes; e; e=e->next) { + if (rte_is_rejected(e) != d->rejected) + continue; + struct ea_list *tmpa; struct proto *p0 = e->attrs->proto; struct proto *p1 = d->export_protocol; struct proto *p2 = d->show_protocol; + + if (ia[0]) + d->net_counter++; d->rt_counter++; ee = e; rte_update_lock(); /* We use the update buffer for filtering */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index e5bc84dd..9f71544e 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1346,7 +1346,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) /* The default case - find a new best-in-group route */ r = new; /* new may not be in the list */ - for (s=net->routes; s; s=s->next) + for (s=net->routes; rte_is_valid(s); s=s->next) if (use_deterministic_med(s) && same_group(s, lpref, lasn)) { s->u.bgp.suppressed = 1; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index dbc59eea..2eb8ccb4 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1188,7 +1188,7 @@ bgp_show_proto_info(struct proto *P) cli_msg(-1006, " Source address: %I", p->source_addr); if (P->cf->in_limit) cli_msg(-1006, " Route limit: %d/%d", - p->p.stats.imp_routes, P->cf->in_limit->limit); + p->p.stats.imp_routes + p->p.stats.rej_routes, P->cf->in_limit->limit); cli_msg(-1006, " Hold timer: %d/%d", tm_remains(c->hold_timer), c->hold_time); cli_msg(-1006, " Keepalive timer: %d/%d", diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 2128e136..6c0e5e91 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -581,7 +581,7 @@ krt_flush_routes(struct krt_proto *p) { net *n = (net *) f; rte *e = n->routes; - if (e && (n->n.flags & KRF_INSTALLED)) + if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED)) { /* FIXME: this does not work if gw is changed in export filter */ krt_replace_rte(p, e->net, NULL, e, NULL); @@ -656,7 +656,7 @@ krt_got_route(struct krt_proto *p, rte *e) } old = net->routes; - if ((net->n.flags & KRF_INSTALLED) && old) + if ((net->n.flags & KRF_INSTALLED) && rte_is_valid(old)) { /* There may be changes in route attributes, we ignore that. Also, this does not work well if gw is changed in export filter */ From a55a90faec5cce09cee65f484e3731207af00335 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 10 Nov 2012 14:54:35 +0100 Subject: [PATCH 2/9] Peer address of stub iface should be announced in OSPF Router LSA. --- proto/ospf/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 177cd53a..bfa071d8 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -305,7 +305,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) /* Now we will originate stub area if there is no primary */ if (net_lsa || (ifa->type == OSPF_IT_VLINK) || - (ifa->addr->flags & IA_PEER) || + ((ifa->addr->flags & IA_PEER) && ! ifa->cf->stub) || configured_stubnet(oa, ifa->addr)) continue; From 227af52fb5be09c841fbd9f86e7bb3992b981a4a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 10 Nov 2012 16:18:12 +0100 Subject: [PATCH 3/9] Fixes OSPF reconfigure w.r.t. downed ifaces. --- proto/ospf/iface.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index aa7f7892..290a8634 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -886,6 +886,10 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) struct ifa *a; WALK_LIST(iface, iface_list) + { + if (! (iface->flags & IF_UP)) + continue; + WALK_LIST(a, iface->addrs) { if (a->flags & IA_SECONDARY) @@ -911,6 +915,7 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_iface_new(oa, a, ip); } } + } } @@ -1014,6 +1019,10 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) struct ifa *a; WALK_LIST(iface, iface_list) + { + if (! (iface->flags & IF_UP)) + continue; + WALK_LIST(a, iface->addrs) { if (a->flags & IA_SECONDARY) @@ -1042,6 +1051,7 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) ospf_iface_new(oa, a, ip); } } + } } #endif From e16469bc4d182428687a5ef5f2fb4707afa15abd Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Mon, 12 Nov 2012 13:48:29 +0100 Subject: [PATCH 4/9] AS# in bgp.agreggator was a signed integer - fixed. --- proto/bgp/attrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 9f71544e..98b2f2c2 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -238,7 +238,7 @@ bgp_format_aggregator(eattr *a, byte *buf, int buflen UNUSED) as = get_u32(data); data += 4; - bsprintf(buf, "%d.%d.%d.%d AS%d", data[0], data[1], data[2], data[3], as); + bsprintf(buf, "%d.%d.%d.%d AS%u", data[0], data[1], data[2], data[3], as); } static int From 15550957957f3c790f3bec3f6b8721559ea25969 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 15 Nov 2012 01:29:01 +0100 Subject: [PATCH 5/9] Changes 'rejected' to 'filtered' in one of the last patches. --- doc/bird.sgml | 12 ++++++------ nest/config.Y | 10 +++++----- nest/proto.c | 16 ++++++++-------- nest/protocol.h | 6 +++--- nest/route.h | 10 +++++----- nest/rt-table.c | 20 ++++++++++---------- proto/bgp/bgp.c | 2 +- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index e5550590..7cea3921 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -459,12 +459,12 @@ to zero to disable it. An empty is equivalent to import keep rejected + import keep filtered Usually, if an import filter rejects a route, the route is - forgotten. When this option is active, rejected routes are + forgotten. When this option is active, these routes are kept in the routing table, but they are hidden and not propagated to other protocols. But it is possible to show them - using import limit @@ -476,7 +476,7 @@ to zero to disable it. An empty is equivalent to You can also select just routes added by a specific protocol. protocol . -

If BIRD is configured to keep rejected routes (see If BIRD is configured to keep filtered routes (see The out_filter = $2; } | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; } | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; } - | IMPORT KEEP REJECTED bool { this_proto->in_keep_rejected = $4; } + | IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; } | TABLE rtable { this_proto->table = $2; } | ROUTER ID idval { this_proto->router_id = $3; } | DESCRIPTION TEXT { this_proto->dsc = $2; } @@ -406,7 +406,7 @@ CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]]) { if_show_summary(); } ; CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]]) -CF_CLI(SHOW ROUTE, r_args, [[[|for |for ] [table ] [filter |where ] [all] [primary] [rejected] [(export|preexport)

] [protocol

] [stats|count]]], [[Show routing table]]) +CF_CLI(SHOW ROUTE, r_args, [[[|for |for ] [table ] [filter |where ] [all] [primary] [filtered] [(export|preexport)

] [protocol

] [stats|count]]], [[Show routing table]]) { rt_show($3); } ; r_args: @@ -452,9 +452,9 @@ r_args: $$ = $1; $$->primary_only = 1; } - | r_args REJECTED { + | r_args FILTERED { $$ = $1; - $$->rejected = 1; + $$->filtered = 1; } | r_args export_or_preexport SYM { struct proto_config *c = (struct proto_config *) $3->def; diff --git a/nest/proto.c b/nest/proto.c index 2fb0e796..e9afa2fe 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -414,7 +414,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config p->main_ahook->out_filter = nc->out_filter; p->main_ahook->in_limit = nc->in_limit; p->main_ahook->out_limit = nc->out_limit; - p->main_ahook->in_keep_rejected = nc->in_keep_rejected; + p->main_ahook->in_keep_filtered = nc->in_keep_filtered; } /* Update routes when filters changed. If the protocol in not UP, @@ -720,7 +720,7 @@ proto_fell_down(struct proto *p) { DBG("Protocol %s down\n", p->name); - u32 all_routes = p->stats.imp_routes + p->stats.rej_routes; + u32 all_routes = p->stats.imp_routes + p->stats.filt_routes; if (all_routes != 0) log(L_ERR "Protocol %s is down but still has %d routes", p->name, all_routes); @@ -798,7 +798,7 @@ proto_schedule_feed(struct proto *p, int initial) p->main_ahook->out_filter = p->cf->out_filter; p->main_ahook->in_limit = p->cf->in_limit; p->main_ahook->out_limit = p->cf->out_limit; - p->main_ahook->in_keep_rejected = p->cf->in_keep_rejected; + p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered; proto_reset_limit(p->main_ahook->in_limit); proto_reset_limit(p->main_ahook->out_limit); } @@ -1096,11 +1096,11 @@ proto_state_name(struct proto *p) } static void -proto_show_stats(struct proto_stats *s, int in_keep_rejected) +proto_show_stats(struct proto_stats *s, int in_keep_filtered) { - if (in_keep_rejected) - cli_msg(-1006, " Routes: %u imported, %u rejected, %u exported, %u preferred", - s->imp_routes, s->rej_routes, s->exp_routes, s->pref_routes); + if (in_keep_filtered) + cli_msg(-1006, " Routes: %u imported, %u filtered, %u exported, %u preferred", + s->imp_routes, s->filt_routes, s->exp_routes, s->pref_routes); else cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", s->imp_routes, s->exp_routes, s->pref_routes); @@ -1142,7 +1142,7 @@ proto_show_basic_info(struct proto *p) proto_show_limit(p->cf->out_limit, "Export limit:"); if (p->proto_state != PS_DOWN) - proto_show_stats(&p->stats, p->cf->in_keep_rejected); + proto_show_stats(&p->stats, p->cf->in_keep_filtered); } void diff --git a/nest/protocol.h b/nest/protocol.h index b10016d7..cf2ca0a4 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -91,7 +91,7 @@ struct proto_config { int class; /* SYM_PROTO or SYM_TEMPLATE */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ unsigned preference, disabled; /* Generic parameters */ - int in_keep_rejected; /* Routes rejected in import filter are kept */ + int in_keep_filtered; /* Routes rejected in import filter are kept */ u32 router_id; /* Protocol specific router ID */ struct rtable_config *table; /* Table we're attached to */ struct filter *in_filter, *out_filter; /* Attached filters */ @@ -107,7 +107,7 @@ struct proto_config { struct proto_stats { /* Import - from protocol to core */ u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ - u32 rej_routes; /* Number of routes rejected in import filter but kept in the routing table */ + u32 filt_routes; /* Number of routes rejected in import filter but kept in the routing table */ u32 pref_routes; /* Number of routes that are preferred, sum over all routing tables */ u32 imp_updates_received; /* Number of route updates received */ u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ @@ -412,7 +412,7 @@ struct announce_hook { 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 */ - int in_keep_rejected; /* Routes rejected in import filter are kept */ + int in_keep_filtered; /* Routes rejected in import filter are kept */ }; struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats); diff --git a/nest/route.h b/nest/route.h index 3c10fc55..177baa38 100644 --- a/nest/route.h +++ b/nest/route.h @@ -221,13 +221,13 @@ typedef struct rte { } rte; #define REF_COW 1 /* Copy this rte on write */ -#define REF_REJECTED 2 /* Route is rejected by import filter */ +#define REF_FILTERED 2 /* Route is rejected by import filter */ /* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ -static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_REJECTED); } +static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); } -/* Route just has REF_REJECTED flag */ -static inline int rte_is_rejected(rte *r) { return !!(r->flags & REF_REJECTED); } +/* Route just has REF_FILTERED flag */ +static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); } /* Types of route announcement, also used as flags */ @@ -271,7 +271,7 @@ struct rt_show_data { struct fib_iterator fit; struct proto *show_protocol; struct proto *export_protocol; - int export_mode, primary_only, rejected; + int export_mode, primary_only, filtered; struct config *running_on_config; int net_counter, rt_counter, show_counter; int stats, show_for; diff --git a/nest/rt-table.c b/nest/rt-table.c index 421a05ea..102218b2 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -667,7 +667,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str { /* No changes, ignore the new route */ - if (!rte_is_rejected(new)) + if (!rte_is_filtered(new)) { stats->imp_updates_ignored++; rte_trace_in(D_ROUTES, p, new, "ignored"); @@ -701,7 +701,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str struct proto_limit *l = ah->in_limit; if (l && !old && new) { - u32 all_routes = stats->imp_routes + stats->rej_routes; + u32 all_routes = stats->imp_routes + stats->filt_routes; if (all_routes >= l->limit) proto_notify_limit(ah, l, all_routes); @@ -715,15 +715,15 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str } } - if (new && !rte_is_rejected(new)) + if (new && !rte_is_filtered(new)) stats->imp_updates_accepted++; else stats->imp_withdraws_accepted++; if (new) - rte_is_rejected(new) ? stats->rej_routes++ : stats->imp_routes++; + rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++; if (old) - rte_is_rejected(old) ? stats->rej_routes-- : stats->imp_routes--; + rte_is_filtered(old) ? stats->filt_routes-- : stats->imp_routes--; if (table->config->sorted) { @@ -929,11 +929,11 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src) stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); - if (! ah->in_keep_rejected) + if (! ah->in_keep_filtered) goto drop; /* new is a private copy, i could modify it */ - new->flags |= REF_REJECTED; + new->flags |= REF_FILTERED; } else { @@ -948,10 +948,10 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src) stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); - if (! ah->in_keep_rejected) + if (! ah->in_keep_filtered) goto drop; - new->flags |= REF_REJECTED; + new->flags |= REF_FILTERED; } if (tmpa != old_tmpa && src->store_tmp_attrs) src->store_tmp_attrs(new, tmpa); @@ -2023,7 +2023,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) for(e=n->routes; e; e=e->next) { - if (rte_is_rejected(e) != d->rejected) + if (rte_is_filtered(e) != d->filtered) continue; struct ea_list *tmpa; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 2eb8ccb4..346c641b 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1188,7 +1188,7 @@ bgp_show_proto_info(struct proto *P) cli_msg(-1006, " Source address: %I", p->source_addr); if (P->cf->in_limit) cli_msg(-1006, " Route limit: %d/%d", - p->p.stats.imp_routes + p->p.stats.rej_routes, P->cf->in_limit->limit); + p->p.stats.imp_routes + p->p.stats.filt_routes, P->cf->in_limit->limit); cli_msg(-1006, " Hold timer: %d/%d", tm_remains(c->hold_timer), c->hold_time); cli_msg(-1006, " Keepalive timer: %d/%d", From 6cadbf325bfcf25a04d869778abb443f9e1b6119 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 15 Nov 2012 14:08:20 +0100 Subject: [PATCH 6/9] Change unnamed ptp link description on OSPFv2. Although it is a slight deviation from the standard, it has no ill consequences for OSPFv2 and the change fixes a compatibility issue with some broken implementations. --- proto/ospf/topology.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index bfa071d8..5f4d1d54 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -258,8 +258,17 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); ln->type = LSART_PTP; ln->id = neigh->rid; - ln->data = (ifa->addr->flags & IA_PEER) ? - ifa->iface_id : ipa_to_u32(ifa->addr->ip); + + /* + * ln->data should be ifa->iface_id in case of no/ptp + * address (ifa->addr->flags & IA_PEER) on PTP link (see + * RFC 2328 12.4.1.1.), but the iface ID value has no use, + * while using IP address even in this case is here for + * compatibility with some broken implementations that use + * this address as a next-hop. + */ + ln->data = ipa_to_u32(ifa->addr->ip); + ln->metric = ifa->cost; ln->padding = 0; i++; From cf3a704b6a2263aba6bb6adb4c2c9dd93b72f470 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 16 Nov 2012 02:34:12 +0100 Subject: [PATCH 7/9] Updates the documentation. --- doc/bird.sgml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/bird.sgml b/doc/bird.sgml index 7cea3921..d833f82f 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1654,6 +1654,15 @@ use cases that use the direct protocol (like abusing eBGP as an IGP routing protocol), in most cases it is not needed to have these device routes in BIRD routing table and to use the direct protocol. +

There is one notable case when you definitely want to use the +direct protocol -- running BIRD on BSD systems. Having high priority +device routes for directly connected networks from the direct protocol +protects kernel device routes from being overwritten or removed by IGP +routes during some transient network conditions, because a lower +priority IGP route for the same network is not exported to the kernel +routing table. This is an issue on BSD systems only, as on Linux +systems BIRD cannot change non-BIRD route in the kernel routing table. +

The only configurable thing about direct is what interfaces it watches:

From 70577529244d6d920b75d95e797156e05141db30 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 16 Nov 2012 13:29:16 +0100 Subject: [PATCH 8/9] Fixes route tracing w.r.t. kept filtered routes. --- nest/rt-table.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index 102218b2..2f0840f0 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -627,6 +627,8 @@ rte_same(rte *x, rte *y) (!x->attrs->proto->rte_same || x->attrs->proto->rte_same(x, y)); } +static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); } + static void rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct proto *src) { @@ -715,10 +717,15 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str } } - if (new && !rte_is_filtered(new)) + int new_ok = rte_is_ok(new); + int old_ok = rte_is_ok(old); + + if (new_ok) stats->imp_updates_accepted++; - else + else if (old_ok) stats->imp_withdraws_accepted++; + else + stats->imp_withdraws_ignored++; if (new) rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++; @@ -808,17 +815,19 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str new->lastmod = now; /* Log the route change */ - if (new) - rte_trace_in(D_ROUTES, p, new, net->routes == new ? "added [best]" : "added"); - - if (!new && (p->debug & D_ROUTES)) + if (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]"); + if (new_ok) + rte_trace(p, new, '>', new == net->routes ? "added [best]" : "added"); + else if (old_ok) + { + if (old != old_best) + rte_trace(p, old, '>', "removed"); + else if (rte_is_ok(net->routes)) + rte_trace(p, old, '>', "removed [replaced]"); + else + rte_trace(p, old, '>', "removed [sole]"); + } } /* Propagate the route change */ @@ -833,17 +842,13 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str (table->gc_time + table->config->gc_min_time <= now)) rt_schedule_gc(table); + if (old_ok && p->rte_remove) + p->rte_remove(net, old); + if (new_ok && p->rte_insert) + p->rte_insert(net, new); + if (old) - { - if (p->rte_remove) - p->rte_remove(net, old); - rte_free_quick(old); - } - if (new) - { - if (p->rte_insert) - p->rte_insert(net, new); - } + rte_free_quick(old); } static int rte_update_nest_cnt; /* Nesting counter to allow recursive updates */ From c93c02088a026b83f452fbd260135ba4c8da7ecf Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 16 Nov 2012 13:30:54 +0100 Subject: [PATCH 9/9] NEWS and version update. --- NEWS | 8 +++++++- misc/bird.spec | 2 +- sysdep/config.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 3aaa4dd6..f8e76601 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Version 1.3.9 (2012-11-16) + o BIRD can be configured to keep and show filtered routes. + o Dragonfly BSD support. + o Fixed OSPFv3 vlinks. + o Several minor bugfixes. + Version 1.3.8 (2012-08-07) o Generalized import and export route limits. o RDNSS and DNSSL support for RAdv. @@ -11,7 +17,7 @@ Version 1.3.8 (2012-08-07) Version 1.3.7 (2012-03-22) o Route Origin Authorization basics. o RIPng working again. - o Extended clist operations in filters. + o Extended clist operations in filters. o Fixes several bugs in BSD iface handling. o Several minor bugfixes and enhancements. diff --git a/misc/bird.spec b/misc/bird.spec index de63a6a0..daf4088b 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.3.8 +Version: 1.3.9 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/sysdep/config.h b/sysdep/config.h index 7106e4ba..e97d9e20 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.3.8" +#define BIRD_VERSION "1.3.9" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h"