Skip to content

Commit

Permalink
bgpd : Adding Selection Deferral Timer handler changes.
Browse files Browse the repository at this point in the history
* Selection Deferral Timer for Graceful Retsart
* Added selection deferral timer handling function
* Route marking as selection defer when update message is received
* Staggered processing of routes which are pending best selection.

Signed-off-by: Biswajit Sadhu <sadhub@vmware.com>
  • Loading branch information
bisdhdh committed Oct 22, 2019
1 parent b7250fe commit 801554d
Show file tree
Hide file tree
Showing 7 changed files with 475 additions and 12 deletions.
158 changes: 157 additions & 1 deletion bgpd/bgp_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@

DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))

extern const char *get_afi_safi_str(afi_t afi,
safi_t safi, bool for_json);
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
Expand Down Expand Up @@ -605,6 +606,33 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread)
return 0;
}

/* Selection deferral timer processing function */
static int bgp_graceful_deferral_timer_expire(struct thread *thread)
{
struct afi_safi_info *info;
afi_t afi;
safi_t safi;
struct bgp *bgp;

info = THREAD_ARG(thread);
afi = info->afi;
safi = info->safi;
bgp = info->bgp;

if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("afi %d, safi %d : graceful restart deferral timer expired",
afi, safi);

bgp->gr_info[afi][safi].t_select_deferral = NULL;

bgp->gr_info[afi][safi].eor_required = 0;
bgp->gr_info[afi][safi].eor_received = 0;
XFREE(MTYPE_TMP, info);

/* Best path selection */
return bgp_best_path_select_defer(bgp, afi, safi);
}

static int bgp_update_delay_applicable(struct bgp *bgp)
{
/* update_delay_over flag should be reset (set to 0) for any new
Expand Down Expand Up @@ -1069,6 +1097,8 @@ int bgp_stop(struct peer *peer)
char orf_name[BUFSIZ];
int ret = 0;
peer->nsf_af_count = 0;
struct bgp *bgp = peer->bgp;
struct graceful_restart_info *gr_info = NULL;

if (peer_dynamic_neighbor(peer)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
Expand Down Expand Up @@ -1135,6 +1165,33 @@ int bgp_stop(struct peer *peer)
peer->nsf[afi][safi] = 0;
}

/* If peer reset before receiving EOR, decrement EOR count and
* cancel the selection deferral timer if there are no
* pending EOR messages to be received
*/
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
FOREACH_AFI_SAFI (afi, safi) {
if (peer->afc_nego[afi][safi] &&
!CHECK_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED)) {
gr_info = &bgp->gr_info[afi][safi];
if (gr_info && gr_info->eor_required)
gr_info->eor_required--;
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("peer %s, EOR %d",
peer->host,
gr_info->eor_required);

/* There is no pending EOR message */
if (gr_info->eor_required == 0) {
BGP_TIMER_OFF(
gr_info->t_select_deferral);
gr_info->eor_received = 0;
}
}
}
}

/* set last reset time */
peer->resettime = peer->uptime = bgp_clock();

Expand Down Expand Up @@ -1567,6 +1624,85 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 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)
{
struct afi_safi_info *thread_info;

/* If the deferral timer is active, then increment eor count */
if (gr_info->t_select_deferral) {
gr_info->eor_required++;
return 0;
}

/* Start the deferral timer when the first peer enabled for the graceful
* restart is established
*/
if (gr_info->eor_required == 0) {
thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
if (thread_info == NULL) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("%s : Error allocating thread info",
__func__);
return -1;
}

thread_info->afi = afi;
thread_info->safi = safi;
thread_info->bgp = bgp;

thread_add_timer(bm->master,
bgp_graceful_deferral_timer_expire,
thread_info, bgp->select_defer_time,
&gr_info->t_select_deferral);
if (gr_info->t_select_deferral == NULL) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("Error starting deferral timer for %s",
get_afi_safi_str(afi, safi, false));
return -1;
}
}

gr_info->eor_required++;
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("Started the deferral timer for %s eor_required %d",
get_afi_safi_str(afi, safi, false),
gr_info->eor_required);
return 0;
}

/* Update the graceful restart information for the specified AFI, SAFI */
static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
{
struct graceful_restart_info *gr_info;
struct bgp *bgp = peer->bgp;
int ret = 0;

if ((afi < AFI_IP) || (afi >= AFI_MAX)) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("%s : invalid afi %d", __func__, afi);
return -1;
}

if ((safi < SAFI_UNICAST) || (safi > SAFI_MPLS_VPN)) {
if (BGP_DEBUG(update, UPDATE_OUT))
zlog_debug("%s : invalid safi %d", __func__, safi);
return -1;
}

