Observing IPv6 link local addresses

Link local addresses play an important role in IPv6 since they enable hosts that are attached to the same subnet to directly exchange packets without requiring any configuration. When an IPv6 host or router boots, the first thing that it tries to do is to create a link-local address for each of its interfaces. It is interesting to observe how those link-local addresses are used in a very simple network.

We consider the most basic topology containing two hosts connected to one router:

                                                                     
  h1 ---- r ---- h2                                                                             

With IPMininet, this network can be created with a simple script

import ipmininet
from ipmininet.cli import IPCLI
from ipmininet.ipnet import IPNet
from ipmininet.router.config import RouterConfig
from ipmininet.iptopo import IPTopo
from mininet.log import lg

class NoIP(IPTopo):

    def build(self, *args, **kwargs):
        r = self.addRouter_v6('r', config=(RouterConfig))
        h1 = self.addHost('h1')
        h2 = self.addHost('h2')
        self.addLink(r, h1)
        self.addLink(r, h2)

    def addRouter_v6(self, name, **kwargs):
        return self.addRouter(name, use_v4=False, use_v6=True, **kwargs)

ipmininet.DEBUG_FLAG = True
lg.setLogLevel("info")

# Start network
net = IPNet(topo=NoIP(), use_v4=False, allocate_IPs=False)

try:
    net.start()
    IPCLI(net)
finally:
    net.stop()

In this network, the simplest way to observe what happens when a host is attached to the network is to collect packet traces on the router with tcpdump.

tcpdump -i r-eth0 -n -vvv 

Once packet capture has started, we can force a reconfiguration of host h1 manually by setting its interface down and up.

#ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: h1-eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:a3:b6:e6:4b:1e brd ff:ff:ff:ff:ff:ff link-netnsid 0

Host h1 has two interfaces: a loopback and an Ethernet interface attached to router r. We disable the interface h1-eth0 with the command ` ip link set h1-eth0 down`. At this point, the only remaining interface is the loopback interface.

We can now activate the h1-eth0 interface with command ` ip link set h1-eth0 up ` and observe the packets that are sent by h1 via tcpdump on the router.

Once the link goes up, h1 automatically creates a link-local address and attaches it to interface h1-eth0.

# ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: h1-eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 fe80::a8a3:b6ff:fee6:4b1e/64 scope link 
       valid_lft forever preferred_lft forever

This link-local address is created by concatenating the well-known fe80::/64 prefix specified in section 2.5.6 of RFC4291 with the 64 bits interface identifier. This identifier is constructed from the MAC address of the interface.

#ip link show h1-eth0
2: h1-eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether aa:a3:b6:e6:4b:1e brd ff:ff:ff:ff:ff:ff link-netnsid 0

The creation of the interface identifier from MAC address aa:a3:b6:e6:4b:1e is specified in section 2.5.1 of RFC4291. The resulting link-local address is fe80::a8a3:b6ff:fee6:4b1e.

At this stage, host h1 needs to verify that no other device is using the same link-local address on the subnet. tcpdump running on the router observes the following packet:


09:40:33.938113 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 24) :: > ff02::1:ffe6:4b1e: [icmp6 sum ok] ICMP6, neighbor solicitation, length 24, who has fe80::a8a3:b6ff:fee6:4b1e

There are several points to note about this packet. First, its source IPv6 address is set to ::, i.e. a block of 128 bits set to zero. This is the unspecified address defined in section 2.5.2 of RFC4291. This address must be used as a source address when a device does not have a link-local address. The destination address is ff02::1:ffe6:4b1e: which is a solicited node-multicast address which is defined in section 2.7.1 of RFC4291. This solicited node-multicast address is created by appending the low order 24 bits of the link-local address (in this case e6:4b1e ) to the FF02:0:0:0:0:1:FF00::/104 prefix. An IPv6 node must listen to the IPv6 solicited node-multicast address that corresponds to each of its addresses to be able to reply to any possible ICMP message sent to this address. This reduces the load on the default all-nodes IPv6 multicast addresses.

After some time without a response to this neighbor sollicitation, host h1 considers that its link-local address is unique. It can then send an ICMPv6 router sollicitation message.

09:40:34.956122 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 16) fe80::a8a3:b6ff:fee6:4b1e > ff02::2: [icmp6 sum ok] ICMP6, router solicitation, length 16
          source link-address option (1), length 8 (1): aa:a3:b6:e6:4b:1e
            0x0000:  aaa3 b6e6 4b1e

This ICMPv6 router sollicitation is sent from the link-local address of host h1which is now considered as unique. The destination is ff02::2 which corresponds to all IPv6 routers. This router sollication message contains the MAC address of the sender inside the source link-address option defined in section 4.6.1 of RFC4861.

As no router has been configured to send router advertisements in this network, host h1 will not receive any answer. According to RFC4861, it should retransmit the router sollicitation message up to 3 times with a delay of 4 seconds between retransmissions (see sections 10 and 6.3.7 of RFC4861](https://tools.ietf.org/html/rfc4861)

Written on November 25, 2017