Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bgpd: Do not send Deconfig/Shutdown message when restarting #12034

Merged
merged 2 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2760,6 +2760,21 @@ void peer_notify_unconfig(struct peer *peer)
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
}

static void peer_notify_shutdown(struct peer *peer)
{
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP configured Graceful-Restart, skipping shutdown notification",
peer);
return;
}

if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
}

void peer_group_notify_unconfig(struct peer_group *group)
{
struct peer *peer, *other;
Expand Down Expand Up @@ -3676,11 +3691,8 @@ int bgp_delete(struct bgp *bgp)
}

/* Inform peers we're going down. */
for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) {
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
}
for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer))
peer_notify_shutdown(peer);

/* Delete static routes (networks). */
bgp_static_delete(bgp);
Expand Down Expand Up @@ -8251,11 +8263,18 @@ void bgp_terminate(void)
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
bgp_close_vrf_socket(bgp);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
if (peer_established(peer) || peer->status == OpenSent
|| peer->status == OpenConfirm)
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug(
"%pBP configured Graceful-Restart, skipping unconfig notification",
peer);
continue;
}
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
}
}

if (bm->listen_sockets)
Expand Down
Empty file.
11 changes: 11 additions & 0 deletions tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
router bgp 65001
no bgp ebgp-requires-policy
bgp graceful-restart
bgp graceful-restart preserve-fw-state
neighbor 192.168.255.2 remote-as external
neighbor 192.168.255.2 timers 1 3
neighbor 192.168.255.2 timers connect 1
address-family ipv4
redistribute connected
exit-address-family
!
7 changes: 7 additions & 0 deletions tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
!
interface lo
ip address 172.16.255.1/32
!
interface r1-eth0
ip address 192.168.255.1/24
!
8 changes: 8 additions & 0 deletions tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
router bgp 65002
no bgp ebgp-requires-policy
bgp graceful-restart
bgp graceful-restart preserve-fw-state
neighbor 192.168.255.1 remote-as external
neighbor 192.168.255.1 timers 1 3
neighbor 192.168.255.1 timers connect 1
!
4 changes: 4 additions & 0 deletions tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
!
interface r2-eth0
ip address 192.168.255.2/24
!
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env python

#
# Copyright (c) 2022 by
# Donatas Abraitis <donatas@opensourcerouting.org>
#
# 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 routes are retained during BGP restarts.
"""

import os
import sys
import json
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.common_config import step, stop_router

pytestmark = [pytest.mark.bgpd]


def build_topo(tgen):
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(build_topo, 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_gr_restart_retain_routes():
tgen = get_topogen()

if tgen.routers_have_failure():
pytest.skip(tgen.errors)

r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]

def _bgp_converge():
output = json.loads(r2.vtysh_cmd("show bgp ipv4 neighbors 192.168.255.1 json"))
expected = {
"192.168.255.1": {
"bgpState": "Established",
"addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
}
}
return topotest.json_cmp(output, expected)

def _bgp_check_bgp_retained_routes():
output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 172.16.255.1/32 json"))
expected = {"paths": [{"stale": True}]}
return topotest.json_cmp(output, expected)

def _bgp_check_kernel_retained_routes():
output = (
r2.cmd("ip route show 172.16.255.1/32 proto bgp dev r2-eth0")
.replace("\n", "")
.rstrip()
)
expected = "172.16.255.1 via 192.168.255.1 metric 20"
diff = topotest.get_textdiff(
output, expected, "Actual IP Routing Table", "Expected IP RoutingTable"
)
if diff:
return False
return True

step("Initial BGP converge")
test_func = functools.partial(_bgp_converge)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to see BGP convergence on R2"

step("Restart R1")
stop_router(tgen, "r1")

step("Check if routes (BGP) are retained at R2")
test_func = functools.partial(_bgp_check_bgp_retained_routes)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to see BGP retained routes on R2"

step("Check if routes (Kernel) are retained at R2")
assert _bgp_check_kernel_retained_routes() == True


if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))