/*
* 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.
/*
* 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;
}
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.
*
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);
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;
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 */
{ .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),
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;
}
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",
? ""
: "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) {
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);
#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.
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
---------------------------------------------------------