diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 4575b8afbe..14dcf2b593 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1105,6 +1105,9 @@ void bgp_fsm_change_status(struct peer *peer, int status) peer->ostatus = peer->status; peer->status = status; + /* Reset received keepalives counter on every FSM change */ + peer->rtt_keepalive_rcv = 0; + /* Fire backward transition hook if that's the case */ if (peer->ostatus > peer->status) hook_call(peer_backward_transition, peer); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0d81403803..15dba37667 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1432,6 +1432,27 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size) bgp_update_implicit_eors(peer); + peer->rtt = sockopt_tcp_rtt(peer->fd); + + /* If the peer's RTT is higher than expected, shutdown + * the peer automatically. + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN) + && peer->rtt > peer->rtt_expected) { + + peer->rtt_keepalive_rcv++; + + if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) { + zlog_warn( + "%s shutdown due to high round-trip-time (%dms > %dms)", + peer->host, peer->rtt, peer->rtt_expected); + peer_flag_set(peer, PEER_FLAG_SHUTDOWN); + } + } else { + if (peer->rtt_keepalive_rcv) + peer->rtt_keepalive_rcv--; + } + return Receive_KEEPALIVE_message; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e94a31b685..d80667699a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4480,6 +4480,64 @@ ALIAS(no_neighbor_shutdown_msg, no_neighbor_shutdown_cmd, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Administratively shut down this neighbor\n") +DEFUN(neighbor_shutdown_rtt, + neighbor_shutdown_rtt_cmd, + "neighbor shutdown rtt (1-65535) [count (1-255)]", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n" + "Shutdown if round-trip-time is higher than expected\n" + "Round-trip-time in milliseconds\n" + "Specify the number of keepalives before shutdown\n" + "The number of keepalives with higher RTT to shutdown\n") +{ + int idx_peer = 1; + int idx_rtt = 4; + int idx_count = 0; + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + peer->rtt_expected = strtol(argv[idx_rtt]->arg, NULL, 10); + + if (argv_find(argv, argc, "count", &idx_count)) + peer->rtt_keepalive_conf = + strtol(argv[idx_count + 1]->arg, NULL, 10); + + return peer_flag_set_vty(vty, argv[idx_peer]->arg, + PEER_FLAG_RTT_SHUTDOWN); +} + +DEFUN(no_neighbor_shutdown_rtt, + no_neighbor_shutdown_rtt_cmd, + "no neighbor shutdown rtt [(1-65535) [count (1-255)]]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Administratively shut down this neighbor\n" + "Shutdown if round-trip-time is higher than expected\n" + "Round-trip-time in milliseconds\n" + "Specify the number of keepalives before shutdown\n" + "The number of keepalives with higher RTT to shutdown\n") +{ + int idx_peer = 2; + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + peer->rtt_expected = 0; + peer->rtt_keepalive_conf = 1; + + return peer_flag_unset_vty(vty, argv[idx_peer]->arg, + PEER_FLAG_RTT_SHUTDOWN); +} + /* neighbor capability dynamic. */ DEFUN (neighbor_capability_dynamic, neighbor_capability_dynamic_cmd, @@ -14829,6 +14887,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s shutdown\n", addr); } + if (peergroup_flag_check(peer, PEER_FLAG_RTT_SHUTDOWN)) + vty_out(vty, " neighbor %s shutdown rtt %u count %u\n", addr, + peer->rtt_expected, peer->rtt_keepalive_conf); + /* bfd */ if (peer->bfd_info) { if (!peer_group_active(peer) || !g_peer->bfd_info) { @@ -16628,6 +16690,8 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_shutdown_cmd); install_element(BGP_NODE, &neighbor_shutdown_msg_cmd); install_element(BGP_NODE, &no_neighbor_shutdown_msg_cmd); + install_element(BGP_NODE, &neighbor_shutdown_rtt_cmd); + install_element(BGP_NODE, &no_neighbor_shutdown_rtt_cmd); /* "neighbor capability extended-nexthop" commands.*/ install_element(BGP_NODE, &neighbor_capability_enhe_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3056a5fe62..d638c6686e 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1604,6 +1604,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, /* Default TTL set. */ peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : BGP_DEFAULT_TTL; + /* Default configured keepalives count for shutdown rtt command */ + peer->rtt_keepalive_conf = 1; + SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); if (afi && safi) { @@ -3865,6 +3868,7 @@ struct peer_flag_action { static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_PASSIVE, 0, peer_change_reset}, {PEER_FLAG_SHUTDOWN, 0, peer_change_reset}, + {PEER_FLAG_RTT_SHUTDOWN, 0, peer_change_none}, {PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none}, @@ -3967,6 +3971,7 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag) peer_nsf_stop(peer); UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); + if (peer->t_pmax_restart) { BGP_TIMER_OFF(peer->t_pmax_restart); if (bgp_debug_neighbor_events(peer)) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 87cdcd2e71..8707ebacb6 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -968,6 +968,9 @@ struct peer { int fd; /* File descriptor */ int ttl; /* TTL of TCP connection to the peer. */ int rtt; /* Estimated round-trip-time from TCP_INFO */ + int rtt_expected; /* Expected round-trip-time for a peer */ + uint8_t rtt_keepalive_rcv; /* Received count for RTT shutdown */ + uint8_t rtt_keepalive_conf; /* Configured count for RTT shutdown */ int gtsm_hops; /* minimum hopcount to peer */ char *desc; /* Description of the peer. */ unsigned short port; /* Destination port for peer */ @@ -1118,6 +1121,7 @@ struct peer { #define PEER_FLAG_GRACEFUL_RESTART_HELPER (1U << 23) /* Helper */ #define PEER_FLAG_GRACEFUL_RESTART (1U << 24) /* Graceful Restart */ #define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */ +#define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */ /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 4a5bdc2428..25eaa577c1 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1216,14 +1216,14 @@ Defining Peers The time in milliseconds that BGP will delay before deciding what peers can be put into an update-group together in order to generate a single update for them. The default time is 1000. - + .. _bgp-configuring-peers: Configuring Peers ^^^^^^^^^^^^^^^^^ -.. index:: [no] neighbor PEER shutdown [message MSG...] -.. clicmd:: [no] neighbor PEER shutdown [message MSG...] +.. index:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] +.. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] Shutdown the peer. We can delete the neighbor's configuration by ``no neighbor PEER remote-as ASN`` but all configuration of the neighbor @@ -1232,6 +1232,12 @@ Configuring Peers Optionally you can specify a shutdown message `MSG`. + Also, you can specify optionally _rtt_ in milliseconds to automatically + shutdown the peer if round-trip-time becomes higher than defined. + + Additional _count_ parameter is the number of keepalive messages to count + before shutdown the peer if round-trip-time becomes higher than defined. + .. index:: [no] neighbor PEER disable-connected-check .. clicmd:: [no] neighbor PEER disable-connected-check