| From 89569abd7c539ee39ebe8f91b04b8f3ae696797b Mon Sep 17 00:00:00 2001 |
| From: Hangbin Liu <liuhangbin@gmail.com> |
| Date: Tue, 3 Mar 2020 14:37:35 +0800 |
| Subject: [PATCH] net/ipv6: remove the old peer route if change it to a new one |
| |
| commit d0098e4c6b83e502cc1cd96d67ca86bc79a6c559 upstream. |
| |
| When we modify the peer route and changed it to a new one, we should |
| remove the old route first. Before the fix: |
| |
| + ip addr add dev dummy1 2001:db8::1 peer 2001:db8::2 |
| + ip -6 route show dev dummy1 |
| 2001:db8::1 proto kernel metric 256 pref medium |
| 2001:db8::2 proto kernel metric 256 pref medium |
| + ip addr change dev dummy1 2001:db8::1 peer 2001:db8::3 |
| + ip -6 route show dev dummy1 |
| 2001:db8::1 proto kernel metric 256 pref medium |
| 2001:db8::2 proto kernel metric 256 pref medium |
| |
| After the fix: |
| + ip addr change dev dummy1 2001:db8::1 peer 2001:db8::3 |
| + ip -6 route show dev dummy1 |
| 2001:db8::1 proto kernel metric 256 pref medium |
| 2001:db8::3 proto kernel metric 256 pref medium |
| |
| This patch depend on the previous patch "net/ipv6: need update peer route |
| when modify metric" to update new peer route after delete old one. |
| |
| Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> |
| Reviewed-by: David Ahern <dsahern@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c |
| index 94a4ea47f366..758dff881c79 100644 |
| --- a/net/ipv6/addrconf.c |
| +++ b/net/ipv6/addrconf.c |
| @@ -1226,11 +1226,13 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) |
| } |
| |
| static void |
| -cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) |
| +cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, |
| + bool del_rt, bool del_peer) |
| { |
| struct fib6_info *f6i; |
| |
| - f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len, |
| + f6i = addrconf_get_prefix_route(del_peer ? &ifp->peer_addr : &ifp->addr, |
| + ifp->prefix_len, |
| ifp->idev->dev, 0, RTF_DEFAULT, true); |
| if (f6i) { |
| if (del_rt) |
| @@ -1293,7 +1295,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) |
| |
| if (action != CLEANUP_PREFIX_RT_NOP) { |
| cleanup_prefix_route(ifp, expires, |
| - action == CLEANUP_PREFIX_RT_DEL); |
| + action == CLEANUP_PREFIX_RT_DEL, false); |
| } |
| |
| /* clean up prefsrc entries */ |
| @@ -4629,6 +4631,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) |
| unsigned long timeout; |
| bool was_managetempaddr; |
| bool had_prefixroute; |
| + bool new_peer = false; |
| |
| ASSERT_RTNL(); |
| |
| @@ -4660,6 +4663,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) |
| cfg->preferred_lft = timeout; |
| } |
| |
| + if (cfg->peer_pfx && |
| + memcmp(&ifp->peer_addr, cfg->peer_pfx, sizeof(struct in6_addr))) { |
| + if (!ipv6_addr_any(&ifp->peer_addr)) |
| + cleanup_prefix_route(ifp, expires, true, true); |
| + new_peer = true; |
| + } |
| + |
| spin_lock_bh(&ifp->lock); |
| was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; |
| had_prefixroute = ifp->flags & IFA_F_PERMANENT && |
| @@ -4675,6 +4685,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) |
| if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority) |
| ifp->rt_priority = cfg->rt_priority; |
| |
| + if (new_peer) |
| + ifp->peer_addr = *cfg->peer_pfx; |
| + |
| spin_unlock_bh(&ifp->lock); |
| if (!(ifp->flags&IFA_F_TENTATIVE)) |
| ipv6_ifa_notify(0, ifp); |
| @@ -4710,7 +4723,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) |
| |
| if (action != CLEANUP_PREFIX_RT_NOP) { |
| cleanup_prefix_route(ifp, rt_expires, |
| - action == CLEANUP_PREFIX_RT_DEL); |
| + action == CLEANUP_PREFIX_RT_DEL, false); |
| } |
| } |
| |
| -- |
| 2.7.4 |
| |