Seyed Pouria Mousavizadeh Tehrani

Closing the IPv6 First-Packet Gap with GRAND

Author image
Seyed Pouria Mousavizadeh Tehrani(community contributor)

11 min read

0
Article lead image

There is a subtle asymmetry in IPv6 Neighbour Discovery: a host knows how to reach its router before the router necessarily knows how to reach the host. GRAND fixes that asymmetry by making the host proactively advertise its address, and I implemented that mechanism in FreeBSD.


A device joins an IPv6 network, receives a Router Advertisement, configures a new IPv6 address, and immediately starts communicating with the Internet.

From the host's perspective, everything is ready. It knows the link-layer address of its default router, so it can immediately send packets towards the Internet.

However, from the router's perspective, things may look different. The router may not yet know how to reach the host's newly configured global IPv6 address.

This creates a subtle asymmetry in IPv6 Neighbour Discovery: the host can already reach the router, while the router may have to perform Neighbour Discovery before it can forward traffic back to the host.

The first IPv6 packet has a problem

Consider a host that has just configured a new IPv6 address.

The host sends a packet towards an off-link destination. The first-hop router receives the packet and forwards it normally. When the remote destination responds, however, the return packet arrives at the router with the host as its destination.

The router may not have a Neighbour Cache entry for that IPv6 address, so it has to resolve the host's link-layer address before it can forward the packet. This puts Neighbour Discovery directly in the critical path of the first return packet.

For a mechanism that is normally invisible to applications, this can have a visible effect: the first packets of a connection may experience additional latency, or potentially be dropped while address resolution is in progress.

The problem is particularly interesting because the host already has all the information the router needs. The host knows that it owns the IPv6 address and knows the corresponding link-layer address, but the router simply hasn't learned it yet.

Why does Neighbour Discovery cause this?

IPv6 Neighbour Discovery is reactive in this situation. When a node needs to communicate with a neighbour for which it does not have a usable Neighbour Cache entry, it starts address resolution by sending a Neighbour Solicitation and waiting for a Neighbour Advertisement.

This works well for established neighbours. The problem appears during the transition from "the address has just become usable" to "the rest of the network knows how to reach it". So, again, the host already knows its IPv6 address and link-layer address while the first-hop router may have no information about the host until traffic arrives.

This is the gap that GRAND addresses.

GRAND: changing reactive Neighbour Discovery into proactive information

Gratuitous Neighbour Discovery changes the direction of information flow so that instead of waiting for the router to discover the host when the first packet arrives, the host proactively announces its IPv6 address and link-layer address using an unsolicited Neighbour Advertisement.

The router can then learn this information before it needs to forward traffic towards the host. This is the central idea behind RFC 9131.

But implementing GRAND is not simply a matter of sending an unsolicited Neighbour Advertisement whenever an address appears. GRAND interacts with several existing Neighbour Discovery rules, including the handling of multiple addresses, anycast and proxy addresses, timing, and Duplicate Address Detection.

Building GRAND on RFC 4861

An important part of implementing GRAND is understanding that unsolicited Neighbour Advertisements already have a defined role in Neighbour Discovery.

RFC 4861 rule 7.2.6 specifies behaviour for unsolicited Neighbour Advertisements, including cases such as changes to a node's link-layer address. It also limits how many advertisements a node can send for multiple addresses and recommends spacing those advertisements to avoid unnecessary congestion.

RFC 4861 rules 7.2.7 and 7.2.8 cover the special case of anycast and proxy Neighbour Advertisements. In these situations, multiple nodes may potentially respond to the same Neighbour Solicitation. If they all transmitted immediately, their purpose becomes ineffective.

To address this, RFC 4861 specifies a random delay before sending an anycast or proxy Neighbour Advertisement. This gives multiple potential responders a chance to avoid transmitting simultaneously.

These timing rules are an important part of the overall design of Neighbour Discovery: making information available quickly is useful, but doing so without creating a multicast storm is equally important.

My implementation adds these behaviours as part of the GRAND work rather than relying on pre-existing queueing and delayed-NA infrastructure.

GRAND and delayed Neighbour Advertisements

One of the less obvious parts of GRAND is therefore the scheduling of Neighbour Advertisements. That's where I decided to implement missing RFC 4861 parts.

The existing implementation did not previously provide the queueing and delayed-transmission machinery needed for these behaviours. Implementing GRAND required adding that infrastructure and then using it to schedule unsolicited Neighbour Advertisements.

In GRAND, a newly configured address may result in an unsolicited Neighbour Advertisement, but the implementation must consider how many addresses are being advertised and when each advertisement should be transmitted. In IPv6, an interface might have hundreds of addresses at the same time.

Sending all advertisements immediately could create an unnecessary burst. For example, consider a datacentre after power is restored, causing many servers to start at once. So the implementation therefore adds the delayed advertisement behaviour described by RFC 4861 7.2.6 and the randomised response behaviour described in 7.2.7 and 7.2.8.

This is particularly relevant for anycast and proxy addresses, where more than one node may be capable of responding.

The goal is not simply to minimise the time before an advertisement is sent. It is to balance fast neighbour discovery with the amount of multicast traffic generated by that discovery.

What does RFC 9131 actually change?

RFC 9131 builds on these Neighbour Discovery mechanisms to address the first-packet problem.

A host sends an unsolicited Neighbour Advertisement when a new IPv6 address becomes usable. The advertisement contains the information that a first-hop router needs to construct a neighbour entry.

However, there is an important second half to the mechanism. Under the original RFC 4861 behaviour, receiving an unsolicited Neighbour Advertisement does not necessarily mean that a router with no existing Neighbour Cache entry will create one.

RFC 9131 changes this behaviour.

