diff --git a/WHATSNEW b/WHATSNEW index d0bbfb448c7..58fe4f3b861 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -471,6 +471,10 @@ Notable bug fixes are the following: The HT mode factory now includes band and preamble format in its cache key. A 5 GHz request after an equivalent 2.4 GHz request therefore receives the requested band and timing. Previously, that request could receive the earlier mode. Identical complete requests still reuse one object. +2. A router sends no Router Advertisement while its link-local address is tentative + + A router sent Router Advertisements from its link-local address while Duplicate Address Detection for that address was running, and before it started, although RFC 4861 Section 4.2 requires the source to be the assigned link-local address, Section 6.2.2 allows them only on an interface with an assigned unicast address, and RFC 4862 does not count a tentative address as assigned. Periodic, solicited and Proxy Mobile IPv6 advertisements are now not sent while the link-local address is tentative; a solicited advertisement that is due after the address is verified is sent as before. Simulations with short advertisement intervals, or with advertisements solicited or sent by Proxy Mobile IPv6 while a router is still verifying its address, produce different results, for example in examples/manetrouting/dymo, examples/ipv6/pmipv6 and examples/inet/hierarchical99. + INET-4.7 (July 2026) — feature release -------------------------------------- diff --git a/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc b/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc index 9785d3f5522..75c2e12730b 100644 --- a/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc +++ b/src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc @@ -1258,9 +1258,15 @@ bool Ipv6NeighbourDiscovery::validateRsPacket(Packet *packet, const Ipv6RouterSo void Ipv6NeighbourDiscovery::createAndSendRaPacket(const Ipv6Address& destAddr, NetworkInterface *ie) { - EV_INFO << "Create and send RA invoked!\n"; // Must use link-local addr. See: RFC2461 Section 6.1.2 Ipv6Address sourceAddr = ie->getProtocolData()->getLinkLocalAddress(); + // RFC 4861 Section 4.2: the source is the link-local address assigned to the interface, + // and a tentative address is not assigned (RFC 4862 Section 5.4) + if (ie->getProtocolData()->isTentativeAddress(sourceAddr)) { + EV_INFO << "Link-local address " << sourceAddr << " is tentative, RA not sent\n"; + return; + } + EV_INFO << "Create and send RA invoked!\n"; // This operation includes all options, regardless whether it is solicited or unsolicited. if (ie->getProtocolData()->getAdvSendAdvertisements()) { // if this is an advertising interface @@ -1682,8 +1688,14 @@ void Ipv6NeighbourDiscovery::sendPeriodicRa(cMessage *msg) NetworkInterface *ie = (NetworkInterface *)msg->getContextPointer(); AdvIfEntry *advIfEntry = fetchAdvIfEntry(ie); Ipv6Address destAddr = Ipv6Address("FF02::1"); - createAndSendRaPacket(destAddr, ie); - advIfEntry->numRASent++; + // an RA that is not sent while the link-local address is tentative does not count + // as one of the initial advertisements + if (!ie->getProtocolData()->isTentativeAddress(ie->getProtocolData()->getLinkLocalAddress())) { + createAndSendRaPacket(destAddr, ie); + advIfEntry->numRASent++; + } + else + EV_INFO << "Link-local address is tentative, periodic RA not sent\n"; // RFC 2461, Section 6.2.4 /*Whenever a multicast advertisement is sent from an interface, the timer is @@ -1726,6 +1738,12 @@ void Ipv6NeighbourDiscovery::sendSolicitedRa(cMessage *msg) NetworkInterface *ie = (NetworkInterface *)msg->getContextPointer(); Ipv6Address destAddr = Ipv6Address("FF02::1"); EV_DETAIL << "Testing condition!\n"; + if (ie->getProtocolData()->isTentativeAddress(ie->getProtocolData()->getLinkLocalAddress())) { + // createAndSendRaPacket() sends nothing; processRsPacket() took this RA as the next + // scheduled one, so point back at the periodic RA, or later RSs would be ignored + if (AdvIfEntry *advIfEntry = fetchAdvIfEntry(ie)) + advIfEntry->nextScheduledRATime = advIfEntry->raTimeoutMsg->getArrivalTime(); + } createAndSendRaPacket(destAddr, ie); delete msg; } diff --git a/tests/fingerprint/examples.csv b/tests/fingerprint/examples.csv index 0180b3bb5a0..f8116f25a57 100644 --- a/tests/fingerprint/examples.csv +++ b/tests/fingerprint/examples.csv @@ -165,7 +165,7 @@ # /examples/inet/hierarchical99/, -f .qtenv.ini -c General -r 0 /examples/inet/hierarchical99/, -f networklayer.ini -c IPv4 -r 0, 10000s, a94d-edae/tplx;1f32-e325/~tNl;b138-ee8b/~tND;66c9-cd73/tyf, PASS, EthernetMac Ipv4 -/examples/inet/hierarchical99/, -f networklayer.ini -c IPv6 -r 0, 10000s, 0001-0108/tplx;3960-479e/~tNl;add1-e848/~tND;2c03-abef/tyf, PASS, EthernetMac +/examples/inet/hierarchical99/, -f networklayer.ini -c IPv6 -r 0, 10000s, 2066-f2bb/tplx;a251-4e01/~tNl;0502-0a17/~tND;b45b-90f6/tyf, PASS, EthernetMac /examples/inet/hierarchical99/, -f networklayer.ini -c Generic -r 0, 10000s, 6ae4-6e75/tplx;2209-80ac/~tNl;93bf-6657/tyf, PASS, EthernetMac /examples/inet/hierarchical99/, -f networklayer.ini -c Flooding -r 0, 10000s, 7ba7-5b91/tplx;b0f0-411e/~tNl;2b94-8906/tyf, PASS, EthernetMac /examples/inet/hierarchical99/, -f networklayer.ini -c ProbabilisticBroadcast -r 0, 10000s, 5a54-9779/tplx;1165-a70b/~tNl;760b-abfc/tyf, PASS, EthernetMac @@ -348,16 +348,16 @@ # /examples/manetrouting/dymo/, -f omnetpp.ini -c _IPv4 -r 0 # abstract-config /examples/manetrouting/dymo/, -f omnetpp.ini -c IPv4 -r 0, 10s, 1a85-cb5d/tplx;dfe8-11b9/~tNl;2b10-4dcb/tyf, PASS, wireless adhoc Ipv4 # /examples/manetrouting/dymo/, -f omnetpp.ini -c _IPv6 -r 0 # abstract-config -/examples/manetrouting/dymo/, -f omnetpp.ini -c IPv6 -r 0, 10s, d3ef-c8cf/tplx;fd53-3e15/~tNl;8301-9264/tyf, PASS, wireless adhoc +/examples/manetrouting/dymo/, -f omnetpp.ini -c IPv6 -r 0, 10s, e6da-b593/tplx;145b-4eb1/~tNl;b4b9-189a/tyf, PASS, wireless adhoc # /examples/manetrouting/dymo/, -f omnetpp.ini -c _Generic -r 0 # abstract-config /examples/manetrouting/dymo/, -f omnetpp.ini -c Generic -r 0, 10s, 5f8a-7174/tplx;9713-e7fe/~tNl;5716-c166/tyf, PASS, wireless adhoc # /examples/manetrouting/dymo/, -f omnetpp.ini -c _Multi -r 0 # abstract-config /examples/manetrouting/dymo/, -f omnetpp.ini -c MultiIPv4 -r 0, 10s, b346-3570/tplx;7bce-e34f/~tNl;4782-99e5/tyf, PASS, wireless adhoc Ipv4 -/examples/manetrouting/dymo/, -f omnetpp.ini -c MultiIPv6 -r 0, 10s, d3ef-c8cf/tplx;fd53-3e15/~tNl;3ba7-352e/tyf, PASS, wireless adhoc +/examples/manetrouting/dymo/, -f omnetpp.ini -c MultiIPv6 -r 0, 10s, e6da-b593/tplx;145b-4eb1/~tNl;0adc-8b6a/tyf, PASS, wireless adhoc /examples/manetrouting/dymo/, -f omnetpp.ini -c MultiGeneric -r 0, 10s, 0354-6dd4/tplx;735c-957d/~tNl;31f0-2788/tyf, PASS, wireless adhoc # /examples/manetrouting/dymo/, -f omnetpp.ini -c _Dynamic -r 0 # abstract-config /examples/manetrouting/dymo/, -f omnetpp.ini -c DynamicIPv4 -r 0, 22s, 2f57-3280/tplx;8f96-3d9c/~tNl;c33f-4f8c/tyf, PASS, wireless adhoc Ipv4 -/examples/manetrouting/dymo/, -f omnetpp.ini -c DynamicIPv6 -r 0, 22s, 1e32-4f69/tplx;c684-e25f/~tNl;3469-a611/tyf, PASS, wireless adhoc +/examples/manetrouting/dymo/, -f omnetpp.ini -c DynamicIPv6 -r 0, 22s, cc61-27bb/tplx;c396-a2df/~tNl;749c-1382/tyf, PASS, wireless adhoc /examples/manetrouting/dymo/, -f omnetpp.ini -c DynamicGeneric -r 0, 22s, b68e-dfe3/tplx;9c68-c2d4/~tNl;8c4d-6bc7/tyf, PASS, wireless adhoc # /examples/manetrouting/gpsr/, -f omnetpp.ini -c Random -r 0, # abstract-config @@ -383,7 +383,7 @@ /examples/ipv6/mipv6/, -f omnetpp.ini -c Handover -r 0, 70s, 68ea-9693/tplx;a44c-17bf/~tNl;96ff-ed7c/~tND;44ef-1a45/tyf, PASS, wireless EthernetMac /examples/ipv6/mipv6/, -f omnetpp.ini -c RouteOptimizationTwoCNs -r 0, 60s, bacf-986a/tplx;e6db-28c0/~tNl;805b-8a25/~tND;ed3e-17fa/tyf, PASS, wireless EthernetMac /examples/ipv6/mipv6roaming/, -f omnetpp.ini -c Roaming -r 0, 70s, b275-b584/tplx;28ce-974e/~tNl;dcec-ae59/~tND;afae-2b3c/tyf, PASS, wireless EthernetMac -/examples/ipv6/pmipv6/, -f omnetpp.ini -c General -r 0, 60s, e801-4d1a/tplx;1064-9bd4/~tNl;bd46-d85c/~tND;0277-d784/tyf, PASS, wireless EthernetMac +/examples/ipv6/pmipv6/, -f omnetpp.ini -c General -r 0, 60s, 1ace-6963/tplx;117c-4089/~tNl;ddb3-870d/~tND;62ee-3f4a/tyf, PASS, wireless EthernetMac /examples/mobility/, -f omnetpp.ini -c AnsimMobility -r 0, 10000s, 72f8-5c0b/tplx;0000-0000/~tNl;0000-0000/~tND;7dd1-18eb/tyf, PASS, /examples/mobility, -f omnetpp.ini -c AttachedMobility, 10s, 566c-6355/tplx;0000-0000/~tNl;0000-0000/~tND;fa92-f68c/tyf, PASS, diff --git a/tests/fingerprint/mipv6-refactoring.csv b/tests/fingerprint/mipv6-refactoring.csv index 4e8ebad4ab4..47cb4c95187 100644 --- a/tests/fingerprint/mipv6-refactoring.csv +++ b/tests/fingerprint/mipv6-refactoring.csv @@ -23,14 +23,14 @@ /examples/ipv6/nclients/, -f omnetpp.ini -c PPP_SCTP -r 0, 100s, 3a7c-924c/~tNlb, PASS, # IPv6 networking examples -/examples/inet/hierarchical99/, -f networklayer.ini -c IPv6 -r 0, 10000s, f206-a0e2/~tNlb, PASS, EthernetMac +/examples/inet/hierarchical99/, -f networklayer.ini -c IPv6 -r 0, 10000s, 5836-f09b/~tNlb, PASS, EthernetMac /examples/inet/udpclientserver/, -f omnetpp.ini -c udp_OK_ipv6 -r 0, 10s, 8feb-3936/~tNlb, PASS, /examples/inet/udpclientserver/, -f omnetpp.ini -c udp_Port_Unav_ipv6 -r 0, 10s, 9661-c1f5/~tNlb, PASS, /examples/inet/udpclientserver/, -f omnetpp.ini -c udp_Host_Unav_ipv6 -r 0, 10s, 6360-9ed1/~tNlb, PASS, # DYMO with IPv6 -/examples/manetrouting/dymo/, -f omnetpp.ini -c IPv6 -r 0, 10s, d23a-ce35/~tNlb, PASS, wireless adhoc -/examples/manetrouting/dymo/, -f omnetpp.ini -c MultiIPv6 -r 0, 10s, d23a-ce35/~tNlb, PASS, wireless adhoc +/examples/manetrouting/dymo/, -f omnetpp.ini -c IPv6 -r 0, 10s, cbc4-92bf/~tNlb, PASS, wireless adhoc +/examples/manetrouting/dymo/, -f omnetpp.ini -c MultiIPv6 -r 0, 10s, cbc4-92bf/~tNlb, PASS, wireless adhoc # EIGRP with IPv6 /examples/eigrp/testing_scenario6/, -f omnetpp.ini -c EIGRP-IPv6_exp1_bandwidth-change -r 0, 3min, c645-565e/~tNlb, PASS, eigrp EthernetMac diff --git a/tests/module/IPv6_ND_no_router_advertisement_from_tentative_address.test b/tests/module/IPv6_ND_no_router_advertisement_from_tentative_address.test new file mode 100644 index 00000000000..c20da07b5ae --- /dev/null +++ b/tests/module/IPv6_ND_no_router_advertisement_from_tentative_address.test @@ -0,0 +1,63 @@ +%description: +A router sends no Router Advertisement while its link-local address is tentative: RFC 4861 +Section 6.2.2 forbids Router Advertisements on an interface that is not an advertising +interface, which needs an assigned unicast address, and RFC 4862 Section 5.4 does not count +a tentative address as assigned. + +Topology: router -- host + +The router's Router Advertisement interval is 30-70 ms, shorter than its Duplicate Address +Detection (DAD) for the link-local address. Only the router's Neighbour Discovery logs, so +no "Create and send RA invoked!" line may come before its "DAD completed for address fe80" +line, and at least one must come after it. + +%#-------------------------------------------------------------------------------------------------------------- +%file: test.ned + +import inet.networklayer.configurator.ipv6.Ipv6FlatNetworkConfigurator; +import inet.node.ipv6.Router6; +import inet.node.ipv6.StandardHost6; +import ned.DatarateChannel; + +network TentativeRouterAdvertisementTest +{ + types: + channel ethline extends DatarateChannel + { + delay = 0.1us; + datarate = 10Mbps; + } + submodules: + configurator: Ipv6FlatNetworkConfigurator; + router: Router6; + host: StandardHost6; + connections: + router.ethg++ <--> ethline <--> host.ethg++; +} + +%#-------------------------------------------------------------------------------------------------------------- +%inifile: omnetpp.ini + +[General] +network = TentativeRouterAdvertisementTest +ned-path = .;../../../../src +sim-time-limit = 3s +record-vector-results = false +cmdenv-express-mode = false + +**.router.ipv6.neighbourDiscovery.minIntervalBetweenRAs = 0.03s +**.router.ipv6.neighbourDiscovery.maxIntervalBetweenRAs = 0.07s + +**.router.ipv6.neighbourDiscovery.cmdenv-log-level = info +**.cmdenv-log-level = off + +%#-------------------------------------------------------------------------------------------------------------- +%contains-regex: stdout +DAD completed for address fe80::[0-9a-f:]+ on eth0, address is unique[\s\S]*Create and send RA invoked! +%#-------------------------------------------------------------------------------------------------------------- +%not-contains-regex: stdout +Create and send RA invoked![\s\S]*DAD completed for address fe80 +%#-------------------------------------------------------------------------------------------------------------- +%not-contains: stdout + Error +%#--------------------------------------------------------------------------------------------------------------