ipv6: verify a care-of address before registering it with the home agent - #1141
Open
adamgeorge309 wants to merge 2 commits into
Open
ipv6: verify a care-of address before registering it with the home agent#1141adamgeorge309 wants to merge 2 commits into
adamgeorge309 wants to merge 2 commits into
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 alreadyholds. 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 handoverlooks 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 withtentative = falseand 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, countingDAD completed for addressforMN[0]:fe80::8aa:ff:fe00:b2001:db8:0:2:8aa:ff:fe00:b2001:db8:0:4:8aa:ff:fe00:b2001:db8:0:6:8aa:ff:fe00:bThe 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:
The fix
Perform the DAD. The blanket
permanentlyAssign()loop now runs before the addressformed 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
dadGlobalListentry being kept until then.dadHasFailed()already erasesthat entry, so a care-of address that is already in use is never registered at all.
Each handover now reads:
Why both halves are needed
Verification
tests/module/MIPv6_care_of_address_DAD.testis added as a regression test. It fails onunmodified 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/masterbefore any change was made, anddiffed afterwards.
-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.testandIPv6_packet_too_big.testfail identically on unmodified master, so they are pre-existingand out of scope.
-m ipv6 -F tyf): 27 tests, all pass.Fingerprints re-recorded for the three affected examples, per ingredient:
~tNl,~tNDand~tNlbmove because each handover now carries the extra DAD Neighbor Solicitations for thecare-of address;
tplxmoves 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/pmipv6is unaffected.Note that
ipv6/mipv6roaming's~tNlbinmipv6-refactoring.csvwas already stale onunmodified master (expected
c8dc-27c2, actual7ed8-bee3), so this re-recording absorbsthat 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
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
pendingDadQueuerather than dropped by the topological guard inIpv6.cc, so narrowing the loops needs measuring first.Ipv6::fragmentPostRouting()applies the RFC 4862 tentative-source check only to datagramswhose 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.