Link state support in BGP.

Configurable fast shutdown of a BGP session when an interface loses link.
This commit is contained in:
Ondrej Zajicek 2015-02-21 11:46:14 +01:00
parent 7730553b7e
commit 523f020b5f
4 changed files with 83 additions and 47 deletions

View file

@ -1691,6 +1691,13 @@ using the following configuration parameters:
Specifies a table that is used as an IGP routing table. Default: the Specifies a table that is used as an IGP routing table. Default: the
same as the table BGP is connected to. 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> <tag>bfd <M>switch</M></tag>
BGP could use BFD protocol as an advisory mechanism for neighbor BGP could use BFD protocol as an advisory mechanism for neighbor
liveness and failure detection. If enabled, BIRD setups a BFD session liveness and failure detection. If enabled, BIRD setups a BFD session

View file

@ -855,25 +855,43 @@ static void
bgp_neigh_notify(neighbor *n) bgp_neigh_notify(neighbor *n)
{ {
struct bgp_proto *p = (struct bgp_proto *) n->proto; 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; 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)) if (!prepare)
{ {
BGP_TRACE(D_EVENTS, "Neighbor found"); BGP_TRACE(D_EVENTS, "Neighbor lost");
bgp_start_neighbor(p); 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 else
{ {
if ((p->p.proto_state == PS_START) || (p->p.proto_state == PS_UP)) if (prepare)
{ {
BGP_TRACE(D_EVENTS, "Neighbor lost"); BGP_TRACE(D_EVENTS, "Neighbor ready");
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); bgp_start_neighbor(p);
bgp_stop(p, 0);
} }
} }
} }
@ -952,8 +970,8 @@ bgp_start_locked(struct object_lock *lock)
return; return;
} }
p->neigh = neigh_find2(&p->p, &cf->remote_ip, cf->iface, NEF_STICKY); neighbor *n = neigh_find2(&p->p, &cf->remote_ip, cf->iface, NEF_STICKY);
if (!p->neigh || (p->neigh->scope == SCOPE_HOST)) if (!n)
{ {
log(L_ERR "%s: Invalid remote address %I%J", p->p.name, cf->remote_ip, cf->iface); 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 */ /* As we do not start yet, we can just disable protocol */
@ -963,10 +981,14 @@ bgp_start_locked(struct object_lock *lock)
return; return;
} }
if (p->neigh->scope > 0) p->neigh = n;
bgp_start_neighbor(p);
else if (n->scope <= 0)
BGP_TRACE(D_EVENTS, "Waiting for %I%J to become my neighbor", cf->remote_ip, cf->iface); 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 static int
@ -1173,6 +1195,9 @@ bgp_check_config(struct bgp_config *c)
ipa_is_link_local(c->source_addr))) ipa_is_link_local(c->source_addr)))
cf_error("Multihop BGP cannot be used with link-local addresses"); 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)) if (c->multihop && c->bfd && ipa_zero(c->source_addr))
cf_error("Multihop BGP with BFD requires specified source address"); 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_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };
static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""}; 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 char *bgp_auto_errors[] = { "", "Route limit exceeded"};
static const char * static const char *

View file

@ -62,6 +62,7 @@ struct bgp_config {
char *password; /* Password used for MD5 authentication */ char *password; /* Password used for MD5 authentication */
struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ 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 */ 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_NEXT_HOP 2
#define BEM_INVALID_MD5 3 /* MD5 authentication kernel request failed (possibly not supported) */ #define BEM_INVALID_MD5 3 /* MD5 authentication kernel request failed (possibly not supported) */
#define BEM_NO_SOCKET 4 #define BEM_NO_SOCKET 4
#define BEM_BFD_DOWN 5 #define BEM_LINK_DOWN 5
#define BEM_GRACEFUL_RESTART 6 #define BEM_BFD_DOWN 6
#define BEM_GRACEFUL_RESTART 7
/* Automatic shutdown error codes */ /* Automatic shutdown error codes */

View file

@ -26,7 +26,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, 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 CF_GRAMMAR
@ -123,6 +124,7 @@ bgp_proto:
| bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; } | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $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); } | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
; ;