pimd/pim6d: fix the wrong check of multicast interface in nb#21107
pimd/pim6d: fix the wrong check of multicast interface in nb#21107anlancs wants to merge 1 commit intoFRRouting:masterfrom
Conversation
Greptile SummaryThis PR fixes a longstanding correctness bug in Key changes:
Confidence Score: 3/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[NB_EV_VALIDATE\npim-enable or gmp-enable modify] --> B[yang_dnode_get_parent\nget interface node]
B --> C[pim_interface_num_get\ncount PIM/GMP enabled interfaces]
C --> D[lyd_parent: get lib container]
D --> E[LY_LIST_FOR all interface list nodes]
E --> F{nodetype == LYS_LIST?}
F -- No --> E
F -- Yes --> G[yang_dnode_getf gmp/enable\nfor current AF]
G --> H[yang_dnode_getf pim/pim-enable\nfor current AF]
H --> I{gmp enabled\nOR pim enabled?}
I -- Yes --> J[cnt++]
I -- No --> E
J --> E
E -- done --> K{cnt > MAXVIFS?\nnote: should be >= MAXVIFS}
K -- Yes --> L[NB_ERR_VALIDATION\nmax multicast interfaces reached]
K -- No --> M[NB_EV_APPLY\npim_cmd_interface_add / pim_cmd_gm_start]
M --> N[pim_if_add_vif\nget next VIF index 1..MAXVIFS-1]
N --> O{index >= MAXVIFS?}
O -- Yes --> P[return -3\nsilent failure\nif cnt was exactly MAXVIFS]
O -- No --> Q[VIF registered successfully]
Prompt To Fix All With AIThis is a comment left during a code review.
Path: pimd/pim_nb_config.c
Line: 2264
Comment:
**Off-by-one: allows one more interface than VIF slots support**
`pim_iface_next_vif_index()` always reserves VIF index 0 for `pimreg` and assigns user interfaces indices 1..`MAXVIFS-1` (see `pim_iface.c:952-956`):
```c
for (i = 1; i < MAXVIFS; i++) { // only MAXVIFS-1 slots
if (pim->iface_vif_index[i] == 0)
return i;
}
return MAXVIFS; // signals "full"
```
`pim_if_add_vif()` rejects any index `>= MAXVIFS`. This means at most **`MAXVIFS-1` user-configured PIM interfaces** can be given VIF indices at apply time.
With `pim_interface_num_get(if_dnode) > MAXVIFS`, the validation passes when count equals exactly `MAXVIFS` (the `MAXVIFS`-th user interface). That interface gets through `NB_EV_VALIDATE` but then fails silently at `NB_EV_APPLY` because `pim_if_add_vif()` returns `-3` (returning `NB_ERR_INCONSISTENCY` only if `pim_cmd_interface_add` propagates the error).
The threshold should be `>= MAXVIFS` so validation catches this one case earlier:
```suggestion
if (pim_interface_num_get(if_dnode) >= MAXVIFS) {
```
The same applies at line 4601 in `lib_interface_gmp_address_family_enable_modify`.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: pimd/pim_nb_config.c
Line: 4601
Comment:
**Same off-by-one as line 2264**
As noted for the PIM-enable handler at line 2264, `> MAXVIFS` should be `>= MAXVIFS` here as well. With `> MAXVIFS`, enabling GMP on the `MAXVIFS`-th interface passes validation but subsequently fails at VIF allocation time.
```suggestion
if (pim_interface_num_get(if_dnode) >= MAXVIFS) {
```
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "pimd/pim6d: fix the ..." |
c61b8d3 to
4616c50
Compare
|
@greptile review |
| return NB_OK; | ||
| } | ||
|
|
||
| static int pim_interface_num_get(const struct lyd_node *if_dnode) |
There was a problem hiding this comment.
I wonder if it'd be better to determine if there are any available VIF indexes available by looking at pim->iface_vif_index instead.
int iface_vif_index[MAXVIFS];
This would more accurately determine if there is a VIF available for the new interface or not.
There was a problem hiding this comment.
It's nb code, seems better to check it in nb way. I'm not sure...
There was a problem hiding this comment.
The part that the NB doesn't account for are the vif indexes used by the pimreg interface(s).
The `yang_get_list_elements_count()` in pim is wrong: The configuration node is added at the end of the link list. Therefore, this function will traverse from the configuration node, so it usually/wrongly returns 1. This commit introduced three changes: 1. replace "== MAXVIFS" with "> MAXVIFS" because the maximum is MAXVIFS. 2. the check of MAXVIFS should be limited to the same address family. 3. check pim and igmp for ipv4 family, and check pim6 and mld for ipv6 family. Signed-off-by: anlan_cs <anlan_cs@126.com>
4616c50 to
10f5e18
Compare
|
@greptile review |
| /* Limiting mcast interfaces to number of VIFs */ | ||
| if (mcast_if_count == MAXVIFS) { | ||
| if_dnode = yang_dnode_get_parent(args->dnode, "interface"); | ||
| if (pim_interface_num_get(if_dnode) > MAXVIFS) { |
There was a problem hiding this comment.
Off-by-one: allows one more interface than VIF slots support
pim_iface_next_vif_index() always reserves VIF index 0 for pimreg and assigns user interfaces indices 1..MAXVIFS-1 (see pim_iface.c:952-956):
for (i = 1; i < MAXVIFS; i++) { // only MAXVIFS-1 slots
if (pim->iface_vif_index[i] == 0)
return i;
}
return MAXVIFS; // signals "full"pim_if_add_vif() rejects any index >= MAXVIFS. This means at most MAXVIFS-1 user-configured PIM interfaces can be given VIF indices at apply time.
With pim_interface_num_get(if_dnode) > MAXVIFS, the validation passes when count equals exactly MAXVIFS (the MAXVIFS-th user interface). That interface gets through NB_EV_VALIDATE but then fails silently at NB_EV_APPLY because pim_if_add_vif() returns -3 (returning NB_ERR_INCONSISTENCY only if pim_cmd_interface_add propagates the error).
The threshold should be >= MAXVIFS so validation catches this one case earlier:
| if (pim_interface_num_get(if_dnode) > MAXVIFS) { | |
| if (pim_interface_num_get(if_dnode) >= MAXVIFS) { |
The same applies at line 4601 in lib_interface_gmp_address_family_enable_modify.
Prompt To Fix With AI
This is a comment left during a code review.
Path: pimd/pim_nb_config.c
Line: 2264
Comment:
**Off-by-one: allows one more interface than VIF slots support**
`pim_iface_next_vif_index()` always reserves VIF index 0 for `pimreg` and assigns user interfaces indices 1..`MAXVIFS-1` (see `pim_iface.c:952-956`):
```c
for (i = 1; i < MAXVIFS; i++) { // only MAXVIFS-1 slots
if (pim->iface_vif_index[i] == 0)
return i;
}
return MAXVIFS; // signals "full"
```
`pim_if_add_vif()` rejects any index `>= MAXVIFS`. This means at most **`MAXVIFS-1` user-configured PIM interfaces** can be given VIF indices at apply time.
With `pim_interface_num_get(if_dnode) > MAXVIFS`, the validation passes when count equals exactly `MAXVIFS` (the `MAXVIFS`-th user interface). That interface gets through `NB_EV_VALIDATE` but then fails silently at `NB_EV_APPLY` because `pim_if_add_vif()` returns `-3` (returning `NB_ERR_INCONSISTENCY` only if `pim_cmd_interface_add` propagates the error).
The threshold should be `>= MAXVIFS` so validation catches this one case earlier:
```suggestion
if (pim_interface_num_get(if_dnode) >= MAXVIFS) {
```
The same applies at line 4601 in `lib_interface_gmp_address_family_enable_modify`.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
It is off by at least one. I believe there is a pimreg interface created for each vrf instance as well.
I take that back, looks like the available VIF is per-vrf/mroute table so it's just off by one, but still needs to count interfaces per-vrf and not globally.
There was a problem hiding this comment.
Looking at the code, I can see each VRF creates its own pimreg interface (pim_instance.c:202), and each pim_instance has its own iface_vif_index[MAXVIFS] array (pim_instance.c:55-56).
However, the key question is whether the validation scope matches the VIF allocation scope:
- VIF allocation is per-VRF: each
pim_instance(VRF) has its owniface_vif_index[]array - But the new
pim_interface_num_get()counts globally (or at least not VRF-scoped)
So you're correct that the check should account for pimreg. But I need to verify: is the validation counting per-VRF or globally?
Looking at the PR code, pim_interface_num_get() iterates lyd_child(lib_dnode) — this traverses all interfaces under the lib node. If that's global (not VRF-filtered), then:
- With 2 VRFs: validation counts 2 pimreg + all user interfaces globally
- But VIF allocation is per-VRF: each VRF can have up to MAXVIFS interfaces (including its own pimreg)
Could you clarify: does the current pim_interface_num_get() count all interfaces globally, or is it scoped to the VRF of the interface being configured?
If it's global, the check is too strict (multi-VRF setups would hit the limit prematurely). If it's per-VRF but doesn't exclude pimreg, then the threshold should indeed be >= MAXVIFS (not >), since:
- User wants to add their Nth user interface
- Count = N user interfaces + 1 pimreg = N+1 total
- At apply time, pimreg takes slot 0, user interfaces need slots 1..N
- Max user interfaces = MAXVIFS - 1, so count should reject at N+1 >= MAXVIFS, i.e., N >= MAXVIFS-1
|
@nabahr Agreed, this commit is not good. |
For example, on this case of interfaces created by frr, no real one on system at that time:
The
yang_get_list_elements_count()in pim is wrong:The configuration node is added at the end of the link list. Therefore,
this function will traverse from the configuration node, so it
usually/wrongly returns 1.
This commit introduced three changes: