summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_fsm.c
diff options
context:
space:
mode:
authorDavid Schweizer <dschweizer@opensourcerouting.org>2020-10-20 16:49:58 +0200
committerDavid Schweizer <dschweizer@opensourcerouting.org>2020-10-20 16:49:58 +0200
commit6c537a18cffeee854a3f80cef1fb459d85f37a15 (patch)
tree414f15c8399655cd10bc113876c957e329831e30 /bgpd/bgp_fsm.c
parentMerge pull request #7645 from sworleys/NHG-IFP-Error2Log (diff)
downloadfrr-6c537a18cffeee854a3f80cef1fb459d85f37a15.tar.xz
frr-6c537a18cffeee854a3f80cef1fb459d85f37a15.zip
bgpd: RFC 4271 DelayOpenTimer
Changes implement the DelayOpenTimer functionality proposed in RFC 4271. Signed-off-by: David Schweizer <dschweizer@opensourcerouting.org>
Diffstat (limited to 'bgpd/bgp_fsm.c')
-rw-r--r--bgpd/bgp_fsm.c177
1 files changed, 161 insertions, 16 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index dd31a9b7c..ce665feb4 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -67,12 +67,14 @@ static const char *const bgp_event_str[] = {
"BGP_Start",
"BGP_Stop",
"TCP_connection_open",
+ "TCP_connection_open_w_delay",
"TCP_connection_closed",
"TCP_connection_open_failed",
"TCP_fatal_error",
"ConnectRetry_timer_expired",
"Hold_Timer_expired",
"KeepAlive_timer_expired",
+ "DelayOpen_timer_expired",
"Receive_OPEN_message",
"Receive_KEEPALIVE_message",
"Receive_UPDATE_message",
@@ -92,6 +94,7 @@ int bgp_event(struct thread *);
static int bgp_start_timer(struct thread *);
static int bgp_connect_timer(struct thread *);
static int bgp_holdtime_timer(struct thread *);
+static int bgp_delayopen_timer(struct thread *);
/* BGP FSM functions. */
static int bgp_start(struct peer *);
@@ -174,10 +177,12 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_connect);
+ BGP_TIMER_OFF(peer->t_delayopen);
BGP_TIMER_OFF(peer->t_connect_check_r);
BGP_TIMER_OFF(peer->t_connect_check_w);
BGP_TIMER_OFF(from_peer->t_routeadv);
BGP_TIMER_OFF(from_peer->t_connect);
+ BGP_TIMER_OFF(from_peer->t_delayopen);
BGP_TIMER_OFF(from_peer->t_connect_check_r);
BGP_TIMER_OFF(from_peer->t_connect_check_w);
BGP_TIMER_OFF(from_peer->t_process_packet);
@@ -233,6 +238,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
peer->v_holdtime = from_peer->v_holdtime;
peer->v_keepalive = from_peer->v_keepalive;
peer->v_routeadv = from_peer->v_routeadv;
+ peer->v_delayopen = from_peer->v_delayopen;
peer->v_gr_restart = from_peer->v_gr_restart;
peer->cap = from_peer->cap;
status = peer->status;
@@ -364,6 +370,7 @@ void bgp_timer_set(struct peer *peer)
BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_OFF(peer->t_delayopen);
break;
case Connect:
@@ -371,8 +378,13 @@ void bgp_timer_set(struct peer *peer)
status. Make sure start timer is off and connect timer is
on. */
BGP_TIMER_OFF(peer->t_start);
- BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
- peer->v_connect);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+ BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+ (peer->v_delayopen + peer->v_connect));
+ else
+ BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+ peer->v_connect);
+
BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv);
@@ -387,8 +399,13 @@ void bgp_timer_set(struct peer *peer)
|| CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
BGP_TIMER_OFF(peer->t_connect);
} else {
- BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
- peer->v_connect);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+ BGP_TIMER_ON(
+ peer->t_connect, bgp_connect_timer,
+ (peer->v_delayopen + peer->v_connect));
+ else
+ BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
+ peer->v_connect);
}
BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
@@ -407,6 +424,7 @@ void bgp_timer_set(struct peer *peer)
}
bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_OFF(peer->t_delayopen);
break;
case OpenConfirm:
@@ -425,6 +443,7 @@ void bgp_timer_set(struct peer *peer)
bgp_keepalives_on(peer);
}
BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_OFF(peer->t_delayopen);
break;
case Established:
@@ -432,6 +451,7 @@ void bgp_timer_set(struct peer *peer)
off. */
BGP_TIMER_OFF(peer->t_start);
BGP_TIMER_OFF(peer->t_connect);
+ BGP_TIMER_OFF(peer->t_delayopen);
/* Same as OpenConfirm, if holdtime is zero then both holdtime
and keepalive must be turned off. */
@@ -455,6 +475,7 @@ void bgp_timer_set(struct peer *peer)
BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_OFF(peer->t_delayopen);
break;
case BGP_STATUS_MAX:
flog_err(EC_LIB_DEVELOPMENT,
@@ -488,6 +509,10 @@ static int bgp_connect_timer(struct thread *thread)
peer = THREAD_ARG(thread);
+ /* stop the DelayOpenTimer if it is running */
+ if (peer->t_delayopen)
+ BGP_TIMER_OFF(peer->t_delayopen);
+
assert(!peer->t_write);
assert(!peer->t_read);
@@ -564,6 +589,23 @@ int bgp_routeadv_timer(struct thread *thread)
return 0;
}
+/* RFC 4271 DelayOpenTimer */
+int bgp_delayopen_timer(struct thread *thread)
+{
+ struct peer *peer;
+
+ peer = THREAD_ARG(thread);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s [FSM] Timer (DelayOpentimer expire)",
+ peer->host);
+
+ THREAD_VAL(thread) = DelayOpen_timer_expired;
+ bgp_event(thread); /* bgp_event unlocks peer */
+
+ return 0;
+}
+
/* BGP Peer Down Cause */
const char *const peer_down_str[] = {"",
"Router ID changed",
@@ -1299,6 +1341,7 @@ int bgp_stop(struct peer *peer)
BGP_TIMER_OFF(peer->t_connect);
BGP_TIMER_OFF(peer->t_holdtime);
BGP_TIMER_OFF(peer->t_routeadv);
+ BGP_TIMER_OFF(peer->t_delayopen);
/* Clear input and output buffer. */
frr_with_mutex(&peer->io_mtx) {
@@ -1357,6 +1400,12 @@ int bgp_stop(struct peer *peer)
peer->v_holdtime = peer->bgp->default_holdtime;
}
+ /* Reset DelayOpenTime */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+ peer->v_delayopen = peer->delayopen;
+ else
+ peer->v_delayopen = peer->bgp->default_delayopen;
+
peer->update_time = 0;
/* Until we are sure that there is no problem about prefix count
@@ -1469,7 +1518,10 @@ static int bgp_connect_check(struct thread *thread)
/* When status is 0 then TCP connection is established. */
if (status == 0) {
- BGP_EVENT_ADD(peer, TCP_connection_open);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN))
+ BGP_EVENT_ADD(peer, TCP_connection_open_w_delay);
+ else
+ BGP_EVENT_ADD(peer, TCP_connection_open);
return 1;
} else {
if (bgp_debug_neighbor_events(peer))
@@ -1516,11 +1568,63 @@ static int bgp_connect_success(struct peer *peer)
zlog_debug("%s passive open", peer->host);
}
+ /* Send an open message */
bgp_open_send(peer);
return 0;
}
+/* TCP connection open with RFC 4271 optional session attribute DelayOpen flag
+ * set.
+ */
+static int bgp_connect_success_w_delayopen(struct peer *peer)
+{
+ if (peer->fd < 0) {
+ flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d",
+ __func__, peer->fd);
+ bgp_stop(peer);
+ return -1;
+ }
+
+ if (bgp_getsockname(peer) < 0) {
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: bgp_getsockname(): failed for peer %s, fd %d",
+ __func__, peer->host, peer->fd);
+ bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
+ bgp_fsm_error_subcode(peer->status));
+ bgp_writes_on(peer);
+ return -1;
+ }
+
+ bgp_reads_on(peer);
+
+ if (bgp_debug_neighbor_events(peer)) {
+ char buf1[SU_ADDRSTRLEN];
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ zlog_debug("%s open active, local address %s",
+ peer->host,
+ sockunion2str(peer->su_local, buf1,
+ SU_ADDRSTRLEN));
+ else
+ zlog_debug("%s passive open", peer->host);
+ }
+
+ /* set the DelayOpenTime to the inital value */
+ peer->v_delayopen = peer->delayopen;
+
+ /* Start the DelayOpenTimer if it is not already running */
+ if (!peer->t_delayopen)
+ BGP_TIMER_ON(peer->t_delayopen, bgp_delayopen_timer,
+ peer->v_delayopen);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds",
+ peer->host, peer->delayopen);
+
+ return 0;
+}
+
/* TCP connect fail */
static int bgp_connect_fail(struct peer *peer)
{
@@ -1535,7 +1639,8 @@ static int bgp_connect_fail(struct peer *peer)
}
/* This function is the first starting point of all BGP connection. It
- try to connect to remote peer with non-blocking IO. */
+ * try to connect to remote peer with non-blocking IO.
+ */
int bgp_start(struct peer *peer)
{
int status;
@@ -1633,6 +1738,7 @@ int bgp_start(struct peer *peer)
zlog_debug(
"%s [FSM] Connect immediately success, fd %d",
peer->host, peer->fd);
+
BGP_EVENT_ADD(peer, TCP_connection_open);
break;
case connect_in_progress:
@@ -1682,6 +1788,10 @@ static int bgp_reconnect(struct peer *peer)
static int bgp_fsm_open(struct peer *peer)
{
+ /* If DelayOpen is active, we may still need to send an open message */
+ if ((peer->status == Connect) || (peer->status == Active))
+ bgp_open_send(peer);
+
/* Send keepalive and make keepalive timer */
bgp_keepalive_send(peer);
@@ -1709,6 +1819,21 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
}
+/* RFC 4271 DelayOpenTimer_Expires event */
+static int bgp_fsm_delayopen_timer_expire(struct peer *peer)
+{
+ /* Stop the DelayOpenTimer */
+ BGP_TIMER_OFF(peer->t_delayopen);
+
+ /* Send open message to peer */
+ bgp_open_send(peer);
+
+ /* Set the HoldTimer to a large value (4 minutes) */
+ peer->v_holdtime = 245;
+
+ return 0;
+}
+
/* Start the selection deferral timer thread for the specified AFI, SAFI */
static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
struct graceful_restart_info *gr_info)
@@ -2089,12 +2214,14 @@ static const struct {
{bgp_start, Connect}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Idle}, /* TCP_connection_open */
+ {bgp_stop, Idle}, /* TCP_connection_open_w_delay */
{bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_ignore, Idle}, /* TCP_connection_open_failed */
{bgp_stop, Idle}, /* TCP_fatal_error */
{bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
{bgp_ignore, Idle}, /* Hold_Timer_expired */
{bgp_ignore, Idle}, /* KeepAlive_timer_expired */
+ {bgp_ignore, Idle}, /* DelayOpen_timer_expired */
{bgp_ignore, Idle}, /* Receive_OPEN_message */
{bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
{bgp_ignore, Idle}, /* Receive_UPDATE_message */
@@ -2106,46 +2233,56 @@ static const struct {
{bgp_ignore, Connect}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
+ {bgp_connect_success_w_delayopen,
+ Connect}, /* TCP_connection_open_w_delay */
{bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_connect_fail, Active}, /* TCP_connection_open_failed */
{bgp_connect_fail, Idle}, /* TCP_fatal_error */
{bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
{bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_delayopen_timer_expire,
+ OpenSent}, /* DelayOpen_timer_expired */
+ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
+ {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
+ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
},
{
/* Active, */
{bgp_ignore, Active}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */
+ {bgp_connect_success_w_delayopen,
+ Active}, /* TCP_connection_open_w_delay */
{bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_ignore, Active}, /* TCP_connection_open_failed */
{bgp_fsm_exeption, Idle}, /* TCP_fatal_error */
{bgp_start, Connect}, /* ConnectRetry_timer_expired */
{bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
- {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
- {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
- {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
- {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
+ {bgp_fsm_delayopen_timer_expire,
+ OpenSent}, /* DelayOpen_timer_expired */
+ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
+ {bgp_fsm_exeption, Idle}, /* Receive_KEEPALIVE_message */
+ {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
+ {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
+ {bgp_fsm_exeption, Idle}, /* Clearing_Completed */
},
{
/* OpenSent, */
{bgp_ignore, OpenSent}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Active}, /* TCP_connection_open */
+ {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
{bgp_stop, Active}, /* TCP_connection_closed */
{bgp_stop, Active}, /* TCP_connection_open_failed */
{bgp_stop, Active}, /* TCP_fatal_error */
{bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
{bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
{bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */
{bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */
@@ -2157,12 +2294,14 @@ static const struct {
{bgp_ignore, OpenConfirm}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Idle}, /* TCP_connection_open */
+ {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
{bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_stop, Idle}, /* TCP_connection_open_failed */
{bgp_stop, Idle}, /* TCP_fatal_error */
{bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
{bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
{bgp_establish, Established}, /* Receive_KEEPALIVE_message */
{bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
@@ -2174,12 +2313,14 @@ static const struct {
{bgp_ignore, Established}, /* BGP_Start */
{bgp_stop, Clearing}, /* BGP_Stop */
{bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_fsm_exeption, Idle}, /* TCP_connection_open_w_delay */
{bgp_stop, Clearing}, /* TCP_connection_closed */
{bgp_stop, Clearing}, /* TCP_connection_open_failed */
{bgp_stop, Clearing}, /* TCP_fatal_error */
{bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
{bgp_ignore, Established}, /* KeepAlive_timer_expired */
+ {bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
{bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_fsm_keepalive,
Established}, /* Receive_KEEPALIVE_message */
@@ -2193,12 +2334,14 @@ static const struct {
{bgp_ignore, Clearing}, /* BGP_Start */
{bgp_stop, Clearing}, /* BGP_Stop */
{bgp_stop, Clearing}, /* TCP_connection_open */
+ {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */
{bgp_stop, Clearing}, /* TCP_connection_closed */
{bgp_stop, Clearing}, /* TCP_connection_open_failed */
{bgp_stop, Clearing}, /* TCP_fatal_error */
{bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_stop, Clearing}, /* Hold_Timer_expired */
{bgp_stop, Clearing}, /* KeepAlive_timer_expired */
+ {bgp_stop, Clearing}, /* DelayOpen_timer_expired */
{bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
{bgp_stop, Clearing}, /* Receive_UPDATE_message */
@@ -2210,12 +2353,14 @@ static const struct {
{bgp_ignore, Deleted}, /* BGP_Start */
{bgp_ignore, Deleted}, /* BGP_Stop */
{bgp_ignore, Deleted}, /* TCP_connection_open */
+ {bgp_ignore, Deleted}, /* TCP_connection_open_w_delay */
{bgp_ignore, Deleted}, /* TCP_connection_closed */
{bgp_ignore, Deleted}, /* TCP_connection_open_failed */
{bgp_ignore, Deleted}, /* TCP_fatal_error */
{bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */
{bgp_ignore, Deleted}, /* Hold_Timer_expired */
{bgp_ignore, Deleted}, /* KeepAlive_timer_expired */
+ {bgp_ignore, Deleted}, /* DelayOpen_timer_expired */
{bgp_ignore, Deleted}, /* Receive_OPEN_message */
{bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */
{bgp_ignore, Deleted}, /* Receive_UPDATE_message */