Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: David S. Miller <davem@davemloft.net>

+64 -11
+33 -8
net/ipv6/addrconf.c
··· 1226 1226 } 1227 1227 1228 1228 static void 1229 - cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) 1229 + cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, 1230 + bool del_rt, bool del_peer) 1230 1231 { 1231 1232 struct fib6_info *f6i; 1232 1233 1233 - f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len, 1234 + f6i = addrconf_get_prefix_route(del_peer ? &ifp->peer_addr : &ifp->addr, 1235 + ifp->prefix_len, 1234 1236 ifp->idev->dev, 0, RTF_DEFAULT, true); 1235 1237 if (f6i) { 1236 1238 if (del_rt) ··· 1295 1293 1296 1294 if (action != CLEANUP_PREFIX_RT_NOP) { 1297 1295 cleanup_prefix_route(ifp, expires, 1298 - action == CLEANUP_PREFIX_RT_DEL); 1296 + action == CLEANUP_PREFIX_RT_DEL, false); 1299 1297 } 1300 1298 1301 1299 /* clean up prefsrc entries */ ··· 4588 4586 } 4589 4587 4590 4588 static int modify_prefix_route(struct inet6_ifaddr *ifp, 4591 - unsigned long expires, u32 flags) 4589 + unsigned long expires, u32 flags, 4590 + bool modify_peer) 4592 4591 { 4593 4592 struct fib6_info *f6i; 4594 4593 u32 prio; 4595 4594 4596 - f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len, 4595 + f6i = addrconf_get_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr, 4596 + ifp->prefix_len, 4597 4597 ifp->idev->dev, 0, RTF_DEFAULT, true); 4598 4598 if (!f6i) 4599 4599 return -ENOENT; ··· 4606 4602 ip6_del_rt(dev_net(ifp->idev->dev), f6i); 4607 4603 4608 4604 /* add new one */ 4609 - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, 4605 + addrconf_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr, 4606 + ifp->prefix_len, 4610 4607 ifp->rt_priority, ifp->idev->dev, 4611 4608 expires, flags, GFP_KERNEL); 4612 4609 } else { ··· 4629 4624 unsigned long timeout; 4630 4625 bool was_managetempaddr; 4631 4626 bool had_prefixroute; 4627 + bool new_peer = false; 4632 4628 4633 4629 ASSERT_RTNL(); 4634 4630 ··· 4661 4655 cfg->preferred_lft = timeout; 4662 4656 } 4663 4657 4658 + if (cfg->peer_pfx && 4659 + memcmp(&ifp->peer_addr, cfg->peer_pfx, sizeof(struct in6_addr))) { 4660 + if (!ipv6_addr_any(&ifp->peer_addr)) 4661 + cleanup_prefix_route(ifp, expires, true, true); 4662 + new_peer = true; 4663 + } 4664 + 4664 4665 spin_lock_bh(&ifp->lock); 4665 4666 was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; 4666 4667 had_prefixroute = ifp->flags & IFA_F_PERMANENT && ··· 4683 4670 if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority) 4684 4671 ifp->rt_priority = cfg->rt_priority; 4685 4672 4673 + if (new_peer) 4674 + ifp->peer_addr = *cfg->peer_pfx; 4675 + 4686 4676 spin_unlock_bh(&ifp->lock); 4687 4677 if (!(ifp->flags&IFA_F_TENTATIVE)) 4688 4678 ipv6_ifa_notify(0, ifp); ··· 4694 4678 int rc = -ENOENT; 4695 4679 4696 4680 if (had_prefixroute) 4697 - rc = modify_prefix_route(ifp, expires, flags); 4681 + rc = modify_prefix_route(ifp, expires, flags, false); 4698 4682 4699 4683 /* prefix route could have been deleted; if so restore it */ 4700 4684 if (rc == -ENOENT) { 4701 4685 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, 4686 + ifp->rt_priority, ifp->idev->dev, 4687 + expires, flags, GFP_KERNEL); 4688 + } 4689 + 4690 + if (had_prefixroute && !ipv6_addr_any(&ifp->peer_addr)) 4691 + rc = modify_prefix_route(ifp, expires, flags, true); 4692 + 4693 + if (rc == -ENOENT && !ipv6_addr_any(&ifp->peer_addr)) { 4694 + addrconf_prefix_route(&ifp->peer_addr, ifp->prefix_len, 4702 4695 ifp->rt_priority, ifp->idev->dev, 4703 4696 expires, flags, GFP_KERNEL); 4704 4697 } ··· 4721 4696 4722 4697 if (action != CLEANUP_PREFIX_RT_NOP) { 4723 4698 cleanup_prefix_route(ifp, rt_expires, 4724 - action == CLEANUP_PREFIX_RT_DEL); 4699 + action == CLEANUP_PREFIX_RT_DEL, false); 4725 4700 } 4726 4701 } 4727 4702
+31 -3
tools/testing/selftests/net/fib_tests.sh
··· 1041 1041 fi 1042 1042 log_test $rc 0 "Prefix route with metric on link up" 1043 1043 1044 + # verify peer metric added correctly 1045 + set -e 1046 + run_cmd "$IP -6 addr flush dev dummy2" 1047 + run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260" 1048 + set +e 1049 + 1050 + check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260" 1051 + log_test $? 0 "Set metric with peer route on local side" 1052 + log_test $? 0 "User specified metric on local address" 1053 + check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260" 1054 + log_test $? 0 "Set metric with peer route on peer side" 1055 + 1056 + set -e 1057 + run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261" 1058 + set +e 1059 + 1060 + check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261" 1061 + log_test $? 0 "Modify metric and peer address on local side" 1062 + check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261" 1063 + log_test $? 0 "Modify metric and peer address on peer side" 1064 + 1044 1065 $IP li del dummy1 1045 1066 $IP li del dummy2 1046 1067 cleanup ··· 1478 1457 1479 1458 run_cmd "$IP addr flush dev dummy2" 1480 1459 run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260" 1481 - run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 261" 1482 1460 rc=$? 1483 1461 if [ $rc -eq 0 ]; then 1484 - check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261" 1462 + check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260" 1485 1463 rc=$? 1486 1464 fi 1487 - log_test $rc 0 "Modify metric of address with peer route" 1465 + log_test $rc 0 "Set metric of address with peer route" 1466 + 1467 + run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261" 1468 + rc=$? 1469 + if [ $rc -eq 0 ]; then 1470 + check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261" 1471 + rc=$? 1472 + fi 1473 + log_test $rc 0 "Modify metric and peer address for peer route" 1488 1474 1489 1475 $IP li del dummy1 1490 1476 $IP li del dummy2