From d7b3cda6f74dda7b127eba0347cab4730116fbbb Mon Sep 17 00:00:00 2001 From: bisdhdh Date: Thu, 24 Oct 2019 10:10:53 +0530 Subject: [PATCH] bgpd: BGP tcp session failed to apply GR configuration on the transferred bgp tcp connection. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When the BGP peer is configured between two bgp routes both routers would create peer structure , when they receive each other’s open message. In this event both speakers, open duplicate TCP sessions and send OPEN messages on each socket simultaneously, the BGP Identifier is used to resolve which socket should be closed. If BGP GR is enabled the old tcp session is dumped and the new session is retained. So while this transfer of connection is happening, if all the bgp gr config is not migrated to the new connection, the new bgp gr mode will never get applied. Fix Summary: 1. Replicate GR configuration from the old session to the new session in bgp_accept(). 2. Replicate GR configuration from stub to full-fledged peer in bgp_establish(). 3. Disable all NSF flags, clear stale routes (if present), stop restart & stale timers (if they are running) when the bgp GR mode is changed to “Disabled”. 4. Disable R-bit in cap, if it is not set the received open message. Signed-off-by: Biswajit Sadhu --- bgpd/bgp_fsm.c | 36 +++++++++++++++++++++++++++++++++++- bgpd/bgp_io.c | 16 +++++++++++++--- bgpd/bgp_network.c | 24 +++++++++++++++++++++--- bgpd/bgp_open.c | 2 ++ bgpd/bgpd.c | 5 ++++- bgpd/bgpd.h | 1 + 6 files changed, 76 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 5e5ac636ed..a86c457b62 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -251,6 +251,20 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->remote_id = from_peer->remote_id; peer->last_reset = from_peer->last_reset; + peer->peer_gr_present_state = from_peer->peer_gr_present_state; + peer->peer_gr_new_status_flag = from_peer->peer_gr_new_status_flag; + bgp_peer_gr_flags_update(peer); + + if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) { + + UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); + + if (CHECK_FLAG(peer->sflags, + PEER_STATUS_NSF_WAIT)) { + peer_nsf_stop(peer); + } + } + if (from_peer->hostname != NULL) { if (peer->hostname) { XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); @@ -2604,5 +2618,25 @@ void bgp_peer_gr_flags_update(struct peer *peer) peer->host, (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) ? - "Set" : "UnSet")); + "Set" : "UnSet")); + + if (!CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART_HELPER)){ + zlog_debug( + "BGP_GR:: Peer %s UNSET PEER_STATUS_NSF_MODE!", + peer->host); + + UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); + + if (CHECK_FLAG(peer->sflags, + PEER_STATUS_NSF_WAIT)) { + + peer_nsf_stop(peer); + zlog_debug( + "BGP_GR:: Peer %s UNSET PEER_STATUS_NSF_WAIT!", + peer->host); + } + } } diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index fed34e5b65..626c36ff05 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -462,7 +462,12 @@ static uint16_t bgp_read(struct peer *peer) safe_strerror(errno)); if (peer->status == Established) { - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { + if ((CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART_HELPER)) && + CHECK_FLAG(peer->sflags, + PEER_STATUS_NSF_MODE)) { peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); } else @@ -475,10 +480,15 @@ static uint16_t bgp_read(struct peer *peer) } else if (nbytes == 0) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] BGP connection closed fd %d", - peer->host, peer->fd); + peer->host, peer->fd); if (peer->status == Established) { - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { + if ((CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART_HELPER)) && + CHECK_FLAG(peer->sflags, + PEER_STATUS_NSF_MODE)) { peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); } else diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 4031d2dfde..4487684de5 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -487,6 +487,18 @@ static int bgp_accept(struct thread *thread) hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); peer_xfer_config(peer, peer1); + bgp_peer_gr_flags_update(peer); + + if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) { + + UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); + + if (CHECK_FLAG(peer->sflags, + PEER_STATUS_NSF_WAIT)) { + peer_nsf_stop(peer); + } + } + UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); peer->doppelganger = peer1; @@ -497,10 +509,9 @@ static int bgp_accept(struct thread *thread) BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); - /* Make dummy peer until read Open packet. */ if (peer1->status == Established - && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { + && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { /* If we have an existing established connection with graceful * restart * capability announced with one or more address families, then @@ -508,7 +519,14 @@ static int bgp_accept(struct thread *thread) * existing established connection and move state to connect. */ peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; - SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT); + + if (CHECK_FLAG(peer1->flags, + PEER_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(peer1->flags, + PEER_FLAG_GRACEFUL_RESTART_HELPER)) + SET_FLAG(peer1->sflags, + PEER_STATUS_NSF_WAIT); + bgp_event_update(peer1, TCP_connection_closed); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index eb6dc1a753..89437a5149 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -462,6 +462,8 @@ static int bgp_capability_restart(struct peer *peer, restart_flag_time = stream_getw(s); if (CHECK_FLAG(restart_flag_time, RESTART_R_BIT)) SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV); + else + UNSET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV); UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index fae91655ab..2c60b818ef 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1326,6 +1326,9 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->flags = peer_src->flags; peer_dst->cap = peer_src->cap; + peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state; + peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag; + peer_dst->local_as = peer_src->local_as; peer_dst->port = peer_src->port; (void)peer_sort(peer_dst); @@ -2213,7 +2216,7 @@ int peer_afc_set(struct peer *peer, afi_t afi, safi_t safi, int enable) return peer_deactivate(peer, afi, safi); } -static void peer_nsf_stop(struct peer *peer) +void peer_nsf_stop(struct peer *peer) { afi_t afi; safi_t safi; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 390dc8a7ff..a8ba6ad258 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2081,5 +2081,6 @@ extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, /* Hooks */ DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer)) +void peer_nsf_stop(struct peer *peer); #endif /* _QUAGGA_BGPD_H */ -- 2.39.5