diff options
author | Takemasa Imada <takemasa.imada@gmail.com> | 2021-08-14 07:32:40 +0200 |
---|---|---|
committer | Takemasa Imada <takemasa.imada@gmail.com> | 2021-08-14 23:08:08 +0200 |
commit | b042667a3da442d086f1e14b30936f374e9374fd (patch) | |
tree | 613b7c3e8c7ee766b33e43f4a6e1de8470525429 | |
parent | Merge pull request #9338 from idryzhov/static-nb-err (diff) | |
download | frr-b042667a3da442d086f1e14b30936f374e9374fd.tar.xz frr-b042667a3da442d086f1e14b30936f374e9374fd.zip |
bgpd: minimum-holdtime knob to prevent session establishment with BGP peer with low holdtime.
Signed-off-by: Takemasa Imada <takemasa.imada@gmail.com>
-rw-r--r-- | bgpd/bgp_packet.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 42 | ||||
-rw-r--r-- | bgpd/bgpd.c | 1 | ||||
-rw-r--r-- | bgpd/bgpd.h | 3 | ||||
-rw-r--r-- | doc/user/bgp.rst | 6 | ||||
-rw-r--r-- | tests/topotests/bgp_minimum_holdtime/__init__.py | 0 | ||||
-rw-r--r-- | tests/topotests/bgp_minimum_holdtime/r1/bgpd.conf | 6 | ||||
-rw-r--r-- | tests/topotests/bgp_minimum_holdtime/r1/zebra.conf | 6 | ||||
-rw-r--r-- | tests/topotests/bgp_minimum_holdtime/r2/bgpd.conf | 5 | ||||
-rw-r--r-- | tests/topotests/bgp_minimum_holdtime/r2/zebra.conf | 6 | ||||
-rwxr-xr-x | tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py | 104 |
11 files changed, 189 insertions, 0 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 3c01c3b48..783115baa 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1353,6 +1353,16 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) return BGP_Stop; } + /* Send notification message when Hold Time received in the OPEN message + * is smaller than configured minimum Hold Time. */ + if (holdtime < peer->bgp->default_min_holdtime + && peer->bgp->default_min_holdtime != 0) { + bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, + (uint8_t *)holdtime_ptr, 2); + return BGP_Stop; + } + /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 63b2fbd4e..5f07a5cd5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2332,6 +2332,38 @@ DEFUN (no_bgp_timers, return CMD_SUCCESS; } +/* BGP minimum holdtime. */ + +DEFUN(bgp_minimum_holdtime, bgp_minimum_holdtime_cmd, + "bgp minimum-holdtime (1-65535)", + "BGP specific commands\n" + "BGP minimum holdtime\n" + "Seconds\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + int idx_number = 2; + unsigned long min_holdtime; + + min_holdtime = strtoul(argv[idx_number]->arg, NULL, 10); + + bgp->default_min_holdtime = min_holdtime; + + return CMD_SUCCESS; +} + +DEFUN(no_bgp_minimum_holdtime, no_bgp_minimum_holdtime_cmd, + "no bgp minimum-holdtime [(1-65535)]", + NO_STR + "BGP specific commands\n" + "BGP minimum holdtime\n" + "Seconds\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + bgp->default_min_holdtime = 0; + + return CMD_SUCCESS; +} DEFUN (bgp_client_to_client_reflection, bgp_client_to_client_reflection_cmd, @@ -17112,6 +17144,12 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " timers bgp %u %u\n", bgp->default_keepalive, bgp->default_holdtime); + /* BGP minimum holdtime configuration. */ + if (bgp->default_min_holdtime != SAVE_BGP_HOLDTIME + && bgp->default_min_holdtime != 0) + vty_out(vty, " bgp minimum-holdtime %u\n", + bgp->default_min_holdtime); + /* Conditional advertisement timer configuration */ if (bgp->condition_check_period != DEFAULT_CONDITIONAL_ROUTES_POLL_TIME) @@ -17506,6 +17544,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_timers_cmd); install_element(BGP_NODE, &no_bgp_timers_cmd); + /* "minimum-holdtime" commands. */ + install_element(BGP_NODE, &bgp_minimum_holdtime_cmd); + install_element(BGP_NODE, &no_bgp_minimum_holdtime_cmd); + /* route-map delay-timer commands - per instance for backwards compat. */ install_element(BGP_NODE, &bgp_set_route_map_delay_timer_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 591fc1214..3d10771bc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3154,6 +3154,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; bgp_timers_unset(bgp); + bgp->default_min_holdtime = 0; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d39743a15..62782f604 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -602,6 +602,9 @@ struct bgp { uint32_t default_connect_retry; uint32_t default_delayopen; + /* BGP minimum holdtime. */ + uint16_t default_min_holdtime; + /* BGP graceful restart */ uint32_t restart_time; uint32_t stalepath_time; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index bc4827129..25ac40afc 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1693,6 +1693,12 @@ Configuring Peers default, the DelayOpenTimer is disabled. The timer interval may be set to a duration of 1 to 240 seconds. +.. clicmd:: bgp minimum-holdtime (1-65535) + + This command allows user to prevent session establishment with BGP peers + with lower holdtime less than configured minimum holdtime. + When this command is not set, minimum holdtime does not work. + Displaying Information about Peers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/topotests/bgp_minimum_holdtime/__init__.py b/tests/topotests/bgp_minimum_holdtime/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/__init__.py diff --git a/tests/topotests/bgp_minimum_holdtime/r1/bgpd.conf b/tests/topotests/bgp_minimum_holdtime/r1/bgpd.conf new file mode 100644 index 000000000..847a2d4b0 --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/r1/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65000 + bgp minimum-holdtime 20 + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 timers 3 10 + neighbor 192.168.255.2 timers connect 10 +! diff --git a/tests/topotests/bgp_minimum_holdtime/r1/zebra.conf b/tests/topotests/bgp_minimum_holdtime/r1/zebra.conf new file mode 100644 index 000000000..e2c399e53 --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/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_minimum_holdtime/r2/bgpd.conf b/tests/topotests/bgp_minimum_holdtime/r2/bgpd.conf new file mode 100644 index 000000000..6d1080c11 --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/r2/bgpd.conf @@ -0,0 +1,5 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.255.1 remote-as 65000 + neighbor 192.168.255.1 timers 3 10 +! diff --git a/tests/topotests/bgp_minimum_holdtime/r2/zebra.conf b/tests/topotests/bgp_minimum_holdtime/r2/zebra.conf new file mode 100644 index 000000000..606c17bec --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/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_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py new file mode 100755 index 000000000..c5afcdf11 --- /dev/null +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Takemasa Imada <takemasa.imada@gmail.com> +# +# 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. +# + +""" +Test if minimum-holdtime works. +""" + +import os +import sys +import json +import time +import pytest +import functools + +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 + +pytestmark = [pytest.mark.bgpd] + + +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_minimum_holdtime(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_neighbor_check_if_notification_sent(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor 192.168.255.2 json") + ) + expected = { + "192.168.255.2": { + "connectionsEstablished": 0, + "lastNotificationReason": "OPEN Message Error/Unacceptable Hold Time", + "lastResetDueTo": "BGP Notification send", + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) + success, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + assert result is None, "Failed to send notification message\n" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) |