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

[IPV6] ADDRCONF: Optimistic Duplicate Address Detection (RFC 4429) Support.

Nominally an autoconfigured IPv6 address is added to an interface in the
Tentative state (as per RFC 2462). Addresses in this state remain in this
state while the Duplicate Address Detection process operates on them to
determine their uniqueness on the network. During this period, these
tentative addresses may not be used for communication, increasing the time
before a node may be able to communicate on a network. Using Optimistic
Duplicate Address Detection, autoconfigured addresses may be used
immediately for communication on the network, as long as certain rules are
followed to avoid conflicts with other nodes during the Duplicate Address
Detection process.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Neil Horman and committed by
David S. Miller
95c385b4 502b0935

+208 -42
+1
include/linux/if_addr.h
··· 39 39 #define IFA_F_TEMPORARY IFA_F_SECONDARY 40 40 41 41 #define IFA_F_NODAD 0x02 42 + #define IFA_F_OPTIMISTIC 0x04 42 43 #define IFA_F_HOMEADDRESS 0x10 43 44 #define IFA_F_DEPRECATED 0x20 44 45 #define IFA_F_TENTATIVE 0x40
+4
include/linux/ipv6.h
··· 178 178 #endif 179 179 __s32 proxy_ndp; 180 180 __s32 accept_source_route; 181 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 182 + __s32 optimistic_dad; 183 + #endif 181 184 void *sysctl; 182 185 }; 183 186 ··· 211 208 DEVCONF_PROXY_NDP, 212 209 __DEVCONF_OPTIMISTIC_DAD, 213 210 DEVCONF_ACCEPT_SOURCE_ROUTE, 211 + DEVCONF_OPTIMISTIC_DAD, 214 212 DEVCONF_MAX 215 213 }; 216 214
+3 -1
include/net/addrconf.h
··· 73 73 extern int ipv6_dev_get_saddr(struct net_device *dev, 74 74 struct in6_addr *daddr, 75 75 struct in6_addr *saddr); 76 - extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); 76 + extern int ipv6_get_lladdr(struct net_device *dev, 77 + struct in6_addr *addr, 78 + unsigned char banned_flags); 77 79 extern int ipv6_rcv_saddr_equal(const struct sock *sk, 78 80 const struct sock *sk2); 79 81 extern void addrconf_join_solict(struct net_device *dev,
+10
net/ipv6/Kconfig
··· 57 57 58 58 If unsure, say N. 59 59 60 + config IPV6_OPTIMISTIC_DAD 61 + bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)" 62 + depends on IPV6 && EXPERIMENTAL 63 + ---help--- 64 + This is experimental support for optimistic Duplicate 65 + Address Detection. It allows for autoconfigured addresses 66 + to be used more quickly. 67 + 68 + If unsure, say N. 69 + 60 70 config INET6_AH 61 71 tristate "IPv6: AH transformation" 62 72 depends on IPV6
+91 -15
net/ipv6/addrconf.c
··· 530 530 531 531 ifa->rt = rt; 532 532 533 + /* 534 + * part one of RFC 4429, section 3.3 535 + * We should not configure an address as 536 + * optimistic if we do not yet know the link 537 + * layer address of our nexhop router 538 + */ 539 + 540 + if (rt->rt6i_nexthop == NULL) 541 + ifa->flags &= ~IFA_F_OPTIMISTIC; 542 + 533 543 ifa->idev = idev; 534 544 in6_dev_hold(idev); 535 545 /* For caller */ ··· 716 706 int tmp_plen; 717 707 int ret = 0; 718 708 int max_addresses; 709 + u32 addr_flags; 719 710 720 711 write_lock(&idev->lock); 721 712 if (ift) { ··· 774 763 spin_unlock_bh(&ifp->lock); 775 764 776 765 write_unlock(&idev->lock); 766 + 767 + addr_flags = IFA_F_TEMPORARY; 768 + /* set in addrconf_prefix_rcv() */ 769 + if (ifp->flags & IFA_F_OPTIMISTIC) 770 + addr_flags |= IFA_F_OPTIMISTIC; 771 + 777 772 ift = !max_addresses || 778 773 ipv6_count_addresses(idev) < max_addresses ? 779 774 ipv6_add_addr(idev, &addr, tmp_plen, 780 - ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; 775 + ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, 776 + addr_flags) : NULL; 781 777 if (!ift || IS_ERR(ift)) { 782 778 in6_ifa_put(ifp); 783 779 in6_dev_put(idev); ··· 916 898 * - Tentative Address (RFC2462 section 5.4) 917 899 * - A tentative address is not considered 918 900 * "assigned to an interface" in the traditional 919 - * sense. 901 + * sense, unless it is also flagged as optimistic. 920 902 * - Candidate Source Address (section 4) 921 903 * - In any case, anycast addresses, multicast 922 904 * addresses, and the unspecified address MUST 923 905 * NOT be included in a candidate set. 924 906 */ 925 - if (ifa->flags & IFA_F_TENTATIVE) 907 + if ((ifa->flags & IFA_F_TENTATIVE) && 908 + (!(ifa->flags & IFA_F_OPTIMISTIC))) 926 909 continue; 927 910 if (unlikely(score.addr_type == IPV6_ADDR_ANY || 928 911 score.addr_type & IPV6_ADDR_MULTICAST)) { ··· 982 963 } 983 964 } 984 965 985 - /* Rule 3: Avoid deprecated address */ 966 + /* Rule 3: Avoid deprecated and optimistic addresses */ 986 967 if (hiscore.rule < 3) { 987 968 if (ipv6_saddr_preferred(hiscore.addr_type) || 988 - !(ifa_result->flags & IFA_F_DEPRECATED)) 969 + (((ifa_result->flags & 970 + (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) 989 971 hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; 990 972 hiscore.rule++; 991 973 } 992 974 if (ipv6_saddr_preferred(score.addr_type) || 993 - !(ifa->flags & IFA_F_DEPRECATED)) { 975 + (((ifa_result->flags & 976 + (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) { 994 977 score.attrs |= IPV6_SADDR_SCORE_PREFERRED; 995 978 if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { 996 979 score.rule = 3; ··· 1132 1111 1133 1112 EXPORT_SYMBOL(ipv6_get_saddr); 1134 1113 1135 - int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) 1114 + int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, 1115 + unsigned char banned_flags) 1136 1116 { 1137 1117 struct inet6_dev *idev; 1138 1118 int err = -EADDRNOTAVAIL; ··· 1144 1122 1145 1123 read_lock_bh(&idev->lock); 1146 1124 for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { 1147 - if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { 1125 + if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { 1148 1126 ipv6_addr_copy(addr, &ifp->addr); 1149 1127 err = 0; 1150 1128 break; ··· 1696 1674 1697 1675 if (ifp == NULL && valid_lft) { 1698 1676 int max_addresses = in6_dev->cnf.max_addresses; 1677 + u32 addr_flags = 0; 1678 + 1679 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 1680 + if (in6_dev->cnf.optimistic_dad && 1681 + !ipv6_devconf.forwarding) 1682 + addr_flags = IFA_F_OPTIMISTIC; 1683 + #endif 1699 1684 1700 1685 /* Do not allow to create too much of autoconfigured 1701 1686 * addresses; this would be too easy way to crash kernel. ··· 1710 1681 if (!max_addresses || 1711 1682 ipv6_count_addresses(in6_dev) < max_addresses) 1712 1683 ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, 1713 - addr_type&IPV6_ADDR_SCOPE_MASK, 0); 1684 + addr_type&IPV6_ADDR_SCOPE_MASK, 1685 + addr_flags); 1714 1686 1715 1687 if (!ifp || IS_ERR(ifp)) { 1716 1688 in6_dev_put(in6_dev); ··· 1919 1889 1920 1890 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 1921 1891 jiffies_to_clock_t(valid_lft * HZ), flags); 1892 + /* 1893 + * Note that section 3.1 of RFC 4429 indicates 1894 + * that the Optimistic flag should not be set for 1895 + * manually configured addresses 1896 + */ 1922 1897 addrconf_dad_start(ifp, 0); 1923 1898 in6_ifa_put(ifp); 1924 1899 addrconf_verify(0); ··· 2100 2065 static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) 2101 2066 { 2102 2067 struct inet6_ifaddr * ifp; 2068 + u32 addr_flags = IFA_F_PERMANENT; 2103 2069 2104 - ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); 2070 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 2071 + if (idev->cnf.optimistic_dad && 2072 + !ipv6_devconf.forwarding) 2073 + addr_flags |= IFA_F_OPTIMISTIC; 2074 + #endif 2075 + 2076 + 2077 + ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); 2105 2078 if (!IS_ERR(ifp)) { 2106 2079 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); 2107 2080 addrconf_dad_start(ifp, 0); ··· 2177 2134 { 2178 2135 struct in6_addr lladdr; 2179 2136 2180 - if (!ipv6_get_lladdr(link_dev, &lladdr)) { 2137 + if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) { 2181 2138 addrconf_add_linklocal(idev, &lladdr); 2182 2139 return 0; 2183 2140 } ··· 2522 2479 unsigned long rand_num; 2523 2480 struct inet6_dev *idev = ifp->idev; 2524 2481 2525 - rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); 2482 + if (ifp->flags & IFA_F_OPTIMISTIC) 2483 + rand_num = 0; 2484 + else 2485 + rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); 2486 + 2526 2487 ifp->probes = idev->cnf.dad_transmits; 2527 2488 addrconf_mod_timer(ifp, AC_DAD, rand_num); 2528 2489 } ··· 2548 2501 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || 2549 2502 !(ifp->flags&IFA_F_TENTATIVE) || 2550 2503 ifp->flags & IFA_F_NODAD) { 2551 - ifp->flags &= ~IFA_F_TENTATIVE; 2504 + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); 2552 2505 spin_unlock_bh(&ifp->lock); 2553 2506 read_unlock_bh(&idev->lock); 2554 2507 ··· 2568 2521 addrconf_dad_stop(ifp); 2569 2522 return; 2570 2523 } 2524 + 2525 + /* 2526 + * Optimistic nodes can start receiving 2527 + * Frames right away 2528 + */ 2529 + if(ifp->flags & IFA_F_OPTIMISTIC) 2530 + ip6_ins_rt(ifp->rt); 2531 + 2571 2532 addrconf_dad_kick(ifp); 2572 2533 spin_unlock_bh(&ifp->lock); 2573 2534 out: ··· 2600 2545 * DAD was successful 2601 2546 */ 2602 2547 2603 - ifp->flags &= ~IFA_F_TENTATIVE; 2548 + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); 2604 2549 spin_unlock_bh(&ifp->lock); 2605 2550 read_unlock_bh(&idev->lock); 2606 2551 ··· 3419 3364 #endif 3420 3365 array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; 3421 3366 array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; 3367 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 3368 + array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; 3369 + #endif 3422 3370 } 3423 3371 3424 3372 static inline size_t inet6_if_nlmsg_size(void) ··· 3636 3578 3637 3579 switch (event) { 3638 3580 case RTM_NEWADDR: 3639 - ip6_ins_rt(ifp->rt); 3581 + /* 3582 + * If the address was optimistic 3583 + * we inserted the route at the start of 3584 + * our DAD process, so we don't need 3585 + * to do it again 3586 + */ 3587 + if (!(ifp->rt->rt6i_node)) 3588 + ip6_ins_rt(ifp->rt); 3640 3589 if (ifp->idev->cnf.forwarding) 3641 3590 addrconf_join_anycast(ifp); 3642 3591 break; ··· 3964 3899 .mode = 0644, 3965 3900 .proc_handler = &proc_dointvec, 3966 3901 }, 3902 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 3903 + { 3904 + .ctl_name = CTL_UNNUMBERED, 3905 + .procname = "optimistic_dad", 3906 + .data = &ipv6_devconf.optimistic_dad, 3907 + .maxlen = sizeof(int), 3908 + .mode = 0644, 3909 + .proc_handler = &proc_dointvec, 3910 + 3911 + }, 3912 + #endif 3967 3913 { 3968 3914 .ctl_name = 0, /* sentinel */ 3969 3915 }
+35
net/ipv6/ip6_output.c
··· 863 863 goto out_err_release; 864 864 } 865 865 866 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 867 + /* 868 + * Here if the dst entry we've looked up 869 + * has a neighbour entry that is in the INCOMPLETE 870 + * state and the src address from the flow is 871 + * marked as OPTIMISTIC, we release the found 872 + * dst entry and replace it instead with the 873 + * dst entry of the nexthop router 874 + */ 875 + if (!((*dst)->neighbour->nud_state & NUD_VALID)) { 876 + struct inet6_ifaddr *ifp; 877 + struct flowi fl_gw; 878 + int redirect; 879 + 880 + ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1); 881 + 882 + redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); 883 + if (ifp) 884 + in6_ifa_put(ifp); 885 + 886 + if (redirect) { 887 + /* 888 + * We need to get the dst entry for the 889 + * default router instead 890 + */ 891 + dst_release(*dst); 892 + memcpy(&fl_gw, fl, sizeof(struct flowi)); 893 + memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); 894 + *dst = ip6_route_output(sk, &fl_gw); 895 + if ((err = (*dst)->error)) 896 + goto out_err_release; 897 + } 898 + } 899 + #endif 900 + 866 901 return 0; 867 902 868 903 out_err_release:
+2 -2
net/ipv6/mcast.c
··· 1411 1411 1412 1412 skb_reserve(skb, LL_RESERVED_SPACE(dev)); 1413 1413 1414 - if (ipv6_get_lladdr(dev, &addr_buf)) { 1414 + if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { 1415 1415 /* <draft-ietf-magma-mld-source-05.txt>: 1416 1416 * use unspecified address as the source address 1417 1417 * when a valid link-local address is not available. ··· 1791 1791 1792 1792 skb_reserve(skb, LL_RESERVED_SPACE(dev)); 1793 1793 1794 - if (ipv6_get_lladdr(dev, &addr_buf)) { 1794 + if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { 1795 1795 /* <draft-ietf-magma-mld-source-05.txt>: 1796 1796 * use unspecified address as the source address 1797 1797 * when a valid link-local address is not available.
+62 -24
net/ipv6/ndisc.c
··· 449 449 ifp = ipv6_get_ifaddr(solicited_addr, dev, 1); 450 450 if (ifp) { 451 451 src_addr = solicited_addr; 452 + if (ifp->flags & IFA_F_OPTIMISTIC) 453 + override = 0; 452 454 in6_ifa_put(ifp); 453 455 } else { 454 456 if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) ··· 546 544 int send_llinfo; 547 545 548 546 if (saddr == NULL) { 549 - if (ipv6_get_lladdr(dev, &addr_buf)) 547 + if (ipv6_get_lladdr(dev, &addr_buf, 548 + (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) 550 549 return; 551 550 saddr = &addr_buf; 552 551 } ··· 627 624 struct sk_buff *skb; 628 625 struct icmp6hdr *hdr; 629 626 __u8 * opt; 627 + struct inet6_ifaddr *ifp; 628 + int send_sllao = dev->addr_len; 630 629 int len; 631 630 int err; 632 631 632 + 633 + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD 634 + /* 635 + * According to section 2.2 of RFC 4429, we must not 636 + * send router solicitations with a sllao from 637 + * optimistic addresses, but we may send the solicitation 638 + * if we don't include the sllao. So here we check 639 + * if our address is optimistic, and if so, we 640 + * supress the inclusion of the sllao. 641 + */ 642 + if (send_sllao) { 643 + ifp = ipv6_get_ifaddr(saddr, dev, 1); 644 + if (ifp) { 645 + if (ifp->flags & IFA_F_OPTIMISTIC) { 646 + send_sllao=0; 647 + in6_ifa_put(ifp); 648 + } 649 + } else { 650 + send_sllao = 0; 651 + } 652 + } 653 + #endif 633 654 ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, 634 655 dev->ifindex); 635 656 ··· 666 639 return; 667 640 668 641 len = sizeof(struct icmp6hdr); 669 - if (dev->addr_len) 642 + if (send_sllao) 670 643 len += ndisc_opt_addr_space(dev); 671 644 672 645 skb = sock_alloc_send_skb(sk, ··· 693 666 694 667 opt = (u8*) (hdr + 1); 695 668 696 - if (dev->addr_len) 669 + if (send_sllao) 697 670 ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, 698 671 dev->addr_len, dev->type); 699 672 ··· 825 798 inc = ipv6_addr_is_multicast(daddr); 826 799 827 800 if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { 828 - if (ifp->flags & IFA_F_TENTATIVE) { 829 - /* Address is tentative. If the source 830 - is unspecified address, it is someone 831 - does DAD, otherwise we ignore solicitations 832 - until DAD timer expires. 833 - */ 834 - if (!dad) 835 - goto out; 836 - if (dev->type == ARPHRD_IEEE802_TR) { 837 - unsigned char *sadr = skb->mac.raw; 838 - if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && 839 - sadr[9] == dev->dev_addr[1] && 840 - sadr[10] == dev->dev_addr[2] && 841 - sadr[11] == dev->dev_addr[3] && 842 - sadr[12] == dev->dev_addr[4] && 843 - sadr[13] == dev->dev_addr[5]) { 844 - /* looped-back to us */ 845 - goto out; 801 + 802 + if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { 803 + if (dad) { 804 + if (dev->type == ARPHRD_IEEE802_TR) { 805 + unsigned char *sadr = skb->mac.raw; 806 + if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && 807 + sadr[9] == dev->dev_addr[1] && 808 + sadr[10] == dev->dev_addr[2] && 809 + sadr[11] == dev->dev_addr[3] && 810 + sadr[12] == dev->dev_addr[4] && 811 + sadr[13] == dev->dev_addr[5]) { 812 + /* looped-back to us */ 813 + goto out; 814 + } 846 815 } 816 + 817 + /* 818 + * We are colliding with another node 819 + * who is doing DAD 820 + * so fail our DAD process 821 + */ 822 + addrconf_dad_failure(ifp); 823 + goto out; 824 + } else { 825 + /* 826 + * This is not a dad solicitation. 827 + * If we are an optimistic node, 828 + * we should respond. 829 + * Otherwise, we should ignore it. 830 + */ 831 + if (!(ifp->flags & IFA_F_OPTIMISTIC)) 832 + goto out; 847 833 } 848 - addrconf_dad_failure(ifp); 849 - return; 850 834 } 851 835 852 836 idev = ifp->idev; ··· 1446 1408 1447 1409 dev = skb->dev; 1448 1410 1449 - if (ipv6_get_lladdr(dev, &saddr_buf)) { 1411 + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { 1450 1412 ND_PRINTK2(KERN_WARNING 1451 1413 "ICMPv6 Redirect: no link-local address on %s\n", 1452 1414 dev->name);