tasklwIP - A Lightweight TCP/IP stack - Tasks: task #13106, Add IPv6 scopes


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

task #13106: Add IPv6 scopes

Submitted by:  Ivan Delamer <idelamer>
Submitted on:  Tue 25 Feb 2014 10:45:42 PM UTC  
Category:  IPv6 Should Start On:  Tue 25 Feb 2014 07:00:00 AM UTC
Should be Finished on:  Wed 25 Feb 2015 07:00:00 AM UTC Priority:  5 - Normal
Status:  Done Privacy:  Public
Percent Complete:  100% Assigned to:  None
Open/Closed:  Closed Planned Release:  None
Effort:  0.00

( Jump to the original submission)

Wed 15 Feb 2017 08:53:42 PM UTC, comment #32: 

I can't make up anything either. Let's just keep it as it is, there are bad names somewhere else too ;-)

--> closed as done.

Simon Goldschmidt <goldsimon>
Project Administrator
Fri 10 Feb 2017 01:01:06 PM UTC, comment #31: 

> Any preferences?

I'm not too happy with my previous suggestions and I can't think of anything better either. So, no :)

David van Moolenbroek <dcvmoole>
Fri 10 Feb 2017 12:04:14 PM UTC, comment #30: 

Right, the _packed macros... we should find a better name for that and ip6_addr_p_t now that this type is actually different to ip6_addr_t (before it was OK because the only difference was really packing/unaligned access).

Any preferences?

Simon Goldschmidt <goldsimon>
Project Administrator
Fri 10 Feb 2017 11:35:56 AM UTC, comment #29: 

Thank you, Dirk! I guess I am more used to a "you break it, you fix it" environment, so I think it's great when others fix my issues, even if indeed there may be little choice with lwIP's myriad of configuration options.

Simon, ah yes, that does look better for icmp6. As for the rest, unless you'd still like to rename the _packed macros, I'd say we're done here..

David van Moolenbroek <dcvmoole>
Thu 09 Feb 2017 08:26:23 PM UTC, comment #28: 

And I agree to all your other explanations :-)

Given that, is there anything left here (I've set it to 90% some days ago) or are we done?

Simon Goldschmidt <goldsimon>
Project Administrator
Thu 09 Feb 2017 08:20:04 PM UTC, comment #27: 

David, I've just pushed a change to icmp6.c which I think cleans it up a bit...

Simon Goldschmidt <goldsimon>
Project Administrator
Thu 09 Feb 2017 06:03:13 PM UTC, comment #26: 

You did not create a mess. The quality of your patches is very good.

The problem is that lwIP suffers from too many #ifdefs in the code. Thats why Simon created task #14097...

Dirk Ziegelmeier <dziegel>
Project Administrator
Tue 07 Feb 2017 10:31:05 PM UTC, comment #25: 

Cool! Thank you Joel and Dirk for cleaning up some of the mess I created.. :)

David van Moolenbroek <dcvmoole>
Tue 07 Feb 2017 04:47:37 PM UTC, comment #24: 

Pushed fix for building sockets on MSVC.  In addition, I can confirm the following configurations work with sockets (with MSVC)

#define LWIP_IPV6_SCOPES           0


#define LWIP_IPV6                  0

Joel Cunningham <jcunningham>
Project Member
Sat 04 Feb 2017 03:15:21 PM UTC, comment #23: 

Dirk, I'm afraid your fix for Axel Lin's reported issue is not the full fix, because this wasn't just a compilation warning - I actually messed it up in such a way that the resulting behavior was wrong. The attached patch 0001, against master, resolves the bug.


> icmp6 looks a bit strange, could we change icmp6_send_response to not rely on "NULL" but instead create sub-functions handling NULL or the old style?

Something like attached patch 0002..? I'm hesitant to make two completely separate versions of the send-response code, because there is a bit too much shared code between the two..

> the diff of ip6_route() confused me. Due to lack of time, for now I hope without scope support, the behaviour doesn't change. I'll try to come back on that when I find the time...

That is indeed the intention. The old algorithm was "if dest is link-local, find the interface that owns src" and that is what the new algorithm should reduce to without scopes support, too.