A router receiving a valid unsolicited Neighbour Advertisement for an address for which it has no existing Neighbour Cache entry can create one using the information supplied in the advertisement. The entry is created in the STALE state, a detail that makes GRAND useful for the first-packet problem.

Why STALE is the key

At first, putting a newly learned neighbour into STALE may seem counterintuitive. Why not mark it REACHABLE? Actually, the distinction is important.

GRAND tells the router that the host is claiming the IPv6 address and provides a link-layer address. It does not necessarily prove that the neighbour is currently reachable in the sense used by Neighbour Unreachability Detection.

STALE allows the router to use the information it has already learned without requiring a new multicast address-resolution operation. The router can subsequently verify reachability using the normal Neighbour Discovery mechanisms. This means that GRAND removes address resolution from the critical path of the first packet without claiming that the neighbour has been permanently verified as reachable.

Implementing GRAND in FreeBSD

Implementing GRAND in FreeBSD therefore involved more than adding code to transmit an unsolicited Neighbour Advertisement.

The existing IPv6 Neighbour Discovery implementation already provided state machines, address lifecycle handling, Duplicate Address Detection, and Neighbour Cache management. However, it did not previously provide the queueing and delayed-Neighbour-Advertisement machinery required for GRAND and the related RFC 4861 behaviours.

The GRAND implementation added that infrastructure.

It also implements the relevant delayed and randomised advertisement behaviour from RFC 4861 rule 7.2.7 and 7.2.8.

This includes handling the timing of advertisements so that multiple addresses, anycast addresses, and proxy-related advertisements do not unnecessarily produce bursts of Neighbour Discovery traffic.

The implementation consequently combines several pieces of Neighbour Discovery behaviour:

  • Proactively advertising newly usable IPv6 addresses
  • Handling link-layer address changes
  • Adding queueing for Neighbour Advertisements
  • Delaying multiple unsolicited advertisements
  • Applying the appropriate randomisation for anycast and proxy responses
  • Integrating the new scheduling machinery with the existing ND state and timer handling

The result is not a separate "GRAND subsystem", but rather an extension of the existing Neighbour Discovery implementation with new queueing and transmission-scheduling support.

Want to take a closer look? You can explore the initial GRAND implementation in FreeBSD, along with the subsequent cleanup.

Handling link-layer address changes

GRAND also connects naturally to one of the existing uses of unsolicited Neighbour Advertisements.

RFC 4861 rule 7.2.6 defines unsolicited advertisements for situations such as a change in the link-layer address. If an interface's link-layer address changes while its IPv6 addresses remain configured, other nodes may still have cached information referring to the previous link-layer address. The implementation can proactively advertise the new mapping rather than waiting for normal Neighbour Discovery to discover the change.

This means that the GRAND implementation covers two closely related situations:

  • An IPv6 address becomes usable
  • The link-layer mapping for an existing IPv6 address changes

In both cases, the objective is the same: make the information available to neighbours before they are forced to discover it reactively.

What I learned while integrating it into FreeBSD

The implementation also highlighted an important difference between implementing a protocol on paper and integrating it into an existing networking stack.

The RFC describes the desired protocol behaviour, but the kernel did not previously have all of the mechanisms needed to implement it. In particular, GRAND required new queueing and delayed-transmission support for Neighbour Advertisements.

Adding GRAND therefore meant introducing those mechanisms and making sure that they interacted correctly with the existing address lifecycle, DAD, Neighbour Cache management, and Neighbour Discovery state handling.

In particular, GRAND-generated advertisements have different semantics from other Neighbour Advertisements. This required changes to the way advertisements are queued, combined, delayed, and eventually transmitted.

The timing requirements also make the implementation more interesting than simply generating packets immediately. The implementation needs to avoid creating unnecessary bursts while still making the information available early enough to solve the first-packet problem.

This is where the details in RFC 4861 rules 7.2.6-7.2.8 become important in practice. They are not merely historical protocol details, they provide the rules needed to make proactive Neighbour Discovery behave well on a real network.

Why does this matter for real IPv6 deployments?

Neighbour Discovery is often invisible when everything works correctly, and this is exactly what makes issues like this easy to overlook. The protocol is normally fast enough that users never think about it. But Neighbour Discovery can sit directly on the forwarding path, which means that its behaviour can affect the first packet of a connection.

This becomes increasingly relevant as IPv6 hosts dynamically configure and remove addresses. Privacy addresses, changing prefixes, mobile devices, virtual machines, containers, and other environments can all result in addresses appearing and disappearing during the lifetime of an interface.

GRAND allows the network to learn about a new address at the time the address becomes available rather than waiting until traffic forces that discovery to happen. And at the same time, the timing mechanisms inherited from the Neighbour Discovery design help ensure that proactive advertisements do not themselves become a source of unnecessary multicast traffic.

GRAND and RFC 9898

GRAND is not just an interesting optimisation described in an RFC. RFC 9898, Neighbour Discovery Considerations in IPv6 Deployments, explicitly identifies GRAND as a mechanism that addresses the router forwarding delay caused by this form of Neighbour Discovery.

This is important because it places the problem in the context of actual IPv6 deployment rather than treating it as a theoretical protocol issue.

Note: The author used AI tools to assist with drafting and language. The technical work, analysis and conclusions are the author’s own. For more information about our policy on AI-generated content, see our Contributing to RIPE Labs page.

0

About the author

Author image

Pouria is a FreeBSD Source Committer, specializing in Internet and network protocols. He focuses on improving the quality of Internet connectivity and has spent nearly a decade working across datacenters, ISPs, and network development teams. He regularly contributes to the FreeBSD project, improving operating system's networking stacks, particularly for IPv6, and Routing. As an IRNOG Steering Committee member, he has organized and presented at seven IRNOG meetings, fostering regional technical collaboration and knowledge sharing.

Comments 0