buglwIP - A Lightweight TCP/IP stack - Bugs: bug #53803, nd6_cleanup_netif should set the...

 
 

You are not allowed to post comments on this tracker with your current authentication level.

bug #53803: nd6_cleanup_netif should set the auto-configured address to invalid

Submitter:  yanhc <yanhc>
Submitted:  Tue 01 May 2018 01:02:08 PM UTC
   
 
Category:  IPv6 Severity:  3 - Normal
Item Group:  Faulty Behaviour Status:  None
Privacy:  Public Assigned to:  None
Open/Closed:  Open Planned Release:  None
lwIP version:  2.0.2

Jump to the original submission

Mon 18 Jun 2018 07:17:45 PM UTC, comment #13: 

Thanks for sharing your test results. I'm with you on the solution from comment #8. I'll have to change the drop down menus to allow a "planned release" of "2.2.0" :-)

Simon Goldschmidt <goldsimon>
Group administrator
Sun 17 Jun 2018 08:53:20 PM UTC, comment #12: 

Alright, I did a little experiment with a VirtualBox network and a MINIX node in IPv6 router configuration (with net.inet6.ip6.forwarding set to '1') and with rtadvd providing router announcements when desired, to test two operating systems on the same virtual network: NetBSD and Linux.

NetBSD 7.1.2 (with net.inet6.ip6.accept_rtadv set to '1'): upon link down, dynamic addresses get the status DETACHED (an extra, BSD-specific IPv6 address state). Then, upon link up, after a short while those DETACHED addresses move to state TENTATIVE and then PREFERRED. That happens regardless of whether router advertisements arrive after the link-up event. In other words, NetBSD will effectively keep using the dynamic addresses from before the link-down event, with no further restriction, even if it is reconnected to another network upon link-up. Indeed, the consequence is that that any TCP connections stay alive as a result, but if the node was reconnected to a different network, NetBSD risks that applications will use the older address as source address, even if there is also a newer address, until its PREFERRED status expires. The same behavior applies to the case that the interface is set down/up administratively.

Linux 4.17.1-1.el7 (from ELRepo, on Centos 7 [1804]): upon link down, dynamic addresses are completely deleted. Then, upon link up, they will be recreated only as a result of router announcements. However, TCP connections are still kept alive during such a window, and (only) once a router announcement restores the previous dynamic address, the TCP connection will resume communication. Again, the same exact behavior is observed upon admin-down/up.

I think the preliminary takeaways from this limited test are that 1) in effect, keeping TCP connections alive across link failures is common and should be a consideration in any solution, and 2) there is very little consistency to be expected between TCP/IP stacks otherwise, and so lwIP can take its own decisions here.

In that light, I do think that my suggestion in comment #8 combines the best of both worlds: it would keep the addresses and thus TCP connections alive, and it would respond to network changes better than NetBSD does right now. An alternative would be to make an exception in the TCP module for auto-configured addresses, as is apparently already the case for IPv4 auto-IP anyway. In that case, dynamic IPv6 addresses can simply be removed as originally suggested, and the resulting behavior will be more like Linux.

David van Moolenbroek <dcvmoole>
Thu 14 Jun 2018 08:40:33 PM UTC, comment #11: 

Agreed on the ARP point, and indeed, I think this issue affects few enough people that taking some time to fix it properly is acceptable.. :) With that said, with a little luck I may be able to do some testing this weekend - either way I'll report back here.

David van Moolenbroek <dcvmoole>
Thu 14 Jun 2018 07:52:26 PM UTC, comment #10: 

In other words, it's probably not worth waiting for 2.1.0 for this to be resolved?

Simon Goldschmidt <goldsimon>
Group administrator
Thu 14 Jun 2018 07:43:16 PM UTC, comment #9: 

OK, so in the case of connecting to a different link, the TCP connection will stay open but it won't have connectivity. That's OK, I guess.

Your comment #8 sounds like the best way to go so far.

Thinking about it, it would probably make sense to call etharp_cleanup_netif() from netif_set_link_down(), too, to ensure ARP entries are removed on link loss.

Simon Goldschmidt <goldsimon>
Group administrator
Thu 14 Jun 2018 07:33:29 PM UTC, comment #8: 

When the link stays up, then the solution for your scenario is simple: the router should announce the prefix with zero lifetimes. That is covered explicitly in RFC 4861 Section 12 in general, although for addresses it is not exactly that simple: such announcements will not cause any existing address to be removed immediately (as per Sec. 5.5.3(e) of RFC 4862) - at most they will be changed from PREFERRED to DEPRECATED state right away. Then, any newly announced prefix may cause the addition of a new address next to that address, and that address will end up with the PREFERRED state. As a result, the old address will remain usable on the host for a while (e.g. for existing TCP connections), while the new address will be preferred for source address selection. I believe it is generally best to have at least enough IPv6 address slots for one preferred dynamic (SLAAC) address and one deprecated one, because such situations are normal and any host system should be able to deal with them.

