Skip to main content

8.5 Autoconfiguration: Stateless Magic

When we wrapped up ipv6_rcv() in the previous section, I actually had a lingering concern.

If you followed my earlier debugging steps, you might have noticed a counterintuitive phenomenon: before you even configure an address, or even type ip addr add, ip addr show sometimes already displays an IPv6 address—and a daunting 128-bit one at that.

Who configured it? No DHCP was run, and no one typed it manually. Where did this address come from?

This is IPv6's most "magical" feature: Autoconfiguration. With this mechanism, a host can conjure up a globally unique address out of thin air. No DHCP server needed, no manual intervention required—just plug in the cable, and it comes alive on its own.

But behind this magic lies a rigorous, step-by-step ritual. Let's break it down into four stages.


When the system boots, the first thing the IPv6 stack does upon waking up isn't asking a router for an address—it's creating a "temporary ID" for itself.

This is the link-local address.

The generation logic is straightforward:

  1. Take the prefix fe80::/10 (commonly written as fe80::/64).
  2. Append its own Interface ID (usually the MAC address in EUI-64 format).

At this point, this address is tagged internally in the kernel with: IFA_F_TENTATIVE (tentative).

This tag is crucial.

In this state, although the interface has an address, it is "crippled"—it cannot send or receive regular traffic, and can only process Neighbor Discovery Protocol messages.

Why? Because it's like walking into a room and shouting, "My name is John Doe." Until you're sure there isn't another "John Doe" in the room, you wouldn't dare actually socialize under that name. This is the job of DAD (Duplicate Address Detection), which we thoroughly dissected in the Neighbor Discovery chapter.

Only when DAD passes and the IFA_F_TENTATIVE flag is cleared can this address officially go to work.

⚠️ Pitfall Warning If DAD fails (an address conflict is detected), the autoconfiguration process terminates immediately. The kernel won't assign a second address, nor will it throw an error—it just fails silently. At this point, your only options are manual configuration or changing the MAC address. This is particularly common in VM cloning scenarios—two VMs end up with the same MAC, their IPv6 addresses collide, and neither can connect. Even ping fails, making it look like the network interface is broken.


Phase 2: Looking for a Guide

Once the link-local address is established (proving "I am unique"), if this machine isn't a router, it starts looking for an exit.

At this stage, the host has a clear need: "I want to know what the outside network looks like, and is there a prefix I can use?"

It doesn't just wait around; it actively calls out to the link. Inside the kernel, it calls ndisc_send_rs() to send a Router Solicitation (RS) message.

  • Destination Address: ff02::2 (the all-routers multicast address).
  • Protocol Type: ICMPv6, Type NDISC_ROUTER_SOLICITATION (133).

This step is like the host shouting down the hallway: "There's a machine here that needs internet access—any router hear me?"


Phase 3: The Router's Proclamation

The router hears it. In response, it sends a Router Advertisement (RA) message.

  • Source Address: The router's link-local address.
  • Destination Address: ff02::1 (the all-nodes multicast address).
  • Protocol Type: ICMPv6, Type NDISC_ROUTER_ADVERTISEMENT (134).

In a Linux environment, this "shouting" role is usually played by a userspace daemon called radvd.

You can install radvd on the router and write the prefix you want to broadcast (e.g., 2001:db8:abcd::/64) in its configuration file. radvd does two things:

  1. Periodic Broadcasting: Sends RAs to ff02::1 at regular intervals, telling newly arrived machines, "This is my turf, and here is the prefix."
  2. Responding to Requests: Listens on ff02::2, and immediately replies with an RA as soon as it hears an RS request.

This RA message is the core of the entire autoconfiguration process. It holds the two things the host wants most:

  1. Prefix Information: For example, 2001:db8:abcd::/64.
  2. Various Flags: Telling the host whether it "can use the prefix I gave you to configure its own address (stateless)" or "must go find a DHCPv6 server (stateful)."

Phase 4: Address Synthesis and "Privacy Mode"

After receiving the RA and seeing the prefix inside, the host knows what to do.

What it does now is simple assembly: IPv6 Address = Prefix (from RA) + Interface ID

  • Prefix: Specified by the router (must be 64 bits).
  • Interface ID: Usually its own MAC address (EUI-64).

The result is a global unicast address.

But there's a hidden catch here.