/* Restarting router */
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
BGP_PEER_RESTARTING_MODE(peer)) {
/* Check if the forwarding state is preserved */
if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) {
gr_info = &(bgp->gr_info[afi][safi]);
ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
}
}
return (ret);
}

/**
* Transition to Established state.
*
Expand All @@ -1580,6 +1716,7 @@ static int bgp_establish(struct peer *peer)
int nsf_af_count = 0;
int ret = 0;
struct peer *other;
int status;

other = peer->doppelganger;
peer = peer_xfer_conn(peer);
Expand Down Expand Up @@ -1619,6 +1756,14 @@ static int bgp_establish(struct peer *peer)

/* graceful restart */
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
if (bgp_debug_neighbor_events(peer)) {
if (BGP_PEER_RESTARTING_MODE(peer))
zlog_debug("peer %s BGP_RESTARTING_MODE",
peer->host);
else if (BGP_PEER_HELPER_MODE(peer))
zlog_debug("peer %s BGP_HELPER_MODE",
peer->host);
}
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
if (peer->afc_nego[afi][safi]
Expand All @@ -1638,6 +1783,17 @@ static int bgp_establish(struct peer *peer)
bgp_clear_stale_route(peer, afi, safi);
peer->nsf[afi][safi] = 0;
}
/* Update the graceful restart information */
if (peer->afc_nego[afi][safi]) {
if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) {
status = bgp_update_gr_info(peer, afi,
safi);
if (status < 0)
zlog_debug("Error in updating graceful restart for %s",
get_afi_safi_str(afi,
safi, false));
}
}
}

peer->nsf_af_count = nsf_af_count;
Expand Down
13 changes: 13 additions & 0 deletions bgpd/bgp_fsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@
UNSET_FLAG(peer->peer_gr_new_status_flag, \
PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)

#define BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) \
(CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && \
CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))

#define BGP_PEER_RESTARTING_MODE(peer)\
(bgp_peer_flag_check(peer, PEER_FLAG_GRACEFUL_RESTART) && \
CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV) && \
!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV))

#define BGP_PEER_HELPER_MODE(peer)\
(bgp_peer_flag_check(peer, PEER_FLAG_GRACEFUL_RESTART_HELPER) && \
CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV) && \
!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV))

/* Prototypes. */
extern void bgp_fsm_event_update(struct peer *peer, int valid);
Expand Down
48 changes: 44 additions & 4 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,13 +723,17 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
if (first) {
snprintf(c, sizeof(c), " %02x",
data[i]);

strlcat(bgp_notify.data, c,
bgp_notify.length);
bgp_notify.length * 3);

} else {
first = 1;
snprintf(c, sizeof(c), "%02x", data[i]);

strlcpy(bgp_notify.data, c,
bgp_notify.length);
bgp_notify.length * 3);

}
}
bgp_notify_print(peer, &bgp_notify, "sending");
Expand Down Expand Up @@ -1404,6 +1408,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
bool restart = false;

enum NLRI_TYPES {
NLRI_UPDATE,
Expand Down Expand Up @@ -1625,6 +1630,12 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
|| (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
afi_t afi = 0;
safi_t safi;
struct graceful_restart_info *gr_info;

/* Restarting router */
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
BGP_PEER_RESTARTING_MODE(peer))
restart = true;

/* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already
* checked
Expand All @@ -1651,6 +1662,31 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
SET_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED);
bgp_update_explicit_eors(peer);
/* Update graceful restart information */
gr_info = &(peer->bgp->gr_info[afi][safi]);
if (restart)
gr_info->eor_received++;
/* If EOR received from all peers and selection
* deferral timer is running, cancel the timer
* and invoke the best path calculation
*/
if (gr_info->eor_required ==
gr_info->eor_received) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s %d, %s %d",
"EOR REQ",
gr_info->eor_required,
"EOR RCV",
gr_info->eor_received);
BGP_TIMER_OFF(
gr_info->t_select_deferral);
gr_info->eor_required = 0;
gr_info->eor_received = 0;
/* Best path selection */
if (bgp_best_path_select_defer(
peer->bgp, afi, safi) < 0)
return BGP_Stop;
}
}

/* NSF delete stale route */
Expand Down Expand Up @@ -1721,14 +1757,18 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
if (first) {
snprintf(c, sizeof(c), " %02x",
stream_getc(peer->curr));

strlcat(bgp_notify.data, c,
bgp_notify.length);
bgp_notify.length * 3);

} else {
first = 1;
snprintf(c, sizeof(c), "%02x",
stream_getc(peer->curr));

strlcpy(bgp_notify.data, c,
bgp_notify.length);
bgp_notify.length * 3);

}
bgp_notify.raw_data = (uint8_t *)peer->notify.data;
}
Expand Down
Loading

0 comments on commit 801554d

Please sign in to comment.