In fact, we could use a highly similar approach to resolve the link-down issue: upon a link-down event, set the address state to TENTATIVE and set the address's preferred (but NOT its valid) lifetime to zero. The result will be that after link-up, it will go from TENTATIVE to DEPRECATED in the absence of new router announcements for the old prefix. Then, the result will be the same as above: the old address will not be selected as source address if there is also a PREFERRED address that was assigned based on new router announcements instead, and at the same time, currently open TCP connections would continue to use the DEPRECATED address (perhaps fruitlessly, perhaps not, depending on the new situation). Again, the only requirement would be to have at least two dynamic IPv6 address slots available, which is probably even reasonable to recommend in opt.h.

That is just an idea though, and I certainly won't claim that I have thought of everything here.. :) In any case: indeed, any such new logic should be invoked on link-down events, not (just) on changes of the netif's administrative state. I suppose that similar considerations apply to both those cases, and so perhaps nd6_cleanup_netif() should also be called on link-down..

But yes, checking other operating systems would definitely be a good start. I'll see what I can contribute there, but that is going to take some time..

David van Moolenbroek <dcvmoole>
Thu 14 Jun 2018 06:42:56 PM UTC, comment #7: 

Yeah, well, maybe the OP called netif_set_down() when the link was lost? I don't get it either, but it seems like I haven't read the original post thoroughly... :-)

Getting back to your thoughts in comment #4, honestly, I don't know what's best either. The only thing comparable in IPv4 is DHCP, and there the scheme "continue using the adddress but check if it is valid" is used. However, I don't want to reinvent something for lwIP but rather just do it like everybody else does. Surely there must be examples of how e.g. Linux or some BSD do it? Or even Windows?

It seems I still don't know my way around IPv6 enough here, so: I would have thought if the on-link prefix expires, there must be some way to detect an address is not usable any more. For example, how does a node detect if, say, a cable router gets a different prefix from its provider? It surely must stop using the address with the old prefix if it wants to keep connectivity? That would be nearly the same as the link-down situation, only that we control the time when to do that check...

Simon Goldschmidt <goldsimon>
Group administrator
Thu 14 Jun 2018 06:16:45 PM UTC, comment #6: 

Aha, well, this was all about link-down events though, right? How did the proposed patch resolve the described problem to begin with?

David van Moolenbroek <dcvmoole>
Thu 14 Jun 2018 06:13:23 PM UTC, comment #5: 

Ehrm, nd6_cleanup_netif() is called from netif_set_down(), not from netif_set_link_down()...

Simon Goldschmidt <goldsimon>
Group administrator
Thu 14 Jun 2018 05:19:40 PM UTC, comment #4: 

Sure! This is a tricky area though: I was unable to find any information on what exactly should happen in a link-down situation, and my own (MINIX) side of the code has a massive "TODO" there. I don't think I ever checked what other operating systems were doing, either. But I can provide some thoughts - first on the policy, then something about the mechanism.

As for the policy (i.e., is this a good idea at all), I do not think the argument holds that removal of the (on-link) prefix should also imply removal of the address: the argument made sense for the lwIP code back then, because lwIP was conflating on-link prefixes and address auto-configuration at the time. That is part of what my change corrected. These days (and in accordance with the RFC), the presence or absence of an on-link prefix says nothing about the address, and it would definitely be wrong to retire an auto-configured address as soon as the matching on-link prefix expires.

However, there is indeed an argument to be made that link disconnection should remove any information for the previously attached network, because that information can no longer be relied upon. That would then include not only on-link prefixes, but also auto-configured addresses. The effect will likely be that it takes a bit more time for the node to regain connectivity though, because it has to reobtain an IP address even after a very brief link interruption - losing any TCP connections and whatnot as a side effect.

Alternatively, and at the very minimum (so there is definitely something to fix here either way), upon link-down the auto-configured addresses should be moved back from PREFERRED/DEPRECATED to TENTATIVE, because even if the link is reconnected to the same network, another node may have appeared with the same address during the downtime. This is in fact what the MINIX code does, because it is required by dhcpcd. I did not put a lot of thought into that beyond implementing that part, and I don't think I realized that it is in fact lwIP that should (always) put the addresses back to TENTATIVE state in that case.

