Source address selection

Dear all,

recently I set up a small network:-Linux-PC (ethernet interface) -Raspberry Pi (ethernet, mrf24j40 radio module) -Riot node (stm32f3discovery, mrf24j40, BME280 environmental sensor)

As mentioned the Pi has an ethernet device and a mrf24j40 radio module as net interfaces. It is configured as a border router with radvd-service. The ipv6-address-prefixes are fc00:0:0:1::/64 (eth0)

fc00:0:0:2::/64 (lowpan0)

After getting this network setup working I ran in some issues: Pinging the Riot-node form the Linux-PC was successful but pinging the Linux-PC from the Riot-node failed. Tshark on Raspberry Pi showed showed the reason: The ip6-packets from the riot-node have the link-local-address as source-address (not the global scope address with fc00::0:0:2-prefix). These packages could not be routed.

I did some further experiments. By adapting the posix-socket.example I configured the Riot-node as an udp-server, sending temperature-data (bme280-sensor) to an udp-client at Linux-PC. In order to get routable ip6-packets, I set the source-address (of the ip6 packages send from Riot-node) by application code. This “solution” worked for a while.

After pulling RIOT master after several weeks without pulling I got a new issue. Pinging Riot node from Linux-PC fails. My client-server-set up also doesn’t work. The Riot-node still gets requests from Linux-PC, but it doesn’t send answers - if I set ip6-source-address by application code. If I don’t set source address by application code, the Riot-node answers, but with its link-local-address which is not routable. Some git diff analysis and ENABLE_DEBUG showed that changes in gnrc_ipv6.c caused the different behavior: my preset global scope source address (fc00::2:6717:7427:32d:1036) is judged to be invalid.

What can I do to force the Riot-note sending ipv6-packets with routable source addresses?

Thanks for your help.

Best regards ,

Raimund Oude Hengel

Hi Raimund,

welcome to the RIOT community! Sorry for the late reply.

For auto-configuration: Have you tried compiling with -DGNRC_IPV6_NIB_CONF_SLAAC=1 already [1]? This compile time configuration is set to 0 for 6LoWPAN/IEEE802.15.4 nodes. 6LoWPAN nodes use a slightly different way of stateless address auto-configuration [2] from the classic SLAAC [3] which inclusion is controlled with the configuration flag. However, Linux does not really support the 6Lo-way of SLAAC so without classic SLAAC activated the address can’t be validated as the ARO is missing from the NAs [4].

[…]

After pulling RIOT master after several weeks without pulling I got a new issue. Pinging Riot node from Linux-PC fails. My client-server-set up also doesn’t work. The Riot-node still gets requests from Linux-PC, but it doesn’t send answers - if I set ip6-source-address by application code. If I don’t set source address by application code, the Riot-node answers, but with its link-local-address which is not routable. Some git diff analysis and ENABLE_DEBUG showed that changes in gnrc_ipv6.c caused the different behavior: my preset global scope source address (fc00::2:6717:7427:32d:1036) is judged to be invalid.

Mh, if you added it as VALID [5] this definitely sounds like a bug. Were you able to pin-point the regressing commit with tools like git bisect or git blame (mentioning “git diff analysis” makes me think you roughly know which line causes the behavior)? Knowing this change would be a great help to determine what is causing this bug.

Kind regards, Martine

[1] http://api.riot-os.org/group__net__gnrc__ipv6__nib__conf.html#gaa47a6efaa52f16c15e9858994a395ce5 [2] https://tools.ietf.org/html/rfc6775 [3] https://tools.ietf.org/html/rfc4862 [4] https://tools.ietf.org/html/rfc6775#section-5.5.2 [5] http://api.riot-os.org/group__net__gnrc__netif.html#gaf96707a5e322b5fa8458fba45de01837

Hi Martine,

thanks you for your reply.

A few minutes ago I tried the compiler option -DGNRC_IPV6_NIB_CONF_SLAAC=1 for the first time. It solved all my (RIOT) problems so far.

To be complete, here is what I wrote down before I tested your suggestion:

In between I did some further analysis and I found out, that the address-flag of the global scope address has to be set appropriately. I took the gnrc_networking example and added some code (main.c):

void setglobaladressflags(void){ /* get interfaces and set their address flags */ gnrc_netif_t *netif = NULL; while ((netif = gnrc_netif_iter(netif))) { ipv6_addr_t ipv6_addrs[GNRC_NETIF_IPV6_ADDRS_NUMOF]; int res = gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, ipv6_addrs, sizeof(ipv6_addrs)); if (res < 0) { continue; } for (unsigned i = 0; i < (unsigned)(res / sizeof(ipv6_addr_t)); i++) { if (ipv6_addr_is_global (&ipv6_addrs[i])){ netif->ipv6.addrs_flags[i]=IPV6_ADDR_MCAST_SCP_ORG_LOCAL; } } } }

