net/ipv6: remove the old peer route if change it to a new one

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>
This commit is contained in:
Hangbin Liu 2020-03-03 14:37:35 +08:00 committed by David S. Miller
parent 617940123e
commit d0098e4c6b

View File

@ -1226,11 +1226,13 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
} }
static void 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; 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); ifp->idev->dev, 0, RTF_DEFAULT, true);
if (f6i) { if (f6i) {
if (del_rt) if (del_rt)
@ -1293,7 +1295,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
if (action != CLEANUP_PREFIX_RT_NOP) { if (action != CLEANUP_PREFIX_RT_NOP) {
cleanup_prefix_route(ifp, expires, cleanup_prefix_route(ifp, expires,
action == CLEANUP_PREFIX_RT_DEL); action == CLEANUP_PREFIX_RT_DEL, false);
} }
/* clean up prefsrc entries */ /* clean up prefsrc entries */
@ -4627,6 +4629,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
unsigned long timeout; unsigned long timeout;
bool was_managetempaddr; bool was_managetempaddr;
bool had_prefixroute; bool had_prefixroute;
bool new_peer = false;
ASSERT_RTNL(); ASSERT_RTNL();
@ -4658,6 +4661,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
cfg->preferred_lft = timeout; 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); spin_lock_bh(&ifp->lock);
was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
had_prefixroute = ifp->flags & IFA_F_PERMANENT && had_prefixroute = ifp->flags & IFA_F_PERMANENT &&
@ -4673,6 +4683,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority) if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority)
ifp->rt_priority = cfg->rt_priority; ifp->rt_priority = cfg->rt_priority;
if (new_peer)
ifp->peer_addr = *cfg->peer_pfx;
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
if (!(ifp->flags&IFA_F_TENTATIVE)) if (!(ifp->flags&IFA_F_TENTATIVE))
ipv6_ifa_notify(0, ifp); ipv6_ifa_notify(0, ifp);
@ -4708,7 +4721,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
if (action != CLEANUP_PREFIX_RT_NOP) { if (action != CLEANUP_PREFIX_RT_NOP) {
cleanup_prefix_route(ifp, rt_expires, cleanup_prefix_route(ifp, rt_expires,
action == CLEANUP_PREFIX_RT_DEL); action == CLEANUP_PREFIX_RT_DEL, false);
} }
} }