There are two new additions even that case though. The first is a test for multicast destinations, which was previously an exception in the UDP code. With scopes support disabled, that is not really an improvement but not really a bad thing either. The second is the rule "if src is link-local, even if dest is not, also find the interface that owns src". From what I've seen, the previous code largely ignored the (rare but real) possibility that a link-local source address would be combined with a global (or ULA etc) destination address, so that addition should be a small improvement.

> having 'packed' in the copy_from/to_packed macros seems a bit strange. I know where the 'packed' comes from (because the packed typedefs are used in protocol structs), but we might need a better (self-explaining) name here (although I can't come up with one right now ;)

Hmm, I guess the most logical alternative (even if strictly not necessarily always correct) would be some suffix that indicates the address is in a packet header, so perhaps _from/_to_header or _from/_to_packet or so? If we can settle on a name I'd be happy to make a patch. Either way this should be done ASAP though, in particular before the lwip-contrib code is repaired..

> tcp_connect: when scopes are disabled, calling ip_route is of no use

In hindsight I should have made a separate patch out of that entire change. My considerations were the following, though:

1) my addition is in the else-clause of an if/else block that tests whether the PCB was bound to an address; the else-clause is for the case that the TCP PCB is indeed bound before connecting, which should be relatively rare in practice and so this should not be the common path;
2) the entire if/else block is directly preceded by a comment saying "check if we have a route to the remote host", suggesting that the route lookup in the if-clause is not done strictly for the purpose of picking a source address;
3) in fact, not having the route lookup in the else-clause creates behavioral disparity between the two cases: since the return value of tcp_output() is not checked later, the behavior of tcp_connect() with an unreachable destination would depend on whether the PCB was bound or not: if not bound, it would fail immediately, while if bound, it would eventually time out;
4) with the previous 0002-tcp-eliminate.. patch, even if IPv6 or scopes support is disabled, the route lookup is useless only if TCP_CALCULATE_EFF_SEND_MSS is also disabled, even though that setting is enabled in opt.h by default.

In other words, this extra route lookup will only be useless for people who a) have IPv6 or scopes support disabled, b) have effective-send-MSS support explicitly disabled, c) bind their TCP sockets before connecting them, and d) do not care about how tcp_connect() behaves in the light of unreachable destinations. For everyone else, the new situation should be no worse and possibly better than before.

It is of course possible to do lazy lookups instead, but it will not make the code prettier. What do you think?

> There's no IPADDR6_INIT() taking a zone, would we need this?

Doubtful, because that is a static initializer while an implementation should not rely on netif->num having a specific value at compile time..

> Oh, and it seemed like the CUSTOM define was used in '#if' although undefined...

That should not be the case: if scopes support is enabled, it is defined to 0 if not previously defined; if scopes support is disabled, it is always defined to 0.

