Skip to content

ipv6: verify a care-of address before registering it with the home agent - #1141

Open
adamgeorge309 wants to merge 2 commits into
masterfrom
topic/gy/mipv6-coa-dad
Open

ipv6: verify a care-of address before registering it with the home agent#1141
adamgeorge309 wants to merge 2 commits into
masterfrom
topic/gy/mipv6-coa-dad

Conversation

@adamgeorge309

@adamgeorge309 adamgeorge309 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

A mobile node that hands over now verifies its new care-of address with Duplicate Address
Detection (DAD) before it registers that address with its home agent. Two things had to
change together for that to hold: the address has to undergo DAD at all, and the Binding
Update has to wait for the result. Either change alone still registers a contested address,
so they are in one commit.

Closes #1140

The problem

processRaPrefixInfoForAddrAutoConf() splits on how many addresses the interface already
holds. With only a link-local address it assigns the new global address as tentative and
performs DAD -- the path added in adfe5ba71e. With more, which is exactly what a handover
looks like (link-local address plus the home address), it marks the existing addresses
tentative, probes the link-local address alone, and defers the new address to
dadGlobalList. makeTentativeAddressPermanent() then assigned it with tentative = false
and cleared the tentative flag on every address of the interface, so the "start DAD for a
tentative global address" loop at the end of that same function found nothing to do.

examples/ipv6/mipv6roaming -c Roaming -r 0, counting DAD completed for address for MN[0]:

address role before after
fe80::8aa:ff:fe00:b link-local 4 4
2001:db8:0:2:8aa:ff:fe00:b home address 1 1
2001:db8:0:4:8aa:ff:fe00:b care-of 0 2
2001:db8:0:6:8aa:ff:fe00:b care-of 0 1

The home address is probed because at boot the interface holds only a link-local address and
takes the correct path; neither care-of address was ever probed.

RFC 4862 Section 5.4 names this exact shortcut and rules it out:

  • Each individual unicast address SHOULD be tested for uniqueness.
    Note that there are implementations deployed that only perform
    Duplicate Address Detection for the link-local address and skip
    the test for the global address that uses the same interface
    identifier as that of the link-local address. [...] this kind of
    "optimization" is NOT RECOMMENDED, and new implementations MUST
    NOT do that optimization.

The fix

Perform the DAD. The blanket permanentlyAssign() loop now runs before the address
formed from the new prefix is added, so it only restores the addresses that were already on
the interface; the new care-of address is then assigned as tentative and the existing loop
starts DAD for it.

Wait for the result. The registration used to start as soon as the link-local DAD
completed, so the Binding Update left 1.67 s before the care-of address was verified. MIPv6
sets the source address of that datagram explicitly, and the RFC 4862 guard in
Ipv6::fragmentPostRouting() only covers datagrams whose source address Ipv6 chooses itself,
so nothing held it back. The MIPv6 protocol is now started when the care-of address passes
its own DAD, the dadGlobalList entry being kept until then. dadHasFailed() already erases
that entry, so a care-of address that is already in use is never registered at all.

Each handover now reads:

43.224  DAD completed for address fe80::8aa:ff:fe00:b
43.224  Starting DAD for tentative global address 2001:db8:0:6:8aa:ff:fe00:b
44.670  DAD completed for address 2001:db8:0:6:8aa:ff:fe00:b
44.670  Initiating Mobile Ipv6 protocol...
44.670  controlInfo: DestAddr=2001:db8:0:2:8aa:ff:fe00:2 SrcAddr=2001:db8:0:6:8aa:ff:fe00:b

Why both halves are needed

change care-of address probed Binding Update waits contested address registered?
neither (master) no no yes
DAD only yes no yes -- the Binding Update is 1.67 s ahead of the result
deferral only no n/a yes -- there is no result to wait for
both yes yes no

Verification

tests/module/MIPv6_care_of_address_DAD.test is added as a regression test. It fails on
unmodified master -- the run logs a DAD completion for the link-local address and for the
home address, but none for the care-of address aaaa:1:66:0:8aa:ff:fe00:8 -- and passes here.

Both suites were baselined on unmodified origin/master before any change was made, and
diffed afterwards.

  • Module tests (-f 'IPv6|MIPv6|Ipv6'): baseline 42 total, 40 PASS, 2 FAIL; now 43 total,
    41 PASS, 2 FAIL. The only difference is the new test. MIPv6_tcp_handover.test and
    IPv6_packet_too_big.test fail identically on unmodified master, so they are pre-existing
    and out of scope.
  • Fingerprints (-m ipv6 -F tyf): 27 tests, all pass.