Then again, that alternative does not resolve the poster's original problem, which basically involves a scenario of reconnecting to another network (i.e., one where the previously auto-configured address is not routable). It is worth pointing out that as per my change, this situation will eventually correct itself, because the address will now eventually time out. However, that may take a long time - much longer than reobtaining an IP address. Increasing the number of addresses per netif (from 3 to 4 in this case) would help the situation, because then the new address can be assigned next to the old one, for as long as the old address is still around. However, I don't think it would stop the old address from getting selected as a source address while it is still around.

I also do not see any way to combine the best of both worlds here, at least without keeping extra state - state that indicates that an address may still be valid but hasn't been confirmed by announcements ever since the last link-up event, or something similar. That gets messy quickly, and is probably overkill.

Adding it all up, I am leaning toward agreeing that removal of the addresses is the right thing to do in this case, but it may have a negative impact in some situations, especially with poor links that drop out every once in a while. I don't know if changing attached networks is a common scenario for the situations in which lwIP is deployed. As always, it would be tempting to turn this into a configurable option and let the user decide.

If address removal is indeed a good idea, that then leaves the mechanism, because the suggested patch no longer works with the current code at all. Instead, the code should basically follow the same logic as the lifetime-based expiry code: for all IPv6 addresses assigned to the netif, if the address is not invalid and not static, set the valid and preferred lifetimes to zero and mark the address state as INVALID.

David van Moolenbroek <dcvmoole>
Thu 14 Jun 2018 10:59:03 AM UTC, comment #3: 
Simon Goldschmidt <goldsimon>
Group administrator
Wed 13 Jun 2018 08:18:04 PM UTC, comment #2: 

The commit that changed that was e0c5e198 from 29.12.2016

Simon Goldschmidt <goldsimon>
Group administrator
Wed 23 May 2018 08:00:29 PM UTC, comment #1: 

This part of the stack has been changed since 2.0.2. struct nd6_prefix_list_entry no longer contains a 'flags' member. As such, your change does not apply.

Could you check if this is still an issue with current git master? Thanks.

Simon Goldschmidt <goldsimon>
Group administrator
Tue 01 May 2018 01:02:08 PM UTC, original submission:  

nd6_cleanup_netif in nd6.c should set the auto-configured address to invalid. nd6_cleanup_netif is called in netif_set_down.
I use my PC to send router advertisement (ra) packet to my board. My test procedure is as follows:
(1)plug the ethernet cable and send ra with prefix A, new address will be generated in slot 2 (slot 0 is link local and slot 1 is manually configured, so slot 2 is for auto configuration);
(2)unplug the ethernet cable;
(3)re-plug the ethernet cable, and send ra with prefix B, no new address will be generated.
I checked the state of the generated address of slot 2 and it is still prefered when the cable is unplugged. So, when I re-plug the cable, even ND receives a new prefix, it will not reconfigure the slot 2.
I think nd6_cleanup_netif should set the auto-configured address to invalid. This is sound, since the prefix is removed and the auto-configured address should also be removed.

I add the following routine (between macro LWIP_IPV6_AUTOCONFIG, same as in nd6_tmr) in nd6_cleanup_netif as follows and everything goes fine.

void
nd6_cleanup_netif(struct netif *netif)
{
  u8_t i;
  s8_t router_index;
  for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
    if (prefix_list[i].netif == netif) {
#if LWIP_IPV6_AUTOCONFIG /* added by yanhc 2018.05.01 */
      /* If any addresses were configured with this prefix, remove them */
      if (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED) {
        s8_t j;
for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
  if ((netif_ip6_addr_state(prefix_list[i].netif, j) != IP6_ADDR_INVALID) &&
      ip6_addr_netcmp(&prefix_list[i].prefix, netif_ip6_addr(prefix_list[i].netif, j))) {
    netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_INVALID);
prefix_list[i].flags = 0;

/* Exit loop. */
            break;
  }
}
  }
#endif /* LWIP_IPV6_AUTOCONFIG */
      prefix_list[i].netif = NULL;
    }
  }

yanhc <yanhc>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by dcvmoole (Posted a comment)
  • -email is unavailable- added by goldsimon
  • -email is unavailable- added by goldsimon (Posted a comment)
  • -email is unavailable- added by yanhc (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

     

    Follow 3 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2018-06-14 goldsimon Planned Release2.1.0 None
    2018-06-14 goldsimon Carbon-Copy- Added -email is unavailable-
    2018-06-13 goldsimon Planned ReleaseNone 2.1.0

    Back to the top

    Powered by Savane 3.13-d3ae.
    Corresponding source code