ip6: pad RDNSS and DNSSL lifetimes to a minimum lifetime value (rh #60055)
authorPavel Šimerda <psimerda@redhat.com>
Wed, 30 May 2012 13:02:51 +0000 (15:02 +0200)
committerPavel Šimerda <psimerda@redhat.com>
Wed, 30 May 2012 17:07:14 +0000 (19:07 +0200)
RFC 6106 says, section 5.1 says:

  In order to provide fixed hosts
  with stable DNS service and allow mobile hosts to
  prefer local RDNSSes to remote RDNSSes, the value of
  Lifetime SHOULD be bounded as
  MaxRtrAdvInterval <= Lifetime <= 2*MaxRtrAdvInterval

I have reported and repeatedly confirmed that values in this interval
trigger frequent RDNSS expiration on unreliable links such as 802.11
wifi. Wireless links *do* have packet loss and actually have a *much*
worse multicast packet loss than unicast. And regular router
advertisements are sent as multicast packets (in multicast frames).

In case of RDNSS expiration, NetworkManager tears down the whole
connection. That of course affects IPv4 networking as well as IPv6.
In a typical wireless network with radvd serving RDNSS it leads to
dropping network connection every ~10 minutes.

This commit improves the previous hack in 0b8ee13 by enforcing a minimum
lifetime of two hours (7200 seconds), which is four times the maximum
allowed value for MaxRtrAdvInterval (see below).

RFC 4861 Neighbor Discovery for IP version 6 (IPv6):

  MaxRtrAdvInterval

  The maximum time allowed between sending
  unsolicited multicast Router Advertisements from
  the interface, in seconds.  MUST be no less than 4
  seconds and no greater than 1800 seconds.

This solution is not recommended by any RFC (and is in fact against
RFC 6106) but it's the easiest hack to fix the problem until IETF
takes action.

My original posting to IETF can be found here:

http://www.ietf.org/mail-archive/web/ipv6/current/msg15816.html

src/ip6-manager/nm-ip6-manager.c

index 5889ca5..8f05ddc 100644 (file)
@@ -748,7 +748,9 @@ process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
         */
        server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
        if (server.expires > 0)
-               server.expires += now + 10;
+               if (server.expires < 7200)
+                       server.expires = 7200;
+               server.expires += now;
 
        for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
                char buf[INET6_ADDRSTRLEN + 1];
@@ -879,7 +881,9 @@ process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
         */
        domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
        if (domain.expires > 0)
-               domain.expires += now + 10;
+               if (domain.expires < 7200)
+                       domain.expires = 7200;
+               domain.expires += now;
 
        while (opt_len) {
                const char *domain_str;