Skip to content

Commit

Permalink
bgpd: Send Hard Reset Notification for BGP_NOTIFY_CEASE_ADMIN_RESET
Browse files Browse the repository at this point in the history
`clear bgp neighbor` should send Hard Reset and graceful restart should be
activated. Let's make this adjustable.

https://datatracker.ietf.org/doc/html/rfc8538#section-5.1

   +-------+------------------------------------+----------------------+
   | Value |                Name                |  Suggested Behavior  |
   +-------+------------------------------------+----------------------+
   |   1   | Maximum Number of Prefixes Reached |      Hard Reset      |
   |   2   |      Administrative Shutdown       |      Hard Reset      |
   |   3   |         Peer De-configured         |      Hard Reset      |
   |   4   |        Administrative Reset        | Provide user control |
   |   5   |        Connection Rejected         |    Graceful Cease    |
   |   6   |     Other Configuration Change     |    Graceful Cease    |
   |   7   |  Connection Collision Resolution   |    Graceful Cease    |
   |   8   |          Out of Resources          |    Graceful Cease    |
   |   9   |             Hard Reset             |      Hard Reset      |
   +-------+------------------------------------+----------------------+

Enabled by default.

Co-authored-by: Biswajit Sadhu <biswajit.sadhu@gmail.com>
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
  • Loading branch information
ton31337 and bisdhdh committed May 10, 2022
1 parent 026f28e commit 1ae314b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 6 deletions.
38 changes: 34 additions & 4 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,8 @@ struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify)
/*
* Check if to send BGP CEASE Notification/Hard Reset?
*/
bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code, uint8_t subcode)
bool bgp_notify_send_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode)
{
/* 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.
Expand All @@ -763,13 +764,22 @@ bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code, uint8_t subcode)
/*
* https://datatracker.ietf.org/doc/html/rfc8538#section-5.1
*/
if (code == BGP_NOTIFY_CEASE || code == BGP_NOTIFY_HOLD_ERR) {
if (code == BGP_NOTIFY_CEASE) {
switch (subcode) {
case BGP_NOTIFY_CEASE_MAX_PREFIX:
case BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN:
case BGP_NOTIFY_CEASE_PEER_UNCONFIG:
case BGP_NOTIFY_CEASE_HARD_RESET:
return true;
case BGP_NOTIFY_CEASE_ADMIN_RESET:
/* Provide user control:
* `bgp hard-adminstrative-reset`
*/
if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_HARD_ADMIN_RESET))
return true;
else
return false;
default:
break;
}
Expand All @@ -778,6 +788,25 @@ bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code, uint8_t subcode)
return false;
}

/*
* Check if received BGP CEASE Notification/Hard Reset?
*/
bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode)
{
/* 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.
*/
if (!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) ||
!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV))
return false;

if (code == BGP_NOTIFY_CEASE && subcode == BGP_NOTIFY_CEASE_HARD_RESET)
return true;

return false;
}

/*
* Creates a BGP Notify and appends it to the peer's output queue.
*
Expand All @@ -802,7 +831,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
uint8_t sub_code, uint8_t *data, size_t datalen)
{
struct stream *s;
bool hard_reset = bgp_notify_is_hard_reset(peer, code, sub_code);
bool hard_reset = bgp_notify_send_hard_reset(peer, code, sub_code);

/* Lock I/O mutex to prevent other threads from pushing packets */
frr_mutex_lock_autounlock(&peer->io_mtx);
Expand Down Expand Up @@ -1992,7 +2021,8 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
memcpy(outer.raw_data, stream_pnt(peer->curr), outer.length);
}

hard_reset = bgp_notify_is_hard_reset(peer, outer.code, outer.subcode);
hard_reset =
bgp_notify_received_hard_reset(peer, outer.code, outer.subcode);
if (hard_reset && outer.length) {
inner = bgp_notify_decapsulate_hard_reset(&outer);
peer->notify.hard_reset = true;
Expand Down
6 changes: 4 additions & 2 deletions bgpd/bgp_packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ extern void bgp_send_delayed_eor(struct bgp *bgp);
void bgp_packet_process_error(struct thread *thread);
extern struct bgp_notify
bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify);
extern bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode);
extern bool bgp_notify_send_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode);
extern bool bgp_notify_received_hard_reset(struct peer *peer, uint8_t code,
uint8_t subcode);

