From 523f020b5f6b63096a7d5e90938baecd4beea0bd Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 21 Feb 2015 11:46:14 +0100 Subject: [PATCH] Link state support in BGP. Configurable fast shutdown of a BGP session when an interface loses link. --- doc/bird.sgml | 53 +++++++++++++++++++++---------------- proto/bgp/bgp.c | 65 ++++++++++++++++++++++++++++++++-------------- proto/bgp/bgp.h | 6 +++-- proto/bgp/config.Y | 6 +++-- 4 files changed, 83 insertions(+), 47 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 2ef3a24b..1ba52481 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -316,20 +316,20 @@ protocol rip { Global options

- include " + include " This statement causes inclusion of a new file.

Filters support two control structures: conditions and case switches. +

Filters support two control structures: conditions and case switches.

Syntax of a condition is: if boolean expression then and you can use { @@ -1267,7 +1267,7 @@ clist for most purposes. The router which the route has originated from. - + Next hop packets routed using this route should be forwarded to. @@ -1448,7 +1448,7 @@ protocol bfd [<name>] { BFD sessions are usually created on demand as requested by other protocols (like OSPF or BGP). This option allows to explicitly add a BFD session to the specified neighbor regardless of such requests. - + The session is identified by the IP address of the neighbor, with optional specification of used interface and local IP. By default the neighbor must be directly connected, unless the the session is @@ -1559,13 +1559,13 @@ MD5 password authentication (RFC 2385), extended communities (RFC 4360), -route reflectors +route reflectors (RFC 4456), graceful restart (RFC 4724), multiprotocol extensions (RFC 4760), -4B AS numbers +4B AS numbers (RFC 4893), and 4B AS numbers in extended communities (RFC 5668). @@ -1691,6 +1691,13 @@ using the following configuration parameters: Specifies a table that is used as an IGP routing table. Default: the same as the table BGP is connected to. + check link switch + BGP could use hardware link state into consideration. If enabled, + BIRD tracks the link state of the associated interface and when link + disappears (e.g. an ethernet cable is unplugged), the BGP session is + immediately shut down. Note that this option cannot be used with + multihop BGP. Default: disabled. + bfd switch BGP could use BFD protocol as an advisory mechanism for neighbor liveness and failure detection. If enabled, BIRD setups a BFD session @@ -1709,7 +1716,7 @@ using the following configuration parameters: (IPv4), 2.6.35+ (IPv6), BSD: since long ago, IPv4 only. Note that full (ICMP protection, for example) RFC 5082 support is provided by Linux only. Default: disabled. - + password Use this password for MD5 authentication of BGP sessions. Default: no authentication. Password has to be set by external utility @@ -1732,7 +1739,7 @@ using the following configuration parameters: id. Clients in a cluster need not know their cluster id and this option is not allowed for them. Default: the same as router id. - rs client + rs client Be a route server and treat the neighbor as a route server client. A route server is used as a replacement for full mesh EBGP routing in Internet exchange points in a similar way to route reflectors used in @@ -1760,7 +1767,7 @@ using the following configuration parameters: TX direction. When active, all available routes accepted by the export filter are advertised to the neighbor. Default: off. - allow local as [ + allow local as [ BGP prevents routing loops by rejecting received routes with the local AS number in the AS path. This option allows to loose or disable the check. Optional bgp; - + BGP_TRACE(D_EVENTS, "BGP session established"); DBG("BGP: UP!!!\n"); @@ -828,7 +828,7 @@ bgp_start_neighbor(struct bgp_proto *p) /* Called only for single-hop BGP sessions */ if (ipa_zero(p->source_addr)) - p->source_addr = p->neigh->ifa->ip; + p->source_addr = p->neigh->ifa->ip; #ifdef IPV6 { @@ -855,25 +855,43 @@ static void bgp_neigh_notify(neighbor *n) { struct bgp_proto *p = (struct bgp_proto *) n->proto; + int ps = p->p.proto_state; - if (! (n->flags & NEF_STICKY)) + if (n != p->neigh) return; - if (n->scope > 0) + if ((ps == PS_DOWN) || (ps == PS_STOP)) + return; + + int prepare = (ps == PS_START) && (p->start_state == BSS_PREPARE); + + if (n->scope <= 0) { - if ((p->p.proto_state == PS_START) && (p->start_state == BSS_PREPARE)) - { - BGP_TRACE(D_EVENTS, "Neighbor found"); - bgp_start_neighbor(p); + if (!prepare) + { + BGP_TRACE(D_EVENTS, "Neighbor lost"); + bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); + /* Perhaps also run bgp_update_startup_delay(p)? */ + bgp_stop(p, 0); + } + } + else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) + { + if (!prepare) + { + BGP_TRACE(D_EVENTS, "Link down"); + bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN); + if (ps == PS_UP) + bgp_update_startup_delay(p); + bgp_stop(p, 0); } } else { - if ((p->p.proto_state == PS_START) || (p->p.proto_state == PS_UP)) + if (prepare) { - BGP_TRACE(D_EVENTS, "Neighbor lost"); - bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); - bgp_stop(p, 0); + BGP_TRACE(D_EVENTS, "Neighbor ready"); + bgp_start_neighbor(p); } } } @@ -952,8 +970,8 @@ bgp_start_locked(struct object_lock *lock) return; } - p->neigh = neigh_find2(&p->p, &cf->remote_ip, cf->iface, NEF_STICKY); - if (!p->neigh || (p->neigh->scope == SCOPE_HOST)) + neighbor *n = neigh_find2(&p->p, &cf->remote_ip, cf->iface, NEF_STICKY); + if (!n) { log(L_ERR "%s: Invalid remote address %I%J", p->p.name, cf->remote_ip, cf->iface); /* As we do not start yet, we can just disable protocol */ @@ -962,11 +980,15 @@ bgp_start_locked(struct object_lock *lock) proto_notify_state(&p->p, PS_DOWN); return; } - - if (p->neigh->scope > 0) - bgp_start_neighbor(p); - else + + p->neigh = n; + + if (n->scope <= 0) BGP_TRACE(D_EVENTS, "Waiting for %I%J to become my neighbor", cf->remote_ip, cf->iface); + else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) + BGP_TRACE(D_EVENTS, "Waiting for link on %s", n->iface->name); + else + bgp_start_neighbor(p); } static int @@ -1173,6 +1195,9 @@ bgp_check_config(struct bgp_config *c) ipa_is_link_local(c->source_addr))) cf_error("Multihop BGP cannot be used with link-local addresses"); + if (c->multihop && c->check_link) + cf_error("Multihop BGP cannot depend on link state"); + if (c->multihop && c->bfd && ipa_zero(c->source_addr)) cf_error("Multihop BGP with BFD requires specified source address"); @@ -1288,7 +1313,7 @@ bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code) static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" }; static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""}; -static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket", "BFD session down", "Graceful restart"}; +static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket", "Link down", "BFD session down", "Graceful restart"}; static char *bgp_auto_errors[] = { "", "Route limit exceeded"}; static const char * @@ -1396,7 +1421,7 @@ bgp_show_proto_info(struct proto *P) tm_remains(c->keepalive_timer), c->keepalive_time); } - if ((p->last_error_class != BE_NONE) && + if ((p->last_error_class != BE_NONE) && (p->last_error_class != BE_MAN_DOWN)) { const char *err1 = bgp_err_classes[p->last_error_class]; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 0fd3a73c..ec0b99c5 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -62,6 +62,7 @@ struct bgp_config { char *password; /* Password used for MD5 authentication */ struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ + int check_link; /* Use iface link state for liveness detection */ int bfd; /* Use BFD for liveness detection */ }; @@ -335,8 +336,9 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi #define BEM_INVALID_NEXT_HOP 2 #define BEM_INVALID_MD5 3 /* MD5 authentication kernel request failed (possibly not supported) */ #define BEM_NO_SOCKET 4 -#define BEM_BFD_DOWN 5 -#define BEM_GRACEFUL_RESTART 6 +#define BEM_LINK_DOWN 5 +#define BEM_BFD_DOWN 6 +#define BEM_GRACEFUL_RESTART 7 /* Automatic shutdown error codes */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index c8345530..e4875b27 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -26,7 +26,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, - SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE) + SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, + CHECK, LINK) CF_GRAMMAR @@ -97,7 +98,7 @@ bgp_proto: | bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; } | bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->source_addr = $4; } | bgp_proto START DELAY TIME expr ';' { BGP_CFG->start_delay_time = $5; } - | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } + | 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 ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; } @@ -123,6 +124,7 @@ bgp_proto: | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; } + | bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; } | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); } ;