(file #39660, file #39661)

David van Moolenbroek <dcvmoole>
Sat 04 Feb 2017 01:03:53 AM UTC, comment #22: 

Thank you for merging the patches, Simon! Great feedback too; please allow me to get back to you on that as soon as I've had some sleep.

For now just to make sure: Joel, that is indeed the part of the patch that I was not able to compile or test myself, and clearly it shows (ouch) - please feel free to do whatever it takes to get that part to work properly and unbreak the build. Your patch looks good to me.

David van Moolenbroek <dcvmoole>
Fri 03 Feb 2017 10:32:12 PM UTC, comment #21: 

I'm seeing the following builds errors on MSVC 2013

1>e:\projects\lwip\src\api\netdb.c(379): error C2039: 'zone' : is not a member of 'ip_addr'
1>          e:\projects\lwip\src\include\lwip\ip_addr.h(69) : see declaration of 'ip_addr'
1>e:\projects\lwip\src\api\sockets.c(323): error C2220: warning treated as error - no 'object' file generated
1>e:\projects\lwip\src\api\sockets.c(323): warning C4242: '=' : conversion from 'const u32_t' to 'u8_t', possible loss of data

The following changes fixed it for me, I can push if this is correct:

$ git diff src/api/netdb.c
diff --git a/src/api/netdb.c b/src/api/netdb.c
index e2353d8..6cf7469 100644
--- a/src/api/netdb.c
+++ b/src/api/netdb.c
@@ -376,7 +376,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
     sa6->sin6_family = AF_INET6;
     sa6->sin6_len = sizeof(struct sockaddr_in6);
     sa6->sin6_port = lwip_htons((u16_t)port_nr);
-    sa6->sin6_scope_id = ip6_addr_zone(&addr);
+    sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
     ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
   } else {

$ git diff src/api/sockets.c
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 9368e5b..2e2810e 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -100,7 +100,7 @@
#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
     inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
     if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
-      ip6_addr_set_zone(ip_2_ip6(ipaddr), (sin6)->sin6_scope_id); \
+      ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)(sin6)->sin6_scope_id); \
     } \
     (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
#endif /* LWIP_IPV6 */

Joel Cunningham <jcunningham>
Project Member
Fri 03 Feb 2017 10:11:10 PM UTC, comment #20: 

Oh, and it seemed like the CUSTOM define was used in '#if' although undefined...

Simon Goldschmidt <goldsimon>
Project Administrator
Fri 03 Feb 2017 09:47:16 PM UTC, comment #19: 

David, I've just pushed your patches. Great work, thanks!

However, I've still got some remarks/questions we should work on:
- icmp6 looks a bit strange, could we change icmp6_send_response to not rely on "NULL" but instead create sub-functions handling NULL or the old style?
- the diff of ip6_route() confused me. Due to lack of time, for now I hope without scope support, the behaviour doesn't change. I'll try to come back on that when I find the time...
- having 'packed' in the copy_from/to_packed macros seems a bit strange. I know where the 'packed' comes from (because the packed typedefs are used in protocol structs), but we might need a better (self-explaining) name here (although I can't come up with one right now ;)
- tcp_connect: when scopes are disabled, calling ip_route is of no use
- There's no IPADDR6_INIT() taking a zone, would we need this?

Sorry for just listing it here, I can't check all that right now an just wanted to write this down somewhere... :-)

Again, thanks for all the work.

Oh, and it's funny to have the first header with copyright on "The MINIX 3 Project" :-)

Simon Goldschmidt <goldsimon>
Project Administrator
Tue 31 Jan 2017 02:12:48 PM UTC, comment #18: 

:) no problem at all..

David van Moolenbroek <dcvmoole>
Mon 30 Jan 2017 08:04:41 PM UTC, comment #17: 

David, thanks again for your effort on this (and on lwIP in general!). Sorry I haven't found the time to look at your patches yet (I've been a bit busy at home lately). From reading your post, everything sounds fine though...

Simon Goldschmidt <goldsimon>
Project Administrator
Fri 27 Jan 2017 05:53:29 PM UTC, comment #16: 

Alright, here is my patch for implementing support for IPv6 scopes. It is fairly big, but I hope that the commit message and code comments explain well enough what's going on. As such I'd like to ask you to look at the patch for a detailed description, so that I can limit this post to the design decisions I took based on the discussion here (and a bit about testing).

Regarding comment #1 and others: as it turns out, adding a separate zone field is an incredible lot easier and cleaner, so as long as the added bit of memory is not an issue, this is by far the better option. Therefore, that is what this patch does. The most significant advantage is that there are essentially no issues with backward compatibility this way, as long as applications either use standard lwIP functionality or otherwise at least zero out the ip6_addr_t structures they generate. Overall, as far as I can tell, embedding would have required a lot more, quite a bit more complex, and as such harder to maintain, code in many places.

Regarding comment #4: for simplicity's sake I have had to make the decision that locally assigned scoped addresses do always have a zone ID. I still agree that with the embedding case this would have been bad, but I'd argue that with an explicit zone field, it is now a good thing: it allows an application to get one of the available addresses from a netif, and use that in (eg) a bind() call directly, as such preserving zone information. Applications that are not scope-aware will only look at the address part, which is as it was before, and ignore the zone part.

