diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 55d7a29d98..f3857162c3 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -442,6 +442,11 @@ static int bgp_accept(struct thread *thread) if (peer1) { /* Dynamic neighbor has been created, let it proceed */ peer1->fd = bgp_sock; + + /* Set the user configured MSS to TCP socket */ + if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) + sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss); + bgp_fsm_change_status(peer1, Active); BGP_TIMER_OFF( peer1->t_start); /* created in peer_create() */ @@ -713,6 +718,10 @@ int bgp_connect(struct peer *peer) set_nonblocking(peer->fd); + /* Set the user configured MSS to TCP socket */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) + sockopt_tcp_mss_set(peer->fd, peer->tcp_mss); + bgp_socket_set_buffer_size(peer->fd); if (bgp_set_socket_ttl(peer, peer->fd) < 0) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index eefadc0202..0347f49cb8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -22,6 +22,7 @@ #include "command.h" #include "lib/json.h" +#include "lib/sockopt.h" #include "lib_errors.h" #include "lib/zclient.h" #include "lib/printfrr.h" @@ -12594,6 +12595,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, uint8_t *msg; json_object *json_neigh = NULL; time_t epoch_tbuf; + uint32_t sync_tcp_mss; bgp = p->bgp; @@ -12855,6 +12857,15 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, p->v_delayopen * 1000); } + /* Configured and Synced tcp-mss value for peer */ + if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { + sync_tcp_mss = sockopt_tcp_mss_get(p->fd); + json_object_int_add(json_neigh, "bgpTcpMssConfigured", + p->tcp_mss); + json_object_int_add(json_neigh, "bgpTcpMssSynced", + sync_tcp_mss); + } + if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) { json_object_int_add(json_neigh, "bgpTimerConfiguredHoldTimeMsecs", @@ -12938,6 +12949,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " Configured DelayOpenTime is %d seconds\n", p->delayopen); + + /* Configured and synced tcp-mss value for peer */ + if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) { + sync_tcp_mss = sockopt_tcp_mss_get(p->fd); + vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); + vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); + } } /* Capability. */ if (p->status == Established) { @@ -16357,6 +16375,55 @@ void cli_show_bgp_global_afi_safi_ip_unicast_redistribution_list( vty_out(vty, "\n"); } +/* Neighbor update tcp-mss. */ +static int peer_tcp_mss_vty(struct vty *vty, const char *peer_str, + const char *tcp_mss_str) +{ + struct peer *peer; + uint32_t tcp_mss_val = 0; + + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (tcp_mss_str) { + tcp_mss_val = strtoul(tcp_mss_str, NULL, 10); + peer_tcp_mss_set(peer, tcp_mss_val); + } else { + peer_tcp_mss_unset(peer); + } + + return CMD_SUCCESS; +} + +DEFUN(neighbor_tcp_mss, neighbor_tcp_mss_cmd, + "neighbor tcp-mss (1-65535)", + NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "TCP max segment size\n" + "TCP MSS value\n") +{ + int peer_index = 1; + int mss_index = 3; + + vty_out(vty, + " Warning: Reset BGP session for tcp-mss value to take effect\n"); + return peer_tcp_mss_vty(vty, argv[peer_index]->arg, + argv[mss_index]->arg); +} + +DEFUN(no_neighbor_tcp_mss, no_neighbor_tcp_mss_cmd, + "no neighbor tcp-mss [(1-65535)]", + NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "TCP max segment size\n" + "TCP MSS value\n") +{ + int peer_index = 2; + + vty_out(vty, + " Warning: Reset BGP session for tcp-mss value to take effect\n"); + return peer_tcp_mss_vty(vty, argv[peer_index]->arg, NULL); +} + static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { @@ -16806,6 +16873,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname); } + /* TCP max segment size */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS)) + vty_out(vty, " neighbor %s tcp-mss %d\n", addr, peer->tcp_mss); + /* passive */ if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE)) vty_out(vty, " neighbor %s passive\n", addr); @@ -19217,6 +19288,10 @@ void bgp_vty_init(void) install_element(BGP_IPV6_NODE, &af_no_route_map_vpn_imexport_cmd); install_element(BGP_IPV4_NODE, &af_no_import_vrf_route_map_cmd); install_element(BGP_IPV6_NODE, &af_no_import_vrf_route_map_cmd); + + /* tcp-mss command */ + install_element(BGP_NODE, &neighbor_tcp_mss_cmd); + install_element(BGP_NODE, &no_neighbor_tcp_mss_cmd); } #include "memory.h" diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 20bb5e5320..2c9aad5d21 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -43,6 +43,7 @@ #include "jhash.h" #include "table.h" #include "lib/json.h" +#include "lib/sockopt.h" #include "frr_pthread.h" #include "bitfield.h" @@ -1439,6 +1440,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->local_as = peer_src->local_as; peer_dst->port = peer_src->port; + /* copy tcp_mss value */ + peer_dst->tcp_mss = peer_src->tcp_mss; (void)peer_sort(peer_dst); peer_dst->rmap_type = peer_src->rmap_type; @@ -5116,6 +5119,26 @@ void peer_port_unset(struct peer *peer) peer->port = BGP_PORT_DEFAULT; } +/* Set the TCP-MSS value in the peer structure, + * This gets applied only after connection reset + * So this value will be used in bgp_connect. + */ +void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss) +{ + peer->tcp_mss = tcp_mss; + SET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); +} + +/* Reset the TCP-MSS value in the peer structure, + * This gets applied only after connection reset + * So this value will be used in bgp_connect. + */ +void peer_tcp_mss_unset(struct peer *peer) +{ + UNSET_FLAG(peer->flags, PEER_FLAG_TCP_MSS); + peer->tcp_mss = 0; +} + /* * Helper function that is called after the name of the policy * being used by a peer has changed (AF specific). Automatically diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 88588952ba..3343b332f4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1241,6 +1241,8 @@ struct peer { #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 */ +#define PEER_FLAG_TIMER_DELAYOPEN (1U << 27) /* delayopen timer */ +#define PEER_FLAG_TCP_MSS (1U << 28) /* tcp-mss */ /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1248,8 +1250,6 @@ struct peer { *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT */ -#define PEER_FLAG_TIMER_DELAYOPEN (1 << 27) /* delayopen timer */ - struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD]; enum peer_mode peer_gr_present_state; /* Non stop forwarding afi-safi count for BGP gr feature*/ @@ -1606,6 +1606,9 @@ struct peer { bool advmap_config_change[AFI_MAX][SAFI_MAX]; bool advmap_table_change; + /* set TCP max segment size */ + uint32_t tcp_mss; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); @@ -2409,4 +2412,6 @@ DECLARE_HOOK(bgp_rpki_prefix_status, void peer_nsf_stop(struct peer *peer); +void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss); +void peer_tcp_mss_unset(struct peer *peer); #endif /* _QUAGGA_BGPD_H */ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 87710e98c6..314873640d 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -3908,6 +3908,147 @@ Example of how to set up a 6-Bone connection. log file bgpd.log ! +.. _bgp-tcp-mss: + +BGP tcp-mss support +=================== +TCP provides a mechanism for the user to specify the max segment size. +setsockopt API is used to set the max segment size for TCP session. We +can configure this as part of BGP neighbor configuration. + +This document explains how to avoid ICMP vulnerability issues by limiting +TCP max segment size when you are using MTU discovery. Using MTU discovery +on TCP paths is one method of avoiding BGP packet fragmentation. + +TCP negotiates a maximum segment size (MSS) value during session connection +establishment between two peers. The MSS value negotiated is primarily based +on the maximum transmission unit (MTU) of the interfaces to which the +communicating peers are directly connected. However, due to variations in +link MTU on the path taken by the TCP packets, some packets in the network +that are well within the MSS value might be fragmented when the packet size +exceeds the link's MTU. + +This feature is supported with TCP over IPv4 and TCP over IPv6. + +CLI Configuration: +------------------ +Below configuration can be done in router bgp mode and allows the user to +configure the tcp-mss value per neighbor. The configuration gets applied +only after hard reset is performed on that neighbor. If we configure tcp-mss +on both the neighbors then both neighbors need to be reset. + +The configuration takes effect based on below rules, so there is a configured +tcp-mss and a synced tcp-mss value per TCP session. + +By default if the configuration is not done then the TCP max segment size is +set to the Maximum Transmission unit (MTU) – (IP/IP6 header size + TCP header +size + ethernet header). For IPv4 its MTU – (20 bytes IP header + 20 bytes TCP +header + 12 bytes ethernet header) and for IPv6 its MTU – (40 bytes IPv6 header ++ 20 bytes TCP header + 12 bytes ethernet header). + +If the config is done then it reduces 12-14 bytes for the ether header and +uses it after synchronizing in TCP handshake. + +.. clicmd:: neighbor tcp-mss (1-65535) + +When tcp-mss is configured kernel reduces 12-14 bytes for ethernet header. +E.g. if tcp-mss is configured as 150 the synced value will be 138. + +Note: configured and synced value is different since TCP module will reduce +12 bytes for ethernet header. + +Running config: +--------------- + +.. code-block:: frr + + frr# show running-config + Building configuration... + + Current configuration: + ! + router bgp 100 + bgp router-id 192.0.2.1 + neighbor 198.51.100.2 remote-as 100 + neighbor 198.51.100.2 tcp-mss 150 => new entry + neighbor 2001:DB8::2 remote-as 100 + neighbor 2001:DB8::2 tcp-mss 400 => new entry + +Show command: +------------- + +.. code-block:: frr + + frr# show bgp neighbors 198.51.100.2 + BGP neighbor is 198.51.100.2, remote AS 100, local AS 100, internal link + Hostname: frr + BGP version 4, remote router ID 192.0.2.2, local router ID 192.0.2.1 + BGP state = Established, up for 02:15:28 + Last read 00:00:28, Last write 00:00:28 + Hold time is 180, keepalive interval is 60 seconds + Configured tcp-mss is 150, synced tcp-mss is 138 => new display + +.. code-block:: frr + + frr# show bgp neighbors 2001:DB8::2 + BGP neighbor is 2001:DB8::2, remote AS 100, local AS 100, internal link + Hostname: frr + BGP version 4, remote router ID 192.0.2.2, local router ID 192.0.2.1 + BGP state = Established, up for 02:16:34 + Last read 00:00:34, Last write 00:00:34 + Hold time is 180, keepalive interval is 60 seconds + Configured tcp-mss is 400, synced tcp-mss is 388 => new display + +Show command json output: +------------------------- + +.. code-block:: frr + + frr# show bgp neighbors 2001:DB8::2 json + { + "2001:DB8::2":{ + "remoteAs":100, + "localAs":100, + "nbrInternalLink":true, + "hostname":"frr", + "bgpVersion":4, + "remoteRouterId":"192.0.2.2", + "localRouterId":"192.0.2.1", + "bgpState":"Established", + "bgpTimerUpMsec":8349000, + "bgpTimerUpString":"02:19:09", + "bgpTimerUpEstablishedEpoch":1613054251, + "bgpTimerLastRead":9000, + "bgpTimerLastWrite":9000, + "bgpInUpdateElapsedTimeMsecs":8347000, + "bgpTimerHoldTimeMsecs":180000, + "bgpTimerKeepAliveIntervalMsecs":60000, + "bgpTcpMssConfigured":400, => new entry + "bgpTcpMssSynced":388, => new entry + +.. code-block:: frr + + frr# show bgp neighbors 198.51.100.2 json + { + "198.51.100.2":{ + "remoteAs":100, + "localAs":100, + "nbrInternalLink":true, + "hostname":"frr", + "bgpVersion":4, + "remoteRouterId":"192.0.2.2", + "localRouterId":"192.0.2.1", + "bgpState":"Established", + "bgpTimerUpMsec":8370000, + "bgpTimerUpString":"02:19:30", + "bgpTimerUpEstablishedEpoch":1613054251, + "bgpTimerLastRead":30000, + "bgpTimerLastWrite":30000, + "bgpInUpdateElapsedTimeMsecs":8368000, + "bgpTimerHoldTimeMsecs":180000, + "bgpTimerKeepAliveIntervalMsecs":60000, + "bgpTcpMssConfigured":150, => new entry + "bgpTcpMssSynced":138, => new entry .. include:: routeserver.rst diff --git a/lib/sockopt.c b/lib/sockopt.c index b624fe2230..98bfda5079 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -667,3 +667,39 @@ int sockopt_tcp_signature(int sock, union sockunion *su, const char *password) { return sockopt_tcp_signature_ext(sock, su, 0, password); } + +/* set TCP mss value to socket */ +int sockopt_tcp_mss_set(int sock, int tcp_maxseg) +{ + int ret = 0; + socklen_t tcp_maxseg_len = sizeof(tcp_maxseg); + + ret = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, + tcp_maxseg_len); + if (ret != 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: setsockopt(%d): %s", __func__, sock, + safe_strerror(errno)); + } + + return ret; +} + +/* get TCP mss value synced by socket */ +int sockopt_tcp_mss_get(int sock) +{ + int ret = 0; + int tcp_maxseg = 0; + socklen_t tcp_maxseg_len = sizeof(tcp_maxseg); + + ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, + &tcp_maxseg_len); + if (ret != 0) { + flog_err_sys(EC_LIB_SYSTEM_CALL, + "%s failed: getsockopt(%d): %s", __func__, sock, + safe_strerror(errno)); + return 0; + } + + return tcp_maxseg; +} diff --git a/lib/sockopt.h b/lib/sockopt.h index 545abe631f..6c80841e3c 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -133,6 +133,26 @@ extern int sockopt_tcp_signature(int sock, union sockunion *su, extern int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen, const char *password); +/* + * set TCP max segment size. This option allows user to configure + * max segment size for TCP session + * + * sock + * Socket to enable option on. + * + * tcp_maxseg + * value used for TCP segment size negotiation during SYN + */ +extern int sockopt_tcp_mss_set(int sock, int tcp_maxseg); + +/* + * get TCP max segment size. This option allows user to get + * the segment size for TCP session + * + * sock + * Socket to get max segement size. + */ +extern int sockopt_tcp_mss_get(int sock); #ifdef __cplusplus } #endif diff --git a/tests/topotests/bgp_tcp_mss/__init__.py b/tests/topotests/bgp_tcp_mss/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_tcp_mss/r1/bgpd.conf b/tests/topotests/bgp_tcp_mss/r1/bgpd.conf new file mode 100644 index 0000000000..07cfe2e2f1 --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/r1/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 timers 3 10 + exit-address-family +! diff --git a/tests/topotests/bgp_tcp_mss/r1/zebra.conf b/tests/topotests/bgp_tcp_mss/r1/zebra.conf new file mode 100644 index 0000000000..6e9b0b4a7e --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_tcp_mss/r2/bgpd.conf b/tests/topotests/bgp_tcp_mss/r2/bgpd.conf new file mode 100644 index 0000000000..b2d945583c --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/r2/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.255.1 remote-as 65000 + neighbor 192.168.255.1 timers 3 10 + exit-address-family +! diff --git a/tests/topotests/bgp_tcp_mss/r2/zebra.conf b/tests/topotests/bgp_tcp_mss/r2/zebra.conf new file mode 100644 index 0000000000..6c14de583b --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py new file mode 100644 index 0000000000..7500c3b3ad --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python + +# +# bgp_tcp_mss.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Abhinay Ramesh +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_tcp_mss.py: + +Test if works the following commands: +router bgp 65000 + neighbor 192.168.255.2 tcp-mss 500 + +Need to verify if the tcp-mss value is reflected in the TCP session. +""" + +import os +import sys +import json +import time +import pytest +import functools + +# add after imports, before defining classes or functions: +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_tcp_mss(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + "192.168.255.2": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 0}}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_conf_tcp_mss(router, as_num, neigh): + router.vtysh_cmd( + """configure terminal + router bgp {0} + neighbor {1} tcp-mss 500""".format( + as_num, neigh + ) + ) + + def _bgp_clear_session(router): + router.vtysh_cmd("clear bgp *") + + def _bgp_check_neighbor_tcp_mss(router, neigh): + output = json.loads(router.vtysh_cmd("show bgp neighbor {} json".format(neigh))) + expected = { + "{}".format(neigh): {"bgpTcpMssConfigured": 500, "bgpTcpMssSynced": 488} + } + return topotest.json_cmp(output, expected) + + logger.info("Check if neighbor sessions are up in {}".format(router1.name)) + test_func = functools.partial(_bgp_converge, router1) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) + + logger.info("BGP neighbor session is up in {}".format(router1.name)) + + logger.info( + "Configure tcp-mss 500 on {} and reset the session".format(router1.name) + ) + _bgp_conf_tcp_mss(router1, "65000", "192.168.255.2") + _bgp_clear_session(router1) + + logger.info( + "Configure tcp-mss 500 on {} and reset the session".format(router2.name) + ) + _bgp_conf_tcp_mss(router2, "65001", "192.168.255.1") + _bgp_clear_session(router2) + + logger.info( + "Check if neighbor session is up after reset in {}".format(router1.name) + ) + test_func = functools.partial(_bgp_converge, router1) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format( + router1.name + ) + + logger.info( + "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name) + ) + test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2") + success, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5) + assert ( + result is None + ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) + logger.info("TCP MSS value is synced with neighbor in {}".format(router1.name)) + + logger.info( + "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name) + ) + test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1") + success, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5) + assert ( + result is None + ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) + logger.info("TCP MSS value is synced with neighbor in {}".format(router2.name)) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args))