Skip to content

icmpv6: send no RA while the link-local address is tentative - #1340

Open
adamgeorge309 wants to merge 1 commit into
masterfrom
topic/gy/ipv6-nd-no-tentative-source
Open

adamgeorge309 wants to merge 1 commit into
masterfrom
topic/gy/ipv6-nd-no-tentative-source

Conversation

@adamgeorge309

Copy link
Copy Markdown
Contributor

A router sent Router Advertisements (RA) from its link-local address while Duplicate Address Detection (DAD) for that address was running, and before DAD started. RFC 4861 Section 6.2.2 allows RAs only on an interface that has a unicast address assigned, Section 4.2 makes the assigned link-local address the source, and RFC 4862 Section 5.4 does not count a tentative address as assigned. The router now sends no RA, periodic, solicited or the unsolicited one of Proxy Mobile IPv6 (PMIPv6), while its link-local address is tentative; such an RA is dropped, not deferred.

Risk: with a periodic RA interval shorter than link-local DAD (about 1 s plus the boot delay), routers advertise only after DAD; with the default 200-600 s interval only the solicited RAs that are due during DAD and the PMIPv6 unsolicited RA are affected. The hosts get the next solicited RA on the link; a PMIPv6 mobile node gets its prefix with the next periodic RA, which the PMIPv6 example sends within seconds, but which comes 200-600 s after start-up with the default interval. Eight fingerprint rows change and are recorded here: examples/manetrouting/dymo IPv6, MultiIPv6 and DynamicIPv6, examples/ipv6/pmipv6 General and examples/inet/hierarchical99 IPv6 (hierarchical99 IPv6 and dymo IPv6 and MultiIPv6 in both examples.csv and mipv6-refactoring.csv); five statistical baselines need re-recording after the merge.

Closes #1339

One commit: icmpv6: fix: send no RA while the link-local address is tentative.

The problem

Ipv6RoutingTable assigns the link-local address as tentative at initialization (src/inet/networklayer/ipv6/Ipv6RoutingTable.cc:264-265); DAD starts after routerBootupTime (default uniform(0s, 0.3s)). Ipv6NeighbourDiscovery::start() creates the periodic RA timer for every interface whose AdvSendAdvertisements flag is set (src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc:2652-2655 on master), and createAndSendRaPacket() (lines 1259-1263) takes getLinkLocalAddress() as the source, which returns a tentative address too (Ipv6InterfaceData.cc:406-413). Solicited RAs go through createAndSendRaPacket() as well.

RFC 4861 Section 4.2, Router Advertisement, Source Address: "MUST be the link-local address assigned to the interface from which this message is sent." Section 6.2.2:

A router MUST NOT send Router Advertisements out any interface that is
not an advertising interface.

with "advertising interface" defined as one "that has at least one unicast IP address assigned to it and whose corresponding AdvSendAdvertisements flag is TRUE". RFC 4862 Section 5.4: "A tentative address is not considered "assigned to an interface" in the traditional sense."

The fix

  • createAndSendRaPacket() returns without sending, and logs Link-local address ... is tentative, RA not sent instead of Create and send RA invoked! (sendPeriodicRa() logs periodic RA not sent before it gets there), while the link-local address is tentative. Every RA goes through it: sendPeriodicRa(), sendSolicitedRa() and sendUnsolicitedRa(), which Pmipv6 calls after a Proxy Binding Acknowledgement (src/inet/networklayer/pmipv6/Pmipv6.cc:463).
  • sendSolicitedRa(), when the link-local address is still tentative at the time the solicited RA is due, sets nextScheduledRATime back to the arrival time of the periodic RA timer. processRsPacket() had set it to the solicited RA's time, and it schedules an RA for a later Router Solicitation (RS) only if that RA comes before nextScheduledRATime; after the dropped RA, the past time would make the router ignore every later RS on the interface, and the host would get no RA until the first periodic one, 200-600 s after start-up with the default interval. A solicited RA that is due after DAD has completed is sent as before, although the RS arrived during DAD.
  • sendPeriodicRa() checks the same condition before sending and increments numRASent only for an RA it sent, so the MAX_INITIAL_RTR_ADVERTISEMENTS initial advertisements of Section 6.2.4 count from the end of DAD. The timer keeps running with its usual random interval.