Fingerprints re-recorded for the three affected examples, per ingredient: ~tNl, ~tND and
~tNlb move because each handover now carries the extra DAD Neighbor Solicitations for the
care-of address; tplx moves because the Binding Update is delayed by one DAD interval
(+1.67 s and +1.36 s at the two handovers measured). Verified identical across two independent
runs. Graphical (tyf) fingerprints left as-is. examples/ipv6/pmipv6 is unaffected.

Note that ipv6/mipv6roaming's ~tNlb in mipv6-refactoring.csv was already stale on
unmodified master
(expected c8dc-27c2, actual 7ed8-bee3), so this re-recording absorbs
that stale value as well as the intended change.

The extra DAD interval per handover is the cost RFC 6275 Section 11.5.3 discusses when it
says a mobile node "preferably SHOULD NOT delay DAD when configuring a new care-of address";
it is not a regression.

Not addressed here

  • The home address is marked tentative while the mobile node is abroad, where its
    uniqueness is irrelevant. It shares the two blanket loops touched here, but the current
    behaviour may be load-bearing by accident: while that address is tentative, packets sourced
    from it are deferred into pendingDadQueue rather than dropped by the topological guard in
    Ipv6.cc, so narrowing the loops needs measuring first.
  • Ipv6::fragmentPostRouting() applies the RFC 4862 tentative-source check only to datagrams
    whose source address it chooses itself; any module that sets the source explicitly bypasses
    it. This pull request removes the MIPv6 trigger, but the general hole remains.

Open in Devin Review

…a handover

Ipv6NeighbourDiscovery::processRaPrefixInfoForAddrAutoConf() has two paths for
an autoconfigured global address. When the interface holds only a link-local
address it assigns the new address as tentative and performs Duplicate Address
Detection (DAD) on it, as RFC 4862 Section 5.4 requires. When it holds more --
which is exactly what a Mobile IPv6 handover looks like, the mobile node having
a link-local address plus its home address -- it marks the existing addresses
tentative, runs DAD on the link-local address alone, and defers the new address
to dadGlobalList.

makeTentativeAddressPermanent() then assigned that address with tentative=false
and cleared the tentative flag on every address of the interface, so the
"start DAD for a tentative global address" loop at the end of the same function
found nothing left to do. The care-of address was therefore put into service
without ever being probed, and the Binding Update registered it with the home
agent. RFC 4862 Section 5.4 names this exact shortcut and rules it out:

    Each individual unicast address SHOULD be tested for uniqueness.  Note
    that there are implementations deployed that only perform Duplicate
    Address Detection for the link-local address and skip the test for the
    global address that uses the same interface identifier as that of the
    link-local address. [...] this kind of "optimization" is NOT RECOMMENDED,
    and new implementations MUST NOT do that optimization.

Assign the address formed from the new prefix as tentative, and clear the
tentative flag on the addresses that were already on the interface before it is
added, so the existing loop starts DAD for it.

Performing the DAD is not enough on its own: the registration used to be started
as soon as the link-local DAD completed, so the Binding Update still left before
the care-of address was verified (1.67 s early in examples/ipv6/mipv6roaming).
Mobile IPv6 sets the source address of that datagram explicitly, and the RFC 4862
guard in Ipv6::fragmentPostRouting() only covers datagrams whose source address
Ipv6 chooses itself, so nothing held it back. Start the MIPv6 protocol when the
care-of address passes its own DAD instead, keeping the dadGlobalList entry until
then. dadHasFailed() already drops that entry, so a care-of address that is
already in use on the visited link is now never registered.

Fingerprints re-recorded for the three affected examples (ipv6/mipv6 Handover and
RouteOptimizationTwoCNs, ipv6/mipv6roaming Roaming): each handover now carries the
extra DAD Neighbor Solicitations for the care-of address (~tNl, ~tND, ~tNlb) and
delays the Binding Update by one DAD interval (tplx). Verified identical across
two independent runs; graphical (tyf) fingerprints left as-is. The ~tNlb value of
ipv6/mipv6roaming in mipv6-refactoring.csv was already stale on unmodified master
(expected c8dc-27c2, actual 7ed8-bee3), so this re-recording also absorbs that.
ipv6/pmipv6 is unaffected.
…Detection

Reuses the Mipv6Network scenario of MIPv6_handover.test: the mobile node boots on
its home link and then moves to the foreign network, where its interface already
holds a link-local address and the home address, so address autoconfiguration
takes the multi-address path.

The test asserts that Duplicate Address Detection (DAD) is started and completes
for the care-of address aaaa:1:66:0:8aa:ff:fe00:8, and that the mobile node only
then registers with its home agent. On unmodified master the run logs a DAD
completion for the link-local address and for the home address, but none for the
care-of address, and sends the Binding Update anyway.

Neighbour discovery logging is enabled for this test, as the module test harness
turns module logging off by default.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ipv6: a care-of address formed at a handover is registered without Duplicate Address Detection

1 participant