bgpd: RFC 4271 DelayOpenTimer

Changes implement the DelayOpenTimer functionality proposed in RFC 4271.

Signed-off-by: David Schweizer <dschweizer@opensourcerouting.org>
This commit is contained in:
David Schweizer 2020-10-20 16:49:58 +02:00
parent b238167a9b
commit 6c537a18cf
No known key found for this signature in database
GPG Key ID: A07D97BEEE79EF7F
5 changed files with 292 additions and 25 deletions

View File

@ -67,12 +67,14 @@ static const char *const bgp_event_str[] = {
"BGP_Start", "BGP_Start",
"BGP_Stop", "BGP_Stop",
"TCP_connection_open", "TCP_connection_open",
"TCP_connection_open_w_delay",
"TCP_connection_closed", "TCP_connection_closed",
"TCP_connection_open_failed", "TCP_connection_open_failed",
"TCP_fatal_error", "TCP_fatal_error",
"ConnectRetry_timer_expired", "ConnectRetry_timer_expired",
"Hold_Timer_expired", "Hold_Timer_expired",
"KeepAlive_timer_expired", "KeepAlive_timer_expired",
"DelayOpen_timer_expired",
"Receive_OPEN_message", "Receive_OPEN_message",
"Receive_KEEPALIVE_message", "Receive_KEEPALIVE_message",
"Receive_UPDATE_message", "Receive_UPDATE_message",
@ -92,6 +94,7 @@ int bgp_event(struct thread *);
static int bgp_start_timer(struct thread *); static int bgp_start_timer(struct thread *);
static int bgp_connect_timer(struct thread *); static int bgp_connect_timer(struct thread *);
static int bgp_holdtime_timer(struct thread *); static int bgp_holdtime_timer(struct thread *);
static int bgp_delayopen_timer(struct thread *);
/* BGP FSM functions. */ /* BGP FSM functions. */
static int bgp_start(struct peer *); 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_routeadv);
BGP_TIMER_OFF(peer->t_connect); 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_r);
BGP_TIMER_OFF(peer->t_connect_check_w); BGP_TIMER_OFF(peer->t_connect_check_w);
BGP_TIMER_OFF(from_peer->t_routeadv); BGP_TIMER_OFF(from_peer->t_routeadv);
BGP_TIMER_OFF(from_peer->t_connect); 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_r);
BGP_TIMER_OFF(from_peer->t_connect_check_w); BGP_TIMER_OFF(from_peer->t_connect_check_w);
BGP_TIMER_OFF(from_peer->t_process_packet); 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_holdtime = from_peer->v_holdtime;
peer->v_keepalive = from_peer->v_keepalive; peer->v_keepalive = from_peer->v_keepalive;
peer->v_routeadv = from_peer->v_routeadv; peer->v_routeadv = from_peer->v_routeadv;
peer->v_delayopen = from_peer->v_delayopen;
peer->v_gr_restart = from_peer->v_gr_restart; peer->v_gr_restart = from_peer->v_gr_restart;
peer->cap = from_peer->cap; peer->cap = from_peer->cap;
status = peer->status; status = peer->status;
@ -364,6 +370,7 @@ void bgp_timer_set(struct peer *peer)
BGP_TIMER_OFF(peer->t_holdtime); BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer); bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_delayopen);
break; break;
case Connect: case Connect:
@ -371,8 +378,13 @@ void bgp_timer_set(struct peer *peer)
status. Make sure start timer is off and connect timer is status. Make sure start timer is off and connect timer is
on. */ on. */
BGP_TIMER_OFF(peer->t_start); BGP_TIMER_OFF(peer->t_start);
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, BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
peer->v_connect); peer->v_connect);
BGP_TIMER_OFF(peer->t_holdtime); BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer); bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
@ -387,6 +399,11 @@ void bgp_timer_set(struct peer *peer)
|| CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { || CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) {
BGP_TIMER_OFF(peer->t_connect); BGP_TIMER_OFF(peer->t_connect);
} else { } else {
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, BGP_TIMER_ON(peer->t_connect, bgp_connect_timer,
peer->v_connect); peer->v_connect);
} }
@ -407,6 +424,7 @@ void bgp_timer_set(struct peer *peer)
} }
bgp_keepalives_off(peer); bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_delayopen);
break; break;
case OpenConfirm: case OpenConfirm:
@ -425,6 +443,7 @@ void bgp_timer_set(struct peer *peer)
bgp_keepalives_on(peer); bgp_keepalives_on(peer);
} }
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_delayopen);
break; break;
case Established: case Established:
@ -432,6 +451,7 @@ void bgp_timer_set(struct peer *peer)
off. */ off. */
BGP_TIMER_OFF(peer->t_start); BGP_TIMER_OFF(peer->t_start);
BGP_TIMER_OFF(peer->t_connect); BGP_TIMER_OFF(peer->t_connect);
BGP_TIMER_OFF(peer->t_delayopen);
/* Same as OpenConfirm, if holdtime is zero then both holdtime /* Same as OpenConfirm, if holdtime is zero then both holdtime
and keepalive must be turned off. */ and keepalive must be turned off. */
@ -455,6 +475,7 @@ void bgp_timer_set(struct peer *peer)
BGP_TIMER_OFF(peer->t_holdtime); BGP_TIMER_OFF(peer->t_holdtime);
bgp_keepalives_off(peer); bgp_keepalives_off(peer);
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_delayopen);
break; break;
case BGP_STATUS_MAX: case BGP_STATUS_MAX:
flog_err(EC_LIB_DEVELOPMENT, flog_err(EC_LIB_DEVELOPMENT,
@ -488,6 +509,10 @@ static int bgp_connect_timer(struct thread *thread)
peer = THREAD_ARG(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_write);
assert(!peer->t_read); assert(!peer->t_read);
@ -564,6 +589,23 @@ int bgp_routeadv_timer(struct thread *thread)
return 0; 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 */ /* BGP Peer Down Cause */
const char *const peer_down_str[] = {"", const char *const peer_down_str[] = {"",
"Router ID changed", "Router ID changed",
@ -1299,6 +1341,7 @@ int bgp_stop(struct peer *peer)
BGP_TIMER_OFF(peer->t_connect); BGP_TIMER_OFF(peer->t_connect);
BGP_TIMER_OFF(peer->t_holdtime); BGP_TIMER_OFF(peer->t_holdtime);
BGP_TIMER_OFF(peer->t_routeadv); BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(peer->t_delayopen);
/* Clear input and output buffer. */ /* Clear input and output buffer. */
frr_with_mutex(&peer->io_mtx) { frr_with_mutex(&peer->io_mtx) {
@ -1357,6 +1400,12 @@ int bgp_stop(struct peer *peer)
peer->v_holdtime = peer->bgp->default_holdtime; 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; peer->update_time = 0;
/* Until we are sure that there is no problem about prefix count /* Until we are sure that there is no problem about prefix count
@ -1469,6 +1518,9 @@ static int bgp_connect_check(struct thread *thread)
/* When status is 0 then TCP connection is established. */ /* When status is 0 then TCP connection is established. */
if (status == 0) { if (status == 0) {
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); BGP_EVENT_ADD(peer, TCP_connection_open);
return 1; return 1;
} else { } else {
@ -1516,11 +1568,63 @@ static int bgp_connect_success(struct peer *peer)
zlog_debug("%s passive open", peer->host); zlog_debug("%s passive open", peer->host);
} }
/* Send an open message */
bgp_open_send(peer); bgp_open_send(peer);
return 0; 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 */ /* TCP connect fail */
static int bgp_connect_fail(struct peer *peer) 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 /* 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 bgp_start(struct peer *peer)
{ {
int status; int status;
@ -1633,6 +1738,7 @@ int bgp_start(struct peer *peer)
zlog_debug( zlog_debug(
"%s [FSM] Connect immediately success, fd %d", "%s [FSM] Connect immediately success, fd %d",
peer->host, peer->fd); peer->host, peer->fd);
BGP_EVENT_ADD(peer, TCP_connection_open); BGP_EVENT_ADD(peer, TCP_connection_open);
break; break;
case connect_in_progress: case connect_in_progress:
@ -1682,6 +1788,10 @@ static int bgp_reconnect(struct peer *peer)
static int bgp_fsm_open(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 */ /* Send keepalive and make keepalive timer */
bgp_keepalive_send(peer); 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); 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 */ /* 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, static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
struct graceful_restart_info *gr_info) struct graceful_restart_info *gr_info)
@ -2089,12 +2214,14 @@ static const struct {
{bgp_start, Connect}, /* BGP_Start */ {bgp_start, Connect}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Idle}, /* TCP_connection_open */ {bgp_stop, Idle}, /* TCP_connection_open */
{bgp_stop, Idle}, /* TCP_connection_open_w_delay */
{bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_stop, Idle}, /* TCP_connection_closed */
{bgp_ignore, Idle}, /* TCP_connection_open_failed */ {bgp_ignore, Idle}, /* TCP_connection_open_failed */
{bgp_stop, Idle}, /* TCP_fatal_error */ {bgp_stop, Idle}, /* TCP_fatal_error */
{bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
{bgp_ignore, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* Hold_Timer_expired */
{bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
{bgp_ignore, Idle}, /* DelayOpen_timer_expired */
{bgp_ignore, Idle}, /* Receive_OPEN_message */ {bgp_ignore, Idle}, /* Receive_OPEN_message */
{bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
{bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */
@ -2106,13 +2233,17 @@ static const struct {
{bgp_ignore, Connect}, /* BGP_Start */ {bgp_ignore, Connect}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */ {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_stop, Idle}, /* TCP_connection_closed */
{bgp_connect_fail, Active}, /* TCP_connection_open_failed */ {bgp_connect_fail, Active}, /* TCP_connection_open_failed */
{bgp_connect_fail, Idle}, /* TCP_fatal_error */ {bgp_connect_fail, Idle}, /* TCP_fatal_error */
{bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */ {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
{bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */ {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */ {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_KEEPALIVE_message */
{bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
{bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
@ -2123,13 +2254,17 @@ static const struct {
{bgp_ignore, Active}, /* BGP_Start */ {bgp_ignore, Active}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* BGP_Stop */
{bgp_connect_success, OpenSent}, /* TCP_connection_open */ {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_stop, Idle}, /* TCP_connection_closed */
{bgp_ignore, Active}, /* TCP_connection_open_failed */ {bgp_ignore, Active}, /* TCP_connection_open_failed */
{bgp_fsm_exeption, Idle}, /* TCP_fatal_error */ {bgp_fsm_exeption, Idle}, /* TCP_fatal_error */
{bgp_start, Connect}, /* ConnectRetry_timer_expired */ {bgp_start, Connect}, /* ConnectRetry_timer_expired */
{bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */ {bgp_fsm_exeption, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_exeption, Idle}, /* KeepAlive_timer_expired */
{bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */ {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_KEEPALIVE_message */
{bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
{bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */ {bgp_fsm_exeption, Idle}, /* Receive_NOTIFICATION_message */
@ -2140,12 +2275,14 @@ static const struct {
{bgp_ignore, OpenSent}, /* BGP_Start */ {bgp_ignore, OpenSent}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Active}, /* TCP_connection_open */ {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_closed */
{bgp_stop, Active}, /* TCP_connection_open_failed */ {bgp_stop, Active}, /* TCP_connection_open_failed */
{bgp_stop, Active}, /* TCP_fatal_error */ {bgp_stop, Active}, /* TCP_fatal_error */
{bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_fsm_exeption, Idle}, /* KeepAlive_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_open, OpenConfirm}, /* Receive_OPEN_message */
{bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */
{bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */
@ -2157,12 +2294,14 @@ static const struct {
{bgp_ignore, OpenConfirm}, /* BGP_Start */ {bgp_ignore, OpenConfirm}, /* BGP_Start */
{bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* BGP_Stop */
{bgp_stop, Idle}, /* TCP_connection_open */ {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_closed */
{bgp_stop, Idle}, /* TCP_connection_open_failed */ {bgp_stop, Idle}, /* TCP_connection_open_failed */
{bgp_stop, Idle}, /* TCP_fatal_error */ {bgp_stop, Idle}, /* TCP_fatal_error */
{bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_exeption, Idle}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
{bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */ {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
{bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
{bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */ {bgp_fsm_exeption, Idle}, /* Receive_OPEN_message */
{bgp_establish, Established}, /* Receive_KEEPALIVE_message */ {bgp_establish, Established}, /* Receive_KEEPALIVE_message */
{bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */ {bgp_fsm_exeption, Idle}, /* Receive_UPDATE_message */
@ -2174,12 +2313,14 @@ static const struct {
{bgp_ignore, Established}, /* BGP_Start */ {bgp_ignore, Established}, /* BGP_Start */
{bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* BGP_Stop */
{bgp_stop, Clearing}, /* TCP_connection_open */ {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_closed */
{bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
{bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* TCP_fatal_error */
{bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
{bgp_ignore, Established}, /* KeepAlive_timer_expired */ {bgp_ignore, Established}, /* KeepAlive_timer_expired */
{bgp_fsm_exeption, Idle}, /* DelayOpen_timer_expired */
{bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_fsm_keepalive, {bgp_fsm_keepalive,
Established}, /* Receive_KEEPALIVE_message */ Established}, /* Receive_KEEPALIVE_message */
@ -2193,12 +2334,14 @@ static const struct {
{bgp_ignore, Clearing}, /* BGP_Start */ {bgp_ignore, Clearing}, /* BGP_Start */
{bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* BGP_Stop */
{bgp_stop, Clearing}, /* TCP_connection_open */ {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_closed */
{bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */
{bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* TCP_fatal_error */
{bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
{bgp_stop, Clearing}, /* Hold_Timer_expired */ {bgp_stop, Clearing}, /* Hold_Timer_expired */
{bgp_stop, Clearing}, /* KeepAlive_timer_expired */ {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
{bgp_stop, Clearing}, /* DelayOpen_timer_expired */
{bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_stop, Clearing}, /* Receive_OPEN_message */
{bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
{bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_UPDATE_message */
@ -2210,12 +2353,14 @@ static const struct {
{bgp_ignore, Deleted}, /* BGP_Start */ {bgp_ignore, Deleted}, /* BGP_Start */
{bgp_ignore, Deleted}, /* BGP_Stop */ {bgp_ignore, Deleted}, /* BGP_Stop */
{bgp_ignore, Deleted}, /* TCP_connection_open */ {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_closed */
{bgp_ignore, Deleted}, /* TCP_connection_open_failed */ {bgp_ignore, Deleted}, /* TCP_connection_open_failed */
{bgp_ignore, Deleted}, /* TCP_fatal_error */ {bgp_ignore, Deleted}, /* TCP_fatal_error */
{bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */ {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */
{bgp_ignore, Deleted}, /* Hold_Timer_expired */ {bgp_ignore, Deleted}, /* Hold_Timer_expired */
{bgp_ignore, Deleted}, /* KeepAlive_timer_expired */ {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */
{bgp_ignore, Deleted}, /* DelayOpen_timer_expired */
{bgp_ignore, Deleted}, /* Receive_OPEN_message */ {bgp_ignore, Deleted}, /* Receive_OPEN_message */
{bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */
{bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_UPDATE_message */

View File

@ -1425,8 +1425,8 @@ int bgp_global_global_config_timers_hold_time_modify(
keepalive = yang_dnode_get_uint16(args->dnode, "../keepalive"); keepalive = yang_dnode_get_uint16(args->dnode, "../keepalive");
holdtime = yang_dnode_get_uint16(args->dnode, NULL); holdtime = yang_dnode_get_uint16(args->dnode, NULL);
bgp_timers_set(bgp, keepalive, holdtime, bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY,
DFLT_BGP_CONNECT_RETRY); BGP_DEFAULT_DELAYOPEN);
break; break;
} }
@ -1466,8 +1466,8 @@ int bgp_global_global_config_timers_keepalive_modify(
keepalive = yang_dnode_get_uint16(args->dnode, NULL); keepalive = yang_dnode_get_uint16(args->dnode, NULL);
holdtime = yang_dnode_get_uint16(args->dnode, "../hold-time"); holdtime = yang_dnode_get_uint16(args->dnode, "../hold-time");
bgp_timers_set(bgp, keepalive, holdtime, bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY,
DFLT_BGP_CONNECT_RETRY); BGP_DEFAULT_DELAYOPEN);
break; break;
} }

View File

@ -457,8 +457,16 @@ static int bgp_accept(struct thread *thread)
BGP_TIMER_OFF( BGP_TIMER_OFF(
peer1->t_start); /* created in peer_create() */ peer1->t_start); /* created in peer_create() */
if (peer_active(peer1)) if (peer_active(peer1)) {
BGP_EVENT_ADD(peer1, TCP_connection_open); if (CHECK_FLAG(peer1->flags,
PEER_FLAG_TIMER_DELAYOPEN))
BGP_EVENT_ADD(
peer1,
TCP_connection_open_w_delay);
else
BGP_EVENT_ADD(peer1,
TCP_connection_open);
}
return 0; return 0;
} }
@ -595,6 +603,9 @@ static int bgp_accept(struct thread *thread)
} }
if (peer_active(peer)) { if (peer_active(peer)) {
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); BGP_EVENT_ADD(peer, TCP_connection_open);
} }

View File

@ -491,12 +491,13 @@ time_t bgp_clock(void)
/* BGP timer configuration. */ /* BGP timer configuration. */
void bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime, void bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime,
uint32_t connect_retry) uint32_t connect_retry, uint32_t delayopen)
{ {
bgp->default_keepalive = bgp->default_keepalive =
(keepalive < holdtime / 3 ? keepalive : holdtime / 3); (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
bgp->default_holdtime = holdtime; bgp->default_holdtime = holdtime;
bgp->default_connect_retry = connect_retry; bgp->default_connect_retry = connect_retry;
bgp->default_delayopen = delayopen;
} }
/* mostly for completeness - CLI uses its own defaults */ /* mostly for completeness - CLI uses its own defaults */
@ -505,6 +506,7 @@ void bgp_timers_unset(struct bgp *bgp)
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
bgp->default_connect_retry = BGP_DEFAULT_CONNECT_RETRY; bgp->default_connect_retry = BGP_DEFAULT_CONNECT_RETRY;
bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN;
} }
/* BGP confederation configuration. */ /* BGP confederation configuration. */
@ -1410,10 +1412,12 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->holdtime = peer_src->holdtime; peer_dst->holdtime = peer_src->holdtime;
peer_dst->keepalive = peer_src->keepalive; peer_dst->keepalive = peer_src->keepalive;
peer_dst->connect = peer_src->connect; peer_dst->connect = peer_src->connect;
peer_dst->delayopen = peer_src->delayopen;
peer_dst->v_holdtime = peer_src->v_holdtime; peer_dst->v_holdtime = peer_src->v_holdtime;
peer_dst->v_keepalive = peer_src->v_keepalive; peer_dst->v_keepalive = peer_src->v_keepalive;
peer_dst->routeadv = peer_src->routeadv; peer_dst->routeadv = peer_src->routeadv;
peer_dst->v_routeadv = peer_src->v_routeadv; peer_dst->v_routeadv = peer_src->v_routeadv;
peer_dst->v_delayopen = peer_src->v_delayopen;
/* password apply */ /* password apply */
if (peer_src->password && !peer_dst->password) if (peer_src->password && !peer_dst->password)
@ -2577,6 +2581,14 @@ static void peer_group2peer_config_copy(struct peer_group *group,
peer->v_connect = peer->bgp->default_connect_retry; peer->v_connect = peer->bgp->default_connect_retry;
} }
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_TIMER_DELAYOPEN)) {
PEER_ATTR_INHERIT(peer, group, delayopen);
if (CHECK_FLAG(conf->flags, PEER_FLAG_TIMER_DELAYOPEN))
peer->v_delayopen = conf->delayopen;
else
peer->v_delayopen = peer->bgp->default_delayopen;
}
/* advertisement-interval apply */ /* advertisement-interval apply */
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_ROUTEADV)) { if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_ROUTEADV)) {
PEER_ATTR_INHERIT(peer, group, routeadv); PEER_ATTR_INHERIT(peer, group, routeadv);
@ -4018,6 +4030,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_ROUTEADV, 0, peer_change_none}, {PEER_FLAG_ROUTEADV, 0, peer_change_none},
{PEER_FLAG_TIMER, 0, peer_change_none}, {PEER_FLAG_TIMER, 0, peer_change_none},
{PEER_FLAG_TIMER_CONNECT, 0, peer_change_none}, {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none},
{PEER_FLAG_TIMER_DELAYOPEN, 0, peer_change_none},
{PEER_FLAG_PASSWORD, 0, peer_change_none}, {PEER_FLAG_PASSWORD, 0, peer_change_none},
{PEER_FLAG_LOCAL_AS, 0, peer_change_none}, {PEER_FLAG_LOCAL_AS, 0, peer_change_none},
{PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none}, {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
@ -5403,6 +5416,90 @@ int peer_advertise_interval_unset(struct peer *peer)
return 0; return 0;
} }
/* set the peers RFC 4271 DelayOpen session attribute flag and DelayOpenTimer
* interval
*/
int peer_timers_delayopen_set(struct peer *peer, uint32_t delayopen)
{
struct peer *member;
struct listnode *node;
/* Set peers session attribute flag and timer interval. */
peer_flag_set(peer, PEER_FLAG_TIMER_DELAYOPEN);
peer->delayopen = delayopen;
peer->v_delayopen = delayopen;
/* Skip group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
/* Set flag and configuration on all peer-group members, unless they are
* explicitely overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS_RO(peer->group->peer, node, member)) {
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->flags_override,
PEER_FLAG_TIMER_DELAYOPEN))
continue;
/* Set session attribute flag and timer intervals on peer-group
* member.
*/
SET_FLAG(member->flags, PEER_FLAG_TIMER_DELAYOPEN);
member->delayopen = delayopen;
member->v_delayopen = delayopen;
}
return 0;
}
/* unset the peers RFC 4271 DelayOpen session attribute flag and reset the
* DelayOpenTimer interval to the default value.
*/
int peer_timers_delayopen_unset(struct peer *peer)
{
struct peer *member;
struct listnode *node;
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
peer_flag_inherit(peer, PEER_FLAG_TIMER_DELAYOPEN);
PEER_ATTR_INHERIT(peer, peer->group, delayopen);
} else {
/* Otherwise remove session attribute flag and set timer
* interval to default value.
*/
peer_flag_unset(peer, PEER_FLAG_TIMER_DELAYOPEN);
peer->delayopen = peer->bgp->default_delayopen;
}
/* Set timer value to zero */
peer->v_delayopen = 0;
/* Skip peer-group mechanics for regular peers. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
/* Remove flag and configuration from all peer-group members, unless
* they are explicitely overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS_RO(peer->group->peer, node, member)) {
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->flags_override,
PEER_FLAG_TIMER_DELAYOPEN))
continue;
/* Remove session attribute flag, reset the timer interval to
* the default value and set the timer value to zero.
*/
UNSET_FLAG(member->flags, PEER_FLAG_TIMER_DELAYOPEN);
member->delayopen = peer->bgp->default_delayopen;
member->v_delayopen = 0;
}
return 0;
}
/* neighbor interface */ /* neighbor interface */
void peer_interface_set(struct peer *peer, const char *str) void peer_interface_set(struct peer *peer, const char *str)
{ {

View File

@ -560,6 +560,7 @@ struct bgp {
uint32_t default_holdtime; uint32_t default_holdtime;
uint32_t default_keepalive; uint32_t default_keepalive;
uint32_t default_connect_retry; uint32_t default_connect_retry;
uint32_t default_delayopen;
/* BGP graceful restart */ /* BGP graceful restart */
uint32_t restart_time; uint32_t restart_time;
@ -904,12 +905,14 @@ enum bgp_fsm_events {
BGP_Start = 1, BGP_Start = 1,
BGP_Stop, BGP_Stop,
TCP_connection_open, TCP_connection_open,
TCP_connection_open_w_delay,
TCP_connection_closed, TCP_connection_closed,
TCP_connection_open_failed, TCP_connection_open_failed,
TCP_fatal_error, TCP_fatal_error,
ConnectRetry_timer_expired, ConnectRetry_timer_expired,
Hold_Timer_expired, Hold_Timer_expired,
KeepAlive_timer_expired, KeepAlive_timer_expired,
DelayOpen_timer_expired,
Receive_OPEN_message, Receive_OPEN_message,
Receive_KEEPALIVE_message, Receive_KEEPALIVE_message,
Receive_UPDATE_message, Receive_UPDATE_message,
@ -1166,6 +1169,8 @@ struct peer {
*and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
*/ */
#define PEER_FLAG_TIMER_DELAYOPEN (1 << 27) /* delayopen timer */
struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD]; struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
enum peer_mode peer_gr_present_state; enum peer_mode peer_gr_present_state;
/* Non stop forwarding afi-safi count for BGP gr feature*/ /* Non stop forwarding afi-safi count for BGP gr feature*/
@ -1259,6 +1264,7 @@ struct peer {
_Atomic uint32_t keepalive; _Atomic uint32_t keepalive;
_Atomic uint32_t connect; _Atomic uint32_t connect;
_Atomic uint32_t routeadv; _Atomic uint32_t routeadv;
_Atomic uint32_t delayopen;
/* Timer values. */ /* Timer values. */
_Atomic uint32_t v_start; _Atomic uint32_t v_start;
@ -1266,6 +1272,7 @@ struct peer {
_Atomic uint32_t v_holdtime; _Atomic uint32_t v_holdtime;
_Atomic uint32_t v_keepalive; _Atomic uint32_t v_keepalive;
_Atomic uint32_t v_routeadv; _Atomic uint32_t v_routeadv;
_Atomic uint32_t v_delayopen;
_Atomic uint32_t v_pmax_restart; _Atomic uint32_t v_pmax_restart;
_Atomic uint32_t v_gr_restart; _Atomic uint32_t v_gr_restart;
@ -1278,6 +1285,7 @@ struct peer {
struct thread *t_connect; struct thread *t_connect;
struct thread *t_holdtime; struct thread *t_holdtime;
struct thread *t_routeadv; struct thread *t_routeadv;
struct thread *t_delayopen;
struct thread *t_pmax_restart; struct thread *t_pmax_restart;
struct thread *t_gr_restart; struct thread *t_gr_restart;
struct thread *t_gr_stale; struct thread *t_gr_stale;
@ -1673,6 +1681,9 @@ struct bgp_nlri {
#define BGP_DEFAULT_EBGP_ROUTEADV 0 #define BGP_DEFAULT_EBGP_ROUTEADV 0
#define BGP_DEFAULT_IBGP_ROUTEADV 0 #define BGP_DEFAULT_IBGP_ROUTEADV 0
/* BGP RFC 4271 DelayOpenTime default value */
#define BGP_DEFAULT_DELAYOPEN 120
/* BGP default local preference. */ /* BGP default local preference. */
#define BGP_DEFAULT_LOCAL_PREF 100 #define BGP_DEFAULT_LOCAL_PREF 100
@ -1877,7 +1888,7 @@ extern int bgp_confederation_peers_add(struct bgp *, as_t);
extern int bgp_confederation_peers_remove(struct bgp *, as_t); extern int bgp_confederation_peers_remove(struct bgp *, as_t);
extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime, extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime,
uint32_t connect_retry); uint32_t connect_retry, uint32_t delayopen);
extern void bgp_timers_unset(struct bgp *); extern void bgp_timers_unset(struct bgp *);
extern int bgp_default_local_preference_set(struct bgp *, uint32_t); extern int bgp_default_local_preference_set(struct bgp *, uint32_t);
@ -1953,6 +1964,9 @@ extern int peer_timers_connect_unset(struct peer *);
extern int peer_advertise_interval_set(struct peer *, uint32_t); extern int peer_advertise_interval_set(struct peer *, uint32_t);
extern int peer_advertise_interval_unset(struct peer *); extern int peer_advertise_interval_unset(struct peer *);
extern int peer_timers_delayopen_set(struct peer *peer, uint32_t delayopen);
extern int peer_timers_delayopen_unset(struct peer *peer);
extern void peer_interface_set(struct peer *, const char *); extern void peer_interface_set(struct peer *, const char *);
extern void peer_interface_unset(struct peer *); extern void peer_interface_unset(struct peer *);