Not changed: an interface whose link-local address is unspecified (getLinkLocalAddress() finds none) behaves as before; isTentativeAddress() is false for it. No C++ interface, Network Description (NED) parameter, message field or feature descriptor changes.

Verification

Reproduction: a Router6 and a StandardHost6 on one 10 Mb/s link (Ipv6FlatNetworkConfigurator), the router's RA interval 30-70 ms (minIntervalBetweenRAs = 0.03s, maxIntervalBetweenRAs = 0.07s), 3 s, the router's Neighbour Discovery log:

Master This change
Create and send RA invoked! 58 27
of them before DAD completed for address fe80::8aa:ff:fe00:1 24, the first at 0.054110534815 s 0
link-local DAD completed at 1.314096661681 s 1.641765394178 s

The first RA with this change leaves at 1.657113533746 s. DAD completes at a different time because all modules draw from one random number generator and the host handles fewer RAs. The test tests/module/IPv6_ND_no_router_advertisement_from_tentative_address.test runs this network and checks that no Create and send RA invoked! comes before the router's link-local DAD completed line and that one comes after it; it fails on master and passes with this change.

The shipped examples whose fingerprints change, run on master and with this change:

Configuration Master This change
examples/manetrouting/dymo IPv6, 10 s, Neighbour Discovery log 3992 RAs, 655 of them before the sending host's own link-local DAD completed; ping replies 0 of 7 3352 RAs, 0 before; ping replies 0 of 7
examples/ipv6/pmipv6 General, 60 s ping replies 102 of 105 102 of 105; mag1's unsolicited RA after the Proxy Binding Acknowledgement at 0.816 s and 4 periodic RAs of lma and mag2 (interval 1-3 s) held back during DAD
examples/inet/hierarchical99 IPv6 (networklayer.ini), 10000 s for the pings, 30 s for the Neighbour Discovery log ping replies 0 of 1 0 of 1; in the first 30 s, 2 solicited RAs that were due during DAD held back; all 72 hosts get an RA, as on master, the 6 on the two links concerned 1.16 s and 0.79 s later, from the next solicited RA there

Release build (make MODE=release in the root and tests/module/lib), each suite run on master 41eee1d619 and with this change:

Command Master This change
tests/fingerprint: ./fingerprinttest -s -F tyf 1774 run, 5 failures, 62 errors, 1 expected error before the new fingerprints were recorded: the same 5 failures with the same computed fingerprints, the same errors, and 8 more failures, the rows named above (hierarchical99 IPv6 in examples.csv and mipv6-refactoring.csv, dymo IPv6 and MultiIPv6 in both, dymo DynamicIPv6 and pmipv6 General in examples.csv); with them, the 21 rows of these three directories pass with every ingredient including tyf (command below)
tests/module: inet_run_module_tests -m release --no-build -l ERROR 653 run, 363 pass, 290 fail 365 pass, 288 fail: the same failing tests by name, without Ieee80211BlockAckVariant_1 and the test that is not on this branch; the new test passes

