diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2015-03-23 18:36:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-23 22:12:09 -0400 |
commit | 5f40ef77adb237954d615a76621df1b80a329b31 (patch) | |
tree | 29c69d4f196d3d7f8fa9e33b7d54ea8c48ba76e1 /net/ipv6 | |
parent | 8e8e676d0b3c7f074c719c7c05b20296b9b0b0b1 (diff) |
ipv6: do retries on stable privacy addresses
If a DAD conflict is detected, we want to retry privacy stable address
generation up to idgen_retries (= 3) times with a delay of idgen_delay
(= 1 second). Add the logic to addrconf_dad_failure.
By design, we don't clean up dad failed permanent addresses.
Cc: Erik Kline <ek@google.com>
Cc: Fernando Gont <fgont@si6networks.com>
Cc: Lorenzo Colitti <lorenzo@google.com>
Cc: YOSHIFUJI Hideaki/吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1cc5320e510f..9b51fdb42ba9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1710,6 +1710,7 @@ static int addrconf_dad_end(struct inet6_ifaddr *ifp) | |||
1710 | 1710 | ||
1711 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1711 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
1712 | { | 1712 | { |
1713 | struct in6_addr addr; | ||
1713 | struct inet6_dev *idev = ifp->idev; | 1714 | struct inet6_dev *idev = ifp->idev; |
1714 | 1715 | ||
1715 | if (addrconf_dad_end(ifp)) { | 1716 | if (addrconf_dad_end(ifp)) { |
@@ -1720,9 +1721,59 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1720 | net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", | 1721 | net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", |
1721 | ifp->idev->dev->name, &ifp->addr); | 1722 | ifp->idev->dev->name, &ifp->addr); |
1722 | 1723 | ||
1723 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | 1724 | spin_lock_bh(&ifp->lock); |
1724 | struct in6_addr addr; | 1725 | |
1726 | if (ifp->flags & IFA_F_STABLE_PRIVACY) { | ||
1727 | int scope = ifp->scope; | ||
1728 | u32 flags = ifp->flags; | ||
1729 | struct in6_addr new_addr; | ||
1730 | struct inet6_ifaddr *ifp2; | ||
1731 | u32 valid_lft, preferred_lft; | ||
1732 | int pfxlen = ifp->prefix_len; | ||
1733 | const unsigned int idgen_retries = 3; | ||
1734 | const unsigned int idgen_delay = 1 * HZ; | ||
1735 | int retries = ifp->stable_privacy_retry + 1; | ||
1736 | |||
1737 | if (retries > idgen_retries) { | ||
1738 | net_info_ratelimited("%s: privacy stable address generation failed because of DAD conflicts!\n", | ||
1739 | ifp->idev->dev->name); | ||
1740 | goto errdad; | ||
1741 | } | ||
1742 | |||
1743 | new_addr = ifp->addr; | ||
1744 | if (ipv6_generate_stable_address(&new_addr, retries, | ||
1745 | idev)) | ||
1746 | goto errdad; | ||
1725 | 1747 | ||
1748 | valid_lft = ifp->valid_lft; | ||
1749 | preferred_lft = ifp->prefered_lft; | ||
1750 | |||
1751 | spin_unlock_bh(&ifp->lock); | ||
1752 | |||
1753 | if (idev->cnf.max_addresses && | ||
1754 | ipv6_count_addresses(idev) >= | ||
1755 | idev->cnf.max_addresses) | ||
1756 | goto lock_errdad; | ||
1757 | |||
1758 | net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", | ||
1759 | ifp->idev->dev->name); | ||
1760 | |||
1761 | ifp2 = ipv6_add_addr(idev, &new_addr, NULL, pfxlen, | ||
1762 | scope, flags, valid_lft, | ||
1763 | preferred_lft); | ||
1764 | if (IS_ERR(ifp2)) | ||
1765 | goto lock_errdad; | ||
1766 | |||
1767 | spin_lock_bh(&ifp2->lock); | ||
1768 | ifp2->stable_privacy_retry = retries; | ||
1769 | ifp2->state = INET6_IFADDR_STATE_PREDAD; | ||
1770 | spin_unlock_bh(&ifp2->lock); | ||
1771 | |||
1772 | addrconf_mod_dad_work(ifp2, idgen_delay); | ||
1773 | in6_ifa_put(ifp2); | ||
1774 | lock_errdad: | ||
1775 | spin_lock_bh(&ifp->lock); | ||
1776 | } else if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | ||
1726 | addr.s6_addr32[0] = htonl(0xfe800000); | 1777 | addr.s6_addr32[0] = htonl(0xfe800000); |
1727 | addr.s6_addr32[1] = 0; | 1778 | addr.s6_addr32[1] = 0; |
1728 | 1779 | ||
@@ -1736,7 +1787,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1736 | } | 1787 | } |
1737 | } | 1788 | } |
1738 | 1789 | ||
1739 | spin_lock_bh(&ifp->lock); | 1790 | errdad: |
1740 | /* transition from _POSTDAD to _ERRDAD */ | 1791 | /* transition from _POSTDAD to _ERRDAD */ |
1741 | ifp->state = INET6_IFADDR_STATE_ERRDAD; | 1792 | ifp->state = INET6_IFADDR_STATE_ERRDAD; |
1742 | spin_unlock_bh(&ifp->lock); | 1793 | spin_unlock_bh(&ifp->lock); |