Regarding comments #8, #9: the current patch does make the whole scopes support optional with a LWIP_IPV6_SCOPES configuration option, at least for now. My reasoning for this is as follows: 1) given that this whole thing is in effect an addition to the code, it is not so difficult to isolate the new parts; there are very few places where there is code only for the LWIP_IPV6_SCOPES==0 case, the rest is just stubbing away of new macros (see the new ip6_zones.h); 2) for now, it gives people the ability to go back to the old situation if this change breaks something, which is particularly relevant because I have not been able to test more than the core API so far; the configuration option can always be phased out later when all other code (within lwIP and outside) is "ready"; 3) alternatively, for single-netif configurations, one could argue that it's still beneficial to remove everything at compile time that is not needed for that case, in which case LWIP_IPV6_SCOPES could be defined to (!LWIP_SINGLE_NETIF) later or so.

Regarding comment #14: in contrast to what I expected, as it turns out, it is incredibly easy, and in fact "natural", to capture the entire IPv6 scoping policy in just three macros, and so that is what this patch does. It provides the ability for the application to disable those three macros' definitions (with IPV6_CUSTOM_SCOPES) and instead supply its own. There is only one exception in the code based on whether such custom scopes are set or not, and that is merely a performance optimization for the default policy. I still don't know if this support will be useful to anyone in practice, and the support can be easily removed again as well, but given that it was this simple (and thus also easy to maintain as an option), I felt there was no reason to leave it out.

So does the resulting system work? As backstory, before I started on this, my lwIP-based sockets implementation already supported IPv6 address scopes, using workarounds such as explicit PCB binding and source/interface preselection. Due to the lack of scope support in lwIP itself, this would work correctly only if all link-local addresses were globally unique, but it was still functional, and I had already written a few tests for this form of scopes support.

With this patch, but with the zone field always set to zero when generating addresses, my implementation continued to pass all its tests, including those related to address scopes (which is good, but not yet very telling). After that, I removed all the workarounds but kept zone IDs set to zero; everything still passed except tests related to address scopes (as expected, but still showing that e.g. no bad-scope assertions were triggered). Finally, I have changed my implementation to properly set zone IDs and fully work with the new implementation here, and now all my tests pass again. In summary, the core API part of this change has seen at least reasonable testing so far.

Moreover, I have done a few specific tests; let me describe the most extreme one. On my lwIP-based system I can now assign the same link-local address (fe80::1) to two different interfaces, and then have two additional nodes (running NetBSD as it happens), each on a separate link attached to one of those two interfaces, with both those nodes assigned the same, second link-local address (fe80::2). With this setup, from the lwIP-based system I can ping (RAW) and make full (TCP) connections to each of the other two nodes, picking one or the other based entirely by providing a zone ID from userland. In addition, I have confirmed that IPv6 reassembly of (UDP) packets with link-local addresses works as expected in this setup, including reassembly timeouts going to the right link. Obviously none of this would have worked before.

There are still several things left to test, though. I have added very basic sin6_scope_id support to the lwIP sockets API in this patch, but I have not even been able to test compilation of that change. In theory however, that should be all that is needed to support address scopes in the sockets layer! As for 6lowpan, I have been able to compile but not test my changes there, and so those could use some scrutiny in particular. Overall, in terms of the lwIP code repository that should be all I think, but the contrib stuff may be another story of course..

The 0002 patch here is a separate TCP-specific mini-optimization that is now easy to make after changes needed for the scopes support anyway.

As an aside, I have a separate patch that extends the ip6addr_aton/ntoa routines to accept and produce "%if0" type suffixes. Technically this is not what such functions do, which is why I did not include that extension here. It may still be convenient for many platforms, though? I would be happy to add this patch as well, possibly making its functionality optional - please let me know.

