diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index dd31a9b7cb..ce665feb4e 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 */ diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index 4cc92eed54..6e7a1b650c 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -1425,8 +1425,8 @@ int bgp_global_global_config_timers_hold_time_modify( keepalive = yang_dnode_get_uint16(args->dnode, "../keepalive"); holdtime = yang_dnode_get_uint16(args->dnode, NULL); - bgp_timers_set(bgp, keepalive, holdtime, - DFLT_BGP_CONNECT_RETRY); + bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY, + BGP_DEFAULT_DELAYOPEN); break; } @@ -1466,8 +1466,8 @@ int bgp_global_global_config_timers_keepalive_modify( keepalive = yang_dnode_get_uint16(args->dnode, NULL); holdtime = yang_dnode_get_uint16(args->dnode, "../hold-time"); - bgp_timers_set(bgp, keepalive, holdtime, - DFLT_BGP_CONNECT_RETRY); + bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY, + BGP_DEFAULT_DELAYOPEN); break; } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index fcbdb2969f..be2c474493 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -457,8 +457,16 @@ static int bgp_accept(struct thread *thread) BGP_TIMER_OFF( peer1->t_start); /* created in peer_create() */ - if (peer_active(peer1)) - BGP_EVENT_ADD(peer1, TCP_connection_open); + if (peer_active(peer1)) { + 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; } @@ -595,7 +603,10 @@ static int bgp_accept(struct thread *thread) } if (peer_active(peer)) { - 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 0; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 82ce0c3882..f1454aaee8 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -491,12 +491,13 @@ time_t bgp_clock(void) /* BGP timer configuration. */ 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 = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); bgp->default_holdtime = holdtime; bgp->default_connect_retry = connect_retry; + bgp->default_delayopen = delayopen; } /* 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_holdtime = BGP_DEFAULT_HOLDTIME; bgp->default_connect_retry = BGP_DEFAULT_CONNECT_RETRY; + bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN; } /* 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->keepalive = peer_src->keepalive; peer_dst->connect = peer_src->connect; + peer_dst->delayopen = peer_src->delayopen; peer_dst->v_holdtime = peer_src->v_holdtime; peer_dst->v_keepalive = peer_src->v_keepalive; peer_dst->routeadv = peer_src->routeadv; peer_dst->v_routeadv = peer_src->v_routeadv; + peer_dst->v_delayopen = peer_src->v_delayopen; /* password apply */ 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; } + 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 */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_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_TIMER, 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_LOCAL_AS, 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; } +/* 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 */ void peer_interface_set(struct peer *peer, const char *str) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 965a35b345..e867159fa6 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -560,6 +560,7 @@ struct bgp { uint32_t default_holdtime; uint32_t default_keepalive; uint32_t default_connect_retry; + uint32_t default_delayopen; /* BGP graceful restart */ uint32_t restart_time; @@ -904,12 +905,14 @@ enum bgp_fsm_events { BGP_Start = 1, 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, @@ -1166,6 +1169,8 @@ struct peer { *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]; enum peer_mode peer_gr_present_state; /* Non stop forwarding afi-safi count for BGP gr feature*/ @@ -1259,6 +1264,7 @@ struct peer { _Atomic uint32_t keepalive; _Atomic uint32_t connect; _Atomic uint32_t routeadv; + _Atomic uint32_t delayopen; /* Timer values. */ _Atomic uint32_t v_start; @@ -1266,6 +1272,7 @@ struct peer { _Atomic uint32_t v_holdtime; _Atomic uint32_t v_keepalive; _Atomic uint32_t v_routeadv; + _Atomic uint32_t v_delayopen; _Atomic uint32_t v_pmax_restart; _Atomic uint32_t v_gr_restart; @@ -1278,6 +1285,7 @@ struct peer { struct thread *t_connect; struct thread *t_holdtime; struct thread *t_routeadv; + struct thread *t_delayopen; struct thread *t_pmax_restart; struct thread *t_gr_restart; struct thread *t_gr_stale; @@ -1673,6 +1681,9 @@ struct bgp_nlri { #define BGP_DEFAULT_EBGP_ROUTEADV 0 #define BGP_DEFAULT_IBGP_ROUTEADV 0 +/* BGP RFC 4271 DelayOpenTime default value */ +#define BGP_DEFAULT_DELAYOPEN 120 + /* BGP default local preference. */ #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 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 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_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_unset(struct peer *);