Zebra local addresses same network 2#22086
Conversation
Greptile SummaryThis PR fixes zebra's handling of multiple connected addresses on the same network by tracking the kernel's
Confidence Score: 3/5Two real defects in interface.c need fixing before merging: an always-true debug guard that floods logs, and a missing UNSET_FLAG branch that prevents the promote-secondaries flag from ever being cleared. The always-true zebra/interface.c — the promote_secondaries sync block at line ~2250 needs both the always-true guard and the missing UNSET_FLAG path corrected before this is safe to merge. Important Files Changed
Sequence DiagramsequenceDiagram
participant K as Linux Kernel
participant NL as if_netlink.c
participant DP as zebra_dplane
participant IC as interface.c
participant ZIF as zebra_if (flags)
participant CD as connected.c
K->>NL: RTM_NEWLINK (IFLA_AF_SPEC with IFLA_INET_CONF)
NL->>NL: netlink_interface_promote_secondaries_update()
NL->>DP: dplane_ctx_set_ifp_promote_secondaries(ctx, val)
DP->>IC: zebra_if_dplane_ifp_handling(ctx)
IC->>DP: dplane_ctx_intf_is_promote_secondaries(ctx)
IC->>ZIF: SET/UNSET ZIF_FLAG_IPV4_PROMOTE_SECONDARIES
K->>NL: RTM_DELADDR (primary address deleted)
NL->>CD: connected_down(ifp, ifc)
CD->>ZIF: CHECK_FLAG(ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)
alt promote_secondaries enabled AND secondary exists
CD->>CD: UNSET ZEBRA_IFA_SECONDARY on surviving addr
CD->>CD: "remove_prefix = false (keep connected route)"
CD->>CD: remove local /32 for deleted address
else no surviving address / promotion disabled
CD->>CD: "remove_prefix = true"
CD->>CD: rib_delete connected + local routes
end
Prompt To Fix All With AIFix the following 4 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 4
zebra/interface.c:2252-2253
**Debug guard always evaluates to true**
`if (1 || IS_ZEBRA_DEBUG_KERNEL)` short-circuits unconditionally, so this `zlog_debug` fires on every interface link-change event regardless of debug settings. This will flood the system log on any deployment that receives frequent RTM_NEWLINK notifications.
### Issue 2 of 4
zebra/interface.c:2250-2257
**`UNSET_FLAG` path missing for promote_secondaries**
When `promote_secondaries` is `false` and `ZIF_FLAG_IPV4_PROMOTE_SECONDARIES` is currently set, the condition is true (they differ) but the code unconditionally calls `SET_FLAG`, re-setting the flag instead of clearing it. Once the flag is set on an interface it can never be cleared, and zebra will continue treating that interface as having `promote_secondaries` enabled even after the sysctl is disabled — causing incorrect connected-route behavior.
```suggestion
if (promote_secondaries !=
!!CHECK_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Intf %s(%u) has promote secondaries turned %s",
name, ifp->ifindex,
promote_secondaries ? "on" : "off");
if (promote_secondaries)
SET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES);
else
UNSET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES);
}
```
### Issue 3 of 4
zebra/connected.c:238-240
**Unused variable `zif` in `connected_up()`**
`zif` is declared but never assigned or referenced in `connected_up()`. It is likely a leftover from a copy-paste from `connected_down()`. While benign, it adds noise and may confuse future readers.
```suggestion
bool install_local = true;
bool install_prefix = true;
```
### Issue 4 of 4
zebra/if_netlink.c:812
**Magic number for inner netlink attribute type**
`j->rta_type == 1` refers to `IFLA_INET_CONF` (value 1 in the kernel's `ifla_inet_attr` enum). Defining a named constant alongside the `IPV4_DEVCONF_*` enum already introduced in this PR would make the intent self-documenting.
Reviews (1): Last reviewed commit: "zebra: upon deletion, promote secondarie..." | Re-trigger Greptile |
| if (1 || IS_ZEBRA_DEBUG_KERNEL) | ||
| zlog_debug("Intf %s(%u) has promote secondaries turned %s", |
There was a problem hiding this comment.
Debug guard always evaluates to true
if (1 || IS_ZEBRA_DEBUG_KERNEL) short-circuits unconditionally, so this zlog_debug fires on every interface link-change event regardless of debug settings. This will flood the system log on any deployment that receives frequent RTM_NEWLINK notifications.
Prompt To Fix With AI
This is a comment left during a code review.
Path: zebra/interface.c
Line: 2252-2253
Comment:
**Debug guard always evaluates to true**
`if (1 || IS_ZEBRA_DEBUG_KERNEL)` short-circuits unconditionally, so this `zlog_debug` fires on every interface link-change event regardless of debug settings. This will flood the system log on any deployment that receives frequent RTM_NEWLINK notifications.
How can I resolve this? If you propose a fix, please make it concise.| if (promote_secondaries != | ||
| !!CHECK_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)) { | ||
| if (1 || IS_ZEBRA_DEBUG_KERNEL) | ||
| zlog_debug("Intf %s(%u) has promote secondaries turned %s", | ||
| name, ifp->ifindex, | ||
| promote_secondaries ? "on" : "off"); | ||
| SET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES); | ||
| } |
There was a problem hiding this comment.
UNSET_FLAG path missing for promote_secondaries
When promote_secondaries is false and ZIF_FLAG_IPV4_PROMOTE_SECONDARIES is currently set, the condition is true (they differ) but the code unconditionally calls SET_FLAG, re-setting the flag instead of clearing it. Once the flag is set on an interface it can never be cleared, and zebra will continue treating that interface as having promote_secondaries enabled even after the sysctl is disabled — causing incorrect connected-route behavior.
| if (promote_secondaries != | |
| !!CHECK_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)) { | |
| if (1 || IS_ZEBRA_DEBUG_KERNEL) | |
| zlog_debug("Intf %s(%u) has promote secondaries turned %s", | |
| name, ifp->ifindex, | |
| promote_secondaries ? "on" : "off"); | |
| SET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES); | |
| } | |
| if (promote_secondaries != | |
| !!CHECK_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)) { | |
| if (IS_ZEBRA_DEBUG_KERNEL) | |
| zlog_debug("Intf %s(%u) has promote secondaries turned %s", | |
| name, ifp->ifindex, | |
| promote_secondaries ? "on" : "off"); | |
| if (promote_secondaries) | |
| SET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES); | |
| else | |
| UNSET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES); | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: zebra/interface.c
Line: 2250-2257
Comment:
**`UNSET_FLAG` path missing for promote_secondaries**
When `promote_secondaries` is `false` and `ZIF_FLAG_IPV4_PROMOTE_SECONDARIES` is currently set, the condition is true (they differ) but the code unconditionally calls `SET_FLAG`, re-setting the flag instead of clearing it. Once the flag is set on an interface it can never be cleared, and zebra will continue treating that interface as having `promote_secondaries` enabled even after the sysctl is disabled — causing incorrect connected-route behavior.
```suggestion
if (promote_secondaries !=
!!CHECK_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Intf %s(%u) has promote secondaries turned %s",
name, ifp->ifindex,
promote_secondaries ? "on" : "off");
if (promote_secondaries)
SET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES);
else
UNSET_FLAG(zif->flags, ZIF_FLAG_IPV4_PROMOTE_SECONDARIES);
}
```
How can I resolve this? If you propose a fix, please make it concise.| bool install_local = true; | ||
| bool install_prefix = true; | ||
| struct zebra_if *zif; |
There was a problem hiding this comment.
Unused variable
zif in connected_up()
zif is declared but never assigned or referenced in connected_up(). It is likely a leftover from a copy-paste from connected_down(). While benign, it adds noise and may confuse future readers.
| bool install_local = true; | |
| bool install_prefix = true; | |
| struct zebra_if *zif; | |
| bool install_local = true; | |
| bool install_prefix = true; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: zebra/connected.c
Line: 238-240
Comment:
**Unused variable `zif` in `connected_up()`**
`zif` is declared but never assigned or referenced in `connected_up()`. It is likely a leftover from a copy-paste from `connected_down()`. While benign, it adds noise and may confuse future readers.
```suggestion
bool install_local = true;
bool install_prefix = true;
```
How can I resolve this? If you propose a fix, please make it concise.| continue; | ||
| for (j = RTA_DATA(i), rem2 = RTA_PAYLOAD(i); RTA_OK(j, rem2); | ||
| j = RTA_NEXT(j, rem2)) { | ||
| if (j->rta_type == 1) { |
There was a problem hiding this comment.
Magic number for inner netlink attribute type
j->rta_type == 1 refers to IFLA_INET_CONF (value 1 in the kernel's ifla_inet_attr enum). Defining a named constant alongside the IPV4_DEVCONF_* enum already introduced in this PR would make the intent self-documenting.
Prompt To Fix With AI
This is a comment left during a code review.
Path: zebra/if_netlink.c
Line: 812
Comment:
**Magic number for inner netlink attribute type**
`j->rta_type == 1` refers to `IFLA_INET_CONF` (value 1 in the kernel's `ifla_inet_attr` enum). Defining a named constant alongside the `IPV4_DEVCONF_*` enum already introduced in this PR would make the intent self-documenting.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
eaf5ed0 to
33941a4
Compare
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
On a setup with 4.4.4.4/24 address present, adding 4.4.4.40/24 address results in unsyncing local entry 4.4.4.40/32. The output on vtysh differs from the output on shell. > # vtysh -c "show ip route" | grep 4.4.4. > C>* 4.4.4.0/24 is directly connected, loo1, weight 1, 00:00:08 > L>* 4.4.4.4/32 is directly connected, loo1, weight 1, 00:00:08 > # ip route show table 255 | grep 4.4.4. > local 4.4.4.4 dev loo1 proto kernel scope host src 4.4.4.4 > local 4.4.4.40 dev loo1 proto kernel scope host src 4.4.4.4 > broadcast 4.4.4.255 dev loo1 proto kernel scope link src 4.4.4.4 Consequently, using the secondary address for routing purposes may be mishandled by ZEBRA. Fix this by keeping all the local entries. Fixes: d4aa24b ("*: Introduce Local Host Routes to FRR") Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
When deleting a primary address on an interface with promoted secondaries turned on, the move of the address from secondary to primary is shared to other daemons by an address delete/add notification. > # ip a a 192.168.0.1/24 dev loo2 > 2026/05/28 10:21:54 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo2(5), addr 192.168.0.1/24 > 2026/05/28 10:21:54 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 192.168.0.1/24 on loo2 vrf default(0) > # ip a a 192.168.0.2/24 dev loo2 > 2026/05/28 10:21:57 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo2(5), addr 192.168.0.2/24 > 2026/05/28 10:21:57 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 192.168.0.2/24 on loo2 vrf default(0) > # ip a a 192.168.0.3/24 dev loo2 > 2026/05/28 10:21:59 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo2(5), addr 192.168.0.3/24 > 2026/05/28 10:21:59 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 192.168.0.3/24 on loo2 vrf default(0) > # ip a a 192.168.0.4/24 dev loo2 > 2026/05/28 10:22:04 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo2(5), addr 192.168.0.4/24 > 2026/05/28 10:22:04 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 192.168.0.4/24 on loo2 vrf default(0) > # ip a d 192.168.0.3/24 dev loo2 > 2026/05/28 10:22:15 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_DEL: ifindex loo2(5), addr 192.168.0.3/24 > 2026/05/28 10:22:15 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 192.168.0.3/24 on loo2 vrf default(0) > # ip a d 192.168.0.1/24 dev loo2 > 2026/05/28 10:22:27 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_DEL: ifindex loo2(5), addr 192.168.0.1/24 > 2026/05/28 10:22:27 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 192.168.0.1/24 on loo2 vrf default(0) > 2026/05/28 10:22:27 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 192.168.0.2/24 on loo2 vrf default(0) > 2026/05/28 10:22:27 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 192.168.0.2/24 on loo2 vrf default(0) > 2026/05/28 10:22:27 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo2(5), addr 192.168.0.2/24 > When such interface has promoted secondaries flag turned off, the addresses deletion are being notified and comply with expected behavior. Note the order of events: address deletion notify the secondary first. > # ip a a 172.31.0.1/24 dev loo1 > 2026/05/28 10:20:48 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo1(4), addr 172.31.0.1/24 > 2026/05/28 10:20:48 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 172.31.0.1/24 on loo1 vrf default(0) > # ip a a 172.31.0.2/24 dev loo1 > 2026/05/28 10:20:50 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo1(4), addr 172.31.0.2/24 > 2026/05/28 10:20:50 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 172.31.0.2/24 on loo1 vrf default(0) > # ip a a 172.31.0.3/24 dev loo1 > 2026/05/28 10:20:54 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_ADD: ifindex loo1(4), addr 172.31.0.3/24 > 2026/05/28 10:20:54 ZEBRA: [NBGDS-5ZDQ9] MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD 172.31.0.3/24 on loo1 vrf default(0) > # ip a d 172.31.0.3/24 dev loo1 > 2026/05/28 10:21:13 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_DEL: ifindex loo1(4), addr 172.31.0.3/24 > 2026/05/28 10:21:13 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 172.31.0.3/24 on loo1 vrf default(0) > # ip a d 172.31.0.1/24 dev loo1 > 2026/05/28 10:21:20 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_DEL: ifindex loo1(4), addr 172.31.0.2/24 > 2026/05/28 10:21:20 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 172.31.0.2/24 on loo1 vrf default(0) > 2026/05/28 10:21:20 ZEBRA: [MZPZA-W042K] zebra_if_addr_update_ctx: INTF_ADDR_DEL: ifindex loo1(4), addr 172.31.0.1/24 > 2026/05/28 10:21:20 ZEBRA: [XN0NB-2NSYE] MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE 172.31.0.1/24 on loo1 vrf default(0) This behavior is correct, and does not require any further changes with the kernel. Modify the comment, remove the XXX. Fixes: 02b4805 ("zebra: don't change connected state from zebra/interface.c") Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
33941a4 to
38d259e
Compare
Add two test cases to test_zebra_multiple_connected.py exercising secondary IPv4 address local routes RIB addition handling at runtime on an interface that is already UP: - test_zebra_secondary_address_local_route: with promote_secondaries=1, verify both the primary and secondary local /32 routes are present after add, and that the deleted primary's /32 is removed (while the surviving secondary's /32 stays) after the kernel promotes it. - test_zebra_secondary_address_no_promote: set promote_secondaries=0. After the primary is deleted the kernel removes the secondary too, and zebra's RIB must end up with neither /32. These exercised the two zebra connected.c fixes from the preceding commits. Signed-off-by: Nelson Lako Tangala <nelson.lako_tangala@6wind.com>
No description provided.