(file #39572, file #39573)

David van Moolenbroek <dcvmoole>
Fri 20 Jan 2017 04:56:13 AM UTC, comment #15: 

I opened a new task (task #14314) for interface name/index APIs and have provided my first set of cleaned up patches

Joel Cunningham <jcunningham>
Project Member
Wed 18 Jan 2017 11:42:56 PM UTC, comment #14: 

Comment #13:

Sounds good! Whatever I would come up with (as always, I can never promise anything) will be limited to the core layers, so any help with the higher-layer stuff would be very welcome.

> scope ID (which is the same as interface index?)

The short answer: practically yes. The long answer is definitely worth discussing here as well though. The theory on scope IDs ("zone indices") is fairly elaborate - see RFC 4007 Sec. 6. In effect, for each scope (0..15), a zone maps to a set of zero or more interfaces, mostly as specified through user configuration. I think that for a lightweight IPv6 implementation, it is acceptable to follow the default model presented there, which is that each interface is assigned its own interface and link zone. The result is that the zone index for interface-local and link-local scopes can effectively be considered the same as the interface index, and that is then also the scope ID. For unicast, this is enough to cover link-local, ULA, and global addresses (site-local addresses have been deprecated for a while now). Multicast is a bit more involved, in that there are also larger-scoped multicast targets (eg admin-local) that would require an associated zone to make sense. However, the default model would simply disregard the scope ID there, and send packets to whatever is the default interface. Interface-local and link-local multicast, which is what's actually used internally already, will still work as expected, though.

Of course it would be nice to use the default model and then provide hooks to implement more elaborate schemes, but I'm afraid that things would get complicated rather quickly that way, and it is not really clear to me whether that kind of flexibility really buys much in practice. For example, I'm pretty sure that having multiple interfaces on the same link has other, bigger issues..

(BTW, thanks for all the input so far everyone!)

David van Moolenbroek <dcvmoole>
Wed 18 Jan 2017 09:56:01 PM UTC, comment #13: 

If there's interest, I have some patches that implement if_index_toname, if_name_toindex, if_nameindex, and if_freenameindex that I can post to the tracker

I was working on these awhile back because my port has some other public custom netif getter/setter APIs that take name and return IP address, gateway, if up/down status, etc and figuring out the all the names and indexes was useful.  I ended up running into some problems with caused by my port's usage of netif->num and I had to shelve the work.

Given that there was no upstream APIs to pass index or name into once retrieved, I wasn't sure the APIs had value outside my use case, but If we are wanting to get the scope ID (which is the same as interface index?) based on the name, then maybe the APIs have a use case and I can dust off my patches

I was writing the implementation according to RFC 3493: Basic Socket Interface Extensions for IPv6

Joel Cunningham <jcunningham>
Project Member
Wed 18 Jan 2017 08:46:09 PM UTC, comment #12: 

Re comment #9 size idea:
For that to work, the IP address type would have to be integrated into each version's IP address struct. As it is now, I also guess the "type" u8_t in ip_addr_t is put on an u32_t alignment boundary.

Simon Goldschmidt <goldsimon>
Project Administrator
Wed 18 Jan 2017 07:57:28 PM UTC, comment #11: 

I agree that having a 1-based scope ID is a good idea, and leave index 0 for "no scope" or "smart guess"

Ivan Delamer <idelamer>
Project Member
Wed 18 Jan 2017 07:55:07 PM UTC, comment #10: 

Comment #4:

> The only thing I'm not sure about is storing the scope in the netif addresses. I would keep it separate.

Hm yeah, that should be fine as well actually. For the embedding case it may be a bit cheaper to have the assigned address prepared for comparisons, basically. With a separate scope field, that is less of an issue.

Comment #5:

> Just as a note to the scope ID: There is an u8_t netif->num - already managed by netif code to be unique.

Ah yes. I remember looking into netif->num earlier and being a bit confused as to what it wants to be, as some places seemed to be treating it as a per-name unit number..

The bigger problem with netif->num is that it starts from zero, and it seems that eg the slipif code even relies on that. That means that at the very least, some remapping will be necessary, although that can be as simple as #define netif_index(netif) ((netif)->num + 1). It's probably best to retain the special value for "no scope" everywhere else.

Otherwise, netif->num would be fine, at least as long as it can be overridden from the netif init callback, because if netif_num overflows, uniqueness is no longer guaranteed. My implementation has to support dynamic interface creation/destruction..

Comment #9:

> When you add the scope ID member AFTER the IP address, then struct ip_addr won't increase in size (at least in dual-stack mode) since the scope member and u8_t type fit into one u32_t alignment.

I believe that's only the case if both structures are packed, and I'm not sure packing is a good idea here?

David van Moolenbroek <dcvmoole>
Wed 18 Jan 2017 07:18:05 PM UTC, comment #9: 

I don't think removing scopes are worth another #ifdef mess. It shouldn't be that much memory overhead.
Simon has created a task "single-netif mode" some time ago - it could be one of these things that is removed in that case (like all routing code etc.). This optimization makes much more sense because it targets towards a global optimization of lwIP to the single-netif use-case, which I guess are most of the applications.

When you add the scope ID member AFTER the IP address, then struct ip_addr won't increase in size (at least in dual-stack mode) since the scope member and u8_t type fit into one u32_t alignment.

Dirk Ziegelmeier <dziegel>
Project Administrator
Wed 18 Jan 2017 07:11:18 PM UTC, comment #8: 

Maybe if we make scopes optional (#define LWIP_IPV6_SCOPES 0) then we can have the extra scope member disappear?

Ivan Delamer <idelamer>
Project Member
Wed 18 Jan 2017 07:07:54 PM UTC, comment #7: 

Dirk was faster than me :-) Is there any drawback on using netif->num?

Oh, and I'd vote for adding an extra scope member instead of embedding the scope into the address.

Simon Goldschmidt <goldsimon>
Project Administrator
Wed 18 Jan 2017 07:06:43 PM UTC, comment #6: 

That's what I was thinking but couldn't remember. I think we should reuse that.

When an application wants to connect on a given netif, we should just pass the netif as an argument. This can be masked by macros to use either the netif name, or a netif address (as used e.g. by IGMP and MLD6)

Ivan Delamer <idelamer>
Project Member
Wed 18 Jan 2017 07:04:22 PM UTC, comment #5: 

Just as a note to the scope ID: There is an u8_t netif->num - already managed by netif code to be unique.

Dirk Ziegelmeier <dziegel>
Project Administrator
Wed 18 Jan 2017 07:00:20 PM UTC, comment #4: 

All good ideas.

I think if the socket spec says that we need an integer, then lets do it so everywhere. 8 bits should be plenty. Lets remember the Lw in LwIP.

The only thing I'm not sure about is storing the scope in the netif addresses. I would keep it separate. I believe this is how I've seen it done elsewhere, using the scope ID as some form of netif handle.

The scope ID embedded in the address should only be a temporary storage solution and should be as invisible to the user as possible. I think we can pull it off without having the scope ID embedded in the netif IPv6 address list.

Ivan Delamer <idelamer>
Project Member
Wed 18 Jan 2017 06:50:00 PM UTC, comment #3: 

Good points; to be honest I was focused on the core part of lwIP so far, as that's the part I am interested in myself :) but indeed, the higher-level (socket API etc) side should be involved in the considerations as well.

For the standard BSD socket API, the scope ID needs to be expressed as a 32-bit integer (sin6_scope_id), with 0 denoting "no scope". I'd contend that adopting such a number system throughout lwIP is the simplest approach, to prevent needless back-and-forth conversion. Note that with the embedding option (#2), the actual limit is like 22 bits. But 8 used bits should be plenty in practice anyway - who could possibly want more than 255 netifs?

My additional implementation ideas so far were as follows - all preliminary though..

Each netif would have its interface index set by the user/application/etc at initialization time. This would be a requirement for anyone that enables support for scope IDs in their configuration. It's up the user to ensure that each netif gets a unique ID this way, although people that use multiple netifs per actual interface could set the same index on each of those. In any case, this approach saves the netif code from having to pick unique IDs, especially since the user may have an easier job at that (eg I for one keep all netifs in an array).

Locally assigned link-local IPv6 addresses would also have a stored scope ID, just like other addresses. Not only would this make the implementation simpler overall I think, but when done properly, this means that the same link-local address could be assigned to multiple interfaces without creating ambiguity. So the scope ID really becomes part of the identity of the address that way.

A core-level netif function would look up a netif based on an address scope ID, as necessary for routing. I am actually guessing/hoping that this is needed by ip6_route() only, so that the ipv6 routing hook can be used to speed this up when possible (e.g. I can just use it to index my netif array).

An API-level if_nametoindex(3) function could do the get-id-by-name part in a standardized way, or possibly call a hook to do such interface name resolution. This is actually related to a bunch of other things (interface/local-address enumeration etc) of which I don't know how they're done in lwIP socket API based applications (if at all?).. but my guess is that adding support for scope IDs does not make things much more complicated than they already were in that area.

David van Moolenbroek <dcvmoole>
Wed 18 Jan 2017 05:55:42 PM UTC, comment #2: 

Great suggestions David. Can't believe it's been three years since I posted this task.

Like you say, this is not straightforward. Otherwise it would have been done already.

I would lean towards solution 2, using macros as you suggest. If we decide to change the implementation to something like 1 in the future, the macros should ensure compatibility.

I've always seen scope IDs as integers, but I don't remember if this is RFC or just general convention. I don't see any issues with adding an integer ID to each netif. However, we should either:
1) add a get_id(netif_name) function to retrieve the ID based on the name
2) add a get_id(src_addr) function to retrieve ID based on an address configured on the netif

