From: Jakub Kicinski kuba@kernel.org
[ Upstream commit c7dc5b5228822d2389e6e441f10169e460bcc67a ]
When an IPv6 address with a finite lifetime (configured with valid_lft and preferred_lft) is manually deleted, the kernel does not clean up the associated prefix route. This results in orphaned routes (marked "proto kernel") remaining in the routing table even after their corresponding address has been deleted.
This is particularly problematic on networks using combination of SLAAC and bridges.
1. Machine comes up and performs RA on eth0. 2. User creates a bridge - does an ip -6 addr flush dev eth0; - adds the eth0 under the bridge. 3. SLAAC happens on br0.
Even tho the address has "moved" to br0 there will still be a route pointing to eth0, but eth0 is not usable for IP any more.
Reviewed-by: David Ahern dsahern@kernel.org Reviewed-by: Ido Schimmel idosch@nvidia.com Link: https://patch.msgid.link/20251113031700.3736285-1-kuba@kernel.org Signed-off-by: Jakub Kicinski kuba@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
# Analysis of Commit: ipv6: clean up routes when manually removing address with a lifetime
## 1. COMMIT MESSAGE ANALYSIS
**Subject:** Fixes route cleanup when IPv6 addresses with finite lifetimes are deleted manually
**Key Problem Described:** - When an IPv6 address configured with `valid_lft` and `preferred_lft` is manually deleted, the kernel fails to clean up the associated prefix route - Results in orphaned routes (marked "proto kernel") remaining in the routing table - Particularly problematic with SLAAC + bridges (a real-world scenario)
**Tags:** - `Reviewed-by: David Ahern` (network subsystem maintainer) - `Reviewed-by: Ido Schimmel` (networking contributor) - `Signed-off-by: Jakub Kicinski` (Linux networking maintainer)
**Notable Missing Tags:** - No `Cc: stable@vger.kernel.org` - No `Fixes:` tag
## 2. CODE CHANGE ANALYSIS
The core fix is extremely minimal - a single condition change in `net/ipv6/addrconf.c`:
**Before:** ```c if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE)) ```
**After:** ```c if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) ```
**Technical Mechanism:** - `IFA_F_PERMANENT` flag is set for addresses WITHOUT a finite lifetime - Addresses with `valid_lft`/`preferred_lft` set do NOT have `IFA_F_PERMANENT` - The old code only cleaned up prefix routes for permanent (infinite lifetime) addresses - Non-permanent addresses (those with lifetimes) would have their routes orphaned on manual deletion - The fix removes the overly-restrictive `IFA_F_PERMANENT` check, ensuring route cleanup for ALL addresses that don't have `IFA_F_NOPREFIXROUTE`
**Root Cause:** Logic error - the condition was too restrictive, failing to clean up routes for addresses with finite lifetimes.
## 3. CLASSIFICATION
- **Bug Fix:** Yes - fixes route leakage/orphaning - **New Feature:** No - corrects existing cleanup behavior - **Security:** No explicit security issue, but orphaned routes can cause routing problems
## 4. SCOPE AND RISK ASSESSMENT
**Lines Changed:** - Core fix: 1 line modified (condition simplification) - Test: ~20 lines added to selftest
**Risk Level: LOW** - The `check_cleanup_prefix_route()` and `cleanup_prefix_route()` functions already exist and are tested - The fix EXTENDS existing cleanup to more cases (non-permanent addresses) - No new code paths introduced, just removes an unnecessary condition - Well-reviewed by multiple networking maintainers
## 5. USER IMPACT
**Affected Users:** - Anyone using IPv6 with finite address lifetimes (SLAAC, DHCPv6) - Users managing bridges with IPv6 addresses - Enterprise/data center environments with complex networking
**Severity:** Medium - Orphaned routes can cause routing confusion and network connectivity issues - The SLAAC + bridge scenario is common in real-world deployments - Routes pointing to unusable interfaces cause operational problems
## 6. STABILITY INDICATORS
**Positive:** - Three experienced networking maintainers involved (Kicinski, Ahern, Schimmel) - Includes selftest (`kci_test_addrlft_route_cleanup`) for regression testing - Simple, surgical change with clear intent
## 7. DEPENDENCY CHECK
- Self-contained fix with no dependencies on other commits - The affected functions (`check_cleanup_prefix_route`, etc.) have existed for a long time - Should apply cleanly to recent stable kernels
## ASSESSMENT SUMMARY
**Pros:** 1. Fixes a real, user-visible bug (orphaned routes) 2. Extremely minimal change (removes one condition) 3. Strong review from key networking maintainers 4. Low regression risk - extends existing behavior to more cases 5. Includes regression test 6. Addresses a practical scenario (SLAAC + bridges)
**Cons/Considerations:** 1. No explicit `Cc: stable@vger.kernel.org` tag - maintainers didn't request backport 2. No `Fixes:` tag - unknown when bug was introduced (likely long- standing) 3. The bug has workarounds (routes eventually expire, or can be manually deleted)
## VERDICT
This commit is a good candidate for stable backporting. It is: - **Obviously correct:** The `IFA_F_PERMANENT` check makes no logical sense for route cleanup - **Fixes a real bug:** Orphaned routes are a tangible problem affecting real users - **Small and contained:** Single condition change in one file - **Low risk:** Extends existing cleanup mechanism to more cases - **Well-tested:** Reviewed by maintainers and includes regression test
The lack of stable tags is notable but not disqualifying. The fix is clearly beneficial and the risk is minimal. Stable tree users dealing with IPv6 address lifetimes and bridges would benefit from this fix.
**YES**
net/ipv6/addrconf.c | 2 +- tools/testing/selftests/net/rtnetlink.sh | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 40e9c336f6c55..b66217d1b2f82 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1324,7 +1324,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) __in6_ifa_put(ifp); }
- if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE)) + if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) action = check_cleanup_prefix_route(ifp, &expires);
list_del_rcu(&ifp->if_list); diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 163a084d525d5..248c2b91fe42b 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -8,6 +8,7 @@ ALL_TESTS=" kci_test_polrouting kci_test_route_get kci_test_addrlft + kci_test_addrlft_route_cleanup kci_test_promote_secondaries kci_test_tc kci_test_gre @@ -323,6 +324,25 @@ kci_test_addrlft() end_test "PASS: preferred_lft addresses have expired" }
+kci_test_addrlft_route_cleanup() +{ + local ret=0 + local test_addr="2001:db8:99::1/64" + local test_prefix="2001:db8:99::/64" + + run_cmd ip -6 addr add $test_addr dev "$devdummy" valid_lft 300 preferred_lft 300 + run_cmd_grep "$test_prefix proto kernel" ip -6 route show dev "$devdummy" + run_cmd ip -6 addr del $test_addr dev "$devdummy" + run_cmd_grep_fail "$test_prefix" ip -6 route show dev "$devdummy" + + if [ $ret -ne 0 ]; then + end_test "FAIL: route not cleaned up when address with valid_lft deleted" + return 1 + fi + + end_test "PASS: route cleaned up when address with valid_lft deleted" +} + kci_test_promote_secondaries() { run_cmd ifconfig "$devdummy"