From 8d7c2d4e831397c84f2592fdf864727de6d32985 Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Mon, 30 Mar 2026 10:25:35 -0400 Subject: [PATCH] import CS frr-8.5.3-12.el9 --- SOURCES/0016-dont-ignore-kernel-route.patch | 276 ++++++++++++++++++++ SOURCES/frr-tmpfiles.conf | 1 + SPECS/frr.spec | 16 +- 3 files changed, 288 insertions(+), 5 deletions(-) create mode 100644 SOURCES/0016-dont-ignore-kernel-route.patch diff --git a/SOURCES/0016-dont-ignore-kernel-route.patch b/SOURCES/0016-dont-ignore-kernel-route.patch new file mode 100644 index 0000000..e52dbcc --- /dev/null +++ b/SOURCES/0016-dont-ignore-kernel-route.patch @@ -0,0 +1,276 @@ +From d528c02a204086da0d542d5655b8724de681a65c Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Fri, 7 Jun 2024 13:50:07 -0400 +Subject: [PATCH] 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 +--- + 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) + 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,24 @@ 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; ++ ++ 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) { ++ 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; + default: + break; +diff --git a/zebra/rib.h b/zebra/rib.h +index fcd6fb6..49506fd 100644 +--- a/zebra/rib.h ++++ b/zebra/rib.h +@@ -353,6 +353,8 @@ extern void _route_entry_dump(const char *func, union prefixconstptr pp, + union prefixconstptr src_pp, + const struct route_entry *re); + ++void zebra_rib_route_entry_free(struct route_entry *re); ++ + struct route_entry * + zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, uint8_t instance, + uint32_t flags, uint32_t nhe_id, uint32_t table_id, +@@ -484,6 +486,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/rt_netlink.c b/zebra/rt_netlink.c +index cf8df97..71250ae 100644 +--- a/zebra/rt_netlink.c ++++ b/zebra/rt_netlink.c +@@ -990,6 +990,8 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, + re, ng, startup, ctx); + if (ng) + nexthop_group_delete(&ng); ++ if (ctx) ++ zebra_rib_route_entry_free(re); + } else { + /* + * I really don't see how this is possible +diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c +index 129416d..ca6be3e 100644 +--- a/zebra/zebra_rib.c ++++ b/zebra/zebra_rib.c +@@ -4145,6 +4145,12 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, + + return re; + } ++ ++void zebra_rib_route_entry_free(struct route_entry *re) ++{ ++ XFREE(MTYPE_RE, re); ++} ++ + /* + * Internal route-add implementation; there are a couple of different public + * signatures. Callers in this path are responsible for the memory they +@@ -4434,7 +4440,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; + diff --git a/SOURCES/frr-tmpfiles.conf b/SOURCES/frr-tmpfiles.conf index c1613b2..89d6865 100644 --- a/SOURCES/frr-tmpfiles.conf +++ b/SOURCES/frr-tmpfiles.conf @@ -1 +1,2 @@ d /run/frr 0755 frr frr - +d /var/log/frr 0755 frr frr diff --git a/SPECS/frr.spec b/SPECS/frr.spec index 71c00ba..e599e68 100644 --- a/SPECS/frr.spec +++ b/SPECS/frr.spec @@ -7,7 +7,7 @@ Name: frr Version: 8.5.3 -Release: 9%{?checkout}%{?dist}.1 +Release: 12%{?checkout}%{?dist} Summary: Routing daemon License: GPLv2+ URL: http://www.frrouting.org @@ -79,6 +79,7 @@ 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 +Patch0016: 0016-dont-ignore-kernel-route.patch %description FRRouting is free software that manages TCP/IP based routing protocols. It takes @@ -152,8 +153,7 @@ bzip2 -9 selinux/%{name}.pp %install mkdir -p %{buildroot}/etc/{frr,rc.d/init.d,sysconfig,logrotate.d,pam.d,default} \ - %{buildroot}/var/log/frr %{buildroot}%{_infodir} \ - %{buildroot}%{_unitdir} + %{buildroot}%{_infodir} %{buildroot}%{_unitdir} mkdir -p -m 0755 %{buildroot}%{_libdir}/frr mkdir -p %{buildroot}%{_tmpfilesdir} @@ -260,7 +260,6 @@ make check PYTHON=%{__python3} %license COPYING %doc doc/mpls %dir %attr(750,frr,frr) %{_sysconfdir}/frr -%dir %attr(755,frr,frr) /var/log/frr %dir %attr(755,frr,frr) /run/frr %{_infodir}/*info* %{_mandir}/man*/* @@ -288,7 +287,13 @@ make check PYTHON=%{__python3} %endif %changelog -* Fri Sep 19 2025 Michal Ruprich - 8.5.3-9.1 +* Fri Jan 16 2026 Michal Ruprich - 8.5.3-12 +- Resolves: RHEL-137180 - Files under /var are not properly created in image-mode + +* Wed Oct 29 2025 Michal Ruprich - 8.5.3-11 +- Resolves: RHEL-64427 - FRR ignores kernel routes from the system + +* 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 @@ -480,3 +485,4 @@ make check PYTHON=%{__python3} * Wed Jun 19 2019 Michal Ruprich - 7.0-2 - Initial build +