int main(void) { puts(“Waiting for address autoconfiguration…”); xtimer_sleep(3); setglobaladressflags(); … }

With this addition Riot note was able to send udp messages to linux host. Furthermore there is no need to preset source address, because the RIOT source address selection algorithm finds the global scope address as the best fitting candidate. My posix-socket- server also works. But for curiosity: Pinging Linux host from Riot mode succeeds, pinging Riot node from Linux host fails. All in all I think that I found a workaround, not a solution. Are there some high level functions to manipulate address flags? Does the compiler option “-DGNRC_IPV6_NIB_CONF_SLAAC=1” have an influence? (YES)

If address flags are not set, the global scope address is not seen as source address candidate. It is sortet out here (gnrc_netif.c:958):

static int _create_candidate_set(const gnrc_netif_t *netif, const ipv6_addr_t *dst, bool ll_only, uint8_t *candidate_set) { … –> if ((netif->ipv6.addrs_flags[i] == 0) || gnrc_netif_ipv6_addr_dad_trans(netif, i)) { continue; … }

If source address is preset in application code, it is sorted out as invalid here (gnrc_ipv6.c:359): static int _fill_ipv6_hdr(gnrc_netif_t *netif, gnrc_pktsnip_t *ipv6) { … gnrc_netif_acquire(netif); invalid_src = ((idx = gnrc_netif_ipv6_addr_idx(netif, &hdr->src)) == -1) || –> (gnrc_netif_ipv6_addr_get_state(netif, idx) != GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID); … }

I hope, I could answer some of your questions. Thanks a lot for your work.

Best regards,

Raimund

Hi Raimund,

[…]

void setglobaladressflags(void){ /* get interfaces and set their address flags */ gnrc_netif_t *netif = NULL; while ((netif = gnrc_netif_iter(netif))) { ipv6_addr_t ipv6_addrs[GNRC_NETIF_IPV6_ADDRS_NUMOF]; int res = gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, ipv6_addrs, sizeof(ipv6_addrs)); if (res < 0) { continue; } for (unsigned i = 0; i < (unsigned)(res / sizeof(ipv6_addr_t)); i++) { if (ipv6_addr_is_global (&ipv6_addrs[i])){ netif->ipv6.addrs_flags[i]=IPV6_ADDR_MCAST_SCP_ORG_LOCAL;

This doesn’t seem correct to me. IPV6_ADDR_MCAST_SCP_ORG_LOCAL is a flag that is supposed to be carried in multicast address [6] [7]. So was the “bug” just caused by you using some “random” value?

[…]

With this addition Riot note was able to send udp messages to linux host. Furthermore there is no need to preset source address, because the RIOT source address selection algorithm finds the global scope address as the best fitting candidate. My posix-socket- server also works. But for curiosity: Pinging Linux host from Riot mode succeeds, pinging Riot node from Linux host fails.

This should be “fixed” with https://github.com/RIOT-OS/RIOT/pull/11970 (now when the address is invalid the packet is discarded in all cases, even when preconfigured).

All in all I think that I found a workaround, not a solution. Are there some high level functions to manipulate address flags? Does the compiler option “-DGNRC_IPV6_NIB_CONF_SLAAC=1” have an influence? (YES)

[…]

I hope, I could answer some of your questions. Thanks a lot for your work.

IPV6_ADDR_MCAST_SCP_ORG_LOCAL and GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_DEPRECATED have the same value, so I am not really surprised anymore, that your addresses were marked as invalid, yes ;-).

Best regards, Martine

[6] https://tools.ietf.org/html/rfc4291#section-2.7 [7] http://api.riot-os.org/group__net__ipv6__addr.html#gab2c7aa747be8ca29c21fcb3619d71ffa

Hi Martine,

Switching on GNRC_IPV6_NIB_CONF_SLAAC was the winning move. Now my little network is in perfect working order - as far as I can see.

-The weather-data-server honestly answers requests from Linux host. -Some other example applications (gcoap, nanocoap) do their work too. -There is no need to preset source addresses. -The best: Riot node is pingable from Linux host and vice versa.

The ifconfig output reflects the differences depending on whether GNRC_IPV6_NIB_CONF_SLAAC is switched on or not.

with CFLAGS += -DGNRC_IPV6_NIB_CONF_SLAAC=1: inet6 addr: fe80::6717:7427:32d:1036 scope: local VAL inet6 addr: fc00::2:6717:7427:32d:1036 scope: global VAL

without: inet6 addr: fe80::6717:7427:32d:1036 scope: local VAL inet6 addr: fc00::2:6717:7427:32d:1036 scope: global TNT[3]

I’m new in ipv6-networking, Riot, microcontroller programming. There are some tiny gaps in knowing what is going on behind the curtain. But now I feel encouraged to climb the next steps.

Thanks and kind regards from Münster,

Raimund