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 /proto/bgp | |
parent | 7730553b7eeb33d21e5597f110334ca584ad532d (diff) |
Link state support in BGP.
Configurable fast shutdown of a BGP session when an interface loses link.
Diffstat (limited to 'proto/bgp')
-rw-r--r-- | proto/bgp/bgp.c | 65 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 6 | ||||
-rw-r--r-- | proto/bgp/config.Y | 6 |
3 files changed, 53 insertions, 24 deletions
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); } ; |