diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2015-02-21 11:46:14 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2015-02-21 12:15:56 +0100 |
commit | 523f020b5f6b63096a7d5e90938baecd4beea0bd (patch) | |
tree | 5ef693c4ff8796db958df1720ff73a6cdde9c2c8 | |
parent | 7730553b7eeb33d21e5597f110334ca584ad532d (diff) |
Link state support in BGP.
Configurable fast shutdown of a BGP session when an interface loses link.
-rw-r--r-- | doc/bird.sgml | 53 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 65 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 6 | ||||
-rw-r--r-- | 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 { <sect>Global options <p><descrip> - <tag>include "<m/filename/"</tag> + <tag>include "<m/filename/"</tag> This statement causes inclusion of a new file. <m/Filename/ could also be a wildcard. The maximal depth is 8. Note that this statement could be used anywhere in the config file, not just as a top-level option. - <tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> + <tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> Set logging of messages having the given class (either <cf/all/ or <cf/{ error, trace }/ etc.) into selected destination (a file specified as a filename string, syslog with optional name argument, or the stderr output). Classes are: <cf/info/, <cf/warning/, <cf/error/ and <cf/fatal/ for messages about local problems, - <cf/debug/ for debugging messages, - <cf/trace/ when you want to know what happens in the network, - <cf/remote/ for messages about misbehavior of remote machines, + <cf/debug/ for debugging messages, + <cf/trace/ when you want to know what happens in the network, + <cf/remote/ for messages about misbehavior of remote machines, <cf/auth/ about authentication failures, <cf/bug/ for internal BIRD bugs. You may specify more than one <cf/log/ line to establish logging to @@ -358,7 +358,7 @@ protocol rip { <tag>function <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag> Define a function. You can learn more about functions in the following chapter. - + <tag>protocol rip|ospf|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag> Define a protocol instance called <cf><m/name/</cf> (or with a name like "rip5" generated automatically if you don't specify any @@ -508,7 +508,7 @@ agreement"). This option can be used to override global router id for a given protocol. Default: uses global router id. - <tag>import all | none | filter <m/name/ | filter { <m/filter commands/ } | where <m/filter expression/</tag> + <tag>import all | none | filter <m/name/ | filter { <m/filter commands/ } | where <m/filter expression/</tag> Specify a filter to be used for filtering routes coming from the protocol to the routing table. <cf/all/ is shorthand for <cf/where true/ and <cf/none/ is shorthand for <cf/where false/. Default: <cf/all/. @@ -586,7 +586,7 @@ agreement"). An interface option can be used more times with different interface-specific options, in that case for given interface the first matching interface option is used. - + This option is allowed in BFD, Direct, OSPF, RAdv and RIP protocols, but in OSPF protocol it is used in the <cf/area/ subsection. @@ -599,7 +599,7 @@ agreement"). <cf>interface "eth1", "eth4", "eth5" { type ptp; };</cf> - start the protocol on enumerated interfaces with <cf>type ptp</cf> option. - + <cf>interface -192.168.1.0/24, 192.168.0.0/16;</cf> - start the protocol on all interfaces that have address from 192.168.0.0/16, but not from 192.168.1.0/24. @@ -632,7 +632,7 @@ agreement"). used. Specifying passwords does not mean that authentication is enabled, authentication can be enabled by separate, protocol-dependent <cf/authentication/ option. - + This option is allowed in OSPF and RIP protocols. BGP has also <cf/password/ option, but it is slightly different and described separately. @@ -1085,7 +1085,7 @@ foot). is true, but <cf>1.0.0.0/16 ˜ [ 1.0.0.0/8- ]</cf> is false. Cisco-style patterns like <cf>10.0.0.0/8 ge 16 le 24</cf> can be expressed - in BIRD as <cf>10.0.0.0/8{16,24}</cf>, <cf>192.168.0.0/16 le 24</cf> as + in BIRD as <cf>10.0.0.0/8{16,24}</cf>, <cf>192.168.0.0/16 le 24</cf> as <cf>192.168.0.0/16{16,24}</cf> and <cf>192.168.0.0/16 ge 24</cf> as <cf>192.168.0.0/16{24,32}</cf>. @@ -1129,7 +1129,7 @@ foot). ˜ [= 2 3 5 * =]</cf> syntax). The masks resemble wildcard patterns as used by UNIX shells. Autonomous system numbers match themselves, <cf/*/ matches any (even empty) sequence of arbitrary AS numbers and - <cf/?/ matches one arbitrary AS number. For example, if <cf>bgp_path</cf> + <cf/?/ matches one arbitrary AS number. For example, if <cf>bgp_path</cf> is 4 3 2 1, then: <tt>bgp_path ˜ [= * 4 3 * =]</tt> is true, but <tt>bgp_path ˜ [= * 4 5 * =]</tt> is false. BGP mask expressions can also contain integer expressions enclosed in parenthesis @@ -1206,7 +1206,7 @@ prefix and an ASN as arguments. <sect>Control structures -<p>Filters support two control structures: conditions and case switches. +<p>Filters support two control structures: conditions and case switches. <p>Syntax of a condition is: <cf>if <M>boolean expression</M> then <m/command1/; else <m/command2/;</cf> and you can use <cf>{ <m/command_1/; <m/command_2/; @@ -1232,9 +1232,9 @@ case arg1 { else: print "something else"; } -if 1234 = i then printn "."; else { - print "not 1234"; - print "You need {} around multiple commands"; +if 1234 = i then printn "."; else { + print "not 1234"; + print "You need {} around multiple commands"; } </code> @@ -1267,7 +1267,7 @@ clist for most purposes. <tag><m/ip/ from</tag> The router which the route has originated from. - + <tag><m/ip/ gw</tag> 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<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2385.txt">), extended communities (RFC 4360<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4360.txt">), -route reflectors +route reflectors (RFC 4456<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4456.txt">), graceful restart (RFC 4724<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4724.txt">), multiprotocol extensions (RFC 4760<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4760.txt">), -4B AS numbers +4B AS numbers (RFC 4893<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4893.txt">), and 4B AS numbers in extended communities (RFC 5668<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc5668.txt">). @@ -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. + <tag>check link <M>switch</M></tag> + 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. + <tag>bfd <M>switch</M></tag> 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. - + <tag>password <m/string/</tag> 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. - <tag>rs client</tag> + <tag>rs client</tag> 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. - <tag>allow local as [<m/number/]</tag> + <tag>allow local as [<m/number/]</tag> 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 <cf/number/ argument can be used to specify the maximum diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 27825d7f..3feffbd9 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -366,7 +366,7 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn) { struct bgp_proto *p = conn->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 != p->neigh) + return; - if (! (n->flags & NEF_STICKY)) + if ((ps == PS_DOWN) || (ps == PS_STOP)) return; - if (n->scope > 0) + 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); } ; |