summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonatas Abraitis <donatas@opensourcerouting.org>2022-10-10 14:46:30 +0200
committerGitHub <noreply@github.com>2022-10-10 14:46:30 +0200
commiteb531283675924c3bfb5034e54d234679208a2b4 (patch)
treeb01d54895bee560fb64af00d51dab5c42b380d5f
parentMerge pull request #12082 from anlancs/fix/cleanup-21 (diff)
parentbgpd: support TCP keepalive for BGP connection (diff)
downloadfrr-eb531283675924c3bfb5034e54d234679208a2b4.tar.xz
frr-eb531283675924c3bfb5034e54d234679208a2b4.zip
Merge pull request #9998 from pguibert6WIND/bgp_tcp_keepalive
Bgp tcp keepalive
-rw-r--r--bgpd/bgp_network.c26
-rw-r--r--bgpd/bgp_vty.c48
-rw-r--r--bgpd/bgpd.c16
-rw-r--r--bgpd/bgpd.h8
-rw-r--r--doc/user/bgp.rst7
-rw-r--r--lib/sockopt.c49
-rw-r--r--lib/sockopt.h22
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