Resolves: RHEL-118620 - Rebase FRR in to version 10.4.1

This commit is contained in:
Michal Ruprich 2025-12-08 16:40:20 +01:00
parent e337c282c8
commit 229dc8b434
12 changed files with 29 additions and 1188 deletions

2
.gitignore vendored
View File

@ -1,7 +1,6 @@
/frr-7.1.tar.gz
/frr-7.2.tar.gz
/frr-7.3.tar.gz
/remove-babeld-ldpd.sh
/frr-7.3.1.tar.gz
/frr-7.4.tar.gz
/frr-7.5.tar.gz
@ -20,3 +19,4 @@
/frr-9.0.1.tar.gz
/frr-9.1.tar.gz
/frr-10.1.tar.gz
/frr-10.4.1.tar.gz

View File

@ -24,8 +24,8 @@ index 0b7af18..0533e24 100644
lib/log_vty.h \
- lib/md5.h \
lib/memory.h \
lib/mgmt.pb-c.h \
lib/mgmt_be_client.h \
lib/mgmt_defines.h \
@@ -191,7 +190,6 @@ pkginclude_HEADERS += \
lib/route_opaque.h \
lib/sbuf.h \

View File

@ -1,487 +0,0 @@
From f450e1cda41f1b7576094a0b3017ba9849cd55ae Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Fri, 7 Jun 2024 12:30:59 -0400
Subject: [PATCH 1/5] zebra: Make p and src_p const for rib_delete
The prefix'es p and src_p are not const. Let's make
them so. Useful to signal that we will not change this
data.
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
---
zebra/rib.h | 2 +-
zebra/zebra_rib.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/zebra/rib.h b/zebra/rib.h
index 84ea766c4733..7f4e3949e02d 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -395,7 +395,7 @@ extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, uint32_t flags,
- struct prefix *p, struct prefix_ipv6 *src_p,
+ const struct prefix *p, const struct prefix_ipv6 *src_p,
const struct nexthop *nh, uint32_t nhe_id,
uint32_t table_id, uint32_t metric, uint8_t distance,
bool fromkernel);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 59190e9dd330..c1bd61e1db31 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4393,8 +4393,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
}
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
- unsigned short instance, uint32_t flags, struct prefix *p,
- struct prefix_ipv6 *src_p, const struct nexthop *nh,
+ unsigned short instance, uint32_t flags, const struct prefix *p,
+ const struct prefix_ipv6 *src_p, const struct nexthop *nh,
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
uint8_t distance, bool fromkernel)
{
From bdfccf69fa128c51c45bbd3528788f72ac17d854 Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Fri, 7 Jun 2024 12:56:35 -0400
Subject: [PATCH 2/5] zebra: Expose rib_update_handle_vrf_all
This function will be used on interface down
events to allow for kernel routes to be cleaned
up.
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
---
zebra/rib.h | 2 ++
zebra/zebra_rib.c | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/zebra/rib.h b/zebra/rib.h
index 7f4e3949e02d..8792fb7908ac 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -477,6 +477,8 @@ extern uint8_t route_distance(int type);
extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq,
bool rt_delete);
+extern void rib_update_handle_vrf_all(enum rib_update_event event, int rtype);
+
/*
* rib_find_rn_from_ctx
*
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index c1bd61e1db31..649450b5c63c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4543,7 +4543,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
}
}
-static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
+void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
{
struct zebra_router_table *zrt;
From d528c02a204086da0d542d5655b8724de681a65c Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Fri, 7 Jun 2024 13:50:07 -0400
Subject: [PATCH 3/5] zebra: Handle kernel routes appropriately
Current code intentionally ignores kernel routes. Modify
zebra to allow these routes to be read in on linux. Also
modify zebra to look to see if a route should be treated
as a connected and mark it as such.
Additionally this should properly handle some of the issues
being seen with NOPREFIXROUTE.
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
---
zebra/interface.c | 2 +
zebra/rib.h | 1 +
zebra/rt_netlink.c | 2 -
zebra/zebra_rib.c | 105 +++++++++++++++++++++++++++++++++++++++------
4 files changed, 96 insertions(+), 14 deletions(-)
diff --git a/zebra/interface.c b/zebra/interface.c
index 03b710e1a0f9..d146004781a5 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1058,6 +1058,8 @@ void if_down(struct interface *ifp)
/* Delete all neighbor addresses learnt through IPv6 RA */
if_down_del_nbr_connected(ifp);
+
+ rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL);
}
void if_refresh(struct interface *ifp)
diff --git a/zebra/rib.h b/zebra/rib.h
index 8792fb7908ac..cd6efbfb36dd 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ {
/* Events/reasons triggering a RIB update. */
enum rib_update_event {
+ RIB_UPDATE_INTERFACE_DOWN,
RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index c22145be693b..ddcb83cd8ce7 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -799,8 +799,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
- if (rtm->rtm_protocol == RTPROT_KERNEL)
- return 0;
selfroute = is_selfroute(rtm->rtm_protocol);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 649450b5c63c..2d6c5148833a 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1619,6 +1619,10 @@ static bool rib_compare_routes(const struct route_entry *re1,
* v6 link-locals, and we also support multiple addresses in the same
* subnet on a single interface.
*/
+ if (re1->type == ZEBRA_ROUTE_CONNECT &&
+ (re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex))
+ return true;
+
if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL)
return true;
@@ -2863,10 +2867,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
- rnode_debug(
- rn, re->vrf_id,
- "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
- rn, re, zebra_route_string(re->type), same, same_count);
+ rnode_debug(rn, re->vrf_id,
+ "Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d",
+ rn, re, zebra_route_string(re->type),
+ afi2str(ere->afi), safi2str(ere->safi), same,
+ same_count);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(
@@ -4383,6 +4388,34 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
nhe.id = re->nhe_id;
n = zebra_nhe_copy(&nhe, 0);
+
+ if (re->type == ZEBRA_ROUTE_KERNEL) {
+ struct interface *ifp;
+ struct connected *connected;
+
+ if (p->family == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) {
+ zebra_nhg_free(n);
+ zebra_rib_route_entry_free(re);
+ return -1;
+ }
+
+ ifp = if_lookup_prefix(p, re->vrf_id);
+ if (ifp) {
+ connected = connected_lookup_prefix(ifp, p);
+
+ if (connected && !CHECK_FLAG(connected->flags,
+ ZEBRA_IFA_NOPREFIXROUTE)) {
+ zebra_nhg_free(n);
+ zebra_rib_route_entry_free(re);
+ return -1;
+ }
+
+ if (ifp->ifindex == ng->nexthop->ifindex)
+ re->type = ZEBRA_ROUTE_CONNECT;
+ }
+ }
+
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup);
/* In error cases, free the route also */
@@ -4458,6 +4491,9 @@ static const char *rib_update_event2str(enum rib_update_event event)
const char *ret = "UNKNOWN";
switch (event) {
+ case RIB_UPDATE_INTERFACE_DOWN:
+ ret = "RIB_UPDATE_INTERFACE_DOWN";
+ break;
case RIB_UPDATE_KERNEL:
ret = "RIB_UPDATE_KERNEL";
break;
@@ -4474,15 +4510,56 @@ static const char *rib_update_event2str(enum rib_update_event event)
return ret;
}
+/*
+ * We now keep kernel routes, but we don't have any
+ * trigger events for them when they are implicitly
+ * deleted. Since we are already walking the
+ * entire table on a down event let's look at
+ * the few kernel routes we may have
+ */
+static void
+rib_update_handle_kernel_route_down_possibility(struct route_node *rn,
+ struct route_entry *re)
+{
+ struct nexthop *nexthop = NULL;
+ bool alive = false;
+
+ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
+ struct interface *ifp = if_lookup_by_index(nexthop->ifindex,
+ nexthop->vrf_id);
+
+ if (ifp && if_is_up(ifp)) {
+ alive = true;
+ break;
+ }
+ }
+
+ if (!alive) {
+ struct rib_table_info *rib_table = srcdest_rnode_table_info(rn);
+ const struct prefix *p;
+ const struct prefix_ipv6 *src_p;
+
+ srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
+
+ rib_delete(rib_table->afi, rib_table->safi, re->vrf_id,
+ re->type, re->instance, re->flags, p, src_p, NULL, 0,
+ re->table, re->metric, re->distance, true);
+ }
+}
+
/* Schedule route nodes to be processed if they match the type */
-static void rib_update_route_node(struct route_node *rn, int type)
+static void rib_update_route_node(struct route_node *rn, int type,
+ enum rib_update_event event)
{
struct route_entry *re, *next;
bool re_changed = false;
RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (type == ZEBRA_ROUTE_ALL || type == re->type) {
+ if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type &&
+ type == ZEBRA_ROUTE_KERNEL)
+ rib_update_handle_kernel_route_down_possibility(rn, re);
+ else if (type == ZEBRA_ROUTE_ALL || type == re->type) {
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
re_changed = true;
}
@@ -4522,20 +4599,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event,
/*
* If we are looking at a route node and the node
* has already been queued we don't
- * need to queue it up again
+ * need to queue it up again, unless it is
+ * an interface down event as that we need
+ * to process this no matter what.
*/
- if (rn->info
- && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_ANY_QUEUED))
+ if (rn->info &&
+ CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+ RIB_ROUTE_ANY_QUEUED) &&
+ event != RIB_UPDATE_INTERFACE_DOWN)
continue;
switch (event) {
+ case RIB_UPDATE_INTERFACE_DOWN:
case RIB_UPDATE_KERNEL:
- rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
+ rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event);
break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
- rib_update_route_node(rn, rtype);
+ rib_update_route_node(rn, rtype, event);
break;
case RIB_UPDATE_MAX:
break;
From 9bc0cd8241f39e4fd751edfa52c09fae6db2db1c Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Wed, 26 Jun 2024 13:21:38 -0400
Subject: [PATCH 4/5] zebra: Prevent accidental re memory leak in odd case
There exists a path in rib_add_multipath where if a decision
is made to not use the passed in re, we just drop the memory
instead of freeing it. Let's free it.
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
---
zebra/zebra_rib.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 2d6c5148833a..b4baee148aef 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4375,8 +4375,10 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
return -1;
/* We either need nexthop(s) or an existing nexthop id */
- if (ng == NULL && re->nhe_id == 0)
+ if (ng == NULL && re->nhe_id == 0) {
+ zebra_rib_route_entry_free(re);
return -1;
+ }
/*
* Use a temporary nhe to convey info to the common/main api.
From 37dd51867f2b98f0fb616fc3cf9922240346fd19 Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Thu, 15 Aug 2024 16:02:55 -0400
Subject: [PATCH 5/5] tests: Add some tests to show new behavior works as
expected
a) A noprefix address by itself should not create a connected route.
This was pre-existing.
b) A noprefix address with a corresponding route should result in a
connected route. This is how NetworkManager appears to work.
This is new behavior, so a new test.
c) A route is added to the system from someone else.
This is new behavior, so a new test.
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
---
.../r1/ip_route_connected.json | 24 +++++++++++
.../r1/ip_route_kernel.json | 24 +++++++++++
.../test_zebra_multiple_connected.py | 43 +++++++++++++++++++
3 files changed, 91 insertions(+)
create mode 100644 tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json
create mode 100644 tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json
diff --git a/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json b/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json
new file mode 100644
index 000000000000..db03ce84a6a4
--- /dev/null
+++ b/tests/topotests/zebra_multiple_connected/r1/ip_route_connected.json
@@ -0,0 +1,24 @@
+{
+ "192.168.44.0/24":[
+ {
+ "prefix":"192.168.44.0/24",
+ "prefixLen":24,
+ "protocol":"connected",
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json
new file mode 100644
index 000000000000..22465cb477d3
--- /dev/null
+++ b/tests/topotests/zebra_multiple_connected/r1/ip_route_kernel.json
@@ -0,0 +1,24 @@
+{
+ "4.5.6.7/32":[
+ {
+ "prefix":"4.5.6.7/32",
+ "prefixLen":32,
+ "protocol":"kernel",
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
index dc47527c74c2..7dbeb6f1ccb3 100644
--- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
+++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
@@ -19,6 +19,9 @@
import pytest
import json
from functools import partial
+from lib.topolog import logger
+
+pytestmark = pytest.mark.random_order(disabled=True)
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -159,6 +162,46 @@ def test_zebra_noprefix_connected():
assert result, "Connected Route should not have been added"
+def test_zebra_noprefix_connected_add():
+ "Test that a noprefixroute created with a manual route works as expected, this is for NetworkManager"
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+ router.run("ip route add 192.168.44.0/24 dev r1-eth1")
+
+ connected = "{}/{}/ip_route_connected.json".format(CWD, router.name)
+ expected = json.loads(open(connected).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route 192.168.44.0/24 json", expected
+ )
+ result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result, "Connected Route should have been added\n{}".format(_)
+
+
+def test_zebra_kernel_route_add():
+ "Test that a random kernel route is properly handled as expected"
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+ router.run("ip route add 4.5.6.7/32 dev r1-eth1")
+
+ kernel = "{}/{}/ip_route_kernel.json".format(CWD, router.name)
+ expected = json.loads(open(kernel).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route 4.5.6.7/32 json", expected
+ )
+ result, _ = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result, "Connected Route should have been added\n{}".format(_)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -1,48 +0,0 @@
From 0998b38e4d61179441f90dd7e7fd6a3a8b7bd8c5 Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Wed, 31 Jul 2024 08:35:14 +0300
Subject: [PATCH] bgpd: Check the actual remaining stream length before taking
TLV value
```
0 0xb50b9f898028 in __sanitizer_print_stack_trace (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x368028) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7)
1 0xb50b9f7ed8e4 in fuzzer::PrintStackTrace() (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x2bd8e4) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7)
2 0xb50b9f7d4d9c in fuzzer::Fuzzer::CrashCallback() (/home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/.libs/bgpd+0x2a4d9c) (BuildId: 3292703ed7958b20076550c967f879db8dc27ca7)
3 0xe0d12d7469cc (linux-vdso.so.1+0x9cc) (BuildId: 1a77697e9d723fe22246cfd7641b140c427b7e11)
4 0xe0d12c88f1fc in __pthread_kill_implementation nptl/pthread_kill.c:43:17
5 0xe0d12c84a678 in gsignal signal/../sysdeps/posix/raise.c:26:13
6 0xe0d12c83712c in abort stdlib/abort.c:79:7
7 0xe0d12d214724 in _zlog_assert_failed /home/ubuntu/frr-public/frr_public_private-libfuzzer/lib/zlog.c:789:2
8 0xe0d12d1285e4 in stream_get /home/ubuntu/frr-public/frr_public_private-libfuzzer/lib/stream.c:324:3
9 0xb50b9f8e47c4 in bgp_attr_encap /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_attr.c:2758:3
10 0xb50b9f8dcd38 in bgp_attr_parse /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_attr.c:3783:10
11 0xb50b9faf74b4 in bgp_update_receive /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:2383:20
12 0xb50b9faf1dcc in bgp_process_packet /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_packet.c:4075:11
13 0xb50b9f8c90d0 in LLVMFuzzerTestOneInput /home/ubuntu/frr-public/frr_public_private-libfuzzer/bgpd/bgp_main.c:582:3
```
Reported-by: Iggy Frankovic <iggyfran@amazon.com>
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
---
bgpd/bgp_attr.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 2ed49935e52b..ac5d08b6fe6e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2749,6 +2749,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
args->total);
}
+ if (STREAM_READABLE(BGP_INPUT(peer)) < sublength) {
+ zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining stream length %zu",
+ sublength, STREAM_READABLE(BGP_INPUT(peer)));
+ return bgp_attr_malformed(args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+ }
+
/* alloc and copy sub-tlv */
/* TBD make sure these are freed when attributes are released */
tlv = XCALLOC(MTYPE_ENCAP_TLV,

View File

@ -1,285 +0,0 @@
From 59f5dd686a324f888602fa4a56f6da90e844103c Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Tue, 11 Jun 2024 11:40:40 +0300
Subject: [PATCH 1/3] tests: Check if BFD notification is sent and session
remains in down state
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
---
.../r1/bfdd.conf | 4 +
.../r1/bgpd.conf | 2 +-
.../test_bgp_bfd_down_cease_notification.py | 3 +
...gp_bfd_down_cease_notification_shutdown.py | 122 ++++++++++++++++++
4 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py
diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf
index 0ae384eb53ca..1033b27c568d 100644
--- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf
+++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf
@@ -1,5 +1,9 @@
bfd
+ profile r1
+ exit
+ !
peer 192.168.255.2 interface r1-eth0
+ profile r1
exit
!
exit
diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf
index e855f75c20de..58a90d1a490c 100644
--- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf
+++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf
@@ -3,7 +3,7 @@ router bgp 65001
neighbor 192.168.255.2 remote-as external
neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 timers connect 1
- neighbor 192.168.255.2 bfd
+ neighbor 192.168.255.2 bfd profile r1
neighbor 192.168.255.2 passive
address-family ipv4
redistribute connected
diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py
index 00142981c502..3be34300078b 100644
--- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py
+++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py
@@ -89,6 +89,9 @@ def _bgp_bfd_down_notification():
"192.168.255.1": {
"lastNotificationReason": "Cease/BFD Down",
"lastNotificationHardReset": True,
+ "peerBfdInfo": {
+ "status": "Up",
+ },
}
}
return topotest.json_cmp(output, expected)
diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py
new file mode 100644
index 000000000000..5ffeed5033ae
--- /dev/null
+++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# bgp_bfd_down_cease_notification_shutdown.py
+#
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Check if Cease/BFD Down notification message is sent/received
+when the BFD is down (administratively).
+"""
+
+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 kill_router_daemons, step
+
+pytestmark = [pytest.mark.bfdd, 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))
+ )
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_bfd_down_notification_shutdown():
+ 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 ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ "peerBfdInfo": {"status": "Up"},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_bfd_down_notification():
+ output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "lastNotificationReason": "Cease/BFD Down",
+ "lastNotificationHardReset": True,
+ "peerBfdInfo": {
+ "status": "Down",
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Initial BGP converge")
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to see BGP convergence on R2"
+
+ r1.vtysh_cmd(
+ """
+ configure
+ bfd
+ profile r1
+ shutdown
+ """
+ )
+
+ step("Check if we received Cease/BFD Down notification message")
+ test_func = functools.partial(_bgp_bfd_down_notification)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Failed to see BGP Cease/BFD Down notification message on R2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
From ae1f3a48513f51c540788a090b05c24750665f55 Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Tue, 11 Jun 2024 11:41:53 +0300
Subject: [PATCH 2/3] bgpd: Keep last notification's state about hard reset
When we receive a hard-reset notification, we always show it if it was a hard,
or not.
For sending side, we missed that. Let's display it too.
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
---
bgpd/bgp_packet.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 3f38790cbda3..8a4453f12472 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -982,6 +982,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection,
peer->notify.code = bgp_notify.code;
peer->notify.subcode = bgp_notify.subcode;
peer->notify.length = bgp_notify.length;
+ peer->notify.hard_reset = hard_reset;
if (bgp_notify.length && data) {
bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
From 1fb48f5d13faf4ec1e6d4c2cdded9ca2dcd6d609 Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Wed, 12 Jun 2024 08:39:48 +0300
Subject: [PATCH 3/3] bgpd: Do not start BGP session if BFD profile is in
shutdown state
If we do:
```
bfd
profile foo
shutdown
```
The session is dropped, but immediately established again because we don't
have a proper check on BFD.
If BFD is administratively shutdown, ignore starting the session.
Fixes: https://github.com/FRRouting/frr/issues/16186
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
---
bgpd/bgpd.c | 6 ++++++
lib/bfd.c | 6 ++++++
lib/bfd.h | 2 ++
3 files changed, 14 insertions(+)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 81506f4410b1..869d2b455214 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4507,6 +4507,12 @@ bool peer_active(struct peer *peer)
{
if (BGP_CONNECTION_SU_UNSPEC(peer->connection))
return false;
+
+ if (peer->bfd_config) {
+ if (bfd_session_is_down(peer->bfd_config->session))
+ return false;
+ }
+
if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST]
|| peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP]
diff --git a/lib/bfd.c b/lib/bfd.c
index 2222bb954737..4535fc123378 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -1334,3 +1334,9 @@ int bfd_nht_update(const struct prefix *match, const struct zapi_route *route)
return 0;
}
+
+bool bfd_session_is_down(const struct bfd_session_params *session)
+{
+ return session->bss.state == BSS_DOWN ||
+ session->bss.state == BSS_ADMIN_DOWN;
+}
diff --git a/lib/bfd.h b/lib/bfd.h
index bfa5287340f2..48929a95642c 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -464,6 +464,8 @@ extern bool bfd_protocol_integration_shutting_down(void);
extern int bfd_nht_update(const struct prefix *match,
const struct zapi_route *route);
+extern bool bfd_session_is_down(const struct bfd_session_params *session);
+
#ifdef __cplusplus
}
#endif

View File

@ -1,69 +0,0 @@
From 247a75d5c662893f6c08daf6ffbe82eb3073205a Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Tue, 5 Nov 2024 15:51:58 +0200
Subject: [PATCH] bgpd: Reset BGP session only if it was a real BFD DOWN event
Without this patch we always see a double-reset, e.g.:
```
2024/11/04 12:42:43.010 BGP: [VQY9X-CQZKG] bgp_peer_bfd_update_source: address [0.0.0.0->172.18.0.3] to [172.18.0.2->172.18.0.3]
2024/11/04 12:42:43.010 BGP: [X8BD9-8RKN4] bgp_peer_bfd_update_source: interface none to eth0
2024/11/04 12:42:43.010 BFD: [MSVDW-Y8Z5Q] ptm-del-dest: deregister peer [mhop:no peer:172.18.0.3 local:0.0.0.0 vrf:default cbit:0x00 minimum-ttl:255]
2024/11/04 12:42:43.010 BFD: [NYF5K-SE3NS] ptm-del-session: [mhop:no peer:172.18.0.3 local:0.0.0.0 vrf:default] refcount=0
2024/11/04 12:42:43.010 BFD: [NW21R-MRYNT] session-delete: mhop:no peer:172.18.0.3 local:0.0.0.0 vrf:default
2024/11/04 12:42:43.010 BGP: [P3D3N-3277A] 172.18.0.3 [FSM] Timer (routeadv timer expire)
2024/11/04 12:42:43.010 BFD: [YA0Q5-C0BPV] control-packet: no session found [mhop:no peer:172.18.0.3 local:172.18.0.2 port:11]
2024/11/04 12:42:43.010 BFD: [MSVDW-Y8Z5Q] ptm-add-dest: register peer [mhop:no peer:172.18.0.3 local:172.18.0.2 vrf:default cbit:0x00 minimum-ttl:255]
2024/11/04 12:42:43.011 BFD: [PSB4R-8T1TJ] session-new: mhop:no peer:172.18.0.3 local:172.18.0.2 vrf:default ifname:eth0
2024/11/04 12:42:43.011 BGP: [Q4BCV-6FHZ5] zclient_bfd_session_update: 172.18.0.2/32 -> 172.18.0.3/32 (interface eth0) VRF default(0) (CPI bit no): Down
2024/11/04 12:42:43.011 BGP: [MKVHZ-7MS3V] bfd_session_status_update: neighbor 172.18.0.3 vrf default(0) bfd state Up -> Down
2024/11/04 12:42:43.011 BGP: [HZN6M-XRM1G] %NOTIFICATION: sent to neighbor 172.18.0.3 6/10 (Cease/BFD Down) 0 bytes
2024/11/04 12:42:43.011 BGP: [QFMSE-NPSNN] zclient_bfd_session_update: sessions updated: 1
2024/11/04 12:42:43.011 BGP: [ZWCSR-M7FG9] 172.18.0.3 [FSM] BGP_Stop (Established->Clearing), fd 22
```
Reset is due to the source address change.
With this patch, we reset the session only if it's a _REAL_ BFD down event, which
means we trigger session reset if BFD session is established earlier than BGP.
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
---
bgpd/bgp_bfd.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 14ff5f2e1151..af6068cb1feb 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -53,14 +53,23 @@ static void bfd_session_status_update(struct bfd_session_params *bsp,
peer->host);
return;
}
- peer->last_reset = PEER_DOWN_BFD_DOWN;
- /* rfc9384 */
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
- bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_BFD_DOWN);
-
- BGP_EVENT_ADD(peer->connection, BGP_Stop);
+ /* Once the BFD session is UP, and later BGP session is UP,
+ * BFD notices that peer->su_local changed, and BFD session goes down.
+ * We should trigger BGP session reset if BFD session is UP
+ * only when BGP session is UP already.
+ * Otherwise, we end up resetting BGP session when BFD session is UP,
+ * when the source address is changed, e.g. 0.0.0.0 -> 10.0.0.1.
+ */
+ if (bss->last_event > peer->uptime) {
+ peer->last_reset = PEER_DOWN_BFD_DOWN;
+ /* rfc9384 */
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status))
+ bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_BFD_DOWN);
+
+ BGP_EVENT_ADD(peer->connection, BGP_Stop);
+ }
}
if (bss->state == BSS_UP && bss->previous_state != BSS_UP &&

View File

@ -1,245 +0,0 @@
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 461f0e8..12c71de 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -201,9 +201,9 @@ def get_normalized_es_id(line):
"""
The es-id or es-sys-mac need to be converted to lower case
"""
- sub_strs = ["evpn mh es-id", "evpn mh es-sys-mac"]
+ sub_strs = [r"evpn mh es-id", r"evpn mh es-sys-mac"]
for sub_str in sub_strs:
- obj = re.match(sub_str + " (?P<esi>\S*)", line)
+ obj = re.match(sub_str + r" (?P<esi>\S*)", line)
if obj:
line = "%s %s" % (sub_str, obj.group("esi").lower())
break
@@ -228,7 +228,7 @@ def get_normalized_interface_vrf(line):
correctly and configurations are matched appropriately.
"""
- intf_vrf = re.search("interface (\S+) vrf (\S+)", line)
+ intf_vrf = re.search(r"interface (\S+) vrf (\S+)", line)
if intf_vrf:
old_line = "vrf %s" % intf_vrf.group(2)
new_line = line.replace(old_line, "").strip()
@@ -813,7 +813,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add):
if ctx_keys[0] not in pg_dict:
pg_dict[ctx_keys[0]] = dict()
# find 'neighbor <pg_name> peer-group'
- re_pg = re.match("neighbor (\S+) peer-group$", line)
+ re_pg = re.match(r"neighbor (\S+) peer-group$", line)
if re_pg and re_pg.group(1) not in pg_dict[ctx_keys[0]]:
pg_dict[ctx_keys[0]][re_pg.group(1)] = {
"nbr": list(),
@@ -836,13 +836,13 @@ def bgp_delete_nbr_remote_as_line(lines_to_add):
if ctx_keys[0] in pg_dict:
for pg_key in pg_dict[ctx_keys[0]]:
# Find 'neighbor <pg_name> remote-as'
- pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key
+ pg_rmtas = r"neighbor %s remote-as (\S+)" % pg_key
re_pg_rmtas = re.search(pg_rmtas, line)
if re_pg_rmtas:
pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True
# Find 'neighbor <peer> [interface] peer-group <pg_name>'
- nb_pg = "neighbor (\S+) peer-group %s$" % pg_key
+ nb_pg = r"neighbor (\S+) peer-group %s$" % pg_key
re_nbr_pg = re.search(nb_pg, line)
if (
re_nbr_pg
@@ -860,7 +860,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add):
and line
and line.startswith("neighbor ")
):
- nbr_rmtas = "neighbor (\S+) remote-as.*"
+ nbr_rmtas = r"neighbor (\S+) remote-as.*"
re_nbr_rmtas = re.search(nbr_rmtas, line)
if re_nbr_rmtas and ctx_keys[0] in pg_dict:
for pg in pg_dict[ctx_keys[0]]:
@@ -889,8 +889,8 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict):
):
if ctx_keys[0] in del_nbr_dict:
for nbr in del_nbr_dict[ctx_keys[0]]:
- re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
- nb_exp = "neighbor %s .*" % nbr
+ re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line)
+ nb_exp = r"neighbor %s .*" % nbr
if not re_nbr_pg:
re_nb = re.search(nb_exp, line)
if re_nb:
@@ -988,7 +988,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
# neighbor uplink1 interface remote-as internal
#
# 'no neighbor peer [interface] remote-as <>'
- nb_remoteas = "neighbor (\S+) .*remote-as (\S+)"
+ nb_remoteas = r"neighbor (\S+) .*remote-as (\S+)"
re_nb_remoteas = re.search(nb_remoteas, line)
if re_nb_remoteas:
lines_to_del_to_app.append((ctx_keys, line))
@@ -996,7 +996,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
# 'no neighbor peer [interface] peer-group <>' is in lines_to_del
# copy the neighbor and look for all config removal lines associated
# to neighbor and delete them from the lines_to_del
- re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
+ re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line)
if re_nbr_pg:
if ctx_keys[0] not in del_nbr_dict:
del_nbr_dict[ctx_keys[0]] = list()
@@ -1008,7 +1008,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
if ctx_keys[0] not in del_dict:
del_dict[ctx_keys[0]] = dict()
# find 'no neighbor <pg_name> peer-group'
- re_pg = re.match("neighbor (\S+) peer-group$", line)
+ re_pg = re.match(r"neighbor (\S+) peer-group$", line)
if re_pg and re_pg.group(1) not in del_dict[ctx_keys[0]]:
del_dict[ctx_keys[0]][re_pg.group(1)] = list()
found_pg_del_cmd = True
@@ -1035,7 +1035,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
if ctx_keys[0] in del_dict:
for pg_key in del_dict[ctx_keys[0]]:
# 'neighbor <peer> [interface] peer-group <pg_name>'
- nb_pg = "neighbor (\S+) .*peer-group %s$" % pg_key
+ nb_pg = r"neighbor (\S+) .*peer-group %s$" % pg_key
re_nbr_pg = re.search(nb_pg, line)
if (
re_nbr_pg
@@ -1053,13 +1053,13 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del):
if ctx_keys[0] in del_dict:
for pg in del_dict[ctx_keys[0]]:
for nbr in del_dict[ctx_keys[0]][pg]:
- nb_exp = "neighbor %s .*" % nbr
+ nb_exp = r"neighbor %s .*" % nbr
re_nb = re.search(nb_exp, line)
# add peer configs to delete list.
if re_nb and line not in lines_to_del_to_del:
lines_to_del_to_del.append((ctx_keys, line))
- pg_exp = "neighbor %s peer-group$" % pg
+ pg_exp = r"neighbor %s peer-group$" % pg
re_pg = re.match(pg_exp, line)
if re_pg:
lines_to_del_to_app.append((ctx_keys, line))
@@ -1093,7 +1093,7 @@ def pim_delete_move_lines(lines_to_add, lines_to_del):
# no ip msdp peer <> does not accept source so strip it off.
if line and line.startswith("ip msdp peer "):
- pim_msdp_peer = re.search("ip msdp peer (\S+) source (\S+)", line)
+ pim_msdp_peer = re.search(r"ip msdp peer (\S+) source (\S+)", line)
if pim_msdp_peer:
source_sub_str = "source %s" % pim_msdp_peer.group(2)
new_line = line.replace(source_sub_str, "").strip()
@@ -1186,10 +1186,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
#
# If so then chop the del line and the corresponding add lines
re_swpx_int_peergroup = re.search(
- "neighbor (\S+) interface peer-group (\S+)", line
+ r"neighbor (\S+) interface peer-group (\S+)", line
)
re_swpx_int_v6only_peergroup = re.search(
- "neighbor (\S+) interface v6only peer-group (\S+)", line
+ r"neighbor (\S+) interface v6only peer-group (\S+)", line
)
if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup:
@@ -1246,7 +1246,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
if re_nbr_bfd_timers:
nbr = re_nbr_bfd_timers.group(1)
- bfd_nbr = "neighbor %s" % nbr
+ bfd_nbr = r"neighbor %s" % nbr
bfd_search_string = bfd_nbr + r" bfd (\S+) (\S+) (\S+)"
for ctx_keys, add_line in lines_to_add:
@@ -1271,13 +1271,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# they actually match and if we are going from a very old style
# command such that the neighbor command is under the `router
# bgp ..` node that we need to handle that appropriately
- re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line)
+ re_nbr_rm = re.search(r"neighbor(.*)route-map(.*)(in|out)$", line)
if re_nbr_rm:
adjust_for_bgp_node = 0
neighbor_name = re_nbr_rm.group(1)
rm_name_del = re_nbr_rm.group(2)
dir = re_nbr_rm.group(3)
- search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir)
+ search = r"neighbor%sroute-map(.*)%s" % (neighbor_name, dir)
save_line = "EMPTY"
for ctx_keys_al, add_line in lines_to_add:
if ctx_keys_al[0].startswith("router bgp"):
@@ -1330,10 +1330,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
#
# If so then chop the del line and the corresponding add lines
re_swpx_int_remoteas = re.search(
- "neighbor (\S+) interface remote-as (\S+)", line
+ r"neighbor (\S+) interface remote-as (\S+)", line
)
re_swpx_int_v6only_remoteas = re.search(
- "neighbor (\S+) interface v6only remote-as (\S+)", line
+ r"neighbor (\S+) interface v6only remote-as (\S+)", line
)
if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas:
@@ -1373,7 +1373,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# unnecessary session resets.
if "multipath-relax" in line:
re_asrelax_new = re.search(
- "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line
+ r"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line
)
old_asrelax_cmd = "bgp bestpath as-path multipath-relax no-as-set"
found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd)
@@ -1398,7 +1398,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# the new syntax. This causes an unnecessary 'no import-table' followed
# by the same old 'ip import-table' which causes perturbations in
# announced routes leading to traffic blackholes. Fix this issue.
- re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0])
+ re_importtbl = re.search(r"^ip\s+import-table\s+(\d+)$", ctx_keys[0])
if re_importtbl:
table_num = re_importtbl.group(1)
for ctx in lines_to_add:
@@ -1419,7 +1419,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# access-list FOO seq 5 permit 2.2.2.2/32
# ipv6 access-list BAR seq 5 permit 2:2:2::2/128
re_acl_pfxlst = re.search(
- "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ r"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
ctx_keys[0],
)
if re_acl_pfxlst:
@@ -1452,7 +1452,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# bgp large-community-list standard llist seq 5 permit 65001:65001:1
# bgp extcommunity-list standard elist seq 5 permit soo 123:123
re_bgp_lists = re.search(
- "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ r"^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
ctx_keys[0],
)
if re_bgp_lists:
@@ -1481,7 +1481,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
# Examples:
# bgp as-path access-list important_internet_bgp_as_numbers seq 30 permit _40841_"
re_bgp_as_path = re.search(
- "^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ r"^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
ctx_keys[0],
)
if re_bgp_as_path:
@@ -1511,7 +1511,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
and ctx_keys[2].startswith("vni")
):
re_route_target = (
- re.search("^route-target import (.*)$", line)
+ re.search(r"^route-target import (.*)$", line)
if line is not None
else False
)
@@ -1648,7 +1648,7 @@ def compare_context_objects(newconf, running):
pcclist_to_del = []
candidates_to_add = []
delete_bgpd = False
- area_stub_no_sum = "area (\S+) stub no-summary"
+ area_stub_no_sum = r"area (\S+) stub no-summary"
deleted_keychains = []
# Find contexts that are in newconf but not in running

