diff options
author | Donatas Abraitis <donatas@opensourcerouting.org> | 2022-10-10 14:46:30 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-10 14:46:30 +0200 |
commit | eb531283675924c3bfb5034e54d234679208a2b4 (patch) | |
tree | b01d54895bee560fb64af00d51dab5c42b380d5f | |
parent | Merge pull request #12082 from anlancs/fix/cleanup-21 (diff) | |
parent | bgpd: support TCP keepalive for BGP connection (diff) | |
download | frr-eb531283675924c3bfb5034e54d234679208a2b4.tar.xz frr-eb531283675924c3bfb5034e54d234679208a2b4.zip |
Merge pull request #9998 from pguibert6WIND/bgp_tcp_keepalive
Bgp tcp keepalive
-rw-r--r-- | bgpd/bgp_network.c | 26 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 48 | ||||
-rw-r--r-- | bgpd/bgpd.c | 16 | ||||
-rw-r--r-- | bgpd/bgpd.h | 8 | ||||
-rw-r--r-- | doc/user/bgp.rst | 7 | ||||
-rw-r--r-- | lib/sockopt.c | 49 | ||||
-rw-r--r-- | lib/sockopt.h | 22 |
7 files changed, 176 insertions, 0 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 9ecc2ae4e..9582ec01e 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -207,6 +207,25 @@ int bgp_md5_set(struct peer *peer) return bgp_md5_set_password(peer, peer->password); } +static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd) +{ + if (!bgp) + return; + if (bgp->tcp_keepalive_idle != 0) { + int ret; + + ret = setsockopt_tcp_keepalive(fd, bgp->tcp_keepalive_idle, + bgp->tcp_keepalive_intvl, + bgp->tcp_keepalive_probes); + if (ret < 0) + zlog_err( + "Can't set TCP keepalive on socket %d, idle %u intvl %u probes %u", + fd, bgp->tcp_keepalive_idle, + bgp->tcp_keepalive_intvl, + bgp->tcp_keepalive_probes); + } +} + int bgp_md5_unset(struct peer *peer) { /* Unset the password from listen socket. */ @@ -415,6 +434,9 @@ static void bgp_accept(struct thread *thread) bgp_socket_set_buffer_size(bgp_sock); + /* Set TCP keepalive when TCP keepalive is enabled */ + bgp_update_setsockopt_tcp_keepalive(bgp, bgp_sock); + /* Check remote IP address */ peer1 = peer_lookup(bgp, &su); @@ -718,12 +740,16 @@ int bgp_connect(struct peer *peer) bgp_socket_set_buffer_size(peer->fd); + /* Set TCP keepalive when TCP keepalive is enabled */ + bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd); + if (bgp_set_socket_ttl(peer, peer->fd) < 0) { peer->last_reset = PEER_DOWN_SOCKET_ERROR; if (bgp_debug_neighbor_events(peer)) zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)", __func__, peer->host, safe_strerror(errno), errno); + return -1; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3c6a05c73..de810aa19 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2348,6 +2348,15 @@ void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp) vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time); } +/* BGP TCP keepalive */ +static void bgp_config_tcp_keepalive(struct vty *vty, struct bgp *bgp) +{ + if (bgp->tcp_keepalive_idle) { + vty_out(vty, " bgp tcp-keepalive %u %u %u\n", + bgp->tcp_keepalive_idle, bgp->tcp_keepalive_intvl, + bgp->tcp_keepalive_probes); + } +} DEFUN (bgp_coalesce_time, bgp_coalesce_time_cmd, @@ -2571,6 +2580,38 @@ DEFUN(no_bgp_minimum_holdtime, no_bgp_minimum_holdtime_cmd, return CMD_SUCCESS; } +DEFPY(bgp_tcp_keepalive, bgp_tcp_keepalive_cmd, + "bgp tcp-keepalive (1-65535)$idle (1-65535)$intvl (1-30)$probes", + BGP_STR + "TCP keepalive parameters\n" + "TCP keepalive idle time (seconds)\n" + "TCP keepalive interval (seconds)\n" + "TCP keepalive maximum probes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + bgp_tcp_keepalive_set(bgp, (uint16_t)idle, (uint16_t)intvl, + (uint16_t)probes); + + return CMD_SUCCESS; +} + +DEFPY(no_bgp_tcp_keepalive, no_bgp_tcp_keepalive_cmd, + "no bgp tcp-keepalive [(1-65535) (1-65535) (1-30)]", + NO_STR + BGP_STR + "TCP keepalive parameters\n" + "TCP keepalive idle time (seconds)\n" + "TCP keepalive interval (seconds)\n" + "TCP keepalive maximum probes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + bgp_tcp_keepalive_unset(bgp); + + return CMD_SUCCESS; +} + DEFUN (bgp_client_to_client_reflection, bgp_client_to_client_reflection_cmd, "bgp client-to-client reflection", @@ -17698,6 +17739,9 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " bgp graceful-restart preserve-fw-state\n"); + /* BGP TCP keepalive */ + bgp_config_tcp_keepalive(vty, bgp); + /* Stale timer for RIB */ if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) vty_out(vty, @@ -19577,6 +19621,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_ttl_security_cmd); install_element(BGP_NODE, &no_neighbor_ttl_security_cmd); + /* "bgp tcp-keepalive" commands */ + install_element(BGP_NODE, &bgp_tcp_keepalive_cmd); + install_element(BGP_NODE, &no_bgp_tcp_keepalive_cmd); + /* "show [ip] bgp memory" commands. */ install_element(VIEW_NODE, &show_bgp_memory_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5a9ec1bbd..1bcd71440 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -551,6 +551,21 @@ void bgp_timers_unset(struct bgp *bgp) bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN; } +void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t keepalive_idle, + uint16_t keepalive_intvl, uint16_t keepalive_probes) +{ + bgp->tcp_keepalive_idle = keepalive_idle; + bgp->tcp_keepalive_intvl = keepalive_intvl; + bgp->tcp_keepalive_probes = keepalive_probes; +} + +void bgp_tcp_keepalive_unset(struct bgp *bgp) +{ + bgp->tcp_keepalive_idle = 0; + bgp->tcp_keepalive_intvl = 0; + bgp->tcp_keepalive_probes = 0; +} + /* BGP confederation configuration. */ void bgp_confederation_id_set(struct bgp *bgp, as_t as) { @@ -3182,6 +3197,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; + bgp_tcp_keepalive_unset(bgp); bgp_timers_unset(bgp); bgp->default_min_holdtime = 0; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index c8bcb5cd5..af4655065 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -132,6 +132,7 @@ struct bgp_master { /* Various BGP global configuration. */ uint8_t options; + #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_NO_LISTEN (1 << 1) #define BGP_OPT_NO_ZEBRA (1 << 2) @@ -768,6 +769,10 @@ struct bgp { char srv6_locator_name[SRV6_LOCNAME_SIZE]; struct list *srv6_locator_chunks; struct list *srv6_functions; + /* TCP keepalive parameters for BGP connection */ + uint16_t tcp_keepalive_idle; + uint16_t tcp_keepalive_intvl; + uint16_t tcp_keepalive_probes; struct timeval ebgprequirespolicywarning; #define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000 @@ -2213,6 +2218,9 @@ extern int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, const char *rmap, struct route_map *route_map); extern int peer_default_originate_unset(struct peer *, afi_t, safi_t); +extern void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t idle, + uint16_t interval, uint16_t probes); +extern void bgp_tcp_keepalive_unset(struct bgp *bgp); extern void peer_port_set(struct peer *, uint16_t); extern void peer_port_unset(struct peer *); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f136ea4ae..25d1cbfb6 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1790,6 +1790,13 @@ Configuring Peers with lower holdtime less than configured minimum holdtime. When this command is not set, minimum holdtime does not work. +.. clicmd:: bgp tcp-keepalive (1-65535) (1-65535) (1-30) + + This command allows user to configure TCP keepalive with new BGP peers. + Each parameter respectively stands for TCP keepalive idle timer (seconds), + interval (seconds), and maximum probes. By default, TCP keepalive is + disabled. + Displaying Information about Peers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/lib/sockopt.c b/lib/sockopt.c index 7a2b8a1c8..de11a9eab 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -693,3 +693,52 @@ int sockopt_tcp_mss_get(int sock) return tcp_maxseg; } + +int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle, + uint16_t keepalive_intvl, + uint16_t keepalive_probes) +{ + int val = 1; + + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: setsockopt SO_KEEPALIVE (%d): %s", + __func__, sock, safe_strerror(errno)); + return -1; + } + +#if defined __OpenBSD__ + return 0; +#else + /* Send first probe after keepalive_idle seconds */ + val = keepalive_idle; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < + 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: setsockopt TCP_KEEPIDLE (%d): %s", + __func__, sock, safe_strerror(errno)); + return -1; + } + + /* Set interval between two probes */ + val = keepalive_intvl; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < + 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: setsockopt TCP_KEEPINTVL (%d): %s", + __func__, sock, safe_strerror(errno)); + return -1; + } + + /* Set maximum probes */ + val = keepalive_probes; + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: setsockopt TCP_KEEPCNT (%d): %s", + __func__, sock, safe_strerror(errno)); + return -1; + } + + return 0; +#endif +} diff --git a/lib/sockopt.h b/lib/sockopt.h index 6c80841e3..694edf763 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -153,6 +153,28 @@ extern int sockopt_tcp_mss_set(int sock, int tcp_maxseg); * Socket to get max segement size. */ extern int sockopt_tcp_mss_get(int sock); + +/* + * Configure TCP keepalive for a given socket + * + * sock + * Socket to enable keepalive option on. + * + * keepalive_idle + * number of seconds a connection needs to be idle + * before sending out keep-alive proves + * + * keepalive_intvl + * number of seconds between TCP keep-alive probes + * + * keepalive_probes + * max number of probers to send before giving up + * and killing tcp connection + */ +extern int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle, + uint16_t keepalive_intvl, + uint16_t keepalive_probes); + #ifdef __cplusplus } #endif |