zebra: skip inactive nexthop when building NHG for kernel install#22133
zebra: skip inactive nexthop when building NHG for kernel install#22133GaladrielZhao wants to merge 2 commits into
Conversation
Greptile SummaryThis PR fixes a kernel NHG install failure that occurs when a recursive nexthop in an NHG's depends tree becomes inactive:
Confidence Score: 4/5The core fix correctly prevents inactive singleton NHEs from poisoning the dataplane group array; the main concern is that the check is placed one branch too early relative to the group-within-group recursion path. The fix targets singleton NHEs (the common and currently-only real case), where checking nhg.nexthop->flags is correct. Positioning the guard before the depends_is_empty branch means that if a sub-group were ever passed as a depend, only its head nexthop would be tested — potentially dropping an entire sub-group whose head happens to be inactive but whose other members are still active. The existing code comment acknowledges group-within-group is not used today, so this is not an immediate regression, but the placement leaves a subtle trap for future changes. zebra/zebra_nhg.c — specifically the placement of the new active check relative to the depends_is_empty branch. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[zebra_nhg_nhe2grp_internal called] --> B[Iterate nhg_depends tree]
B --> C{NEXTHOP_GROUP_RECURSIVE?}
C -- Yes --> D[zebra_nhg_resolve]
D --> E{resolve succeeded?}
E -- No --> F[log error, continue]
C -- No --> G
E -- Yes --> G
G{NEW: depend->nhg.nexthop && !NEXTHOP_FLAG_ACTIVE?}
G -- Yes --> H[log debug, skip - continue]
G -- No --> I{depends_is_empty?}
I -- No --> J[Group within group: recurse into sub-group]
J --> B
I -- Yes --> K{NEXTHOP_GROUP_VALID?}
K -- No --> L[log, skip - continue]
K -- Yes --> M{INSTALLED or QUEUED?}
M -- No --> N[log, skip - continue]
M -- Yes --> O{Duplicate ID?}
O -- Yes --> P[skip - continue]
O -- No --> Q[Append depend ID to nh_grp array]
Q --> B
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
zebra/zebra_nhg.c:3325-3334
**Active check fires on sub-groups, tests only the head nexthop**
The new guard is placed before the `depends_is_empty` branch, so it also runs when `depend` is a sub-group (group-within-group path). In that case `depend->nhg.nexthop` is the head of the linked list; if that head nexthop is inactive while the remaining nexthops in the sub-group are still active, the entire sub-group is silently skipped instead of letting the recursive call process each member individually. Moving the check inside the `else` branch (singleton case, where `nhg.nexthop` is always a single entry) limits its effect to the intended target and lets the recursion handle partial sub-groups correctly.
### Issue 2 of 2
tests/topotests/zebra_nhg_inactive_skip/test_zebra_nhg_inactive_skip.py:156-160
**Log-file assertion silently passes when the file doesn't exist**
`r1.net.cmd("grep -c ... /tmp/r1/zebra.log 2>/dev/null || echo 0")` returns `"0"` both when there are no matching log lines AND when the file is absent (or zebra wasn't configured to write to that path). If the log file never materialises the `assert error_count == 0` always passes, making this step a no-op. Consider verifying the file exists before grepping, or use the topotest router log helpers that expose the actual daemon log path rather than hard-coding `/tmp/r1/zebra.log`.
Reviews (1): Last reviewed commit: "tests: add topotest for NHG inactive nex..." | Re-trigger Greptile |
When a nexthop in an NHG's depends tree becomes inactive (e.g., due to recursive resolution failure), its singleton NHG is never programmed into the kernel. However, zebra_nhg_nhe2grp_internal() still references that NHE's ID in the nh_grp array sent to the kernel, which fails the entire NHG install and cascades into route install failures for every route referencing the group. Add a NEXTHOP_FLAG_ACTIVE check before appending an NHE from the depends tree to the dataplane install group, so that inactive singletons are skipped rather than poisoning the whole NHG programming. Signed-off-by: Yuqing Zhao <galadriel.zyq@alibaba-inc.com>
dab5a79 to
50d16c7
Compare
|
@donaldsharp does this overlap with some of your existing nhg work? |
Add a topotest that verifies zebra correctly skips inactive nexthops when building a nexthop group for kernel installation. The test uses recursive static routes so that removing a resolving route makes one recursive nexthop unresolvable while the NHE persists in the group's depends tree. Signed-off-by: Yuqing Zhao <yuqing.zyq@alibaba-inc.com>
78c8900 to
ab9c40e
Compare
|
ci:rerun |
1 similar comment
|
ci:rerun |
|
I don't even understand how we can have gotten to this state. It makes no sense to me. Please provide a topotest showing the problem at the very least |
Hi @donaldsharp , thanks for the review. Here's the scenario where we hit this. Output of The kernel rejects with EINVAL because the inactive nexthop is unreachable: A topotest will be provided to demonstrate this scenario. |
|
Hi @donaldsharp , this issue is caused by the skip_kernel logic in the RIB/FIB. In RIB/FIB, the received NHGs are set to skip kernel programming and sent to FPM directly, with Our proposal is to introduce a new flag |
When a nexthop in an NHG's depends tree becomes inactive (e.g., due to
recursive resolution failure), its singleton NHG is never programmed
into the kernel. However, zebra_nhg_nhe2grp_internal() still references that
NHE's ID in the nh_grp array sent to the kernel, which fails the entire
NHG install and cascades into route install failures for every route
referencing the group.
Add a NEXTHOP_FLAG_ACTIVE check before appending an NHE from the depends
tree to the dataplane install group, so that inactive singletons are
skipped rather than poisoning the whole NHG programming.