Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_netif: add option to always join solicited-node multicast group (for connectivity across border router restart) #16988

Closed
wants to merge 6 commits into from

Conversation

benpicco
Copy link
Contributor

Contribution description

A border router will send a neighbor solicitation to the solicited-node multicasts if it encounters a packet from a global address that is not registered with the border router.

This happens when the border router is restarted while some nodes were online.

As the nodes were not in the solicited-node multicast group, they would drop the neighbor solicitation which resulted in them not being able to route any packets through the border router until they would reboot themself (or their prefix expired).

To fix this, always join the solicited-node multicast address as a 6LN.
This allows to have a connection across BR restarts.

Testing procedure

To make sure the border router retains it's address across reboots, we have to provide it with a EUI-64:

--- a/examples/gnrc_border_router/Makefile.native.conf
+++ b/examples/gnrc_border_router/Makefile.native.conf
@@ -23,3 +23,4 @@ TERMPROG ?= sudo $(RIOTTOOLS)/zep_dispatch/start_network.sh $(TERMPROG_FLAGS)
 
 # -z [::1]:$PORT for each ZEP device
 TERMFLAGS ?= $(patsubst %,-z [::1]:%, $(shell seq $(ZEP_PORT_BASE) $(ZEP_PORT_MAX)))
+TERMFLAGS += -U 7A:37:FC:7D:1A:AF

ARSM is enabled for routers, so to reproduce this our node must be a simple 6LN:

--- a/examples/gnrc_networking/Makefile
+++ b/examples/gnrc_networking/Makefile
@@ -14,7 +14,7 @@ USEMODULE += auto_init_gnrc_netif
 # Activate ICMPv6 error messages
 USEMODULE += gnrc_icmpv6_error
 # Specify the mandatory networking modules for IPv6 and UDP
-USEMODULE += gnrc_ipv6_router_default
+USEMODULE += gnrc_ipv6_default
 USEMODULE += gnrc_udp
 # Add a routing protocol
 USEMODULE += gnrc_rpl
  • start the (native) border router:
$ make -C examples/gnrc_border_router BOARD=native all term

> ifconfig
Iface  7  HWaddr: 00:00  Channel: 26  NID: 0x23 
          Long HWaddr: 7A:37:FC:7D:1A:AF:00:00 
          L2-PDU:102  MTU:1280  HL:64  RTR  
          RTR_ADV  6LO  IPHC  
          Source address length: 8
          Link type: wireless
          inet6 addr: fe80::7837:fc7d:1aaf:0  scope: link  VAL
          inet6 addr: 2001:db8::7837:fc7d:1aaf:0  scope: global  VAL
          inet6 group: ff02::2
          inet6 group: ff02::1
          inet6 group: ff02::1:ffaf:0
          
Iface  6  HWaddr: 7A:37:FC:7D:1A:AF 
          L2-PDU:1500  MTU:1500  HL:64  RTR  
          Source address length: 6
          Link type: wired
          inet6 addr: fe80::7837:fcff:fe7d:1aaf  scope: link  VAL
          inet6 addr: fe80::2  scope: link  VAL
          inet6 group: ff02::2
          inet6 group: ff02::1
          inet6 group: ff02::1:ff7d:1aaf
          inet6 group: ff02::1:ff00:2
  • start the 6LoWPAN node
$ make -C examples/gnrc_networking USE_ZEP=1 all term

> ifconfig
Iface  7  HWaddr: 34:18  Channel: 26  NID: 0x23 
          Long HWaddr: DA:A0:EF:4A:D1:76:34:18 
          L2-PDU:102  MTU:1280  HL:64  6LO  
          IPHC  
          Source address length: 8
          Link type: wireless
          inet6 addr: fe80::d8a0:ef4a:d176:3418  scope: link  VAL
          inet6 addr: 2001:db8::d8a0:ef4a:d176:3418  scope: global  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:ff76:3418
          
          Statistics for Layer 2
            RX packets 4  bytes 286
            TX packets 3 (Multicast: 1)  bytes 171
            TX succeeded 6 errors 0
          Statistics for IPv6
            RX packets 3  bytes 304
            TX packets 3 (Multicast: 1)  bytes 224
            TX succeeded 3 errors 0