View File

@ -1,42 +0,0 @@
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 7479885..fbce4fb 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4525,8 +4525,11 @@ bool peer_active(struct peer *peer)
return false;
if (peer->bfd_config) {
- if (bfd_session_is_down(peer->bfd_config->session))
+ if (bfd_session_is_admin_down(peer->bfd_config->session))
return false;
+ else if (peer_established(peer->connection) &&
+ bfd_session_is_down(peer->bfd_config->session))
+ return false;
}
if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST]
diff --git a/lib/bfd.c b/lib/bfd.c
index 4535fc1..9898922 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -1340,3 +1340,8 @@ bool bfd_session_is_down(const struct bfd_session_params *session)
return session->bss.state == BSS_DOWN ||
session->bss.state == BSS_ADMIN_DOWN;
}
+
+bool bfd_session_is_admin_down(const struct bfd_session_params *session)
+{
+ return session->bss.state == BSS_ADMIN_DOWN;
+}
diff --git a/lib/bfd.h b/lib/bfd.h
index 48929a9..29c960a 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -465,6 +465,7 @@ extern int bfd_nht_update(const struct prefix *match,
const struct zapi_route *route);
extern bool bfd_session_is_down(const struct bfd_session_params *session);
+extern bool bfd_session_is_admin_down(const struct bfd_session_params *session);
#ifdef __cplusplus
}

