summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2015-02-21 11:46:14 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2015-02-21 12:15:56 +0100
commit523f020b5f6b63096a7d5e90938baecd4beea0bd (patch)
tree5ef693c4ff8796db958df1720ff73a6cdde9c2c8 /proto/bgp
parent7730553b7eeb33d21e5597f110334ca584ad532d (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.c65
-rw-r--r--proto/bgp/bgp.h6
-rw-r--r--proto/bgp/config.Y6
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); }
;