1) and 2) would then have a macro that creates a LL destination address using that integer ID

3) don't use and integer ID at all and have a macro create a LL dest address embedding some private info. The macro could take either the netif name or a src address.

Cheers, Ivan

Ivan Delamer <idelamer>
Project Member
Wed 18 Jan 2017 05:41:53 PM UTC, comment #1: 

For correctness of multi-interface IPv6 nodes this is a rather important task, because there may be overlap between link-local addresses used on separate links, and the current IPv6 code is in no way ready to deal with that.

The way I see it, before any work can be done on this task, a crucial decision has to be taken first. Each netif will have to be extended with an interface index field that will serve as the scope ID of the interface; this is the easy part. IPv6 addresses (struct ip6_addr) will similarly have to be extended with a scope ID however, and this is where things are less clear. There appear to be two options:

1. Extend "struct ip6_addr" with a separate field to store the scope ID. The field itself needs to be only a u8_t, but due to structure alignment rules, this will still increase the size of the IPv6 address structure from 16 to 20 bytes (and dual-stack ip_addr_t from 20 to 24 bytes).

2. Embed the scope ID into "unused" bits of link-local addresses. In this case, the lower 8 bits of the first 32-bit word of link-local addresses would contain the scope ID. For example, the internal representation of fe80::1 on interface lo0 would be fe80:2::1, with 2 being the interface index of lo0. This type of embedding is what the IPv6 implementation of the BSDs (WIDE/KAME) does as well.