If your Interface ID directly uses your MAC address, then wherever you go, the last 64 bits of your IPv6 address remain the same. This means that Google, advertisers, or even your next-door neighbor can track your physical device just by looking at the IPv6 packets you send—you switch to a different Wi-Fi, the prefix changes, but the last 64 bits are still there, and they still know it's you.

To solve this problem, Linux introduced Privacy Extensions (kernel config CONFIG_IPV6_PRIVACY).

When this feature is enabled, the kernel appends a randomly generated Interface ID after the prefix when generating an IPv6 address, instead of using the MAC address.

This brings two benefits:

  1. The outside world cannot reverse-engineer your MAC address from your IPv6 address.
  2. This temporary address periodically expires and a new one is generated, making tracking extremely difficult.

Returning to our analogy:

Earlier, we compared autoconfiguration to "getting an ID card."

Normal Mode: Your ID number is always 110101[你的MAC地址]. No matter where you move, the second half never changes, and anyone can look up your records.

Privacy Mode: Every time you go to a new place, you give yourself a new name, like 110101[随机字符串]. People in that place (under that prefix) know you, but the next time you move away, no one knows that "random string" was you.


The Art of Time: Lifetime

Automatically configured addresses aren't permanent; they come with a strict countdown. In the RA message, the router attaches two time parameters to each prefix:

  1. Valid Lifetime:

    • This is the "shelf life" of the address.
    • When the countdown ends, this address is deleted directly by the kernel and disappears from the interface.
    • Before it expires, already established TCP connections can continue to use it, but new connections cannot use this address.
  2. Preferred Lifetime:

    • This is shorter than the Valid Lifetime.
    • Once the countdown ends, this address enters the "Deprecated" state.
    • At this point, the system will no longer actively use this address to initiate communication (for example, if you want to ping6 someone, the system won't select this address as the source address), but it will still receive packets sent to this address (to maintain existing connections).

In the kernel's inet6_ifaddr structure (include/net/if_inet6.h), these two parameters correspond to the valid_lft and prefered_lft fields.

These two designs exist to support Renumbering.

Imagine you're the network administrator and want to replace the entire company's IPv6 prefix (for example, because you switched ISPs). You don't need to run commands on every single machine. You just need to do the following in the radvd configuration:

  1. Add the new prefix and give it a long Lifetime.
  2. Set the old prefix's Lifetime to something very short (or to 0).

After hosts receive the new RA, they will automatically:

  • Let the old address slowly expire.
  • Configure the new address.
  • Smoothly switch subsequent traffic to the new address.

This is the seamless renumbering process described in RFC 4192.


Stateless vs. Stateful (DHCPv6)

So far, everything we've discussed has been Stateless Address Autoconfiguration (SLAAC). Its core characteristic is that the router only broadcasts the prefix, and the host calculates its own address. The router doesn't need to keep track of who is using which address—it is "stateless."

But sometimes, the network administrator (that's you) wants more fine-grained control. You want to know who has which IP, or you want to forcefully push down DNS server addresses (although RA can also push DNS, it's not supported in all scenarios).

This is where DHCPv6 comes in.

  • Stateful: The host gets an address from a DHCPv6 server, and the server maintains a database recording the MAC -> IP mapping. This is the old IPv4 approach.
  • Stateless: The host still calculates its own address, but can get other configuration information (like DNS) via DHCPv6. This is called "stateless DHCPv6."

If the kernel receives an RA with the "Managed" flag (M flag), it understands: "In this place, I need to find a DHCPv6 server to get an address," and only then will it start a DHCPv6 client.


Summary

In this section, we walked through the entire process of an IPv6 host going from "bare metal" to "connected":

  1. Self-Assertion: Generate a link-local address and confirm uniqueness via DAD.
  2. Looking for Signposts: Send an RS to request a router.
  3. Receiving Gifts: Receive an RA and obtain the prefix.
  4. Assembling an Identity: Prefix + Interface ID (with optional privacy extensions) generates a global unicast address.
  5. Birth and Death: As the Preferred/Valid Lifetime ticks down, addresses naturally age out or are renewed.

Now, your machine has a legitimate, routable IPv6 address.

The cable is plugged in, and the address is set. Next, when a real IPv6 packet comes in from the outside, how does the kernel handle it? In the next section, we'll dive inside ipv6_rcv() to look at the details on the receive path that we've glossed over so far.