> ping fdea:dbee:f::1   
12 bytes from fdea:dbee:f::1: icmp_seq=0 ttl=63 rssi=-512 dBm time=0.649 ms
12 bytes from fdea:dbee:f::1: icmp_seq=1 ttl=63 rssi=-512 dBm time=0.600 ms
12 bytes from fdea:dbee:f::1: icmp_seq=2 ttl=63 rssi=-512 dBm time=0.723 ms

--- fdea:dbee:f::1 PING statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.600/0.657/0.723 ms

We can now reboot the border router, our node keeps it's packets routed:

> ping -c 100 fdea:dbee:f::1
ping -c 100 fdea:dbee:f::1
12 bytes from fdea:dbee:f::1: icmp_seq=0 ttl=63 rssi=-512 dBm time=0.488 ms
12 bytes from fdea:dbee:f::1: icmp_seq=1 ttl=63 rssi=-512 dBm time=0.529 ms
12 bytes from fdea:dbee:f::1: icmp_seq=2 ttl=63 rssi=-512 dBm time=0.539 ms
# border router restart
nib: Creating NCE for (ipv6 = 2001:db8::7837:fc7d:1aaf:0, iface = 7, nud_state = STALE)
nib: Neighbor cache full
12 bytes from fdea:dbee:f::1: icmp_seq=3 ttl=63 rssi=-512 dBm time=1.338 ms
12 bytes from fdea:dbee:f::1: icmp_seq=4 ttl=63 rssi=-512 dBm time=0.528 ms
12 bytes from fdea:dbee:f::1: icmp_seq=5 ttl=63 rssi=-512 dBm time=0.590 ms
12 bytes from fdea:dbee:f::1: icmp_seq=6 ttl=63 rssi=-512 dBm time=0.590 ms
12 bytes from fdea:dbee:f::1: icmp_seq=7 ttl=63 rssi=-512 dBm time=0.592 ms
# border router restart
nib: Creating NCE for (ipv6 = 2001:db8::7837:fc7d:1aaf:0, iface = 7, nud_state = STALE)
nib: Neighbor cache full
12 bytes from fdea:dbee:f::1: icmp_seq=8 ttl=63 rssi=-512 dBm time=1.357 ms
12 bytes from fdea:dbee:f::1: icmp_seq=9 ttl=63 rssi=-512 dBm time=0.602 ms
12 bytes from fdea:dbee:f::1: icmp_seq=10 ttl=63 rssi=-512 dBm time=0.598 ms

compared to the situation on master:

> ifconfig
Iface  7  HWaddr: 08:64  Channel: 26  NID: 0x23 
          Long HWaddr: 7A:30:7B:E2:5D:42:88:64 
          L2-PDU:102  MTU:1280  HL:64  6LO  
          IPHC  
          Source address length: 8
          Link type: wireless
          inet6 addr: fe80::7830:7be2:5d42:8864  scope: link  VAL
          inet6 addr: 2001:db8::7830:7be2:5d42:8864  scope: global  VAL
          inet6 group: ff02::1
          
          Statistics for Layer 2
            RX packets 4  bytes 286
            TX packets 3 (Multicast: 1)  bytes 171
            TX succeeded 6 errors 0
          Statistics for IPv6
            RX packets 3  bytes 304
            TX packets 3 (Multicast: 1)  bytes 224
            TX succeeded 3 errors 0

> ping -c 100 fdea:dbee:f::1
ping -c 100 fdea:dbee:f::1
12 bytes from fdea:dbee:f::1: icmp_seq=0 ttl=63 rssi=3584 dBm time=0.508 ms
12 bytes from fdea:dbee:f::1: icmp_seq=1 ttl=63 rssi=3584 dBm time=0.662 ms
12 bytes from fdea:dbee:f::1: icmp_seq=2 ttl=63 rssi=3584 dBm time=0.330 ms
12 bytes from fdea:dbee:f::1: icmp_seq=3 ttl=63 rssi=3584 dBm time=0.765 ms
12 bytes from fdea:dbee:f::1: icmp_seq=4 ttl=63 rssi=3584 dBm time=0.748 ms
# border router restart - node never recovers

