| From 71500732f5fb13df306a61800ff1690481c30f68 Mon Sep 17 00:00:00 2001 |
| From: Benjamin Poirier <bpoirier@cumulusnetworks.com> |
| Date: Wed, 12 Feb 2020 10:41:06 +0900 |
| Subject: [PATCH] ipv6: Fix route replacement with dev-only route |
| |
| commit e404b8c7cfb31654c9024d497cec58a501501692 upstream. |
| |
| After commit 27596472473a ("ipv6: fix ECMP route replacement") it is no |
| longer possible to replace an ECMP-able route by a non ECMP-able route. |
| For example, |
| ip route add 2001:db8::1/128 via fe80::1 dev dummy0 |
| ip route replace 2001:db8::1/128 dev dummy0 |
| does not work as expected. |
| |
| Tweak the replacement logic so that point 3 in the log of the above commit |
| becomes: |
| 3. If the new route is not ECMP-able, and no matching non-ECMP-able route |
| exists, replace matching ECMP-able route (if any) or add the new route. |
| |
| We can now summarize the entire replace semantics to: |
| When doing a replace, prefer replacing a matching route of the same |
| "ECMP-able-ness" as the replace argument. If there is no such candidate, |
| fallback to the first route found. |
| |
| Fixes: 27596472473a ("ipv6: fix ECMP route replacement") |
| Signed-off-by: Benjamin Poirier <bpoirier@cumulusnetworks.com> |
| Reviewed-by: Michal Kubecek <mkubecek@suse.cz> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c |
| index 455f1292e479..457956468618 100644 |
| --- a/net/ipv6/ip6_fib.c |
| +++ b/net/ipv6/ip6_fib.c |
| @@ -1004,8 +1004,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, |
| found++; |
| break; |
| } |
| - if (rt_can_ecmp) |
| - fallback_ins = fallback_ins ?: ins; |
| + fallback_ins = fallback_ins ?: ins; |
| goto next_iter; |
| } |
| |
| @@ -1048,7 +1047,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, |
| } |
| |
| if (fallback_ins && !found) { |
| - /* No ECMP-able route found, replace first non-ECMP one */ |
| + /* No matching route with same ecmp-able-ness found, replace |
| + * first matching route |
| + */ |
| ins = fallback_ins; |
| iter = rcu_dereference_protected(*ins, |
| lockdep_is_held(&rt->fib6_table->tb6_lock)); |
| diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh |
| index 19f04cfac48a..6944212e3712 100755 |
| --- a/tools/testing/selftests/net/fib_tests.sh |
| +++ b/tools/testing/selftests/net/fib_tests.sh |
| @@ -884,6 +884,12 @@ ipv6_rt_replace_mpath() |
| check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024" |
| log_test $? 0 "Multipath with single path via multipath attribute" |
| |
| + # multipath with dev-only |
| + add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" |
| + run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1" |
| + check_route6 "2001:db8:104::/64 dev veth1 metric 1024" |
| + log_test $? 0 "Multipath with dev-only" |
| + |
| # route replace fails - invalid nexthop 1 |
| add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2" |
| run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3" |
| -- |
| 2.7.4 |
| |