Commit f650bcd4 authored by David S. Miller's avatar David S. Miller

Merge branch 'Fix-IPv6-peer-route-update'

Hangbin Liu says:

====================
Fix IPv6 peer route update

Currently we have two issues for peer route update on IPv6.
1. When update peer route metric, we only updated the local one.
2. If peer address changed, we didn't remove the old one and add new one.

The first two patches fixed these issues and the third patch add new
tests to cover it.

With the fixes and updated test:
]# ./fib_tests.sh
IPv6 prefix route tests
    TEST: Default metric                                                [ OK ]
    TEST: User specified metric on first device                         [ OK ]
    TEST: User specified metric on second device                        [ OK ]
    TEST: Delete of address on first device                             [ OK ]
    TEST: Modify metric of address                                      [ OK ]
    TEST: Prefix route removed on link down                             [ OK ]
    TEST: Prefix route with metric on link up                           [ OK ]
    TEST: Set metric with peer route on local side                      [ OK ]
    TEST: User specified metric on local address                        [ OK ]
    TEST: Set metric with peer route on peer side                       [ OK ]
    TEST: Modify metric with peer route on local side                   [ OK ]
    TEST: Modify metric with peer route on peer side                    [ OK ]

IPv4 prefix route tests
    TEST: Default metric                                                [ OK ]
    TEST: User specified metric on first device                         [ OK ]
    TEST: User specified metric on second device                        [ OK ]
    TEST: Delete of address on first device                             [ OK ]
    TEST: Modify metric of address                                      [ OK ]
    TEST: Prefix route removed on link down                             [ OK ]
    TEST: Prefix route with metric on link up                           [ OK ]
    TEST: Modify metric of .0/24 address                                [ OK ]
    TEST: Set metric of address with peer route                         [ OK ]
    TEST: Modify metric of address with peer route                      [ OK ]

Tests passed:  22
Tests failed:   0
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a6fbcdda 0d29169a
...@@ -1226,11 +1226,13 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) ...@@ -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) ...@@ -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 */
...@@ -4586,12 +4588,14 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -4586,12 +4588,14 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
} }
static int modify_prefix_route(struct inet6_ifaddr *ifp, static int modify_prefix_route(struct inet6_ifaddr *ifp,
unsigned long expires, u32 flags) unsigned long expires, u32 flags,
bool modify_peer)
{ {
struct fib6_info *f6i; struct fib6_info *f6i;
u32 prio; u32 prio;
f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len, f6i = addrconf_get_prefix_route(modify_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)
return -ENOENT; return -ENOENT;
...@@ -4602,7 +4606,8 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp, ...@@ -4602,7 +4606,8 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp,
ip6_del_rt(dev_net(ifp->idev->dev), f6i); ip6_del_rt(dev_net(ifp->idev->dev), f6i);
/* add new one */ /* add new one */
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, addrconf_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr,
ifp->prefix_len,
ifp->rt_priority, ifp->idev->dev, ifp->rt_priority, ifp->idev->dev,
expires, flags, GFP_KERNEL); expires, flags, GFP_KERNEL);
} else { } else {
...@@ -4624,6 +4629,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4624,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();
...@@ -4655,6 +4661,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4655,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 &&
...@@ -4670,6 +4683,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4670,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);
...@@ -4678,7 +4694,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4678,7 +4694,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
int rc = -ENOENT; int rc = -ENOENT;
if (had_prefixroute) if (had_prefixroute)
rc = modify_prefix_route(ifp, expires, flags); rc = modify_prefix_route(ifp, expires, flags, false);
/* prefix route could have been deleted; if so restore it */ /* prefix route could have been deleted; if so restore it */
if (rc == -ENOENT) { if (rc == -ENOENT) {
...@@ -4686,6 +4702,15 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4686,6 +4702,15 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
ifp->rt_priority, ifp->idev->dev, ifp->rt_priority, ifp->idev->dev,
expires, flags, GFP_KERNEL); expires, flags, GFP_KERNEL);
} }
if (had_prefixroute && !ipv6_addr_any(&ifp->peer_addr))
rc = modify_prefix_route(ifp, expires, flags, true);
if (rc == -ENOENT && !ipv6_addr_any(&ifp->peer_addr)) {
addrconf_prefix_route(&ifp->peer_addr, ifp->prefix_len,
ifp->rt_priority, ifp->idev->dev,
expires, flags, GFP_KERNEL);
}
} else if (had_prefixroute) { } else if (had_prefixroute) {
enum cleanup_prefix_rt_t action; enum cleanup_prefix_rt_t action;
unsigned long rt_expires; unsigned long rt_expires;
...@@ -4696,7 +4721,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg) ...@@ -4696,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);
} }
} }
......
...@@ -1041,6 +1041,27 @@ ipv6_addr_metric_test() ...@@ -1041,6 +1041,27 @@ ipv6_addr_metric_test()
fi fi
log_test $rc 0 "Prefix route with metric on link up" log_test $rc 0 "Prefix route with metric on link up"
# verify peer metric added correctly
set -e
run_cmd "$IP -6 addr flush dev dummy2"
run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
set +e
check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
log_test $? 0 "Set metric with peer route on local side"
log_test $? 0 "User specified metric on local address"
check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
log_test $? 0 "Set metric with peer route on peer side"
set -e
run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
set +e
check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
log_test $? 0 "Modify metric and peer address on local side"
check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
log_test $? 0 "Modify metric and peer address on peer side"
$IP li del dummy1 $IP li del dummy1
$IP li del dummy2 $IP li del dummy2
cleanup cleanup
...@@ -1457,13 +1478,20 @@ ipv4_addr_metric_test() ...@@ -1457,13 +1478,20 @@ ipv4_addr_metric_test()
run_cmd "$IP addr flush dev dummy2" run_cmd "$IP addr flush dev dummy2"
run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260" run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 261"
rc=$? rc=$?
if [ $rc -eq 0 ]; then if [ $rc -eq 0 ]; then
check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261" check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
rc=$?
fi
log_test $rc 0 "Set metric of address with peer route"
run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
rc=$?
if [ $rc -eq 0 ]; then
check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
rc=$? rc=$?
fi fi
log_test $rc 0 "Modify metric of address with peer route" log_test $rc 0 "Modify metric and peer address for peer route"
$IP li del dummy1 $IP li del dummy1
$IP li del dummy2 $IP li del dummy2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment