aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2015-03-23 18:36:04 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-23 22:12:09 -0400
commit5f40ef77adb237954d615a76621df1b80a329b31 (patch)
tree29c69d4f196d3d7f8fa9e33b7d54ea8c48ba76e1 /net/ipv6
parent8e8e676d0b3c7f074c719c7c05b20296b9b0b0b1 (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.c57
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
1711void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1711void 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);
1774lock_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); 1790errdad:
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);