bgpd: Activate Graceful-Restart when receiving CEASE/HOLDTIME notifications

If we receive CEASE Notification or HOLDTIME notification, retain STALE
routes if it's not a CEASE/Hard Reset.

When doing `clear ip bgp PEER`, we can control if this would be CEASE/Hard Reset
or not by using `bgp hard-administrative-reset` knob.

When `bgp graceful-restart notification` is disabled, STALE routes won't be
retained when receiving Notification message.

Co-authored-by: Biswajit Sadhu <biswajit.sadhu@gmail.com>
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
Donatas Abraitis 2022-05-11 19:42:53 +03:00
parent daa97042a2
commit 20170775da
3 changed files with 26 additions and 4 deletions

View File

@ -1961,6 +1961,15 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
if (bgp_debug_neighbor_events(peer)) if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [FSM] Hold timer expire", peer->host); zlog_debug("%s [FSM] Hold timer expire", peer->host);
/* RFC8538 updates RFC 4724 by defining an extension that permits
* the Graceful Restart procedures to be performed when the BGP
* speaker receives a BGP NOTIFICATION message or the Hold Time expires.
*/
if (peer_established(peer) &&
bgp_has_graceful_restart_notification(peer))
if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE))
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0); return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
} }

View File

@ -748,6 +748,13 @@ struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify)
return bn; return bn;
} }
/* Check if Graceful-Restart N-bit is exchanged */
bool bgp_has_graceful_restart_notification(struct peer *peer)
{
return CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) &&
CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
}
/* /*
* Check if to send BGP CEASE Notification/Hard Reset? * Check if to send BGP CEASE Notification/Hard Reset?
*/ */
@ -757,8 +764,7 @@ bool bgp_notify_send_hard_reset(struct peer *peer, uint8_t code,
/* When the "N" bit has been exchanged, a Hard Reset message is used to /* When the "N" bit has been exchanged, a Hard Reset message is used to
* indicate to the peer that the session is to be fully terminated. * indicate to the peer that the session is to be fully terminated.
*/ */
if (!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) || if (!bgp_has_graceful_restart_notification(peer))
!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV))
return false; return false;
/* /*
@ -797,8 +803,7 @@ bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code,
/* When the "N" bit has been exchanged, a Hard Reset message is used to /* When the "N" bit has been exchanged, a Hard Reset message is used to
* indicate to the peer that the session is to be fully terminated. * indicate to the peer that the session is to be fully terminated.
*/ */
if (!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) || if (!bgp_has_graceful_restart_notification(peer))
!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV))
return false; return false;
if (code == BGP_NOTIFY_CEASE && subcode == BGP_NOTIFY_CEASE_HARD_RESET) if (code == BGP_NOTIFY_CEASE && subcode == BGP_NOTIFY_CEASE_HARD_RESET)
@ -2094,6 +2099,13 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
/* If Graceful-Restart N-bit (Notification) is exchanged,
* and it's not a Hard Reset, let's retain the routes.
*/
if (bgp_has_graceful_restart_notification(peer) && !hard_reset &&
CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE))
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
bgp_peer_gr_flags_update(peer); bgp_peer_gr_flags_update(peer);
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp,
peer->bgp->peer); peer->bgp->peer);

View File

@ -88,6 +88,7 @@ extern void bgp_send_delayed_eor(struct bgp *bgp);
void bgp_packet_process_error(struct thread *thread); void bgp_packet_process_error(struct thread *thread);
extern struct bgp_notify extern struct bgp_notify
bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify); bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify);
extern bool bgp_has_graceful_restart_notification(struct peer *peer);
extern bool bgp_notify_send_hard_reset(struct peer *peer, uint8_t code, extern bool bgp_notify_send_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode); uint8_t subcode);
extern bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code, extern bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code,