From 0ff86d054efa8005c5df943acf6d2122781d3175 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 3 Jan 2018 14:12:00 +0100 Subject: [PATCH 1/4] 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 2/4] 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 3/4] 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 d6cf996151307d083c30e4ecde0f1d7449b19253 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 23 Jan 2018 17:05:45 +0100 Subject: [PATCH 4/4] 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; }