Compared to #1, the approach of #2 costs no extra memory, but it makes the implementation somewhat more error-prone, as the scope ID has to be removed whenever anything is put on the wire, and it is relatively easy to forget that and and leak the scope ID.

With appropriate macro abstractions, it should be fairly easy to make support for scope IDs a compile-time option, which may be part of the consideration here. This would be mainly for single-netif configurations though, since for RFC compliance, support for proper scoping is absolutely required.

What do people is the better of the two approaches? Does either option sound unacceptable, even? Or did I forget something? All input appreciated!

David van Moolenbroek <dcvmoole>
Tue 25 Feb 2014 10:45:42 PM UTC, original submission:  

We should add scopes to differentiate link-local addresses in separate netifs.

And add the corresponding field to the socket struct.

Ivan Delamer <idelamer>
Project Member


Depends on the following items: None found

Items that depend on this one: None found


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

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.




    Follow 8 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2017-02-15 goldsimon StatusNone => Done
        Percent Complete90% => 100%
        Open/ClosedOpen => Closed
    2017-02-04 dcvmoole Attached File- => Added 0001-ip6-fix-parentheses-in-ip6_addr_has_scope.patch, #39660
        Attached File- => Added 0002-ip6-split-icmp6_send_response-from-_with_addrs.patch, #39661
    2017-02-03 goldsimon Percent Complete0% => 90%
    2017-01-27 dcvmoole Attached File- => Added 0001-Add-support-for-IPv6-address-scopes.patch, #39572
        Attached File- => Added 0002-tcp-eliminate-some-redundant-route-lookups.patch, #39573

    Back to the top

    Powered by Savane 3.5