Issues/PRs references

A border router will send a neighbor solicitation to the
solicited-node multicasts if it encounters a packet from a global address
that is not registered with the border router.

This happens when the border router is restarted while some nodes were
online.

As the nodes were not in the solicited-node multicast group, they would
drop the neighbor solicitation which resulted in them not being able to
route any packets through the border router until they would reboot themself
(or their prefix expired).

To fix this, always join the solicited-node multicast address as a 6LN.
This allows to have a connection across BR restarts.
@benpicco benpicco added the Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) label Oct 14, 2021
@github-actions github-actions bot added Area: network Area: Networking Area: sys Area: System labels Oct 14, 2021
@benpicco benpicco requested a review from chrysn October 14, 2021 13:29
}
#else /* CONFIG_GNRC_IPV6_NIB_ARSM */
if (!gnrc_netif_is_6ln(netif)) {
if (IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ARSM) || gnrc_netif_is_6ln(netif)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://datatracker.ietf.org/doc/html/rfc6775#section-5.2

There is no need to join the solicited-node multicast address, since
nobody multicasts NSs in this type of network. A host MUST join the
all-nodes multicast address.

IMHO this should be made configurable for 6LNs (and default turned off), so a user can set it in accordance with their respective use case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, I just don't see why this should not be enabled. To me this appears like a case of 'broken defaults'.

Copy link
Contributor Author

@benpicco benpicco Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nobody multicasts NSs in this type of network

Is this a bug on the border router then? Because it clearly does.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5.1.  Forbidden Actions

   A host MUST NOT multicast an NS message.

so if BR does it is a bug in BR

Copy link
Contributor

@kfessel kfessel Jan 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like how ipv6 avoids broadcast by doing multicast -> then some extensions happens and there should not be any multicast NS but there is no broadcast -> so it is an all-multicast which by the wording is no multicast

It it close to some philosophy discussion.

Copy link
Contributor

@kfessel kfessel Jan 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rfc6775 seems to define a essential part
of
rfc4861 illegal
rfc4861 sec 4.1

destination address: Either the solicited-node multicast address 
 corresponding to the target address, or the target address.

@github-actions github-actions bot added the Area: Kconfig Area: Kconfig integration label Oct 14, 2021
sys/include/net/gnrc/ipv6/nib/conf.h Outdated Show resolved Hide resolved
sys/include/net/gnrc/ipv6/nib/conf.h Outdated Show resolved Hide resolved
sys/include/net/gnrc/ipv6/nib/conf.h Show resolved Hide resolved
sys/net/gnrc/network_layer/ipv6/nib/Kconfig Outdated Show resolved Hide resolved
benpicco and others added 3 commits October 14, 2021 17:26
Co-authored-by: Martine Lenders <mail@martine-lenders.eu>
Co-authored-by: Martine Lenders <mail@martine-lenders.eu>
@benpicco benpicco changed the title gnrc_netif: always join solicited-node multicast group if 6LN gnrc_netif: add option to always join solicited-node multicast group (for connectivity across border router restart) Oct 17, 2021
@benpicco
Copy link
Contributor Author

benpicco commented Nov 2, 2021

The thing is: why not have this as default when gnrc_sixlowpan_border_router expects the address to be present?
So this is either a bug in the border router that it tries to send to the solicited-node address to resolve a 6LoWPAN address or a bug in the node that it does not join the solicited-node multicast group.

@benpicco benpicco added this to the Release 2022.01 milestone Dec 2, 2021
@benpicco benpicco requested a review from biboc December 21, 2021 11:18
@benpicco benpicco requested a review from kfessel January 4, 2022 09:54
@OlegHahm
Copy link
Member

OlegHahm commented Mar 9, 2022

@benpicco, where are we at here?

@benpicco
Copy link
Contributor Author

benpicco commented Mar 9, 2022

Waiting for a response from @miri64

@fabian18
Copy link
Contributor

I think I have also recently discovered this. My fix was CFLAGS+=-DCONFIG_GNRC_IPV6_NIB_ARSM=1
Because in conf.h it was explicitly disabled for hosts.

#if !CONFIG_GNRC_IPV6_NIB_6LR
# ifndef CONFIG_GNRC_IPV6_NIB_ARSM
# define CONFIG_GNRC_IPV6_NIB_ARSM                    0
# endif
# ifndef CONFIG_GNRC_IPV6_NIB_NUMOF
/* only needs to store default router */
# define CONFIG_GNRC_IPV6_NIB_NUMOF                  (1)
# endif
#endif

I think it can actually be enabled by default, even when we are a host (RFC4861)

On Linux, an interface also joins the solicited-node multicast address, even if it only has a link local address:

$ sysctl -w net.ipv6.conf.all.forwarding=0
$ ip link set eth0 down
# replug cable
$ ip link set eth0 up
$ ip a
5: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0e:c6:b4:b4:f4 brd ff:ff:ff:ff:ff:ff
    altname enp0s20f0u2u4u1u2
    inet6 fe80::3478:9157:9fd5:81c3/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
$ ip maddr show
5:      eth0
        link  01:00:5e:00:00:01
        link  33:33:00:00:00:01
        link  33:33:00:00:00:fb
        link  33:33:ff:d5:81:c3
        inet  224.0.0.1
        inet6 ff02::1:ffd5:81c3
        inet6 ff02::fb
        inet6 ff02::1
        inet6 ff01::1

@fabian18
Copy link
Contributor

See https://datatracker.ietf.org/doc/html/rfc6775#section-5.2

There is no need to join the solicited-node multicast address, since
nobody multicasts NSs in this type of network. A host MUST join the
all-nodes multicast address.

IMHO this should be made configurable for 6LNs (and default turned off), so a user can set it in accordance with their respective use case.

Ah true, 6LN host ...

@benpicco
Copy link
Contributor Author

benpicco commented Apr 18, 2022

#11038 suggests Linux here behaves the same as our gnrc_border_router.
I'm not sure what the BR is supposed to do instead, but if just joining the the solicited-node multicast group is such an easy fix, why not do it on our side?

@fabian18
Copy link
Contributor

but if just joining the solicited-node multicast group is such an easy fix, why not do it on our side?

hm, because @miri64 is, right. Technically the RFC clearly says that a 6LN host is not supposed to join that group.
I think the ping from the BR to the host simply does not work until the host has re-registered at the router.

Linux somehow does join the group, also as a 6LN host. Maybe the kernel does not fully support RFC6775.

$ sudo sysctl -w net.ipv6.conf.all.forwarding=0
$ sudo ip a a fd00:a:a:a:c4b0:b9f6:fefa:c8d3/64 dev lowpan0
8:      lowpan0
        inet  224.0.0.1
        inet6 ff02::fb
        inet6 ff02::1:fffa:c8d3 users 2
        inet6 ff02::1
        inet6 ff01::1

I am not saying that I am against a configuration flag to force-join the group.

@benpicco benpicco removed this from the Release 2022.04 milestone May 18, 2022
@miri64
Copy link
Member

miri64 commented May 23, 2022

Linux somehow does join the group, also as a 6LN host. Maybe the kernel does not fully support RFC6775.

Yes, Linux does not implement RFC 6775 and uses normal (energy-intensive) NDP with 6LoWPAN.

@miri64
Copy link
Member

miri64 commented May 23, 2022

The compromise, if it yields a problem in communication with Linux: Deactivate 6Lo-ND completely. This of course increases multicast messages within the network.

@miri64
Copy link
Member

miri64 commented Mar 16, 2023

With the description in https://forum.riot-os.org/t/telnet-server-example/3893/2:

[…] so addresses not registered with the border router will be ignored.

Is this really a bug then? If a (6LN) node did not register its address, the address is not valid anyways, so why would the border router need to send to those addresses?

@benpicco
Copy link
Contributor Author

benpicco commented Feb 8, 2024

With #20046 merged this PR does not make sense anymore.

@benpicco benpicco closed this Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Kconfig Area: Kconfig integration Area: network Area: Networking Area: sys Area: System Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants