diff --git a/filter/filter.c b/filter/filter.c index 4e17f974..42e60a68 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -587,7 +587,8 @@ val_format_str(struct f_val v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define runtime(fmt, ...) do { \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + if (!(f_flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ res.type = T_RETURN; \ res.val.i = F_ERROR; \ return res; \ @@ -903,7 +904,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) { @@ -1793,7 +1795,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 89cd80e6..49004c33 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -208,6 +208,7 @@ 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 */ /* Bird Tests */ struct f_bt_test_suite { diff --git a/nest/rt-show.c b/nest/rt-show.c index 41a141a2..70dabc1f 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -156,7 +156,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(ec->out_filter, &e, &tmpa, c->show_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + (f_run(ec->out_filter, &e, &tmpa, c->show_pool, + FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT); if (do_export != (d->export_mode == RSEM_EXPORT)) goto skip; diff --git a/nest/rt-table.c b/nest/rt-table.c index b0dd6d3f..4640d6a9 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -387,7 +387,8 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpo } 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) @@ -1419,7 +1420,8 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *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) diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 1310582b..30424abb 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -118,6 +118,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 */ int check_link; /* Use iface link state for liveness detection */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 04e6d666..41eaa729 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -32,6 +32,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, %type bgp_afi +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 '}' ) @@ -74,6 +80,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 ';' @@ -117,6 +146,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 95a974eb..aa08732d 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2772,6 +2772,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 diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index cd2558b2..012deaf0 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -958,10 +958,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) @@ -1012,6 +1008,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; } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index bfdbfa4e..e7bd79e3 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -578,7 +578,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;