From 0ff86d054efa8005c5df943acf6d2122781d3175 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 3 Jan 2018 14:12:00 +0100 Subject: [PATCH 01/18] ROA: Fix reconfiguration --- nest/rt-roa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nest/rt-roa.c b/nest/rt-roa.c index 0fd89667..bf457e30 100644 --- a/nest/rt-roa.c +++ b/nest/rt-roa.c @@ -306,10 +306,10 @@ void roa_commit(struct config *new, struct config *old) { struct roa_table_config *cf; - struct roa_table *t; + struct roa_table *t, *tx; if (old) - WALK_LIST(t, roa_table_list) + WALK_LIST_DELSAFE(t, tx, roa_table_list) { struct symbol *sym = cf_find_symbol(new, t->name); if (sym && sym->class == SYM_ROA) From b94057911554e04df9b709f8354e2e220131096a Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 16 Jan 2018 16:20:01 +0100 Subject: [PATCH 02/18] Filter: Allow silent filter execution A filter should log messages only if executed explicitly (e.g., during route export or route import). When a filter is executed for technical reasons (e.g., to establish whether a route was exported before), it should run silently. --- filter/filter.c | 9 ++++++--- filter/filter.h | 1 + nest/rt-table.c | 9 ++++++--- sysdep/unix/krt.c | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 1e8f7d5a..b0c56046 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -590,7 +590,8 @@ f_rta_cow(void) static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define runtime(x) do { \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \ + if (!(f_flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \ res.type = T_RETURN; \ res.val.i = F_ERROR; \ return res; \ @@ -889,7 +890,8 @@ interpret(struct f_inst *what) break; case P('p',','): ONEARG; - if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) + if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && + !(f_flags & FF_SILENT)) log_commit(*L_INFO, &f_buf); switch (what->a2.i) { @@ -1723,7 +1725,8 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc if (res.type != T_RETURN) { - log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); + if (!(f_flags & FF_SILENT)) + log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); return F_ERROR; } DBG( "done (%u)\n", res.val.i ); diff --git a/filter/filter.h b/filter/filter.h index 72b37461..efb4b978 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -227,5 +227,6 @@ struct f_trie #define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); #define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */ +#define FF_SILENT 2 /* Silent filter execution */ #endif diff --git a/nest/rt-table.c b/nest/rt-table.c index bcb48b53..28fe5baa 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -273,7 +273,8 @@ export_filter_(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa } v = filter && ((filter == FILTER_REJECT) || - (f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT)); + (f_run(filter, &rt, tmpa, pool, + FF_FORCE_TMPATTR | (silent ? FF_SILENT : 0)) > F_ACCEPT)); if (v) { if (silent) @@ -1298,7 +1299,8 @@ rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool); int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0; if (v == RIC_PROCESS) - v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + v = (f_run(filter, &rt, &tmpa, rte_update_pool, + FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT); /* Discard temporary rte */ if (rt != n->routes) @@ -2493,7 +2495,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) * command may change the export filter and do not update routes. */ int do_export = (ic > 0) || - (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + (f_run(a->out_filter, &e, &tmpa, rte_update_pool, + FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT); if (do_export != (d->export_mode == RSEM_EXPORT)) goto skip; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 07a55c0d..526c0cab 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -632,7 +632,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa) if (filter == FILTER_ACCEPT) goto accept; - if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT) + if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR | FF_SILENT) > F_ACCEPT) goto reject; From 63472779ad4ecdecbcfedf2d2bb40abc2f8c84b0 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 16 Jan 2018 19:17:04 +0100 Subject: [PATCH 03/18] BGP: Implement 'disable after cease' option The option allows to specify that some cease subcodes should disable the protocol when received. --- proto/bgp/bgp.h | 1 + proto/bgp/config.Y | 30 ++++++++++++++++++++++++++++++ proto/bgp/packets.c | 10 ++++++++++ 3 files changed, 41 insertions(+) diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 22a150ab..b3db8b7e 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -62,6 +62,7 @@ struct bgp_config { unsigned error_delay_time_min; /* Time to wait after an error is detected */ unsigned error_delay_time_max; unsigned disable_after_error; /* Disable the protocol when error is detected */ + u32 disable_after_cease; /* Disable it when cease is received, bitfield */ char *password; /* Password used for MD5 authentication */ struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 55c602f1..075403a3 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -29,6 +29,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY) +CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER, + CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION, + OUT, OF, RESOURCES) + +%type bgp_cease_mask bgp_cease_list bgp_cease_flag + CF_GRAMMAR CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } ) @@ -64,6 +70,29 @@ bgp_nbr_opts: | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; } ; +bgp_cease_mask: + /* true -> all except connection collision */ + bool { $$ = $1 ? ~(1 << 7) : 0; } + | '{' bgp_cease_list '}' { $$ = $2; } + ; + +bgp_cease_list: + bgp_cease_flag + | bgp_cease_list ',' bgp_cease_flag { $$ = $1 | $3; } + ; + +bgp_cease_flag: + CEASE { $$ = 1 << 0; } + | PREFIX LIMIT HIT { $$ = 1 << 1; } + | ADMINISTRATIVE SHUTDOWN { $$ = 1 << 2; } + | PEER DECONFIGURED { $$ = 1 << 3; } + | ADMINISTRATIVE RESET { $$ = 1 << 4; } + | CONNECTION REJECTED { $$ = 1 << 5; } + | CONFIGURATION CHANGE { $$ = 1 << 6; } + | CONNECTION COLLISION { $$ = 1 << 7; } + | OUT OF RESOURCES { $$ = 1 << 8; } + ; + bgp_proto: bgp_proto_start proto_name '{' | bgp_proto proto_item ';' @@ -107,6 +136,7 @@ bgp_proto: | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; } | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; } + | bgp_proto DISABLE AFTER CEASE bgp_cease_mask ';' { BGP_CFG->disable_after_cease = $5; } | bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; } | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; } | bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index af3b15b5..f0049d3a 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1607,6 +1607,16 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); } + else + { + uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0); + if (p->cf->disable_after_cease & subcode_bit) + { + log(L_INFO "%s: Disabled after Cease notification", p->p.name); + p->startup_delay = 0; + p->p.disabled = 1; + } + } } static void From c591810d46ae31c9e46768388878321e78e4ef94 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Tue, 16 Jan 2018 14:46:06 +0100 Subject: [PATCH 04/18] Pipe: fixed template bug When pipe inherited from template, every channel config was lost. --- proto/pipe/config.Y | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y index 4f96fdcb..b3c332be 100644 --- a/proto/pipe/config.Y +++ b/proto/pipe/config.Y @@ -25,13 +25,19 @@ CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } ) pipe_proto_start: proto_start PIPE { this_proto = proto_config_new(&proto_pipe, $1); - this_channel = channel_config_new(NULL, NULL, 0, this_proto); - this_channel->in_filter = FILTER_ACCEPT; - this_channel->out_filter = FILTER_ACCEPT; +} +proto_name +{ + this_channel = proto_cf_main_channel(this_proto); + if (!this_channel) { + this_channel = channel_config_new(NULL, NULL, 0, this_proto); + this_channel->in_filter = FILTER_ACCEPT; + this_channel->out_filter = FILTER_ACCEPT; + } }; pipe_proto: - pipe_proto_start proto_name '{' + pipe_proto_start '{' | pipe_proto proto_item ';' | pipe_proto channel_item ';' | pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; } From 8adaf730c0e2dae2debd7aa09633899e28428b11 Mon Sep 17 00:00:00 2001 From: Jan Maria Matejka Date: Tue, 16 Jan 2018 16:10:13 +0100 Subject: [PATCH 05/18] Pipe: show export state --- proto/pipe/pipe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 310f3c01..49ff52e2 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -249,6 +249,8 @@ pipe_show_stats(struct pipe_proto *p) s2->imp_withdraws_ignored, s2->imp_withdraws_accepted); } +static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" }; + static void pipe_show_proto_info(struct proto *P) { @@ -257,6 +259,8 @@ pipe_show_proto_info(struct proto *P) cli_msg(-1006, " Channel %s", "main"); cli_msg(-1006, " Table: %s", p->pri->table->name); cli_msg(-1006, " Peer table: %s", p->sec->table->name); + cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]); + cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]); cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter)); From def6efa1ef98966424a73923832c6912acefc0ba Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 23 Jan 2018 14:26:18 +0100 Subject: [PATCH 06/18] Doc: Fix example --- doc/bird.conf.example2 | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/doc/bird.conf.example2 b/doc/bird.conf.example2 index d7048b64..815651c7 100644 --- a/doc/bird.conf.example2 +++ b/doc/bird.conf.example2 @@ -28,20 +28,15 @@ flow6 table flowtab6; protocol device { - scan time 10; } protocol kernel kernel4 { - scan time 20; - ipv4 { export all; }; } protocol kernel kernel6 { - scan time 20; - ipv6 { export all; }; @@ -169,8 +164,6 @@ protocol pipe { } protocol ospf v2 ospf4 { -# ecmp; - ipv4 { import all; # export where source = RTS_STATIC; @@ -186,8 +179,6 @@ protocol ospf v2 ospf4 { protocol ospf v3 ospf6 { -# ecmp; - ipv6 { import all; # export where source = RTS_STATIC; @@ -251,7 +242,7 @@ protocol bgp { }; # IPv6 with MPLS labels (2/4) - ipv6 multicast { + ipv6 mpls { # explicit IPv6 table table mtab6; import all; From e5ff7929c4d85b84496cdfc46f006b8cd1b4c0e5 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 23 Jan 2018 14:48:07 +0100 Subject: [PATCH 07/18] KRT: Remove useless option --- sysdep/unix/krt.Y | 1 - sysdep/unix/krt.c | 2 +- sysdep/unix/krt.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 1cb28389..31f5f1d4 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -78,7 +78,6 @@ kern_item: cf_error("Learning of kernel routes not supported on this platform"); #endif } - | DEVICE ROUTES bool { THIS_KRT->devroutes = $3; } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } | MERGE PATHS bool kern_mp_limit { krt_set_merge_paths(this_channel, $3, $4); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 29d2d01e..d4c0db72 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -1159,7 +1159,7 @@ krt_reconfigure(struct proto *p, struct proto_config *CF) return 0; /* persist, graceful restart need not be the same */ - return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes; + return o->scan_time == n->scan_time && o->learn == n->learn; } struct proto_config * diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 3bfccfc2..8d3add0e 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -49,7 +49,6 @@ struct krt_config { btime scan_time; /* How often we re-scan routes */ int persist; /* Keep routes when we exit */ int learn; /* Learn routes from other sources */ - int devroutes; /* XXX: remove */ int graceful_restart; /* Regard graceful restart recovery */ }; From ace3072e09e445b2fd8554492b80bea5cc1f3411 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 23 Jan 2018 15:12:43 +0100 Subject: [PATCH 08/18] KRT: Fix option 'merge paths' --- sysdep/unix/krt.Y | 12 +----------- sysdep/unix/krt.c | 9 ++++++++- sysdep/unix/krt.h | 1 + 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 31f5f1d4..9aac8668 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -16,16 +16,6 @@ CF_DEFINES #define THIS_KIF ((struct kif_config *) this_proto) #define KIF_IFACE ((struct kif_iface_config *) this_ipatt) -static void -krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit) -{ - if ((limit <= 0) || (limit > 255)) - cf_error("Merge paths limit must be in range 1-255"); - - cc->ra_mode = merge ? RA_MERGED : RA_OPTIMAL; - cc->merge_limit = limit; -} - static void kif_set_preferred(ip_addr ip) { @@ -80,7 +70,7 @@ kern_item: } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } | MERGE PATHS bool kern_mp_limit { - krt_set_merge_paths(this_channel, $3, $4); + THIS_KRT->merge_paths = $3 ? $4 : 0; #ifndef KRT_ALLOW_MERGE_PATHS if ($3) cf_error("Path merging not supported on this platform"); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index d4c0db72..bfdbfa4e 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -1059,11 +1059,18 @@ krt_postconfig(struct proto_config *CF) cf_error("All kernel syncers must use the same table scan interval"); #endif - struct rtable_config *tab = proto_cf_main_channel(CF)->table; + struct channel_config *cc = proto_cf_main_channel(CF); + struct rtable_config *tab = cc->table; if (tab->krt_attached) cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name); tab->krt_attached = CF; + if (cf->merge_paths) + { + cc->ra_mode = RA_MERGED; + cc->merge_limit = cf->merge_paths; + } + krt_sys_postconfig(cf); } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 8d3add0e..b627882d 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -50,6 +50,7 @@ struct krt_config { int persist; /* Keep routes when we exit */ int learn; /* Learn routes from other sources */ int graceful_restart; /* Regard graceful restart recovery */ + int merge_paths; /* Exported routes are merged for ECMP */ }; struct krt_proto { From d6cf996151307d083c30e4ecde0f1d7449b19253 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 23 Jan 2018 17:05:45 +0100 Subject: [PATCH 09/18] IO: Fix socket priority On Linux, setting the ToS will also set the priority and the range of accepted values is quite limited (masked by 0x1e). Therefore, 0xc0 is translated to a priority of 0, not something we want, overriding the "7" priority which was set previously explicitely. To avoid that, just move setting priority later in the code. Thanks to Vincent Bernat for the patch. --- sysdep/unix/io.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 6d6a0990..53a37a50 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1238,10 +1238,6 @@ sk_setup(sock *s) #endif } - if (s->priority >= 0) - if (sk_set_priority(s, s->priority) < 0) - return -1; - if (sk_is_ipv4(s)) { if (s->flags & SKF_LADDR_RX) @@ -1292,6 +1288,11 @@ sk_setup(sock *s) return -1; } + /* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */ + if (s->priority >= 0) + if (sk_set_priority(s, s->priority) < 0) + return -1; + return 0; } From 345e50d59ff299e466fab6d0e0d37c210d624d96 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 24 Jan 2018 13:55:12 +0100 Subject: [PATCH 10/18] Nest: remove duplicate function --- nest/rt-fib.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 24a7facc..c09f2759 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -92,8 +92,7 @@ fib_ht_free(struct fib_node **h) } -static u32 -fib_hash(struct fib *f, const net_addr *a); +static inline u32 fib_hash(struct fib *f, const net_addr *a); /** * fib_init - initialize a new FIB @@ -198,24 +197,11 @@ fib_rehash(struct fib *f, int step) }) -static u32 +static inline u32 fib_hash(struct fib *f, const net_addr *a) { - ASSERT(f->addr_type == a->type); - - switch (f->addr_type) - { - case NET_IP4: return FIB_HASH(f, a, ip4); - case NET_IP6: return FIB_HASH(f, a, ip6); - case NET_VPN4: return FIB_HASH(f, a, vpn4); - case NET_VPN6: return FIB_HASH(f, a, vpn6); - case NET_ROA4: return FIB_HASH(f, a, roa4); - case NET_ROA6: return FIB_HASH(f, a, roa6); - case NET_FLOW4: return FIB_HASH(f, a, flow4); - case NET_FLOW6: return FIB_HASH(f, a, flow6); - case NET_MPLS: return FIB_HASH(f, a, mpls); - default: bug("invalid type"); - } + /* Same as FIB_HASH() */ + return net_hash(a) >> f->hash_shift; } void * From 85ad5855a02e8b185a61bbcb601f005d2e6747db Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 29 Jan 2018 12:49:37 +0100 Subject: [PATCH 11/18] Nest: Fix corner case in recursive next hop lookup Thanks to Svenne Krap for the bugreport. --- nest/rt-table.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index 4640d6a9..6ee261e8 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2392,12 +2392,13 @@ static int rt_update_hostentry(rtable *tab, struct hostentry *he) { rta *old_src = he->src; + int direct = 0; int pxlen = 0; /* Reset the hostentry */ he->src = NULL; - he->nexthop_linkable = 0; he->dest = RTD_UNREACHABLE; + he->nexthop_linkable = 0; he->igp_metric = 0; net_addr he_addr; @@ -2417,9 +2418,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - he->dest = a->dest; - he->nexthop_linkable = 1; - if (he->dest == RTD_UNICAST) + if (a->dest == RTD_UNICAST) { for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) if (ipa_zero(nh->gw)) @@ -2432,12 +2431,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - he->nexthop_linkable = 0; - break; + direct++; } } he->src = rta_clone(a); + he->dest = a->dest; + he->nexthop_linkable = !direct; he->igp_metric = rt_get_igp_metric(e); } From 28b3b551222ab58456a067a9be4790824cdbb60e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 6 Feb 2018 16:08:45 +0100 Subject: [PATCH 12/18] KRT: Fix IPv6 route learn Internal table used for route learn was created with non-matching net type for IPv6 kernel proto. Thanks to Toke Hoiland-Jorgensen for the bugreport --- bird.conf | 7 ++++--- nest/route.h | 2 +- nest/rt-table.c | 19 ++++++++----------- sysdep/unix/krt.c | 8 +++++++- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/bird.conf b/bird.conf index 410f190c..e383c934 100644 --- a/bird.conf +++ b/bird.conf @@ -22,13 +22,14 @@ protocol direct { # Feed routes to kernel FIB protocol kernel { - ipv4 { export all; }; -# learn; # Learn all routes from the kernel + ipv4 { export all; import all; }; + learn; # Learn all routes from the kernel # scan time 10; # Scan kernel tables every 10 seconds } protocol kernel { - ipv6; + ipv6 { import all; }; + learn; } # Static route feed diff --git a/nest/route.h b/nest/route.h index 43d7d696..1c86110b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -282,7 +282,7 @@ void rt_preconfig(struct config *); void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); -void rt_setup(pool *, rtable *, char *, struct rtable_config *); +void rt_setup(pool *, rtable *, struct rtable_config *); static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } static inline net *net_find_valid(rtable *tab, const net_addr *addr) { net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 6ee261e8..784f6cfb 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1599,22 +1599,19 @@ rt_event(void *ptr) } void -rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf) +rt_setup(pool *p, rtable *t, struct rtable_config *cf) { bzero(t, sizeof(*t)); - t->name = name; + t->name = cf->name; t->config = cf; - t->addr_type = cf ? cf->addr_type : NET_IP4; + t->addr_type = cf->addr_type; fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL); init_list(&t->channels); - if (cf) - { - t->rt_event = ev_new(p); - t->rt_event->hook = rt_event; - t->rt_event->data = t; - t->gc_time = current_time(); - } + t->rt_event = ev_new(p); + t->rt_event->hook = rt_event; + t->rt_event->data = t; + t->gc_time = current_time(); } /** @@ -2090,7 +2087,7 @@ rt_commit(struct config *new, struct config *old) { rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable)); DBG("\t%s: created\n", r->name); - rt_setup(rt_table_pool, t, r->name, r); + rt_setup(rt_table_pool, t, r); add_tail(&routing_tables, &t->n); r->table = t; } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index e7bd79e3..a3cbb336 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -506,7 +506,13 @@ static void krt_learn_init(struct krt_proto *p) { if (KRT_CF->learn) - rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL); + { + struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config)); + cf->name = "Inherited"; + cf->addr_type = p->p.net_type; + + rt_setup(p->p.pool, &p->krt_table, cf); + } } static void From a82f692e5844d5efdc091a796dc0e8ae8ab5a322 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 6 Feb 2018 17:43:55 +0100 Subject: [PATCH 13/18] Nest: Trivial whitespace cleanup --- lib/net.c | 64 +++++++++++++++++++++++----------------------- nest/a-path.c | 2 +- nest/a-path_test.c | 6 ++--- nest/cli.c | 4 +-- nest/config.Y | 8 +++--- nest/iface.c | 2 +- nest/mrtdump.h | 1 - nest/neighbor.c | 2 +- nest/proto-hooks.c | 2 +- nest/protocol.h | 2 +- nest/route.h | 6 ++--- nest/rt-attr.c | 2 +- nest/rt-dev.c | 10 ++++---- nest/rt-fib.c | 2 +- nest/rt-show.c | 5 ++-- nest/rt-table.c | 10 ++++---- 16 files changed, 63 insertions(+), 65 deletions(-) diff --git a/lib/net.c b/lib/net.c index 9335b78f..3e5d62e2 100644 --- a/lib/net.c +++ b/lib/net.c @@ -6,50 +6,50 @@ const char * const net_label[] = { - [NET_IP4] = "ipv4", - [NET_IP6] = "ipv6", - [NET_VPN4] = "vpn4", - [NET_VPN6] = "vpn6", - [NET_ROA4] = "roa4", - [NET_ROA6] = "roa6", - [NET_FLOW4] = "flow4", - [NET_FLOW6] = "flow6", + [NET_IP4] = "ipv4", + [NET_IP6] = "ipv6", + [NET_VPN4] = "vpn4", + [NET_VPN6] = "vpn6", + [NET_ROA4] = "roa4", + [NET_ROA6] = "roa6", + [NET_FLOW4] = "flow4", + [NET_FLOW6] = "flow6", [NET_MPLS] = "mpls", }; const u16 net_addr_length[] = { - [NET_IP4] = sizeof(net_addr_ip4), - [NET_IP6] = sizeof(net_addr_ip6), - [NET_VPN4] = sizeof(net_addr_vpn4), - [NET_VPN6] = sizeof(net_addr_vpn6), - [NET_ROA4] = sizeof(net_addr_roa4), - [NET_ROA6] = sizeof(net_addr_roa6), - [NET_FLOW4] = 0, - [NET_FLOW6] = 0, + [NET_IP4] = sizeof(net_addr_ip4), + [NET_IP6] = sizeof(net_addr_ip6), + [NET_VPN4] = sizeof(net_addr_vpn4), + [NET_VPN6] = sizeof(net_addr_vpn6), + [NET_ROA4] = sizeof(net_addr_roa4), + [NET_ROA6] = sizeof(net_addr_roa6), + [NET_FLOW4] = 0, + [NET_FLOW6] = 0, [NET_MPLS] = sizeof(net_addr_mpls), }; const u8 net_max_prefix_length[] = { - [NET_IP4] = IP4_MAX_PREFIX_LENGTH, - [NET_IP6] = IP6_MAX_PREFIX_LENGTH, - [NET_VPN4] = IP4_MAX_PREFIX_LENGTH, - [NET_VPN6] = IP6_MAX_PREFIX_LENGTH, - [NET_ROA4] = IP4_MAX_PREFIX_LENGTH, - [NET_ROA6] = IP6_MAX_PREFIX_LENGTH, - [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, - [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, + [NET_IP4] = IP4_MAX_PREFIX_LENGTH, + [NET_IP6] = IP6_MAX_PREFIX_LENGTH, + [NET_VPN4] = IP4_MAX_PREFIX_LENGTH, + [NET_VPN6] = IP6_MAX_PREFIX_LENGTH, + [NET_ROA4] = IP4_MAX_PREFIX_LENGTH, + [NET_ROA6] = IP6_MAX_PREFIX_LENGTH, + [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, + [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, [NET_MPLS] = 0, }; const u16 net_max_text_length[] = { - [NET_IP4] = 18, /* "255.255.255.255/32" */ - [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ - [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ - [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ - [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ - [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ - [NET_FLOW4] = 0, /* "flow4 { ... }" */ - [NET_FLOW6] = 0, /* "flow6 { ... }" */ + [NET_IP4] = 18, /* "255.255.255.255/32" */ + [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ + [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ + [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ + [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ + [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ + [NET_FLOW4] = 0, /* "flow4 { ... }" */ + [NET_FLOW6] = 0, /* "flow6 { ... }" */ [NET_MPLS] = 7, /* "1048575" */ }; diff --git a/nest/a-path.c b/nest/a-path.c index 32ffc72c..c0d16c30 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -810,7 +810,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask) case PM_ASN_RANGE: val = mask->val; val2 = mask->val2; - goto step; + goto step; case PM_QUESTION: step: nh = nl = -1; diff --git a/nest/a-path_test.c b/nest/a-path_test.c index 5e122396..a71b48ba 100644 --- a/nest/a-path_test.c +++ b/nest/a-path_test.c @@ -43,14 +43,14 @@ t_as_path_match(void) bt_debug("Prepending ASN: %10u \n", val); if (i == 0) - first_prepended = val; + first_prepended = val; if (i == AS_PATH_LENGTH-1) - last_prepended = val; + last_prepended = val; mask[i].kind = PM_ASN; mask[i].val = val; if (i) - mask[i].next = &mask[i-1]; + mask[i].next = &mask[i-1]; } bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path"); diff --git a/nest/cli.c b/nest/cli.c index ad81d384..c421cc7e 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -60,7 +60,7 @@ * the new one. When the consumer processes everything in the buffer * queue, it calls cli_written(), tha frees all buffers (except the * first one) and schedules cli.event . - * + * */ #include "nest/bird.h" @@ -136,7 +136,7 @@ cli_printf(cli *c, int code, char *msg, ...) } else if (cd == CLI_ASYNC_CODE) { - size = 1; buf[0] = '+'; + size = 1; buf[0] = '+'; errcode = cd; } else diff --git a/nest/config.Y b/nest/config.Y index 044aba2b..af5114f5 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -151,7 +151,7 @@ CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6) CF_ADDTO(conf, table) table_sorted: - { $$ = 0; } + { $$ = 0; } | SORTED { $$ = 1; } ; @@ -454,9 +454,9 @@ password_item: password_item_begin: PASSWORD text { if (!this_p_list) { - this_p_list = cfg_alloc(sizeof(list)); - init_list(this_p_list); - password_id = 1; + this_p_list = cfg_alloc(sizeof(list)); + init_list(this_p_list); + password_id = 1; } this_p_item = cfg_alloc(sizeof (struct password_item)); this_p_item->password = $2; diff --git a/nest/iface.c b/nest/iface.c index 54c16c58..a633f748 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -317,7 +317,7 @@ if_update(struct iface *new) new->sysdep = i->sysdep; memcpy(&new->addrs, &i->addrs, sizeof(i->addrs)); memcpy(i, new, sizeof(*i)); - i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ + i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ goto newif; } diff --git a/nest/mrtdump.h b/nest/mrtdump.h index 73932553..28b3bdfd 100644 --- a/nest/mrtdump.h +++ b/nest/mrtdump.h @@ -28,4 +28,3 @@ void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len); #endif - diff --git a/nest/neighbor.c b/nest/neighbor.c index fb05d96c..4f93e29e 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -156,7 +156,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) WALK_LIST(i, iface_list) if ((!p->vrf || p->vrf == i->master) && ((scope = if_connected(a, i, &addr)) >= 0)) - { + { ifa = i; break; } diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index 92863f8e..71cddd64 100644 --- a/nest/proto-hooks.c +++ b/nest/proto-hooks.c @@ -281,7 +281,7 @@ int import_control(struct proto *p, rte **e, ea_list **attrs, struct linpool *po /** * rte_recalculate - prepare routes for comparison - * @table: a routing table + * @table: a routing table * @net: a network entry * @new: new route for the network * @old: old route for the network diff --git a/nest/protocol.h b/nest/protocol.h index 9afd3a0a..8a22d76b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -337,7 +337,7 @@ void proto_notify_state(struct proto *p, unsigned state); * * HUNGRY ----> FEEDING * ^ | - * | V + * | V * FLUSHING <---- HAPPY * * States: HUNGRY Protocol either administratively down (i.e., diff --git a/nest/route.h b/nest/route.h index 1c86110b..79127519 100644 --- a/nest/route.h +++ b/nest/route.h @@ -74,7 +74,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e) void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init); void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */ void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */ -void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ +void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */ void fib_delete(struct fib *, void *); /* Remove fib entry */ void fib_free(struct fib *); /* Destroy the fib */ @@ -104,7 +104,7 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin type *z; \ for(;;) { \ if (!fn_) \ - { \ + { \ if (++hpos_ >= count_) \ break; \ fn_ = (fib)->hash_table[hpos_]; \ @@ -663,7 +663,7 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX]; * Default protocol preferences */ -#define DEF_PREF_DIRECT 240 /* Directly connected */ +#define DEF_PREF_DIRECT 240 /* Directly connected */ #define DEF_PREF_STATIC 200 /* Static route */ #define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */ #define DEF_PREF_BABEL 130 /* Babel */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 761ba9fe..881687de 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1204,7 +1204,7 @@ rta_dump(rta *a) static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE", "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", - "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; + "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; debug("p=%s uc=%d %s %s%s h=%04x", diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b3d5bf97..718c4578 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -159,13 +159,13 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src) } struct protocol proto_device = { - .name = "Direct", - .template = "direct%d", + .name = "Direct", + .template = "direct%d", .preference = DEF_PREF_DIRECT, .channel_mask = NB_IP, .proto_size = sizeof(struct rt_dev_proto), .config_size = sizeof(struct rt_dev_config), - .init = dev_init, - .reconfigure = dev_reconfigure, - .copy_config = dev_copy_config + .init = dev_init, + .reconfigure = dev_reconfigure, + .copy_config = dev_copy_config }; diff --git a/nest/rt-fib.c b/nest/rt-fib.c index c09f2759..169d6a4f 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -603,7 +603,7 @@ fib_histogram(struct fib *f) for (e = f->hash_table[i]; e != NULL; e = e->next) j++; if (j > 0) - log(L_WARN "Histogram line %d: %d", i, j); + log(L_WARN "Histogram line %d: %d", i, j); } log(L_WARN "Histogram dump end"); diff --git a/nest/rt-show.c b/nest/rt-show.c index 70dabc1f..1f1b73d2 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -74,7 +74,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm char weight[16] = ""; if (nh->labels) - { + { lsp += bsprintf(lsp, " mpls %d", nh->label[0]); for (int i=1;ilabels; i++) lsp += bsprintf(lsp, "/%d", nh->label[i]); @@ -129,7 +129,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) /* Special case for merged export */ if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) - { + { rte *rt_free; e = rt_export_merged(ec, n, &rt_free, &tmpa, c->show_pool, 1); pass = 1; @@ -419,4 +419,3 @@ rt_show(struct rt_show_data *d) cli_msg(8001, "Network not found"); } } - diff --git a/nest/rt-table.c b/nest/rt-table.c index 784f6cfb..0f53c93f 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -614,9 +614,9 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang old_meet = 1; } - /* + /* * Second, handle the feed case. That means we do not care for - * old_best. It is NULL for feed, and the new_best for refeed. + * old_best. It is NULL for feed, and the new_best for refeed. * For refeed, there is a hack similar to one in rt_notify_basic() * to ensure withdraws in case of changed filters */ @@ -825,7 +825,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed * @new_best: the new best route for the same network * @old_best: the previous best route for the same network * @before_old: The previous route before @old for the same network. - * If @before_old is NULL @old was the first. + * If @before_old is NULL @old was the first. * * This function gets a routing table update and announces it * to all protocols that acccepts given type of route announcement @@ -1387,7 +1387,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) /* Independent call to rte_announce(), used from next hop recalculation, outside of rte_update(). new must be non-NULL */ -static inline void +static inline void rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *new_best, rte *old_best) { @@ -2357,7 +2357,7 @@ if_local_addr(ip_addr a, struct iface *i) return 0; } -static u32 +static u32 rt_get_igp_metric(rte *rt) { eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC); From be17805c0bbd37e865dc9b17b56e8e8d210c2c6c Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 13 Feb 2018 16:27:57 +0100 Subject: [PATCH 14/18] Add support for source-specific IPv6 routes to BIRD core This patch adds support for source-specific IPv6 routes to BIRD core. This is based on Dean Luga's original patch, with the review comments addressed. SADR support is added to network address parsing in confbase.Y and to the kernel protocol on Linux. Currently there is no way to mix source-specific and non-source-specific routes (i.e., SADR tables cannot be connected to non-SADR tables). Thanks to Toke Hoiland-Jorgensen for the original patch. Minor changes by Ondrej Santiago Zajicek. --- conf/confbase.Y | 24 ++++++++++- lib/net.c | 23 +++++++++++ lib/net.h | 90 +++++++++++++++++++++++++++++++++++++----- nest/config.Y | 13 ++++-- nest/rt-fib.c | 2 + nest/rt-table.c | 42 ++++++++++++++++++++ sysdep/cf/linux.h | 1 + sysdep/linux/netlink.c | 43 ++++++++++++++++---- sysdep/unix/krt.c | 25 ++++++++---- 9 files changed, 233 insertions(+), 30 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index 7e0537c5..c2d647eb 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -83,7 +83,7 @@ CF_DECLS %type