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