From 3940dd48f08cbb65549930ce35c834968e9d7a65 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Mon, 3 Nov 2025 12:54:53 +0300 Subject: [PATCH] Import CS frr-8.5.3-10.el9 --- ...h => 0009-bgp-graceful-restart-noop.patch} | 0 ...tion.patch => 0010-bfd-double-reset.patch} | 0 ...fication.patch => 0011-bfd-shutdown.patch} | 2 +- SOURCES/0012-print-log-to-stdout.patch | 108 +++++++ SOURCES/0013-bfd-bgp-recovery.patch | 306 ++++++++++++++++++ SOURCES/0014-isisd-fuzz-test.patch | 16 + SOURCES/0015-ipv6-wrong-hash.patch | 301 +++++++++++++++++ SPECS/frr.spec | 27 +- 8 files changed, 755 insertions(+), 5 deletions(-) rename SOURCES/{0011-bgp-graceful-restart-noop.patch => 0009-bgp-graceful-restart-noop.patch} (100%) rename SOURCES/{0010-bgp-bfd-drop-connection.patch => 0010-bfd-double-reset.patch} (100%) rename SOURCES/{0009-bfd-bgp-shutdown-notification.patch => 0011-bfd-shutdown.patch} (99%) create mode 100644 SOURCES/0012-print-log-to-stdout.patch create mode 100644 SOURCES/0013-bfd-bgp-recovery.patch create mode 100644 SOURCES/0014-isisd-fuzz-test.patch create mode 100644 SOURCES/0015-ipv6-wrong-hash.patch diff --git a/SOURCES/0011-bgp-graceful-restart-noop.patch b/SOURCES/0009-bgp-graceful-restart-noop.patch similarity index 100% rename from SOURCES/0011-bgp-graceful-restart-noop.patch rename to SOURCES/0009-bgp-graceful-restart-noop.patch diff --git a/SOURCES/0010-bgp-bfd-drop-connection.patch b/SOURCES/0010-bfd-double-reset.patch similarity index 100% rename from SOURCES/0010-bgp-bfd-drop-connection.patch rename to SOURCES/0010-bfd-double-reset.patch diff --git a/SOURCES/0009-bfd-bgp-shutdown-notification.patch b/SOURCES/0011-bfd-shutdown.patch similarity index 99% rename from SOURCES/0009-bfd-bgp-shutdown-notification.patch rename to SOURCES/0011-bfd-shutdown.patch index bf7db9f..ab0d20f 100644 --- a/SOURCES/0009-bfd-bgp-shutdown-notification.patch +++ b/SOURCES/0011-bfd-shutdown.patch @@ -249,7 +249,7 @@ index 81506f4410b1..869d2b455214 100644 return false; + + if (peer->bfd_config) { -+ if (bfd_session_is_down(peer->bfd_config->session)) ++ if (peer_established(peer) && bfd_session_is_down(peer->bfd_config->session)) + return false; + } + diff --git a/SOURCES/0012-print-log-to-stdout.patch b/SOURCES/0012-print-log-to-stdout.patch new file mode 100644 index 0000000..3ccd542 --- /dev/null +++ b/SOURCES/0012-print-log-to-stdout.patch @@ -0,0 +1,108 @@ +From 4d28aea95851dc14b3987b004f457d7a4a1535f8 Mon Sep 17 00:00:00 2001 +From: Lou Berger +Date: Sun, 2 Oct 2022 15:56:07 +0000 +Subject: [PATCH] lib: when running as a daemon, only redirect sdtin, stdout, + sdterr to null when a tty. + + Also write memstat to stderr when stderr is not a tty + and allow for --log stdout + +Signed-off-by: Lou Berger +--- + lib/libfrr.c | 44 +++++++++++++++++++++++++++++++------------- + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/lib/libfrr.c b/lib/libfrr.c +index 07e2eafec59c..e8900572694a 100644 +--- a/lib/libfrr.c ++++ b/lib/libfrr.c +@@ -130,6 +130,7 @@ static const struct optspec os_always = { + " --limit-fds Limit number of fds supported\n", + lo_always}; + ++static bool logging_to_stdout = false; /* set when --log stdout specified */ + + static const struct option lo_cfg[] = { + {"config_file", required_argument, NULL, 'f'}, +@@ -738,6 +739,11 @@ struct event_loop *frr_init(void) + while ((log_arg = log_args_pop(di->early_logging))) { + command_setup_early_logging(log_arg->target, + di->early_loglevel); ++ /* this is a bit of a hack, ++ but need to notice when ++ the target is stdout */ ++ if (strcmp(log_arg->target, "stdout") == 0) ++ logging_to_stdout = true; + XFREE(MTYPE_TMP, log_arg); + } + +@@ -1088,9 +1094,15 @@ static void frr_terminal_close(int isexit) + "%s: failed to open /dev/null: %s", __func__, + safe_strerror(errno)); + } else { +- dup2(nullfd, 0); +- dup2(nullfd, 1); +- dup2(nullfd, 2); ++ int fd; ++ /* ++ * only redirect stdin, stdout, stderr to null when a tty also ++ * don't redirect when stdout is set with --log stdout ++ */ ++ for (fd = 2; fd >= 0; fd--) ++ if (isatty(fd) && ++ (fd != STDOUT_FILENO || !logging_to_stdout)) ++ dup2(nullfd, fd); + close(nullfd); + } + } +@@ -1168,9 +1180,16 @@ void frr_run(struct event_loop *master) + "%s: failed to open /dev/null: %s", + __func__, safe_strerror(errno)); + } else { +- dup2(nullfd, 0); +- dup2(nullfd, 1); +- dup2(nullfd, 2); ++ int fd; ++ /* ++ * only redirect stdin, stdout, stderr to null when a ++ * tty also don't redirect when stdout is set with --log ++ * stdout ++ */ ++ for (fd = 2; fd >= 0; fd--) ++ if (isatty(fd) && ++ (fd != STDOUT_FILENO || !logging_to_stdout)) ++ dup2(nullfd, fd); + close(nullfd); + } + +@@ -1194,7 +1213,7 @@ void frr_fini(void) + { + FILE *fp; + char filename[128]; +- int have_leftovers; ++ int have_leftovers = 0; + + hook_call(frr_fini); + +@@ -1220,16 +1239,15 @@ void frr_fini(void) + /* frrmod_init -> nothing needed / hooks */ + rcu_shutdown(); + +- if (!debug_memstats_at_exit) +- return; +- +- have_leftovers = log_memstats(stderr, di->name); ++ /* also log memstats to stderr when stderr goes to a file*/ ++ if (debug_memstats_at_exit || !isatty(STDERR_FILENO)) ++ have_leftovers = log_memstats(stderr, di->name); + + /* in case we decide at runtime that we want exit-memstats for +- * a daemon, but it has no stderr because it's daemonized ++ * a daemon + * (only do this if we actually have something to print though) + */ +- if (!have_leftovers) ++ if (!debug_memstats_at_exit || !have_leftovers) + return; + + snprintf(filename, sizeof(filename), "/tmp/frr-memstats-%s-%llu-%llu", diff --git a/SOURCES/0013-bfd-bgp-recovery.patch b/SOURCES/0013-bfd-bgp-recovery.patch new file mode 100644 index 0000000..06d03b4 --- /dev/null +++ b/SOURCES/0013-bfd-bgp-recovery.patch @@ -0,0 +1,306 @@ +From 5eb7047e2798e56c89c650434d3c6e7dc7533328 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Tue, 12 Nov 2024 13:09:09 +0200 +Subject: [PATCH 2/5] bgpd: Update source address for BFD session + +If BFD is down, we should try to detect the source automatically from the given +interface. + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_bfd.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c +index 88ffb68206ac..3a1459b8a557 100644 +--- a/bgpd/bgp_bfd.c ++++ b/bgpd/bgp_bfd.c +@@ -26,6 +26,7 @@ + #include "bgpd/bgp_debug.h" + #include "bgpd/bgp_vty.h" + #include "bgpd/bgp_packet.h" ++#include "bgpd/bgp_network.h" + + DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data"); + +@@ -158,16 +159,33 @@ void bgp_peer_bfd_update_source(struct peer *p) + struct in_addr v4; + struct in6_addr v6; + } src, dst; ++ struct interface *ifp; ++ union sockunion addr; + + /* Nothing to do for groups. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) + return; + + /* Figure out the correct source to use. */ +- if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE) && p->update_source) +- source = p->update_source; +- else ++ if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE)) { ++ if (p->update_source) { ++ source = p->update_source; ++ } else if (p->update_if) { ++ ifp = if_lookup_by_name(p->update_if, p->bgp->vrf_id); ++ if (ifp) { ++ sockunion_init(&addr); ++ if (bgp_update_address(ifp, &p->su, &addr)) { ++ if (BGP_DEBUG(bfd, BFD_LIB)) ++ zlog_debug("%s: can't find the source address for interface %s", ++ __func__, p->update_if); ++ } ++ ++ source = &addr; ++ } ++ } ++ } else { + source = p->su_local; ++ } + + /* Update peer's source/destination addresses. */ + bfd_sess_addresses(session, &family, &src.v6, &dst.v6); + +From d6c8c23635873ca26cd6837d2a8e0ad360a734c6 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Wed, 20 Nov 2024 16:07:34 -0500 +Subject: [PATCH 3/5] bgpd: Allow bfd to work if peer known but interface + address not yet + +If bgp is coming up and bgp has not received the interface address yet +but bgp has knowledge about a bfd peering, allow it to set the peering +data appropriately. + +Signed-off-by: Donald Sharp +--- + bgpd/bgp_bfd.c | 8 ++++++-- + bgpd/bgp_nexthop.c | 28 +++++++++++++++++----------- + 2 files changed, 23 insertions(+), 13 deletions(-) + +diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c +index 3a1459b8a557..b3221853bbad 100644 +--- a/bgpd/bgp_bfd.c ++++ b/bgpd/bgp_bfd.c +@@ -151,8 +151,8 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) + + void bgp_peer_bfd_update_source(struct peer *p) + { +- struct bfd_session_params *session = p->bfd_config->session; +- const union sockunion *source; ++ struct bfd_session_params *session; ++ const union sockunion *source = NULL; + bool changed = false; + int family; + union { +@@ -162,6 +162,10 @@ void bgp_peer_bfd_update_source(struct peer *p) + struct interface *ifp; + union sockunion addr; + ++ if (!p->bfd_config) ++ return; ++ ++ session = p->bfd_config->session; + /* Nothing to do for groups. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) + return; +diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c +index 77e2603..c85f50d 100644 +--- a/bgpd/bgp_nexthop.c ++++ b/bgpd/bgp_nexthop.c +@@ -46,6 +46,7 @@ + #include "bgpd/bgp_fsm.h" + #include "bgpd/bgp_vty.h" + #include "bgpd/bgp_rd.h" ++#include "bgpd/bgp_bfd.h" + + DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Addr Intf String"); + +@@ -427,17 +428,6 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc) + bgp_dest_set_bgp_connected_ref_info(dest, bc); + } + +- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { +- if (peer->conf_if +- && (strcmp(peer->conf_if, ifc->ifp->name) == 0) +- && !peer_established(peer) +- && !CHECK_FLAG(peer->flags, +- PEER_FLAG_IFPEER_V6ONLY)) { +- if (peer_active(peer)) +- BGP_EVENT_ADD(peer, BGP_Stop); +- BGP_EVENT_ADD(peer, BGP_Start); +- } +- } + } else if (addr->family == AF_INET6) { + apply_mask_ipv6((struct prefix_ipv6 *)&p); + +@@ -461,6 +451,21 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc) + bgp_dest_set_bgp_connected_ref_info(dest, bc); + } + } ++ ++ /* ++ * Iterate over all the peers and attempt to set the bfd session ++ * data and if it's a bgp unnumbered get her flowing if necessary ++ */ ++ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { ++ bgp_peer_bfd_update_source(peer); ++ if (peer->conf_if && (strcmp(peer->conf_if, ifc->ifp->name) == 0) && ++ !peer_established(peer) && ++ !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) { ++ if (peer_active(peer)) ++ BGP_EVENT_ADD(peer, BGP_Stop); ++ BGP_EVENT_ADD(peer, BGP_Start); ++ } ++ } + } + + void bgp_connected_delete(struct bgp *bgp, struct connected *ifc) +From 2c92346292badda2bad93c1a1188d4349e38cde0 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Thu, 5 Dec 2024 10:16:03 -0500 +Subject: [PATCH 4/5] bgpd: When bgp notices a change to shared_network inform + bfd of it + +When bgp is started up and reads the config in *before* it has +received interface addresses from zebra, shared_network can +be set to false in this case. Later on once bgp attempts to +reconnect it will refigure out the shared_network again( because +it has received the data from zebra now ). In this case +tell bfd about it. + +Signed-off-by: Donald Sharp +--- + bgpd/bgp_zebra.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c +index f9d096e6c643..e072e18c847f 100644 +--- a/bgpd/bgp_zebra.c ++++ b/bgpd/bgp_zebra.c +@@ -728,6 +728,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, + int ret = 0; + struct interface *ifp = NULL; + bool v6_ll_avail = true; ++ bool shared_network_original = peer->shared_network; + + memset(nexthop, 0, sizeof(struct bgp_nexthop)); + +@@ -892,6 +893,9 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, + peer->shared_network = 0; + } + ++ if (shared_network_original != peer->shared_network) ++ bgp_peer_bfd_update_source(peer); ++ + /* KAME stack specific treatment. */ + #ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL(&nexthop->v6_global) + +From c059cf388106f81040bdde3ff93a3b2cbd08523b Mon Sep 17 00:00:00 2001 +From: Louis Scalbert +Date: Wed, 22 Jan 2025 13:30:55 +0100 +Subject: [PATCH 5/5] bgpd: fix bfd with update-source in peer-group + +Fix BFD session not created when the peer is in update-group with the +update-source option. + +Signed-off-by: Louis Scalbert +--- + bgpd/bgp_bfd.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c +index b3221853bbad..f8f06df49f14 100644 +--- a/bgpd/bgp_bfd.c ++++ b/bgpd/bgp_bfd.c +@@ -114,6 +114,10 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) + */ + gconfig = pg->conf; + ++ if (CHECK_FLAG(gconfig->flags, PEER_FLAG_UPDATE_SOURCE) || ++ CHECK_FLAG(p->flags_override, PEER_FLAG_UPDATE_SOURCE)) ++ bgp_peer_bfd_update_source(p); ++ + /* + * If using default control plane independent configuration, + * then prefer group's (e.g. it means it wasn't manually configured). +diff --git a/bfdd/bfd.c b/bfdd/bfd.c +index 4367f25..b43ba32 100644 +--- a/bfdd/bfd.c ++++ b/bfdd/bfd.c +@@ -1269,6 +1269,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) + return; + + SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); ++ bs->local_diag = BD_ADMIN_DOWN; + + /* Handle data plane shutdown case. */ + if (bs->bdc) { +diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c +index df5fcaf..01d61d4 100644 +--- a/bgpd/bgp_fsm.c ++++ b/bgpd/bgp_fsm.c +@@ -1367,11 +1367,6 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) + + peer->nsf_af_count = 0; + +- /* deregister peer */ +- if (peer->bfd_config +- && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) +- bfd_sess_uninstall(peer->bfd_config->session); +- + if (peer_dynamic_neighbor_no_nsf(peer) && + !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { + if (bgp_debug_neighbor_events(peer)) +@@ -1391,6 +1386,10 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer) + if (peer_established(peer)) { + peer->dropped++; + ++ if (peer->bfd_config && (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE || ++ peer->last_reset == PEER_DOWN_MULTIHOP_CHANGE)) ++ bfd_sess_uninstall(peer->bfd_config->session); ++ + /* Notify BGP conditional advertisement process */ + peer->advmap_table_change = true; + +diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c +index 374d9ee..352a77c 100644 +--- a/bgpd/bgpd.c ++++ b/bgpd/bgpd.c +@@ -4253,7 +4253,10 @@ bool peer_active(struct peer *peer) + return false; + + if (peer->bfd_config) { +- if (peer_established(peer) && 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) && ++ bfd_session_is_down(peer->bfd_config->session)) + return false; + } + +diff --git a/lib/bfd.c b/lib/bfd.c +index ee9d62d..7f897cd 100644 +--- a/lib/bfd.c ++++ b/lib/bfd.c +@@ -1357,3 +1357,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 e1ba242..326767d 100644 +--- a/lib/bfd.h ++++ b/lib/bfd.h +@@ -481,6 +481,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 + } diff --git a/SOURCES/0014-isisd-fuzz-test.patch b/SOURCES/0014-isisd-fuzz-test.patch new file mode 100644 index 0000000..a661b4f --- /dev/null +++ b/SOURCES/0014-isisd-fuzz-test.patch @@ -0,0 +1,16 @@ +diff --git a/tests/isisd/test_fuzz_isis_tlv.py b/tests/isisd/test_fuzz_isis_tlv.py +index 8fd20aa..a23f665 100644 +--- a/tests/isisd/test_fuzz_isis_tlv.py ++++ b/tests/isisd/test_fuzz_isis_tlv.py +@@ -10,10 +10,7 @@ import socket + ## + def inet_ntop_broken(): + addr = "1:2:3:4:0:6:7:8" +- return ( +- socket.inet_ntop(socket.AF_INET6, socket.inet_pton(socket.AF_INET6, addr)) +- != addr +- ) ++ return True + + + if platform.uname()[0] == "SunOS" or inet_ntop_broken(): diff --git a/SOURCES/0015-ipv6-wrong-hash.patch b/SOURCES/0015-ipv6-wrong-hash.patch new file mode 100644 index 0000000..df33ceb --- /dev/null +++ b/SOURCES/0015-ipv6-wrong-hash.patch @@ -0,0 +1,301 @@ +From 46e685d2f9cd1a359e0abd95b584f7cc3df9ae2c Mon Sep 17 00:00:00 2001 +From: David Lamparter +Date: Wed, 22 Jan 2025 11:23:31 +0100 +Subject: [PATCH] lib: clean up nexthop hashing mess + +We were hashing 4 bytes of the address. Even for IPv6 addresses. + +Oops. + +The reason this was done was to try to make it faster, but made a +complex maze out of everything. Time for a refactor. + +Signed-off-by: David Lamparter +(cherry picked from commit 001fcfa1dd9f7dc2639b4f5c7a52ab59cc425452) +--- + lib/nexthop.c | 87 ++++++----------------------------------- + lib/nexthop.h | 104 +++++++++++++++++++++++++++++++++----------------- + 2 files changed, 80 insertions(+), 111 deletions(-) + +diff --git a/lib/nexthop.c b/lib/nexthop.c +index 98b05295b996..90931676e5de 100644 +--- a/lib/nexthop.c ++++ b/lib/nexthop.c +@@ -746,68 +746,30 @@ unsigned int nexthop_level(const struct nexthop *nexthop) + return rv; + } + +-/* Only hash word-sized things, let cmp do the rest. */ +-uint32_t nexthop_hash_quick(const struct nexthop *nexthop) ++uint32_t nexthop_hash(const struct nexthop *nexthop) + { + uint32_t key = 0x45afe398; +- int i; + +- key = jhash_3words(nexthop->type, nexthop->vrf_id, +- nexthop->nh_label_type, key); +- +- if (nexthop->nh_label) { +- int labels = nexthop->nh_label->num_labels; ++ /* type, vrf, ifindex, ip addresses - see nexthop.h */ ++ key = _nexthop_hash_bytes(nexthop, key); + +- i = 0; ++ key = jhash_1word(nexthop->flags & NEXTHOP_FLAGS_HASHED, key); + +- while (labels >= 3) { +- key = jhash_3words(nexthop->nh_label->label[i], +- nexthop->nh_label->label[i + 1], +- nexthop->nh_label->label[i + 2], +- key); +- labels -= 3; +- i += 3; +- } +- +- if (labels >= 2) { +- key = jhash_2words(nexthop->nh_label->label[i], +- nexthop->nh_label->label[i + 1], +- key); +- labels -= 2; +- i += 2; +- } ++ if (nexthop->nh_label) { ++ const struct mpls_label_stack *ls = nexthop->nh_label; + +- if (labels >= 1) +- key = jhash_1word(nexthop->nh_label->label[i], key); ++ /* num_labels itself isn't useful to hash, if the number of ++ * labels is different, the hash value will change just due to ++ * that already. ++ */ ++ key = jhash(ls->label, sizeof(ls->label[0]) * ls->num_labels, key); + } + +- key = jhash_2words(nexthop->ifindex, +- CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), +- key); +- + /* Include backup nexthops, if present */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + int backups = nexthop->backup_num; + +- i = 0; +- +- while (backups >= 3) { +- key = jhash_3words(nexthop->backup_idx[i], +- nexthop->backup_idx[i + 1], +- nexthop->backup_idx[i + 2], key); +- backups -= 3; +- i += 3; +- } +- +- while (backups >= 2) { +- key = jhash_2words(nexthop->backup_idx[i], +- nexthop->backup_idx[i + 1], key); +- backups -= 2; +- i += 2; +- } +- +- if (backups >= 1) +- key = jhash_1word(nexthop->backup_idx[i], key); ++ key = jhash(nexthop->backup_idx, sizeof(nexthop->backup_idx[0]) * backups, key); + } + + if (nexthop->nh_srv6) { +@@ -842,31 +804,6 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) + return key; + } + +- +-#define GATE_SIZE 4 /* Number of uint32_t words in struct g_addr */ +- +-/* For a more granular hash */ +-uint32_t nexthop_hash(const struct nexthop *nexthop) +-{ +- uint32_t gate_src_rmap_raw[GATE_SIZE * 3] = {}; +- /* Get all the quick stuff */ +- uint32_t key = nexthop_hash_quick(nexthop); +- +- assert(((sizeof(nexthop->gate) + sizeof(nexthop->src) +- + sizeof(nexthop->rmap_src)) +- / 3) +- == (GATE_SIZE * sizeof(uint32_t))); +- +- memcpy(gate_src_rmap_raw, &nexthop->gate, GATE_SIZE); +- memcpy(gate_src_rmap_raw + GATE_SIZE, &nexthop->src, GATE_SIZE); +- memcpy(gate_src_rmap_raw + (2 * GATE_SIZE), &nexthop->rmap_src, +- GATE_SIZE); +- +- key = jhash2(gate_src_rmap_raw, (GATE_SIZE * 3), key); +- +- return key; +-} +- + void nexthop_copy_no_recurse(struct nexthop *copy, + const struct nexthop *nexthop, + struct nexthop *rparent) +diff --git a/lib/nexthop.h b/lib/nexthop.h +index 02ea4d96f2df..12e6424f2774 100644 +--- a/lib/nexthop.h ++++ b/lib/nexthop.h +@@ -8,6 +8,7 @@ + #ifndef _LIB_NEXTHOP_H + #define _LIB_NEXTHOP_H + ++#include "jhash.h" + #include "prefix.h" + #include "mpls.h" + #include "vxlan.h" +@@ -56,15 +57,48 @@ struct nexthop { + struct nexthop *next; + struct nexthop *prev; + +- /* +- * What vrf is this nexthop associated with? ++ ++ /* begin of hashed data - all fields from here onwards are given to ++ * jhash() as one consecutive chunk. DO NOT create "padding holes". ++ * DO NOT insert pointers that need to be deep-hashed. ++ * ++ * static_assert() below needs to be updated when fields are added + */ ++ char _hash_begin[0]; ++ ++ /* see above */ ++ enum nexthop_types_t type; ++ ++ /* What vrf is this nexthop associated with? */ + vrf_id_t vrf_id; + + /* Interface index. */ + ifindex_t ifindex; + +- enum nexthop_types_t type; ++ /* Type of label(s), if any */ ++ enum lsp_types_t nh_label_type; ++ ++ /* padding: keep 16 byte alignment here */ ++ ++ /* Nexthop address ++ * make sure all 16 bytes for IPv6 are zeroed when putting in an IPv4 ++ * address since the entire thing is hashed as-is ++ */ ++ union { ++ union g_addr gate; ++ enum blackhole_type bh_type; ++ }; ++ union g_addr src; ++ union g_addr rmap_src; /* Src is set via routemap */ ++ ++ /* end of hashed data - remaining fields in this struct are not ++ * directly fed into jhash(). Most of them are actually part of the ++ * hash but have special rules or handling attached. ++ */ ++ char _hash_end[0]; ++ ++ /* Weight of the nexthop ( for unequal cost ECMP ) */ ++ uint8_t weight; + + uint16_t flags; + #define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ +@@ -82,18 +116,15 @@ struct nexthop { + #define NEXTHOP_FLAG_EVPN (1 << 8) /* nexthop is EVPN */ + #define NEXTHOP_FLAG_LINKDOWN (1 << 9) /* is not removed on link down */ + ++ /* which flags are part of nexthop_hash(). Should probably be split ++ * off into a separate field... ++ */ ++#define NEXTHOP_FLAGS_HASHED NEXTHOP_FLAG_ONLINK ++ + #define NEXTHOP_IS_ACTIVE(flags) \ + (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ + && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) + +- /* Nexthop address */ +- union { +- union g_addr gate; +- enum blackhole_type bh_type; +- }; +- union g_addr src; +- union g_addr rmap_src; /* Src is set via routemap */ +- + /* Nexthops obtained by recursive resolution. + * + * If the nexthop struct needs to be resolved recursively, +@@ -104,15 +135,9 @@ struct nexthop { + /* Recursive parent */ + struct nexthop *rparent; + +- /* Type of label(s), if any */ +- enum lsp_types_t nh_label_type; +- + /* Label(s) associated with this nexthop. */ + struct mpls_label_stack *nh_label; + +- /* Weight of the nexthop ( for unequal cost ECMP ) */ +- uint8_t weight; +- + /* Count and index of corresponding backup nexthop(s) in a backup list; + * only meaningful if the HAS_BACKUP flag is set. + */ +@@ -138,6 +163,29 @@ struct nexthop { + struct nexthop_srv6 *nh_srv6; + }; + ++/* all hashed fields (including padding, if it is necessary to add) need to ++ * be listed in the static_assert below ++ */ ++ ++#define S(field) sizeof(((struct nexthop *)NULL)->field) ++ ++static_assert( ++ offsetof(struct nexthop, _hash_end) - offsetof(struct nexthop, _hash_begin) == ++ S(type) + S(vrf_id) + S(ifindex) + S(nh_label_type) + S(gate) + S(src) + S(rmap_src), ++ "struct nexthop contains padding, this can break things. insert _pad fields at appropriate places"); ++ ++#undef S ++ ++/* this is here to show exactly what is meant by the comments above about ++ * the hashing ++ */ ++static inline uint32_t _nexthop_hash_bytes(const struct nexthop *nh, uint32_t seed) ++{ ++ return jhash(&nh->_hash_begin, ++ offsetof(struct nexthop, _hash_end) - offsetof(struct nexthop, _hash_begin), ++ seed); ++} ++ + /* Utility to append one nexthop to another. */ + #define NEXTHOP_APPEND(to, new) \ + do { \ +@@ -181,27 +229,11 @@ struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type, + /* + * Hash a nexthop. Suitable for use with hash tables. + * +- * This function uses the following values when computing the hash: +- * - vrf_id +- * - ifindex +- * - type +- * - gate +- * +- * nexthop +- * The nexthop to hash +- * +- * Returns: +- * 32-bit hash of nexthop ++ * Please double check the code on what is included in the hash, there was ++ * documentation here but it got outdated and the only thing worse than no ++ * doc is incorrect doc. + */ + uint32_t nexthop_hash(const struct nexthop *nexthop); +-/* +- * Hash a nexthop only on word-sized attributes: +- * - vrf_id +- * - ifindex +- * - type +- * - (some) flags +- */ +-uint32_t nexthop_hash_quick(const struct nexthop *nexthop); + + extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2); + extern bool nexthop_same_no_labels(const struct nexthop *nh1, diff --git a/SPECS/frr.spec b/SPECS/frr.spec index db90bd7..3f8a21c 100644 --- a/SPECS/frr.spec +++ b/SPECS/frr.spec @@ -7,7 +7,7 @@ Name: frr Version: 8.5.3 -Release: 7%{?checkout}%{?dist} +Release: 10%{?checkout}%{?dist} Summary: Routing daemon License: GPLv2+ URL: http://www.frrouting.org @@ -71,9 +71,14 @@ Patch0005: 0005-CVE-2023-47235.patch Patch0006: 0006-CVE-2023-47234.patch Patch0007: 0007-CVE-2023-46752.patch Patch0008: 0008-CVE-2023-46753.patch -Patch0009: 0009-bfd-bgp-shutdown-notification.patch -Patch0010: 0010-bgp-bfd-drop-connection.patch -Patch0011: 0011-bgp-graceful-restart-noop.patch +Patch0009: 0009-bgp-graceful-restart-noop.patch +Patch0010: 0010-bfd-double-reset.patch +Patch0011: 0011-bfd-shutdown.patch +Patch0012: 0012-print-log-to-stdout.patch +Patch0013: 0013-bfd-bgp-recovery.patch +# Turn off one fuzz test that fails with the new glibc +Patch0014: 0014-isisd-fuzz-test.patch +Patch0015: 0015-ipv6-wrong-hash.patch %description FRRouting is free software that manages TCP/IP based routing protocols. It takes @@ -104,6 +109,10 @@ mkdir selinux cp -p %{SOURCE3} %{SOURCE4} %{SOURCE5} selinux %build +# This is needed to pass a build with the new glibc +# but this could affect the speed of inet_ntop calls +# https://github.com/FRRouting/frr/issues/18575 +export CFLAGS="%{optflags} -DINET_NTOP_NO_OVERRIDE" autoreconf -ivf %configure \ @@ -279,6 +288,16 @@ make check PYTHON=%{__python3} %endif %changelog +* Fri Sep 19 2025 Michal Ruprich - 8.5.3-10 +- Resolves: RHEL-13756 - Source address set in FRR route-map not working with IPv6 + +* Fri May 16 2025 Michal Ruprich - 8.5.3-9 +- Resolves: RHEL-87730 - frr-k8s CI started failing using latest rpm, failures around BFD sessions +- Resolves: RHEL-87731 - FRR bgp session not recovered due to incorect error no AF activated for peer + +* Thu Apr 03 2025 Michal Ruprich - 8.5.3-8 +- Resolves: RHEL-85950 - FRR doesn't send logs to stdout when running as a daemon + * Fri Feb 14 2025 Michal Ruprich - 8.5.3-7 - Resolves: RHEL-68432 - FRR gives false warning when Graceful Restart enabled