summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/topotests/lib/bgp.py2
-rw-r--r--zebra/rib.h7
-rw-r--r--zebra/zebra_nhg.c28
-rw-r--r--zebra/zebra_rib.c17
4 files changed, 47 insertions, 7 deletions
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 218f2dbe2b..a09b0b8b2e 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -2797,7 +2797,7 @@ def verify_best_path_as_per_admin_distance(
if route in rib_routes_json:
st_found = True
# Verify next_hop in rib_routes_json
- if rib_routes_json[route][0]["nexthops"][0]["ip"] == _next_hop:
+ if [nh for nh in rib_routes_json[route][0]["nexthops"] if nh['ip'] == _next_hop]:
nh_found = True
else:
errormsg = (
diff --git a/zebra/rib.h b/zebra/rib.h
index 99f52bcd4e..166500fa5c 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -158,6 +158,13 @@ struct route_entry {
* differs from the rib/normal set of nexthops.
*/
#define ROUTE_ENTRY_USE_FIB_NHG 0x40
+/*
+ * Route entries that are going to the dplane for a Route Replace
+ * let's note the fact that this is happening. This will
+ * be useful when zebra is determing if a route can be
+ * used for nexthops
+ */
+#define ROUTE_ENTRY_ROUTE_REPLACING 0x80
/* Sequence value incremented for each dataplane operation */
uint32_t dplane_sequence;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index e50023201b..ded2bd04bb 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2369,11 +2369,33 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
resolved = 0;
- /* Only useful if installed */
- if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
+ /*
+ * Only useful if installed or being Route Replacing
+ * Why Being Route Replaced as well?
+ * Imagine a route A and route B( that depends on A )
+ * for recursive resolution and A already exists in the
+ * zebra rib. If zebra receives the routes
+ * for resolution at aproximately the same time in the [
+ * B, A ] order on the workQ. If this happens then
+ * normal route resolution will happen and B will be
+ * resolved successfully and then A will be resolved
+ * successfully. Now imagine the reversed order [A, B].
+ * A will be resolved and then scheduled for installed
+ * (Thus not having the ROUTE_ENTRY_INSTALLED flag ). B
+ * will then get resolved and fail to be installed
+ * because the original below test. Let's `loosen` this
+ * up a tiny bit and allow the
+ * ROUTE_ENTRY_ROUTE_REPLACING flag ( that is set when a
+ * Route Replace operation is being initiated on A now )
+ * to now satisfy this situation. This will allow
+ * either order in the workQ to work properly.
+ */
+ if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED) &&
+ !CHECK_FLAG(match->status,
+ ROUTE_ENTRY_ROUTE_REPLACING)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%s: match %p (%pNG) not installed",
+ "%s: match %p (%pNG) not installed or being Route Replaced",
__func__, match, match->nhe);
goto done_with_match;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index fceaaaa9f0..54ef4768eb 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -292,13 +292,16 @@ static char *_dump_re_status(const struct route_entry *re, char *buf,
}
snprintfrr(
- buf, len, "%s%s%s%s%s%s%s",
+ buf, len, "%s%s%s%s%s%s%s%s",
CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
? "Label Changed "
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING)
+ ? "Replacing"
+ : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
@@ -713,6 +716,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
if (old) {
SET_FLAG(old->status, ROUTE_ENTRY_QUEUED);
+ SET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
/* Free old FIB nexthop group */
UNSET_FLAG(old->status, ROUTE_ENTRY_USE_FIB_NHG);
@@ -1538,6 +1542,7 @@ static void zebra_rib_fixup_system(struct route_node *rn)
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
for (ALL_NEXTHOPS(re->nhe->nhg, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -1995,8 +2000,12 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
} else {
if (!zrouter.asic_offloaded ||
(CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED) ||
- CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED)))
+ CHECK_FLAG(re->flags,
+ ZEBRA_FLAG_OFFLOAD_FAILED))) {
+ UNSET_FLAG(re->status,
+ ROUTE_ENTRY_ROUTE_REPLACING);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ }
}
}
@@ -2252,8 +2261,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
}
/* Ensure we clear the QUEUED flag */
- if (!zrouter.asic_offloaded)
+ if (!zrouter.asic_offloaded) {
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
+ }
/* Is this a notification that ... matters? We mostly care about
* the route that is currently selected for installation; we may also