Ieee80211BlockAckVariant_1 fails and passes on master too (it passed in 7 runs after failing in 2, one of them with master's Ipv6NeighbourDiscovery.cc), so its result here does not come from this change. With the recorded values, ./fingerprinttest -s -m 'dymo|hierarchical99|pmipv6' passes its 21 rows. The 5 fingerprint failures are rows of mipv6-refactoring.csv whose recorded ~tNlb fingerprints are stale on master; the 62 errors are configurations whose optional features are not built. Of the 290 module failures on master, 274 are tcp_* tests, one is a test that is not on this branch (IPv6_ND_solicitation_ends_address_resolution, #1337), and 15 are ConvolutionalCoder12, ConvolutionalCoder34, DimensionalMediumAnalogModel_PrintAttenuation_1, EtherHost_lifecycle, ExternalProcess_3, Ieee80211BitDomain, Ieee80211BlockAckVariant_1, Ieee80211SymbolDomain, Ieee8021d-Rstp, Ieee8021d-Stp, IPv6_packet_too_big, LogNormalShadowing_Correlated_4, MIPv6_tcp_handover, PacketGate_1, UDPSocket_1; all of them except Ieee80211BlockAckVariant_1 fail with this change as well.

Debug build (make MODE=debug in the root and tests/module/lib, exit 0, no compiler warning in Ipv6NeighbourDiscovery.cc): inet_run_module_tests -m debug --no-build -l ERROR passes the new test and IPv6_NUD_stale_to_probe.

Statistical baselines (the separate statistics repository at 8fdf7f5): the scalars of pmipv6 General, hierarchical99 IPv6 and dymo IPv6 computed on master all equal the baseline scalar at the same position (840, 13414 and 2300 scalars; the baselines record more); with this change part of them differ in each. These three and dymo MultiIPv6 and DynamicIPv6 belong in a commit to the statistics repository after this merges, naming this one. Not verified by a test: the solicited and the PMIPv6 paths; the examples above exercise them.

Gates: check-pull-request.sh --base origin/master (commits, classification, includes, NED parameters, description), check-source-seals.sh --base origin/master and check-architecture.sh src/inet/networklayer/icmpv6 pass.

Relationship to other pull requests

#1181 makes the interface an advertising interface at the end of link-local DAD for the initial-interval clamp of Section 6.2.4, in makeTentativeAddressPermanent(); this change makes sending follow the same rule. The two edit different lines of Ipv6NeighbourDiscovery.cc. Other open pull requests change the same fingerprint rows, so that whichever merges later re-records them; among the Neighbour Discovery ones: #1139, #1162, #1181, #1183 and #1260 (hierarchical99 IPv6, and in #1183 and #1260 also dymo and pmipv6 rows) and #1285 (dymo, pmipv6); pmipv6 General is also changed by Proxy Mobile IPv6 and Mobile IPv6 pull requests such as #1243, #1262 and #1322. #1139 adds the same nextScheduledRATime assignment to sendSolicitedRa() for every solicited RA (#1138), so the two conflict there; whichever merges second keeps the assignment unconditional. #1297 exempts Neighbour Discovery messages from its hold of datagrams with a tentative source; after this change no RA has one. #1322, #1324, #1326, #1328, #1334 and #1337 also add an entry under "Notable bug fixes" in WHATSNEW; whichever merges later renumbers. #1337 also changes examples.csv, in other rows.

A router sent Router Advertisements (RA) from its link-local address
while Duplicate Address Detection (DAD) for that address was running,
and before DAD started: start() creates the periodic RA timer whatever
the state of the addresses, and createAndSendRaPacket() took the
link-local address as the source without checking it. RFC 4861 Section
6.2.2 forbids RAs on an interface that has no unicast address assigned,
Section 4.2 makes the assigned link-local address the source, and RFC
4862 Section 5.4 does not count a tentative address as assigned.

createAndSendRaPacket() now sends nothing while the link-local address
is tentative, which covers periodic RAs, solicited RAs and the
unsolicited RA that Pmipv6 sends after a Proxy Binding Acknowledgement.
An RA not sent is dropped, not deferred. When sendSolicitedRa() drops
one, it points nextScheduledRATime back at the periodic RA, because
processRsPacket() ignores every Router Solicitation (RS) that would be
answered later than that time, and the dropped RA would otherwise have
left the time in the past. sendPeriodicRa() keeps its timer running
but does not count an RA it did not send, so the first
periodic RA sent after DAD completes counts as the first of the initial
advertisements of Section 6.2.4.

With a 30-70 ms RA interval, a router sent 24 of its 58 RAs in 3 s
before DAD of its link-local address completed; after this commit it
sends none before that.

tests/module/IPv6_ND_no_router_advertisement_from_tentative_address.test
runs that case and checks that no RA comes before DAD completes; it
fails before this commit.

The fingerprints of examples/manetrouting/dymo IPv6, MultiIPv6 and
DynamicIPv6 (RAs every 30-70 ms), examples/ipv6/pmipv6 General (RAs
every 1-3 s, and the Proxy Mobile IPv6 RA) and
examples/inet/hierarchical99 IPv6 (solicited RAs) change, and this
commit records them; their statistical baselines change too.

Change: src.networklayer.icmpv6.Ipv6NeighbourDiscovery | behavior.change.fix | test fingerprint statistical whatsnew

This branch has not been deployed

No deployments
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 router sends Router Advertisements from its link-local address while Duplicate Address Detection for it is still running

1 participant