summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c12
-rw-r--r--bgpd/bgp_vty.c28
-rw-r--r--bgpd/bgpd.c27
-rw-r--r--isisd/isis_spf.c3
-rw-r--r--lib/libfrr.h29
-rw-r--r--ospfd/ospf_main.c30
-rw-r--r--tests/topotests/bgp_vrf_different_asn/__init__.py0
-rw-r--r--tests/topotests/bgp_vrf_different_asn/r1/frr.conf18
-rw-r--r--tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py107
9 files changed, 231 insertions, 23 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 75a7d85e88..baf1d4ca6d 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -6333,16 +6333,16 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
{
struct bgp_dest *dest = NULL;
- uint32_t ann_count = zebra_announce_count(&bm->zebra_announce_head);
+ struct bgp_dest *dest_next = NULL;
- while (ann_count) {
- dest = zebra_announce_pop(&bm->zebra_announce_head);
- ann_count--;
+ for (dest = zebra_announce_first(&bm->zebra_announce_head); dest;
+ dest = dest_next) {
+ dest_next = zebra_announce_next(&bm->zebra_announce_head, dest);
if (dest->za_vpn == vpn) {
bgp_path_info_unlock(dest->za_bgp_pi);
bgp_dest_unlock_node(dest);
- } else
- zebra_announce_add_tail(&bm->zebra_announce_head, dest);
+ zebra_announce_del(&bm->zebra_announce_head, dest);
+ }
}
bgp_evpn_remote_ip_hash_destroy(vpn);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 0ef1351835..bce8202377 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1701,6 +1701,10 @@ DEFUN (no_router_bgp,
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) {
if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
+
+ if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
if (CHECK_FLAG(
tmp_bgp->af_flags[AFI_IP]
[SAFI_UNICAST],
@@ -10567,12 +10571,20 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
vrf_bgp = bgp_lookup_by_name(import_name);
if (!vrf_bgp) {
- if (strcmp(import_name, VRF_DEFAULT_NAME) == 0)
+ if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) {
vrf_bgp = bgp_default;
- else
+ } else {
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
NULL, ASNOTATION_UNDEFINED);
+
+ /* Auto created VRF instances should be marked
+ * properly, otherwise we have a state after bgpd
+ * restart where VRF instance has default VRF's ASN.
+ */
+ SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO);
+ }
+
if (ret) {
vty_out(vty,
"VRF %s is not configured as a bgp instance\n",
@@ -12745,6 +12757,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!is_first)
@@ -16130,6 +16145,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!(json = json_object_new_object())) {
@@ -16689,6 +16707,9 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
vrf_name = bgp->name;
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
if (use_json) {
json_vrf = json_object_new_object();
} else {
@@ -16779,6 +16800,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
struct bgp *bgp;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
if (!uj)
vty_out(vty, "\nInstance %s:\n",
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 3810413adc..476a01b8ef 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3936,21 +3936,34 @@ int bgp_delete(struct bgp *bgp)
safi_t safi;
int i;
struct bgp_dest *dest = NULL;
+ struct bgp_dest *dest_next = NULL;
+ struct bgp_table *dest_table = NULL;
struct graceful_restart_info *gr_info;
- uint32_t ann_count = zebra_announce_count(&bm->zebra_announce_head);
+ uint32_t cnt_before, cnt_after;
assert(bgp);
- while (ann_count) {
- dest = zebra_announce_pop(&bm->zebra_announce_head);
- ann_count--;
- if (dest->za_bgp_pi->peer->bgp == bgp) {
+ /*
+ * Iterate the pending dest list and remove all the dest pertaininig to
+ * the bgp under delete.
+ */
+ cnt_before = zebra_announce_count(&bm->zebra_announce_head);
+ for (dest = zebra_announce_first(&bm->zebra_announce_head); dest;
+ dest = dest_next) {
+ dest_next = zebra_announce_next(&bm->zebra_announce_head, dest);
+ dest_table = bgp_dest_table(dest);
+ if (dest_table->bgp == bgp) {
bgp_path_info_unlock(dest->za_bgp_pi);
bgp_dest_unlock_node(dest);
- } else
- zebra_announce_add_tail(&bm->zebra_announce_head, dest);
+ zebra_announce_del(&bm->zebra_announce_head, dest);
+ }
}
+ cnt_after = zebra_announce_count(&bm->zebra_announce_head);
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Zebra Announce Fifo cleanup count before %u and after %u during BGP %s deletion",
+ cnt_before, cnt_after, bgp->name_pretty);
+
bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL);
/* make sure we withdraw any exported routes */
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 7aa9147e71..86302076f8 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -873,6 +873,9 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
|| (mt_router_info && !mt_router_info->overload));
lspfragloop:
+ if (!lsp->tlvs)
+ return ISIS_OK;
+
if (lsp->hdr.seqno == 0) {
zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
return ISIS_WARNING;
diff --git a/lib/libfrr.h b/lib/libfrr.h
index db9cfbcb1f..8018672c1a 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -222,10 +222,39 @@ extern void frr_fini(void);
extern char config_default[512];
extern char frr_zclientpath[512];
+
+/* refer to lib/config_paths.h (generated during ./configure) for build config
+ * values of the following:
+ */
+
+/* sysconfdir is generally /etc/frr/, some BSDs may use /usr/local/etc/frr/.
+ * Will NOT include "pathspace" (namespace) suffix from -N. (libfrr.c handles
+ * pathspace'ing config files.) Has a slash at the end for "historical"
+ * reasons.
+ */
extern const char frr_sysconfdir[];
+
+/* runstatedir is *ephemeral* across reboots. It may either be a ramdisk,
+ * or be wiped during boot. Use only for pid files, sockets, and the like,
+ * not state. Commonly /run/frr or /var/run/frr.
+ * Will include "pathspace" (namespace) suffix from -N.
+ */
extern char frr_runstatedir[256];
+
+/* libstatedir is *persistent*. It's the place to put state like sequence
+ * numbers or databases. Commonly /var/lib/frr.
+ * Will include "pathspace" (namespace) suffix from -N.
+ */
extern char frr_libstatedir[256];
+
+/* moduledir is something along the lines of /usr/lib/frr/modules or
+ * /usr/lib/x86_64-linux-gnu/frr/modules. It is not guaranteed to be a
+ * subdirectory of the directory that the daemon binaries reside in. (e.g.
+ * the "x86_64-linux-gnu" component will be absent from daemon paths.)
+ */
extern const char frr_moduledir[];
+
+/* scriptdir is for Lua scripts, generally ${frr_sysconfdir}/scripts */
extern const char frr_scriptdir[];
extern char frr_protoname[];
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index fdb4e5c587..5c11027506 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -48,14 +48,20 @@
#include "ospfd/ospf_apiserver.h"
#define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir
-#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i
+#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i
/* this one includes the path... because the instance number was in the path
* before :( ... which totally didn't have a mkdir anywhere.
+ *
+ * ... and libstatedir & runstatedir got switched around while changing this;
+ * for non-instance it read the wrong path, for instance it wrote the wrong
+ * path. (There is no COMPAT2 for non-instance because it was writing to the
+ * right place, i.e. no extra path to check exists from reading a wrong path.)
*/
-#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_libstatedir
-#define OSPFD_COMPAT_INST_STATE_NAME(i) \
+#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_runstatedir
+#define OSPFD_COMPAT1_INST_STATE_NAME(i) \
"%s-%d/ospfd-gr.json", frr_runstatedir, i
+#define OSPFD_COMPAT2_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i
/* ospfd privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@@ -139,10 +145,12 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
/* actual paths filled in main() */
static char state_path[512];
-static char state_compat_path[512];
+static char state_compat1_path[512];
+static char state_compat2_path[512];
static char *state_paths[] = {
state_path,
- state_compat_path,
+ state_compat1_path,
+ state_compat2_path, /* NULLed out if not needed */
NULL,
};
@@ -242,12 +250,18 @@ int main(int argc, char **argv)
if (ospf_instance) {
snprintf(state_path, sizeof(state_path),
OSPFD_INST_STATE_NAME(ospf_instance));
- snprintf(state_compat_path, sizeof(state_compat_path),
- OSPFD_COMPAT_INST_STATE_NAME(ospf_instance));
+ snprintf(state_compat1_path, sizeof(state_compat1_path),
+ OSPFD_COMPAT1_INST_STATE_NAME(ospf_instance));
+ snprintf(state_compat2_path, sizeof(state_compat2_path),
+ OSPFD_COMPAT2_INST_STATE_NAME(ospf_instance));
} else {
snprintf(state_path, sizeof(state_path), OSPFD_STATE_NAME);
- snprintf(state_compat_path, sizeof(state_compat_path),
+ snprintf(state_compat1_path, sizeof(state_compat1_path),
OSPFD_COMPAT_STATE_NAME);
+ /* no COMPAT2 here since it was reading that was broken,
+ * there is no additional path that would've been written
+ */
+ state_paths[2] = NULL;
}
/* OSPF master init. */
diff --git a/tests/topotests/bgp_vrf_different_asn/__init__.py b/tests/topotests/bgp_vrf_different_asn/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_vrf_different_asn/__init__.py
diff --git a/tests/topotests/bgp_vrf_different_asn/r1/frr.conf b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf
new file mode 100644
index 0000000000..b325dfb7f0
--- /dev/null
+++ b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf
@@ -0,0 +1,18 @@
+!
+vrf vrf100
+ vni 10100
+exit-vrf
+!
+interface r1-eth0 vrf vrf100
+ ip address 192.168.1.1/24
+!
+router bgp 65000
+ address-family ipv4 unicast
+ import vrf vrf100
+ exit-address-family
+!
+router bgp 65100 vrf vrf100
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py
new file mode 100644
index 0000000000..9a1a9ec766
--- /dev/null
+++ b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 2):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ r1 = tgen.gears["r1"]
+ r1.run("ip link add vrf100 type vrf table 1001")
+ r1.run("ip link set up dev vrf100")
+ r1.run("ip link set r1-eth0 master vrf100")
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_vrf_different_asn():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_instances():
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp vrf all json"))
+ expected = {
+ "default": {
+ "vrfName": "default",
+ "localAS": 65000,
+ },
+ "vrf100": {
+ "vrfName": "vrf100",
+ "localAS": 65100,
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_instances)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see vrf100 to be under 65100 ASN"
+
+ def _bgp_check_imported_route():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show ip route 192.168.1.0/24 json")
+ )
+ expected = {
+ "192.168.1.0/24": [
+ {
+ "installed": True,
+ "selected": True,
+ "nexthops": [
+ {
+ "interfaceName": "vrf100",
+ "vrf": "vrf100",
+ "active": True,
+ }
+ ],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_imported_route)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see 192.168.1.0/24 being imported into a default VRF"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))