#endif /* _QUAGGA_BGP_PACKET_H */
36 changes: 36 additions & 0 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_GRACEFUL_NOTIFICATION,
{ .val_bool = false, .match_version = "< 8.3", },
{ .val_bool = true },
);
FRR_CFG_DEFAULT_BOOL(BGP_HARD_ADMIN_RESET,
{ .val_bool = false, .match_version = "< 8.3", },
{ .val_bool = true },
);

DEFINE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
Expand Down Expand Up @@ -575,6 +579,8 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
SET_FLAG((*bgp)->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
if (DFLT_BGP_GRACEFUL_NOTIFICATION)
SET_FLAG((*bgp)->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);
if (DFLT_BGP_HARD_ADMIN_RESET)
SET_FLAG((*bgp)->flags, BGP_FLAG_HARD_ADMIN_RESET);

ret = BGP_SUCCESS;
}
Expand Down Expand Up @@ -2892,6 +2898,23 @@ DEFPY (bgp_graceful_restart_notification,
return CMD_SUCCESS;
}

DEFPY (bgp_administrative_reset,
bgp_administrative_reset_cmd,
"[no$no] bgp hard-administrative-reset",
NO_STR
BGP_STR
"Send Hard Reset CEASE Notification for 'Administrative Reset'\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);

if (no)
UNSET_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET);
else
SET_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET);

return CMD_SUCCESS;
}

DEFUN (bgp_graceful_restart_disable,
bgp_graceful_restart_disable_cmd,
"bgp graceful-restart-disable",
Expand Down Expand Up @@ -17167,6 +17190,16 @@ int bgp_config_write(struct vty *vty)
? ""
: "no ");

/* Send Hard Reset CEASE Notification for 'Administrative Reset'
*/
if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_HARD_ADMIN_RESET) !=
SAVE_BGP_HARD_ADMIN_RESET)
vty_out(vty, " %sbgp hard-administrative-reset\n",
CHECK_FLAG(bgp->flags,
BGP_FLAG_HARD_ADMIN_RESET)
? ""
: "no ");

/* BGP default <afi>-<safi> */
FOREACH_AFI_SAFI (afi, safi) {
if (afi == AFI_IP && safi == SAFI_UNICAST) {
Expand Down Expand Up @@ -17950,6 +17983,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);

/* "bgp hard-administrative-reset" commands */
install_element(BGP_NODE, &bgp_administrative_reset_cmd);

/* "bgp long-lived-graceful-restart" commands */
install_element(BGP_NODE, &bgp_llgr_stalepath_time_cmd);
install_element(BGP_NODE, &no_bgp_llgr_stalepath_time_cmd);
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,8 @@ struct bgp {
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 29)
/* Indicate Graceful Restart support for BGP NOTIFICATION messages */
#define BGP_FLAG_GRACEFUL_NOTIFICATION (1 << 30)
/* Send Hard Reset CEASE Notification for 'Administrative Reset' */
#define BGP_FLAG_HARD_ADMIN_RESET (1 << 31)

/* BGP default address-families.
* New peers inherit enabled afi/safis from bgp instance.
Expand Down
13 changes: 13 additions & 0 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,19 @@ Suppress duplicate updates
Suppress duplicate updates if the route actually not changed.
Default: enabled.

Send Hard Reset CEASE Notification for Administrative Reset
-----------------------------------------------------------

.. clicmd:: bgp hard-administrative-reset

Send Hard Reset CEASE Notification for 'Administrative Reset' events.

When disabled, and Graceful Restart Notification capability is exchanged
between the peers, Graceful Restart procedures apply, and routes will be
retained.

Enabled by default.

Disable checking if nexthop is connected on EBGP sessions
---------------------------------------------------------

Expand Down

0 comments on commit 1ae314b

Please sign in to comment.