mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
Merge 13283b6238
into 3dd4d417be
This commit is contained in:
commit
c6a6dc7aaf
|
@ -186,6 +186,8 @@ static const struct message bgp_notify_fsm_msg[] = {
|
|||
const char *const bgp_origin_str[] = {"i", "e", "?"};
|
||||
const char *const bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"};
|
||||
|
||||
const char *const bgp_global_gr_mode_str[] = { "Helper", "Restarter", "Disabled", "Invalid" };
|
||||
|
||||
static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc,
|
||||
struct prefix *p);
|
||||
/* Given a string return a pointer the corresponding peer structure */
|
||||
|
|
|
@ -161,6 +161,7 @@ struct bgp_debug_filter {
|
|||
#define CONF_BGP_DEBUG(a, b) (unlikely(conf_bgp_debug_##a & BGP_DEBUG_##b))
|
||||
|
||||
extern const char *const bgp_type_str[];
|
||||
extern const char *const bgp_global_gr_mode_str[];
|
||||
|
||||
extern bool bgp_dump_attr(struct attr *attr, char *buf, size_t size);
|
||||
extern bool bgp_debug_peer_updout_enabled(char *host);
|
||||
|
|
495
bgpd/bgp_fsm.c
495
bgpd/bgp_fsm.c
|
@ -852,12 +852,11 @@ static void bgp_graceful_deferral_timer_expire(struct event *thread)
|
|||
"afi %d, safi %d : graceful restart deferral timer expired",
|
||||
afi, safi);
|
||||
|
||||
bgp->gr_info[afi][safi].eor_required = 0;
|
||||
bgp->gr_info[afi][safi].eor_received = 0;
|
||||
bgp->gr_info[afi][safi].select_defer_over = true;
|
||||
XFREE(MTYPE_TMP, info);
|
||||
|
||||
/* Best path selection */
|
||||
bgp_best_path_select_defer(bgp, afi, safi);
|
||||
bgp_do_deferred_path_selection(bgp, afi, safi);
|
||||
}
|
||||
|
||||
static bool bgp_update_delay_applicable(struct bgp *bgp)
|
||||
|
@ -1227,6 +1226,226 @@ static void bgp_update_delay_process_status_change(struct peer *peer)
|
|||
}
|
||||
}
|
||||
|
||||
static bool bgp_gr_check_all_eors(struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct peer *peer = NULL;
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s: Checking all peers for EOR receipt for %s", bgp->name_pretty,
|
||||
get_afi_safi_str(afi, safi, false));
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("....examining peer %s status %s flags 0x%" PRIx64
|
||||
" af_sflags 0x%x",
|
||||
peer->host,
|
||||
lookup_msg(bgp_status_msg, peer->connection->status, NULL),
|
||||
peer->flags, peer->af_sflags[afi][safi]);
|
||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) ||
|
||||
CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN) ||
|
||||
!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART))
|
||||
continue;
|
||||
|
||||
if (!CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR))
|
||||
continue;
|
||||
|
||||
if (!CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) {
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug(".... EOR still awaited from this peer for this %s",
|
||||
get_afi_safi_str(afi, safi, false));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug(".... EOR received from all expected peers for this %s",
|
||||
get_afi_safi_str(afi, safi, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bgp_gr_check_path_select(struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct graceful_restart_info *gr_info;
|
||||
|
||||
if (bgp_gr_check_all_eors(bgp, afi, safi)) {
|
||||
gr_info = &(bgp->gr_info[afi][safi]);
|
||||
EVENT_OFF(gr_info->t_select_deferral);
|
||||
gr_info->select_defer_over = true;
|
||||
bgp_do_deferred_path_selection(bgp, afi, safi);
|
||||
}
|
||||
}
|
||||
|
||||
static void bgp_gr_mark_for_deferred_selection(struct bgp *bgp)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct peer *peer;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
/*
|
||||
* Mark all peers in the instance for EOR wait for the
|
||||
* AFI/SAFI supported for GR.
|
||||
*/
|
||||
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
if (bgp_gr_supported_for_afi_safi(afi, safi))
|
||||
SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
else
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the selection deferral timer thread for the specified AFI, SAFI,
|
||||
* mark peers from whom we need an EOR and inform zebra
|
||||
*/
|
||||
static void 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;
|
||||
|
||||
/* Start the timer */
|
||||
thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
|
||||
|
||||
thread_info->afi = afi;
|
||||
thread_info->safi = safi;
|
||||
thread_info->bgp = bgp;
|
||||
|
||||
event_add_timer(bm->master, bgp_graceful_deferral_timer_expire, thread_info,
|
||||
bgp->select_defer_time, &gr_info->t_select_deferral);
|
||||
|
||||
gr_info->af_enabled = true;
|
||||
bgp->gr_route_sync_pending = true;
|
||||
|
||||
/* Inform zebra */
|
||||
bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
|
||||
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s: Started path-select deferral timer for %s, duration %ds",
|
||||
bgp->name_pretty, get_afi_safi_str(afi, safi, false),
|
||||
bgp->select_defer_time);
|
||||
}
|
||||
|
||||
static void bgp_gr_process_peer_up_ignore(struct bgp *bgp, struct peer *peer)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
/*
|
||||
* If peer has restarted, GR is disabled for peer or not negotiated
|
||||
* with the peer, we have to ignore this peer for EOR-wait. This
|
||||
* might also be the last peer we were waiting for, so check if
|
||||
* we can move forward with path-selection.
|
||||
*/
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
if (bgp_gr_supported_for_afi_safi(afi, safi))
|
||||
bgp_gr_check_path_select(bgp, afi, safi);
|
||||
}
|
||||
}
|
||||
|
||||
static void bgp_gr_process_peer_up_include(struct bgp *bgp, struct peer *peer)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct graceful_restart_info *gr_info;
|
||||
|
||||
/*
|
||||
* If peer has not restarted and is potentially a valid Helper,
|
||||
* we need to wait for EOR from the peer for each AFI/SAFI that
|
||||
* has been negotiated. This should also start the path selection
|
||||
* deferral, if not yet done. OTOH, for non-negotiated AFI/SAFI,
|
||||
* we need to check if path-selection can proceed.
|
||||
*/
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
if (!peer->afc_nego[afi][safi]) {
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
if (bgp_gr_supported_for_afi_safi(afi, safi))
|
||||
bgp_gr_check_path_select(bgp, afi, safi);
|
||||
} else if (!bgp_gr_supported_for_afi_safi(afi, safi)) {
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
} else {
|
||||
SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
gr_info = &(bgp->gr_info[afi][safi]);
|
||||
if (!gr_info->t_select_deferral)
|
||||
bgp_start_deferral_timer(bgp, afi, safi, gr_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bgp_gr_process_peer_status_change(struct peer *peer)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
bgp = peer->bgp;
|
||||
if (peer_established(peer->connection)) {
|
||||
/*
|
||||
* If we haven't yet evaluated for path selection deferral,
|
||||
* do it now.
|
||||
*/
|
||||
if (!bgp->gr_select_defer_evaluated) {
|
||||
bgp_gr_mark_for_deferred_selection(bgp);
|
||||
bgp->gr_select_defer_evaluated = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Peer has come up. We need to figure out if we need to
|
||||
* wait for EOR from this peer for negotiated AFI/SAFI
|
||||
* and potentially start deferred path selection. For any
|
||||
* non-negotiated AFI/SAFI or if the peer has restarted etc.,
|
||||
* evaluate if path-selection deferral should end
|
||||
*/
|
||||
if (CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) ||
|
||||
!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) ||
|
||||
!BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s: Peer %s cap 0x%" PRIx64 " flags 0x%" PRIx64
|
||||
" restarted or GR not negotiated, check for path-selection",
|
||||
bgp->name_pretty, peer->host, peer->cap, peer->flags);
|
||||
|
||||
bgp_gr_process_peer_up_ignore(bgp, peer);
|
||||
} else {
|
||||
bgp_gr_process_peer_up_include(bgp, peer);
|
||||
}
|
||||
} else if (peer->connection->ostatus == Established) {
|
||||
/*
|
||||
* If a peer (Helper) went down after establishing the
|
||||
* session, we will not wait for a EOR from it.
|
||||
* Note: This is not spelt out well in the RFC.
|
||||
*/
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi)
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
}
|
||||
}
|
||||
|
||||
static bool gr_path_select_deferral_applicable(struct bgp *bgp)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct graceful_restart_info *gr_info;
|
||||
|
||||
/* True if BGP has (re)started gracefully (based on start
|
||||
* settings and GR is not complete and path selection
|
||||
* deferral not yet done for this instance
|
||||
*/
|
||||
if (!bgp_in_graceful_restart())
|
||||
return false;
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
if (!bgp_gr_supported_for_afi_safi(afi, safi))
|
||||
continue;
|
||||
gr_info = &(bgp->gr_info[afi][safi]);
|
||||
if (!gr_info->select_defer_over)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Called after event occurred, this function change status and reset
|
||||
read/write and timer thread. */
|
||||
void bgp_fsm_change_status(struct peer_connection *connection,
|
||||
|
@ -1326,9 +1545,10 @@ void bgp_fsm_change_status(struct peer_connection *connection,
|
|||
peer->bgp->maxmed_onstartup_over = 1;
|
||||
}
|
||||
|
||||
/* If update-delay processing is applicable, do the necessary. */
|
||||
if (bgp_update_delay_configured(peer->bgp)
|
||||
&& bgp_update_delay_applicable(peer->bgp))
|
||||
/* Check for GR restarter or update-delay processing. */
|
||||
if (gr_path_select_deferral_applicable(peer->bgp))
|
||||
bgp_gr_process_peer_status_change(peer);
|
||||
else if (bgp_update_delay_configured(peer->bgp) && bgp_update_delay_applicable(peer->bgp))
|
||||
bgp_update_delay_process_status_change(peer);
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
|
@ -1359,8 +1579,6 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection)
|
|||
char orf_name[BUFSIZ];
|
||||
enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
|
||||
struct peer *peer = connection->peer;
|
||||
struct bgp *bgp = peer->bgp;
|
||||
struct graceful_restart_info *gr_info = NULL;
|
||||
|
||||
peer->nsf_af_count = 0;
|
||||
|
||||
|
@ -1443,42 +1661,6 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection)
|
|||
peer, bgp_peer_get_connection_direction(connection));
|
||||
}
|
||||
|
||||
/* 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))
|
||||
continue;
|
||||
|
||||
gr_info = &bgp->gr_info[afi][safi];
|
||||
if (!gr_info)
|
||||
continue;
|
||||
|
||||
if (gr_info->eor_required)
|
||||
gr_info->eor_required--;
|
||||
|
||||
if (BGP_DEBUG(update, UPDATE_OUT))
|
||||
zlog_debug("peer %s, EOR_required %d for %s", peer->host,
|
||||
gr_info->eor_required,
|
||||
bgp_peer_get_connection_direction(connection));
|
||||
|
||||
/* There is no pending EOR message */
|
||||
if (gr_info->eor_required == 0) {
|
||||
if (gr_info->t_select_deferral) {
|
||||
void *info = EVENT_ARG(
|
||||
gr_info->t_select_deferral);
|
||||
XFREE(MTYPE_TMP, info);
|
||||
}
|
||||
EVENT_OFF(gr_info->t_select_deferral);
|
||||
gr_info->eor_received = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set last reset time */
|
||||
peer->resettime = peer->uptime = monotime(NULL);
|
||||
|
||||
|
@ -2048,77 +2230,67 @@ bgp_fsm_delayopen_timer_expire(struct peer_connection *connection)
|
|||
return BGP_FSM_SUCCESS;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
/*
|
||||
* Upon session becoming established, process the GR capabilities announced
|
||||
* by the peer, and clear stale routes if the peer has not announced a
|
||||
* previously announced (afi,safi) or doesn't preserve forwarding for them.
|
||||
* The clearing of stale routes applies only to a Helper router.
|
||||
*/
|
||||
static void bgp_peer_process_gr_cap_clear_stale(struct peer *peer)
|
||||
{
|
||||
struct afi_safi_info *thread_info;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
int nsf_af_count = 0;
|
||||
|
||||
/* If the deferral timer is active, then increment eor count */
|
||||
if (gr_info->t_select_deferral) {
|
||||
gr_info->eor_required++;
|
||||
return 0;
|
||||
if (peer->connection->t_gr_restart) {
|
||||
EVENT_OFF(peer->connection->t_gr_restart);
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%pBP: graceful restart timer stopped", peer);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
if (peer->afc_nego[afi][safi] && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) &&
|
||||
CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) {
|
||||
/*
|
||||
* If an (afi,safi) is negotiated with the
|
||||
* peer and it has announced the GR capab
|
||||
* for it, it supports NSF for this (afi,
|
||||
* safi). However, if the peer didn't adv
|
||||
* the F-bit, any previous (stale) routes
|
||||
* should be flushed.
|
||||
*/
|
||||
if (peer->nsf[afi][safi] &&
|
||||
!CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
|
||||
bgp_clear_stale_route(peer, afi, safi);
|
||||
|
||||
thread_info->afi = afi;
|
||||
thread_info->safi = safi;
|
||||
thread_info->bgp = bgp;
|
||||
|
||||
event_add_timer(bm->master, bgp_graceful_deferral_timer_expire,
|
||||
thread_info, bgp->select_defer_time,
|
||||
&gr_info->t_select_deferral);
|
||||
}
|
||||
gr_info->eor_required++;
|
||||
/* Send message to RIB indicating route update pending */
|
||||
if (gr_info->af_enabled == false) {
|
||||
gr_info->af_enabled = true;
|
||||
gr_info->route_sync = false;
|
||||
bgp->gr_route_sync_pending = true;
|
||||
bgp_zebra_update(bgp, afi, safi,
|
||||
ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
|
||||
}
|
||||
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_gr_is_forwarding_preserved(bgp)) {
|
||||
gr_info = &(bgp->gr_info[afi][safi]);
|
||||
ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
|
||||
peer->nsf[afi][safi] = 1;
|
||||
nsf_af_count++;
|
||||
} else {
|
||||
/*
|
||||
* Some other situation like (afi,safi) not
|
||||
* negotiated, GR not negotiated etc. Clear
|
||||
* any previous (stale) routes.
|
||||
*/
|
||||
if (peer->nsf[afi][safi])
|
||||
bgp_clear_stale_route(peer, afi, safi);
|
||||
peer->nsf[afi][safi] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
peer->nsf_af_count = nsf_af_count;
|
||||
|
||||
if (nsf_af_count)
|
||||
SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
|
||||
else {
|
||||
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
|
||||
if (peer->connection->t_gr_stale) {
|
||||
EVENT_OFF(peer->connection->t_gr_stale);
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%s: graceful restart stalepath timer stopped",
|
||||
peer->host);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2132,10 +2304,8 @@ bgp_establish(struct peer_connection *connection)
|
|||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
int nsf_af_count = 0;
|
||||
enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
|
||||
struct peer *other;
|
||||
int status;
|
||||
struct peer *peer = connection->peer;
|
||||
struct peer *orig = peer;
|
||||
|
||||
|
@ -2192,101 +2362,12 @@ bgp_establish(struct peer_connection *connection)
|
|||
: VRF_DEFAULT_NAME)
|
||||
: "");
|
||||
}
|
||||
|
||||
/* assign update-group/subgroup */
|
||||
update_group_adjust_peer_afs(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("%pBP BGP_RESTARTING_MODE %s", peer,
|
||||
bgp_peer_get_connection_direction(connection));
|
||||
else if (BGP_PEER_HELPER_MODE(peer))
|
||||
zlog_debug("%pBP BGP_HELPER_MODE %s", peer,
|
||||
bgp_peer_get_connection_direction(connection));
|
||||
}
|
||||
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
if (peer->afc_nego[afi][safi] &&
|
||||
CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) &&
|
||||
CHECK_FLAG(peer->af_cap[afi][safi],
|
||||
PEER_CAP_RESTART_AF_RCV)) {
|
||||
if (peer->nsf[afi][safi] &&
|
||||
!CHECK_FLAG(peer->af_cap[afi][safi],
|
||||
PEER_CAP_RESTART_AF_PRESERVE_RCV))
|
||||
bgp_clear_stale_route(peer, afi, safi);
|
||||
|
||||
peer->nsf[afi][safi] = 1;
|
||||
nsf_af_count++;
|
||||
} else {
|
||||
if (peer->nsf[afi][safi])
|
||||
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_err(
|
||||
"Error in updating graceful restart for %s",
|
||||
get_afi_safi_str(afi, safi,
|
||||
false));
|
||||
} else {
|
||||
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
|
||||
BGP_PEER_RESTARTING_MODE(peer) &&
|
||||
bgp_gr_is_forwarding_preserved(peer->bgp))
|
||||
peer->bgp->gr_info[afi][safi]
|
||||
.eor_required++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
|
||||
if ((bgp_peer_gr_mode_get(peer) == PEER_GR)
|
||||
|| ((bgp_peer_gr_mode_get(peer) == PEER_GLOBAL_INHERIT)
|
||||
&& (bgp_global_gr_mode_get(peer->bgp) == GLOBAL_GR))) {
|
||||
FOREACH_AFI_SAFI (afi, safi)
|
||||
/* Send route processing complete
|
||||
message to RIB */
|
||||
bgp_zebra_update(
|
||||
peer->bgp, afi, safi,
|
||||
ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
|
||||
}
|
||||
} else {
|
||||
/* Peer sends R-bit. In this case, we need to send
|
||||
* ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */
|
||||
if (CHECK_FLAG(peer->cap,
|
||||
PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) {
|
||||
FOREACH_AFI_SAFI (afi, safi)
|
||||
/* Send route processing complete
|
||||
message to RIB */
|
||||
bgp_zebra_update(
|
||||
peer->bgp, afi, safi,
|
||||
ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
peer->nsf_af_count = nsf_af_count;
|
||||
|
||||
if (nsf_af_count)
|
||||
SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
|
||||
else {
|
||||
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
|
||||
if (connection->t_gr_stale) {
|
||||
EVENT_OFF(connection->t_gr_stale);
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%pBP graceful restart stalepath timer stopped for %s",
|
||||
peer, bgp_peer_get_connection_direction(connection));
|
||||
}
|
||||
}
|
||||
|
||||
if (connection->t_gr_restart) {
|
||||
EVENT_OFF(connection->t_gr_restart);
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%pBP graceful restart timer stopped for %s", peer,
|
||||
bgp_peer_get_connection_direction(connection));
|
||||
}
|
||||
/* graceful restart handling */
|
||||
bgp_peer_process_gr_cap_clear_stale(peer);
|
||||
|
||||
/* Reset uptime, turn on keepalives, send current table. */
|
||||
if (!peer->v_holdtime)
|
||||
|
@ -2817,8 +2898,9 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd)
|
|||
|
||||
if (global_old_state == GLOBAL_INVALID)
|
||||
return BGP_ERR_GR_OPERATION_FAILED;
|
||||
/* Next state 'invalid is actually an 'ignore' */
|
||||
if (global_new_state == GLOBAL_INVALID)
|
||||
return BGP_ERR_GR_INVALID_CMD;
|
||||
return BGP_GR_NO_OPERATION;
|
||||
if (global_new_state == global_old_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
|
||||
|
@ -2930,8 +3012,9 @@ int bgp_neighbor_graceful_restart(struct peer *peer,
|
|||
if (peer_old_state == PEER_INVALID)
|
||||
return BGP_ERR_GR_OPERATION_FAILED;
|
||||
|
||||
/* Next state 'invalid' is actually an 'ignore' */
|
||||
if (peer_new_state == PEER_INVALID)
|
||||
return BGP_ERR_GR_INVALID_CMD;
|
||||
return BGP_GR_NO_OPERATION;
|
||||
|
||||
if (peer_new_state == peer_old_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
|
@ -2962,8 +3045,10 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state,
|
|||
|
||||
if (old_state == new_state)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID))
|
||||
if (old_state == PEER_INVALID)
|
||||
return BGP_ERR_GR_INVALID_CMD;
|
||||
if (new_state == PEER_INVALID)
|
||||
return BGP_GR_NO_OPERATION;
|
||||
|
||||
global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
|
||||
|
||||
|
|
|
@ -167,4 +167,5 @@ const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
|
|||
const char *print_global_gr_mode(enum global_mode gl_mode);
|
||||
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
|
||||
int bgp_peer_reg_with_nht(struct peer *peer);
|
||||
void bgp_gr_check_path_select(struct bgp *bgp, afi_t afi, safi_t safi);
|
||||
#endif /* _QUAGGA_BGP_FSM_H */
|
||||
|
|
|
@ -1603,7 +1603,7 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
|
|||
rcapp = stream_get_endp(s);
|
||||
stream_putc(s, 0);
|
||||
restart_time = bgp->restart_time;
|
||||
if (peer->bgp->t_startup || bgp_in_graceful_restart()) {
|
||||
if (bgp_in_graceful_restart()) {
|
||||
SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT);
|
||||
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV);
|
||||
}
|
||||
|
@ -1636,6 +1636,8 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
|
|||
|
||||
if (!peer->afc[afi][safi])
|
||||
continue;
|
||||
if (!bgp_gr_supported_for_afi_safi(afi, safi))
|
||||
continue;
|
||||
|
||||
/* Convert AFI, SAFI to values for
|
||||
* packet.
|
||||
|
|
|
@ -482,6 +482,12 @@ void bgp_generate_updgrp_packets(struct event *thread)
|
|||
return;
|
||||
}
|
||||
|
||||
/* If a GR restarter, we have to wait till path-selection
|
||||
* is complete.
|
||||
*/
|
||||
if (bgp_in_graceful_restart())
|
||||
return;
|
||||
|
||||
do {
|
||||
enum bgp_af_index index;
|
||||
|
||||
|
@ -1319,7 +1325,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
|
|||
stream_putc(s, 0);
|
||||
gr_restart_time = peer->bgp->restart_time;
|
||||
|
||||
if (peer->bgp->t_startup || bgp_in_graceful_restart()) {
|
||||
if (bgp_in_graceful_restart()) {
|
||||
SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT);
|
||||
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV);
|
||||
}
|
||||
|
@ -2232,6 +2238,40 @@ static void bgp_refresh_stalepath_timer_expire(struct event *thread)
|
|||
bgp_timer_set(peer->connection);
|
||||
}
|
||||
|
||||
static void bgp_update_receive_eor(struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id);
|
||||
|
||||
zlog_info("%s: rcvd End-of-RIB for %s from %s in vrf %s", __func__,
|
||||
get_afi_safi_str(afi, safi, false), peer->host,
|
||||
vrf ? vrf->name : VRF_DEFAULT_NAME);
|
||||
|
||||
/* End-of-RIB received */
|
||||
if (!CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) {
|
||||
SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED);
|
||||
|
||||
/* update-delay related processing */
|
||||
bgp_update_explicit_eors(peer);
|
||||
|
||||
/* graceful-restart related processing */
|
||||
UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_GR_WAIT_EOR);
|
||||
if (bgp_in_graceful_restart() && bgp_gr_supported_for_afi_safi(afi, safi)) {
|
||||
struct graceful_restart_info *gr_info;
|
||||
|
||||
gr_info = &(bgp->gr_info[afi][safi]);
|
||||
if (!gr_info->select_defer_over) {
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s: check for path-selection", bgp->name_pretty);
|
||||
bgp_gr_check_path_select(bgp, afi, safi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[afi][safi])
|
||||
bgp_clear_stale_route(peer, afi, safi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process BGP UPDATE message for peer.
|
||||
*
|
||||
|
@ -2251,7 +2291,7 @@ static int bgp_update_receive(struct peer_connection *connection,
|
|||
bgp_size_t attribute_len;
|
||||
bgp_size_t update_len;
|
||||
bgp_size_t withdraw_len;
|
||||
bool restart = false;
|
||||
struct bgp *bgp = peer->bgp;
|
||||
|
||||
enum NLRI_TYPES {
|
||||
NLRI_UPDATE,
|
||||
|
@ -2480,13 +2520,6 @@ static int bgp_update_receive(struct peer_connection *connection,
|
|||
if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) {
|
||||
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
|
||||
* update and withdraw NLRI lengths are 0.
|
||||
|
@ -2500,55 +2533,8 @@ static int bgp_update_receive(struct peer_connection *connection,
|
|||
safi = nlris[NLRI_MP_WITHDRAW].safi;
|
||||
}
|
||||
|
||||
if (afi && peer->afc[afi][safi]) {
|
||||
struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
|
||||
|
||||
/* End-of-RIB received */
|
||||
if (!CHECK_FLAG(peer->af_sflags[afi][safi],
|
||||
PEER_STATUS_EOR_RECEIVED)) {
|
||||
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);
|
||||
if (gr_info->t_select_deferral) {
|
||||
void *info = EVENT_ARG(
|
||||
gr_info->t_select_deferral);
|
||||
XFREE(MTYPE_TMP, info);
|
||||
}
|
||||
EVENT_OFF(gr_info->t_select_deferral);
|
||||
gr_info->eor_required = 0;
|
||||
gr_info->eor_received = 0;
|
||||
/* Best path selection */
|
||||
bgp_best_path_select_defer(peer->bgp,
|
||||
afi, safi);
|
||||
}
|
||||
}
|
||||
|
||||
/* NSF delete stale route */
|
||||
if (peer->nsf[afi][safi])
|
||||
bgp_clear_stale_route(peer, afi, safi);
|
||||
|
||||
zlog_info(
|
||||
"%s: rcvd End-of-RIB for %s from %s in vrf %s",
|
||||
__func__, get_afi_safi_str(afi, safi, false),
|
||||
peer->host, vrf ? vrf->name : VRF_DEFAULT_NAME);
|
||||
}
|
||||
if (afi && peer->afc[afi][safi])
|
||||
bgp_update_receive_eor(bgp, peer, afi, safi);
|
||||
}
|
||||
|
||||
/* Everything is done. We unintern temporary structures which
|
||||
|
|
|
@ -500,9 +500,9 @@ static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete)
|
|||
if (!CHECK_FLAG(dest->flags, BGP_NODE_SELECT_DEFER))
|
||||
bgp->gr_info[afi][safi].gr_deferred++;
|
||||
SET_FLAG(dest->flags, BGP_NODE_SELECT_DEFER);
|
||||
if (BGP_DEBUG(update, UPDATE_OUT))
|
||||
zlog_debug("DEFER route %pBD(%s), dest %p",
|
||||
dest, bgp->name_pretty, dest);
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s: Defer route %pBD, dest %p", bgp->name_pretty, dest,
|
||||
dest);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2947,7 +2947,7 @@ static void bgp_route_select_timer_expire(struct event *thread)
|
|||
XFREE(MTYPE_TMP, info);
|
||||
|
||||
/* Best path selection */
|
||||
bgp_best_path_select_defer(bgp, afi, safi);
|
||||
bgp_do_deferred_path_selection(bgp, afi, safi);
|
||||
}
|
||||
|
||||
void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
|
||||
|
@ -4007,12 +4007,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
|
|||
}
|
||||
|
||||
/* Process the routes with the flag BGP_NODE_SELECT_DEFER set */
|
||||
void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
void bgp_do_deferred_path_selection(struct bgp *bgp, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct bgp_dest *dest;
|
||||
int cnt = 0;
|
||||
struct afi_safi_info *thread_info;
|
||||
bool route_sync_pending = false;
|
||||
|
||||
if (bgp->gr_info[afi][safi].t_route_select) {
|
||||
struct event *t = bgp->gr_info[afi][safi].t_route_select;
|
||||
|
@ -4051,21 +4050,25 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
|
|||
|
||||
/* Send EOR message when all routes are processed */
|
||||
if (!bgp->gr_info[afi][safi].gr_deferred) {
|
||||
bool route_sync_pending = false;
|
||||
|
||||
bgp_send_delayed_eor(bgp);
|
||||
/* Send route processing complete message to RIB */
|
||||
bgp_zebra_update(bgp, afi, safi,
|
||||
ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
|
||||
bgp->gr_info[afi][safi].route_sync = true;
|
||||
|
||||
/* If this instance is all done, check for GR completion overall */
|
||||
FOREACH_AFI_SAFI_NSF (afi, safi) {
|
||||
/*
|
||||
* If this instance is all done,
|
||||
* check for GR completion overall
|
||||
*/
|
||||
FOREACH_AFI_SAFI (afi, safi) {
|
||||
if (bgp->gr_info[afi][safi].af_enabled &&
|
||||
!bgp->gr_info[afi][safi].route_sync) {
|
||||
route_sync_pending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!route_sync_pending) {
|
||||
bgp->gr_route_sync_pending = false;
|
||||
bgp_update_gr_completion();
|
||||
|
@ -4457,9 +4460,6 @@ static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest,
|
|||
* the workqueue
|
||||
*/
|
||||
if (CHECK_FLAG(dest->flags, BGP_NODE_SELECT_DEFER)) {
|
||||
if (BGP_DEBUG(update, UPDATE_OUT))
|
||||
zlog_debug("BGP_NODE_SELECT_DEFER set for route %p",
|
||||
dest);
|
||||
bgp->node_deferred_on_queue++;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -975,7 +975,7 @@ extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t
|
|||
struct bgp_table *table, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg,
|
||||
uint16_t show_flags);
|
||||
extern void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
|
||||
extern void bgp_do_deferred_path_selection(struct bgp *bgp, afi_t afi, safi_t safi);
|
||||
extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
uint8_t type, uint8_t stype,
|
||||
struct attr *attr, struct bgp_dest *dest);
|
||||
|
|
1028
bgpd/bgp_vty.c
1028
bgpd/bgp_vty.c
File diff suppressed because it is too large
Load diff
|
@ -55,14 +55,13 @@ FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
|
|||
"V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc\n"
|
||||
#define BGP_SHOW_SUMMARY_HEADER_FAILED "EstdCnt DropCnt ResetTime Reason\n"
|
||||
|
||||
#define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json) \
|
||||
do { \
|
||||
bgp_show_neighbor_graceful_restart_local_mode(vty, p, json); \
|
||||
bgp_show_neighbor_graceful_restart_remote_mode(vty, p, json); \
|
||||
bgp_show_neighnor_graceful_restart_flags(vty, p, json); \
|
||||
bgp_show_neighbor_graceful_restart_time(vty, p, json); \
|
||||
bgp_show_neighbor_graceful_restart_capability_per_afi_safi( \
|
||||
vty, p, json); \
|
||||
#define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, json) \
|
||||
do { \
|
||||
bgp_show_neighbor_graceful_restart_local_mode(vty, p, json); \
|
||||
bgp_show_neighbor_graceful_restart_remote_mode(vty, p, json); \
|
||||
bgp_show_neighnor_graceful_restart_flags(vty, p, json); \
|
||||
bgp_show_neighbor_graceful_restart_time(vty, p, json); \
|
||||
bgp_show_peer_gr_info_afi_safi(vty, p, use_json, json); \
|
||||
} while (0)
|
||||
|
||||
#define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \
|
||||
|
@ -140,6 +139,11 @@ FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
|
|||
} while (0)
|
||||
|
||||
extern void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi);
|
||||
|
||||
/* Peer show flags */
|
||||
/* Value of 0 means show all information */
|
||||
#define VTY_BGP_PEER_SHOW_GR_INFO (1 << 0)
|
||||
|
||||
extern void bgp_vty_init(void);
|
||||
extern void community_alias_vty(void);
|
||||
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
|
||||
|
|
31
bgpd/bgpd.c
31
bgpd/bgpd.c
|
@ -1364,9 +1364,6 @@ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer)
|
|||
|
||||
int bgp_global_gr_init(struct bgp *bgp)
|
||||
{
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s called ..", __func__);
|
||||
|
||||
int local_GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE][BGP_GLOBAL_GR_EVENT_CMD] = {
|
||||
/* GLOBAL_HELPER Mode */
|
||||
{
|
||||
|
@ -1436,9 +1433,6 @@ int bgp_global_gr_init(struct bgp *bgp)
|
|||
|
||||
int bgp_peer_gr_init(struct peer *peer)
|
||||
{
|
||||
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
|
||||
zlog_debug("%s called ..", __func__);
|
||||
|
||||
struct bgp_peer_gr local_Peer_GR_FSM[BGP_PEER_GR_MODE]
|
||||
[BGP_PEER_GR_EVENT_CMD] = {
|
||||
{
|
||||
|
@ -1618,9 +1612,6 @@ struct peer *peer_new(struct bgp *bgp)
|
|||
SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN);
|
||||
SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN);
|
||||
|
||||
/* Initialize per peer bgp GR FSM */
|
||||
bgp_peer_gr_init(peer);
|
||||
|
||||
/* Get service port number. */
|
||||
sp = getservbyname("bgp", "tcp");
|
||||
peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs(sp->s_port);
|
||||
|
@ -2069,7 +2060,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
|
|||
bgp_timer_set(peer->connection);
|
||||
}
|
||||
|
||||
bgp_peer_gr_flags_update(peer);
|
||||
/* Initialize per peer bgp GR FSM */
|
||||
bgp_peer_gr_init(peer);
|
||||
|
||||
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
|
||||
|
||||
return peer;
|
||||
|
@ -2086,6 +2079,9 @@ struct peer *peer_create_accept(struct bgp *bgp)
|
|||
listnode_add_sort(bgp->peer, peer);
|
||||
(void)hash_get(bgp->peerhash, peer, hash_alloc_intern);
|
||||
|
||||
/* Initialize per peer bgp GR FSM */
|
||||
bgp_peer_gr_init(peer);
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
|
@ -3425,14 +3421,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bgp_startup_timer_expire(struct event *thread)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
|
||||
bgp = EVENT_ARG(thread);
|
||||
bgp->t_startup = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* On shutdown we call the cleanup function which
|
||||
* does a free of the link list nodes, free up
|
||||
|
@ -3544,11 +3532,10 @@ peer_init:
|
|||
bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
|
||||
multipath_num, 0);
|
||||
/* Initialize graceful restart info */
|
||||
bgp->gr_info[afi][safi].eor_required = 0;
|
||||
bgp->gr_info[afi][safi].eor_received = 0;
|
||||
bgp->gr_info[afi][safi].t_select_deferral = NULL;
|
||||
bgp->gr_info[afi][safi].t_route_select = NULL;
|
||||
bgp->gr_info[afi][safi].gr_deferred = 0;
|
||||
bgp->gr_info[afi][safi].select_defer_over = false;
|
||||
}
|
||||
|
||||
bgp->v_update_delay = bm->v_update_delay;
|
||||
|
@ -3612,9 +3599,6 @@ peer_init:
|
|||
if (name && !bgp->name)
|
||||
bgp->name = XSTRDUP(MTYPE_BGP_NAME, name);
|
||||
|
||||
event_add_timer(bm->master, bgp_startup_timer_expire, bgp,
|
||||
bgp->restart_time, &bgp->t_startup);
|
||||
|
||||
/* printable name we can use in debug messages */
|
||||
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT && !hidden) {
|
||||
bgp->name_pretty = XSTRDUP(MTYPE_BGP_NAME, "VRF default");
|
||||
|
@ -4151,7 +4135,6 @@ int bgp_delete(struct bgp *bgp)
|
|||
EVENT_OFF(bgp->t_revalidate[afi][safi]);
|
||||
|
||||
EVENT_OFF(bgp->t_condition_check);
|
||||
EVENT_OFF(bgp->t_startup);
|
||||
EVENT_OFF(bgp->t_maxmed_onstartup);
|
||||
EVENT_OFF(bgp->t_update_delay);
|
||||
EVENT_OFF(bgp->t_establish_wait);
|
||||
|
|
34
bgpd/bgpd.h
34
bgpd/bgpd.h
|
@ -323,11 +323,9 @@ enum bgp_instance_type {
|
|||
BGP_INSTANCE_TYPE_VIEW
|
||||
};
|
||||
|
||||
#define BGP_SEND_EOR(bgp, afi, safi) \
|
||||
(!CHECK_FLAG(bgp->flags, BGP_FLAG_GR_DISABLE_EOR) \
|
||||
&& ((bgp->gr_info[afi][safi].t_select_deferral == NULL) \
|
||||
|| (bgp->gr_info[afi][safi].eor_required \
|
||||
== bgp->gr_info[afi][safi].eor_received)))
|
||||
#define BGP_SEND_EOR(bgp, afi, safi) \
|
||||
(!CHECK_FLAG(bgp->flags, BGP_FLAG_GR_DISABLE_EOR) && \
|
||||
(!bgp_in_graceful_restart() || bgp->gr_info[afi][safi].select_defer_over))
|
||||
|
||||
/* BGP GR Global ds */
|
||||
|
||||
|
@ -336,10 +334,6 @@ enum bgp_instance_type {
|
|||
|
||||
/* Graceful restart selection deferral timer info */
|
||||
struct graceful_restart_info {
|
||||
/* Count of EOR message expected */
|
||||
uint32_t eor_required;
|
||||
/* Count of EOR received */
|
||||
uint32_t eor_received;
|
||||
/* Deferral Timer */
|
||||
struct event *t_select_deferral;
|
||||
/* Routes Deferred */
|
||||
|
@ -350,6 +344,7 @@ struct graceful_restart_info {
|
|||
bool af_enabled;
|
||||
/* Route update completed */
|
||||
bool route_sync;
|
||||
bool select_defer_over;
|
||||
};
|
||||
|
||||
enum global_mode {
|
||||
|
@ -559,9 +554,6 @@ struct bgp {
|
|||
struct as_confed *confed_peers;
|
||||
int confed_peers_cnt;
|
||||
|
||||
/* start-up timer on only once at the beginning */
|
||||
struct event *t_startup;
|
||||
|
||||
struct event *clearing_end;
|
||||
|
||||
uint32_t v_maxmed_onstartup; /* Duration of max-med on start-up */
|
||||
|
@ -682,6 +674,11 @@ struct bgp {
|
|||
*/
|
||||
enum zebra_gr_mode present_zebra_gr_state;
|
||||
|
||||
/* Is deferred path selection evaluated? Currently, this is done
|
||||
* upon first peer establishing in an instance.
|
||||
*/
|
||||
bool gr_select_defer_evaluated;
|
||||
|
||||
/* Is deferred path selection still not complete? */
|
||||
bool gr_route_sync_pending;
|
||||
|
||||
|
@ -1810,7 +1807,7 @@ struct peer {
|
|||
#define PEER_STATUS_LLGR_WAIT (1U << 11)
|
||||
#define PEER_STATUS_REFRESH_PENDING (1U << 12) /* refresh request from peer */
|
||||
#define PEER_STATUS_RTT_SHUTDOWN (1U << 13) /* In shutdown state due to RTT */
|
||||
|
||||
#define PEER_STATUS_GR_WAIT_EOR (1U << 14) /* wait for EOR */
|
||||
/* Configured timer values. */
|
||||
_Atomic uint32_t holdtime;
|
||||
_Atomic uint32_t keepalive;
|
||||
|
@ -3027,6 +3024,17 @@ static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp)
|
|||
CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD));
|
||||
}
|
||||
|
||||
static inline bool bgp_gr_supported_for_afi_safi(afi_t afi, safi_t safi)
|
||||
{
|
||||
/*
|
||||
* GR restarter behavior is supported only for IPv4-unicast
|
||||
* and IPv6-unicast.
|
||||
*/
|
||||
if ((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For benefit of rfapi */
|
||||
extern struct peer *peer_new(struct bgp *bgp);
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ from lib.common_config import (
|
|||
start_topology,
|
||||
kill_router_daemons,
|
||||
start_router_daemons,
|
||||
start_router_daemons_gr,
|
||||
verify_rib,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
|
@ -1034,7 +1035,8 @@ def test_BGP_GR_TC_4_p0(request):
|
|||
)
|
||||
|
||||
logger.info("[Phase 5] : R2 is about to come up now ")
|
||||
start_router_daemons(tgen, "r2", ["bgpd"])
|
||||
|
||||
start_router_daemons_gr(tgen, "r2", ["bgpd"])
|
||||
|
||||
logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
|
||||
|
||||
|
@ -1200,15 +1202,16 @@ def test_BGP_GR_TC_5_1_2_p1(request):
|
|||
tc_name, result
|
||||
)
|
||||
|
||||
#Verify that the Rbit is be set to false
|
||||
result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
|
||||
assert result is True, "Testcase {} : Failed \n Error {}".format(
|
||||
assert result is not True, "Testcase {} : Failed \n Error {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
logger.info("[Phase 2] : Restart BGPd on router R2. ")
|
||||
kill_router_daemons(tgen, "r2", ["bgpd"])
|
||||
|
||||
start_router_daemons(tgen, "r2", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r2", ["bgpd"])
|
||||
|
||||
logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
|
||||
|
||||
|
|
|
@ -113,6 +113,7 @@ from lib.common_config import (
|
|||
start_topology,
|
||||
kill_router_daemons,
|
||||
start_router_daemons,
|
||||
start_router_daemons_gr,
|
||||
verify_rib,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
|
@ -359,7 +360,7 @@ def test_BGP_GR_TC_8_p1(request):
|
|||
kill_router_daemons(tgen, "r1", ["bgpd"])
|
||||
|
||||
logger.info("[Phase 3] : R1 is about to come up now ")
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r1", ["bgpd"])
|
||||
|
||||
logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
|
||||
|
||||
|
|
|
@ -1597,7 +1597,7 @@ def test_BGP_GR_TC_9_p1(request):
|
|||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
result = verify_f_bit(
|
||||
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
|
||||
|
|
|
@ -109,6 +109,7 @@ from lib.common_config import (
|
|||
start_topology,
|
||||
kill_router_daemons,
|
||||
start_router_daemons,
|
||||
start_router_daemons_gr,
|
||||
verify_rib,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
|
@ -546,12 +547,12 @@ def test_BGP_GR_chaos_28_p1(request):
|
|||
logger.info("[Step 3] : Start BGPd daemon on R1..")
|
||||
|
||||
# Start BGPd daemon on R1
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r1", ["bgpd"])
|
||||
|
||||
logger.info("[Step 4] : Start BGPd daemon on R3..")
|
||||
|
||||
# Start BGPd daemon on R3
|
||||
start_router_daemons(tgen, "r3", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r3", ["bgpd"])
|
||||
|
||||
# Verify r_bit
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
|
|
@ -108,11 +108,13 @@ from lib.common_config import (
|
|||
start_topology,
|
||||
kill_router_daemons,
|
||||
start_router_daemons,
|
||||
start_router_daemons_gr,
|
||||
verify_rib,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
check_router_status,
|
||||
get_frr_ipv6_linklocal,
|
||||
run_frr_cmd,
|
||||
required_linux_kernel_version,
|
||||
)
|
||||
|
||||
|
@ -722,10 +724,9 @@ def test_BGP_GR_chaos_37_p1(request):
|
|||
logger.info("[Step 4] : Start BGPd daemon on R1..")
|
||||
|
||||
# Start BGPd daemon on R1
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r1", ["bgpd"])
|
||||
|
||||
logger.info("[Step 5] : Kill BGPd daemon on R3..")
|
||||
|
||||
# Kill BGPd daemon on R3
|
||||
kill_router_daemons(tgen, "r3", ["bgpd"])
|
||||
|
||||
|
@ -738,7 +739,10 @@ def test_BGP_GR_chaos_37_p1(request):
|
|||
logger.info("[Step 6] : Start BGPd daemon on R3..")
|
||||
|
||||
# Start BGPd daemon on R3
|
||||
start_router_daemons(tgen, "r3", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r3", ["bgpd"])
|
||||
|
||||
#Wait for session to come up
|
||||
sleep(120)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Verify r_bit
|
||||
|
@ -910,7 +914,10 @@ def test_BGP_GR_chaos_30_p1(request):
|
|||
logger.info("[Step 4] : Start BGPd daemon on R1..")
|
||||
|
||||
# Start BGPd daemon on R1
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
start_router_daemons_gr(tgen, "r1", ["bgpd"])
|
||||
|
||||
# Wait for select-deferral-timer to expire/EORs to be received
|
||||
sleep(360)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Verifying BGP RIB routes before shutting down BGPd daemon
|
||||
|
|
|
@ -3403,42 +3403,65 @@ def verify_graceful_restart(
|
|||
rmode = "Helper"
|
||||
else:
|
||||
rmode = "Helper"
|
||||
|
||||
if show_bgp_graceful_json_out["localGrMode"] == lmode:
|
||||
if (
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"]["localGrMode"]
|
||||
== lmode
|
||||
):
|
||||
logger.info(
|
||||
"[DUT: {}]: localGrMode : {} ".format(
|
||||
dut, show_bgp_graceful_json_out["localGrMode"]
|
||||
dut,
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"localGrMode"
|
||||
],
|
||||
)
|
||||
)
|
||||
else:
|
||||
errormsg = (
|
||||
"[DUT: {}]: localGrMode is not correct"
|
||||
" Expected: {}, Found: {}".format(
|
||||
dut, lmode, show_bgp_graceful_json_out["localGrMode"]
|
||||
dut,
|
||||
lmode,
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"localGrMode"
|
||||
],
|
||||
)
|
||||
)
|
||||
return errormsg
|
||||
|
||||
if show_bgp_graceful_json_out["remoteGrMode"] == rmode:
|
||||
if (
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"]["remoteGrMode"]
|
||||
== rmode
|
||||
):
|
||||
logger.info(
|
||||
"[DUT: {}]: remoteGrMode : {} ".format(
|
||||
dut, show_bgp_graceful_json_out["remoteGrMode"]
|
||||
dut,
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"remoteGrMode"
|
||||
],
|
||||
)
|
||||
)
|
||||
elif (
|
||||
show_bgp_graceful_json_out["remoteGrMode"] == "NotApplicable"
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"]["remoteGrMode"]
|
||||
== "NotApplicable"
|
||||
and rmode == "Disable"
|
||||
):
|
||||
logger.info(
|
||||
"[DUT: {}]: remoteGrMode : {} ".format(
|
||||
dut, show_bgp_graceful_json_out["remoteGrMode"]
|
||||
dut,
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"remoteGrMode"
|
||||
],
|
||||
)
|
||||
)
|
||||
else:
|
||||
errormsg = (
|
||||
"[DUT: {}]: remoteGrMode is not correct"
|
||||
" Expected: {}, Found: {}".format(
|
||||
dut, rmode, show_bgp_graceful_json_out["remoteGrMode"]
|
||||
dut,
|
||||
rmode,
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"remoteGrMode"
|
||||
],
|
||||
)
|
||||
)
|
||||
return errormsg
|
||||
|
@ -3556,8 +3579,8 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
|
|||
)
|
||||
return errormsg
|
||||
|
||||
if "rBit" in show_bgp_graceful_json_out:
|
||||
if show_bgp_graceful_json_out["rBit"]:
|
||||
if "rBit" in show_bgp_graceful_json_out["gracefulRestartInfo"]:
|
||||
if show_bgp_graceful_json_out["gracefulRestartInfo"]["rBit"]:
|
||||
logger.info("[DUT: {}]: Rbit true {}".format(dut, neighbor_ip))
|
||||
else:
|
||||
errormsg = "[DUT: {}]: Rbit false {}".format(dut, neighbor_ip)
|
||||
|
@ -3682,7 +3705,9 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
|
|||
errormsg = "Address type %s is not supported" % (addr_type)
|
||||
return errormsg
|
||||
|
||||
eor_json = show_bgp_graceful_json_out[afi]["endOfRibStatus"]
|
||||
eor_json = show_bgp_graceful_json_out["gracefulRestartInfo"][afi][
|
||||
"endOfRibStatus"
|
||||
]
|
||||
if "endOfRibSend" in eor_json:
|
||||
if eor_json["endOfRibSend"]:
|
||||
logger.info(
|
||||
|
@ -3827,9 +3852,9 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
|
|||
isjson=True,
|
||||
)
|
||||
|
||||
show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
|
||||
show_bgp_graceful_nbr_json_out = show_bgp_graceful_json[neighbor_ip]
|
||||
|
||||
if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
|
||||
if show_bgp_graceful_nbr_json_out["neighborAddr"] == neighbor_ip:
|
||||
logger.info(
|
||||
"[DUT: {}]: Neighbor ip matched {}".format(dut, neighbor_ip)
|
||||
)
|
||||
|
@ -3839,6 +3864,10 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
|
|||
)
|
||||
return errormsg
|
||||
|
||||
show_bgp_graceful_json_out = show_bgp_graceful_nbr_json_out[
|
||||
"gracefulRestartInfo"
|
||||
]
|
||||
|
||||
if "ipv4Unicast" in show_bgp_graceful_json_out:
|
||||
if show_bgp_graceful_json_out["ipv4Unicast"]["fBit"]:
|
||||
logger.info(
|
||||
|
@ -3975,9 +4004,9 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
|
|||
if rs_timer == "restart-time":
|
||||
receivedTimer = value
|
||||
if (
|
||||
show_bgp_graceful_json_out["timers"][
|
||||
"receivedRestartTimer"
|
||||
]
|
||||
show_bgp_graceful_json_out["gracefulRestartInfo"][
|
||||
"timers"
|
||||
]["receivedRestartTimer"]
|
||||
== receivedTimer
|
||||
):
|
||||
logger.info(
|
||||
|
@ -4071,7 +4100,7 @@ def verify_gr_address_family(
|
|||
return errormsg
|
||||
|
||||
if addr_family == "ipv4Unicast":
|
||||
if "ipv4Unicast" in show_bgp_graceful_json_out:
|
||||
if "ipv4Unicast" in show_bgp_graceful_json_out["gracefulRestartInfo"]:
|
||||
logger.info("ipv4Unicast present for {} ".format(neighbor_ip))
|
||||
return True
|
||||
else:
|
||||
|
@ -4079,7 +4108,7 @@ def verify_gr_address_family(
|
|||
return errormsg
|
||||
|
||||
elif addr_family == "ipv6Unicast":
|
||||
if "ipv6Unicast" in show_bgp_graceful_json_out:
|
||||
if "ipv6Unicast" in show_bgp_graceful_json_out["gracefulRestartInfo"]:
|
||||
logger.info("ipv6Unicast present for {} ".format(neighbor_ip))
|
||||
return True
|
||||
else:
|
||||
|
|
|
@ -430,6 +430,24 @@ def start_router_daemons(tgen, router, daemons):
|
|||
return res
|
||||
|
||||
|
||||
def start_router_daemons_gr(tgen, router, daemons):
|
||||
"""
|
||||
Set -K option in daemons file before starting
|
||||
the daemon so that it can start in GR restarter mode.
|
||||
Currently supported for bgpd and zebra only.
|
||||
Remove -K option from daemons file once started
|
||||
"""
|
||||
#Adds extra parameters to daemons file for graceful restart
|
||||
for daemon in daemons:
|
||||
tgen.net[router].daemons_options[daemon] = "-K"
|
||||
|
||||
# Start daemon
|
||||
start_router_daemons(tgen, router, daemons)
|
||||
|
||||
# Remove graceful restart option
|
||||
for daemon in daemons:
|
||||
tgen.net[router].daemons_options[daemon] = ""
|
||||
|
||||
def check_router_status(tgen):
|
||||
"""
|
||||
Check if all daemons are running for all routers in topology
|
||||
|
|
Loading…
Reference in a new issue