View File

@ -8,8 +8,8 @@
%bcond selinux 1
Name: frr
Version: 10.1
Release: 11%{?dist}
Version: 10.4.1
Release: 1%{?dist}
Summary: Routing daemon
License: GPL-2.0-or-later AND ISC AND LGPL-2.0-or-later AND BSD-2-Clause AND BSD-3-Clause AND (GPL-2.0-or-later OR ISC) AND MIT
URL: http://www.frrouting.org
@ -20,18 +20,13 @@ Source2: %{name}-sysusers.conf
Source3: frr.fc
Source4: frr.te
Source5: frr.if
Source6: remove-babeld-ldpd.sh
Patch0000: 0000-remove-babeld-and-ldpd.patch
Patch0002: 0002-enable-openssl.patch
Patch0003: 0003-disable-eigrp-crypto.patch
Patch0004: 0004-fips-mode.patch
Patch0005: 0005-remove-grpc-test.patch
Patch0006: 0006-noprefixroute-network-manager.patch
Patch0007: 0007-CVE-2024-44070.patch
Patch0008: 0008-bfd-bgp-shutdown-notification.patch
Patch0009: 0009-bgp-bfd-drop-connection.patch
Patch0010: 0010-frr-reload-escape-strings.patch
Patch0011: 0011-bfd-peer-established.patch
BuildRequires: autoconf
BuildRequires: automake
@ -115,6 +110,7 @@ cp -p %{SOURCE3} %{SOURCE4} %{SOURCE5} selinux
sed -r -i 's/(AX_CXX_COMPILE_STDCXX\(\[)11(\])/\117\2/' configure.ac
%build
export CFLAGS="%{optflags} -DINET_NTOP_NO_OVERRIDE"
autoreconf -ivf
%configure \
@ -282,6 +278,9 @@ rm tests/lib/*grpc*
%endif
%changelog
* Mon Dec 08 2025 Michal Ruprich <mruprich@redhat.com> - 10.4.1-1
- Resolves: RHEL-118620 - Rebase FRR in to version 10.4.1
* Wed Aug 06 2025 Michal Ruprich <mruprich@redhat.com> - 10.1-11
- Resolves: RHEL-107464 - bgp session not recovered due to incorect error no AF activated for peer

3
frr.te
View File

@ -98,12 +98,15 @@ corenet_tcp_bind_cmadmin_port(frr_t)
corenet_udp_bind_cmadmin_port(frr_t)
corenet_tcp_bind_firepower_port(frr_t)
corenet_tcp_bind_generic_port(frr_t)
corenet_udp_bind_generic_port(frr_t)
corenet_tcp_bind_priority_e_com_port(frr_t)
corenet_udp_bind_router_port(frr_t)
corenet_tcp_bind_qpasa_agent_port(frr_t)
corenet_tcp_bind_smntubootstrap_port(frr_t)
corenet_tcp_bind_versa_tek_port(frr_t)
corenet_tcp_bind_zebra_port(frr_t)
# general reserved port for pimd
corenet_tcp_bind_reserved_port(frr_t)
domain_use_interactive_fds(frr_t)

16
remove-babeld-ldpd.sh Normal file
View File

@ -0,0 +1,16 @@
#!/bin/sh
#this script is used to remove babled and ldpd from the tar sources
#Usage: sh remove-babeld-ldpd.sh <VERSION>
#Example: sh remove-babeld-ldpd.sh 7.3.1 - this is for frr-7.3.1.tar.gz file
VERSION=$1
TAR=frr-${VERSION}.tar.gz
DIR=frr-${VERSION}
echo ${VERSION}
echo ${TAR}
echo ${DIR}
tar -xzf ${TAR}
rm -rf ${DIR}/babeld ${DIR}/ldpd
tar -czf ${TAR} ${DIR}

View File

@ -1,2 +1 @@
SHA512 (frr-10.1.tar.gz) = 7484238a502ab12f178e4a210e6e4a33d0ce53edbb49b127fdc3167e31dd61c1122c1ef2d30e4bcb83b7f520b37fb9ad73e2a6a16790b608b1adf2e23b556445
SHA512 (remove-babeld-ldpd.sh) = a5bf67a3722cb20d43cef1dac28f839db68df73a1b7d34d8438e4f9366da3b67d85c1f44281f93434e8dd8ebcb2d3dc258b77eaa5627475b7395d207f020839d
SHA512 (frr-10.4.1.tar.gz) = 79ab8bced3ea1ac123c23de8568ed6d1a136b33b7b3edba0936b8cd5dea7cceb796d32632688f06f9e98e8c7f3e07aa57881331e74180edb761f620c8b20f77a