Summary
Ipv6NeighbourDiscovery::sendSolicitedNa()
(src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc:1974) decides the Override flag of an
outgoing Neighbor Advertisement (NA) from whether the incoming Neighbor Solicitation (NS)
carried a Source Link-Layer Address option. RFC 4861 keys the flag on whether the outgoing
Neighbor Advertisement (NA) carries a Target Link-Layer Address option. Those are two
different options, on two different messages, travelling in opposite directions.
The function quotes the rule correctly in the comment above the test and then tests the other
option (lines 1999-2013):
/*If the (NS)Target Address is either an anycast address or a unicast
address for which the node is providing proxy service, or the Target
Link-Layer Address option is not included,*/
// TODO: anycast target address handling is not implemented
MacAddress sourceLinkLayerAddress;
if (auto sla = check_and_cast_nullable<const Ipv6NdSourceLinkLayerAddress *>(ns->getOptions().findOption(IPv6ND_SOURCE_LINK_LAYER_ADDR_OPTION)))
sourceLinkLayerAddress = sla->getLinkLayerAddress();
if (sourceLinkLayerAddress.isUnspecified())
// the Override flag SHOULD be set to zero.
na->setOverrideFlag(false);
else
// Otherwise, the Override flag SHOULD be set to one.
na->setOverrideFlag(true);
The same function appends a Target Link-Layer Address option to the Neighbor Advertisement (NA)
unconditionally, nine lines earlier (lines 1990-1993), and both call sites
(processNsForNonTentativeAddress() at line 1923 and processNsWithSpecifiedSrcAddr() at line
1971) go through that code. Anycast targets are an unimplemented TODO and Neighbour Discovery
proxy service is not modelled either, so all three of the RFC's exceptions are out of reach and
the correct value on master is 1 for every solicited Neighbor Advertisement (NA) the model can
produce.
What the standard says
RFC 4861, Section 7.2.4 (Sending Solicited Neighbor Advertisements):
If the Target Address is either an anycast address or a unicast
address for which the node is providing proxy service, or the Target
Link-Layer Address option is not included, the Override flag SHOULD
be set to zero. Otherwise, the Override flag SHOULD be set to one.
Proper setting of the Override flag ensures that nodes give
preference to non-proxy advertisements, even when received after
proxy advertisements, and also ensures that the first advertisement
for an anycast address "wins".
RFC 4861, Section 4.4 (Neighbor Advertisement Message Format), on the O bit:
Override flag. When set, the O-bit indicates that
the advertisement should override an existing cache
entry and update the cached link-layer address.
When it is not set the advertisement will not
update a cached link-layer address though it will
update an existing Neighbor Cache entry for which
no link-layer address is known. It SHOULD NOT be
set in solicited advertisements for anycast
addresses and in solicited proxy advertisements.
It SHOULD be set in other solicited advertisements
and in unsolicited advertisements.
Why it matters
Neighbor Solicitations (NS) reach sendSolicitedNa() without a Source Link-Layer Address option
on two ordinary paths, because createAndSendNsPacket() (line 1781) adds that option only when
the solicitation goes to a solicited-node multicast address and has a specified source:
- Duplicate Address Detection (DAD) defence. A Duplicate Address Detection (DAD) probe is
sent from the unspecified address, and RFC 4861 Section 4.3 forbids a Source Link-Layer
Address option on such a solicitation. The node that already owns the address answers through
processNsForNonTentativeAddress(), and its Neighbor Advertisement (NA) goes out with
Override clear.
- Neighbour Unreachability Detection (NUD).
processNudTimeout() (line 516) sends a
unicast Neighbor Solicitation (NS) to the cached address, so the destination is not a
solicited-node multicast address and no Source Link-Layer Address option is added. Every
answer to a Neighbour Unreachability Detection (NUD) probe therefore also carries Override
clear.
INET honours the flag on receipt. processNaForOtherNceStates() (line 2268) implements RFC 4861
Section 7.2.5: with Override clear and a Target Link-Layer Address that differs from the cached
one, a REACHABLE entry is downgraded to STALE and any other entry is ignored, with the cache left
unchanged. So a wrong Override flag suppresses exactly the cache updates the standard intends to
happen — which is what makes this matter after a link-layer address change, and in any scenario
where a node has to correct a stale entry in a neighbour's cache. It also matters for emulation:
a real host outside the simulation applies the same RFC 4861 Section 7.2.5 rules to INET's
advertisements.
Duplicate Address Detection (DAD) itself keeps working, because the prober only needs an answer
to exist, whatever its flags. That is why the defect has gone unnoticed.
Reproduction
On origin/master (7aef79d5c0), release build, examples/ipv6/mipv6roaming, which reaches the
Neighbour Unreachability Detection (NUD) path twice:
cd examples/ipv6/mipv6roaming
inet -u Cmdenv -c Roaming -r 0 -f omnetpp.ini \
--**.checksumMode='"computed"' --**.fcsMode='"computed"' \
--*.Home_Agent.numPcapRecorders=1 \
--*.Home_Agent.pcapRecorder[0].pcapFile='"ha.pcap"'
tshark -r ha.pcap -Y "icmpv6.type == 136" -T fields \
-e frame.number -e frame.time_relative -e icmpv6.nd.na.flag
Every solicited Neighbor Advertisement (NA) captured at the home agent (R = Router,
S = Solicited, O = Override):
| Frame |
t (s) |
Answers |
Source Link-Layer Address option in the solicitation |
Flags |
O |
| 8 |
2.2338 |
address resolution |
present |
0xe0000000 R+S+O |
1 |
| 18 |
4.2353 |
address resolution |
present |
0x60000000 S+O |
1 |
| 35 |
4.2830 |
address resolution |
present |
0xe0000000 R+S+O |
1 |
| 84 |
9.2377 |
Neighbour Unreachability Detection (NUD) probe |
absent |
0xc0000000 R+S |
0 |
| 234 |
47.1651 |
Neighbour Unreachability Detection (NUD) probe |
absent |
0xc0000000 R+S |
0 |
Frame 83, the unicast Neighbor Solicitation (NS) that frame 84 answers, carries only the Reserved
field and the Target Address — no Source Link-Layer Address option. Frame 84 nevertheless carries
a Target Link-Layer Address option and its target fe80::8aa:ff:fe00:2 is an ordinary unicast
address the home agent owns, so RFC 4861 Section 7.2.4 asks for Override = 1.
The Duplicate Address Detection (DAD) defence path needs a node that joins the link after
another node already holds the address permanently, which no example on master arranges. A small
purpose-built network reproduces it on master alone: host1 and host2 on one Ethernet switch
with the same MAC address, host2 held down and started by a ScenarioManager <startup> at
t = 10 s, and a packet capture on host1.
| Build |
Solicitation |
Answer at t = 10.1799 |
Flags |
unmodified origin/master |
DAD probe from :: at t = 10.1799 |
Neighbor Advertisement (NA) with a Target Link-Layer Address option |
0x00000000, Override 0 |
| with the fix |
same |
same |
0x20000000, Override 1 |
Router clear is correct (host1 is a host) and Solicited clear is correct (the probe came from
the unspecified address). Override clear is the defect.
Not a regression
The condition appears to be original to the function; git log -S over
sourceLinkLayerAddress.isUnspecified() finds only file moves and the 2019 option-model redesign.
Summary
Ipv6NeighbourDiscovery::sendSolicitedNa()(
src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc:1974) decides the Override flag of anoutgoing Neighbor Advertisement (NA) from whether the incoming Neighbor Solicitation (NS)
carried a Source Link-Layer Address option. RFC 4861 keys the flag on whether the outgoing
Neighbor Advertisement (NA) carries a Target Link-Layer Address option. Those are two
different options, on two different messages, travelling in opposite directions.
The function quotes the rule correctly in the comment above the test and then tests the other
option (lines 1999-2013):
The same function appends a Target Link-Layer Address option to the Neighbor Advertisement (NA)
unconditionally, nine lines earlier (lines 1990-1993), and both call sites
(
processNsForNonTentativeAddress()at line 1923 andprocessNsWithSpecifiedSrcAddr()at line1971) go through that code. Anycast targets are an unimplemented
TODOand Neighbour Discoveryproxy service is not modelled either, so all three of the RFC's exceptions are out of reach and
the correct value on master is 1 for every solicited Neighbor Advertisement (NA) the model can
produce.
What the standard says
RFC 4861, Section 7.2.4 (Sending Solicited Neighbor Advertisements):
RFC 4861, Section 4.4 (Neighbor Advertisement Message Format), on the O bit:
Why it matters
Neighbor Solicitations (NS) reach
sendSolicitedNa()without a Source Link-Layer Address optionon two ordinary paths, because
createAndSendNsPacket()(line 1781) adds that option only whenthe solicitation goes to a solicited-node multicast address and has a specified source:
sent from the unspecified address, and RFC 4861 Section 4.3 forbids a Source Link-Layer
Address option on such a solicitation. The node that already owns the address answers through
processNsForNonTentativeAddress(), and its Neighbor Advertisement (NA) goes out withOverride clear.
processNudTimeout()(line 516) sends aunicast Neighbor Solicitation (NS) to the cached address, so the destination is not a
solicited-node multicast address and no Source Link-Layer Address option is added. Every
answer to a Neighbour Unreachability Detection (NUD) probe therefore also carries Override
clear.
INET honours the flag on receipt.
processNaForOtherNceStates()(line 2268) implements RFC 4861Section 7.2.5: with Override clear and a Target Link-Layer Address that differs from the cached
one, a REACHABLE entry is downgraded to STALE and any other entry is ignored, with the cache left
unchanged. So a wrong Override flag suppresses exactly the cache updates the standard intends to
happen — which is what makes this matter after a link-layer address change, and in any scenario
where a node has to correct a stale entry in a neighbour's cache. It also matters for emulation:
a real host outside the simulation applies the same RFC 4861 Section 7.2.5 rules to INET's
advertisements.
Duplicate Address Detection (DAD) itself keeps working, because the prober only needs an answer
to exist, whatever its flags. That is why the defect has gone unnoticed.
Reproduction
On
origin/master(7aef79d5c0), release build,examples/ipv6/mipv6roaming, which reaches theNeighbour Unreachability Detection (NUD) path twice:
Every solicited Neighbor Advertisement (NA) captured at the home agent (R = Router,
S = Solicited, O = Override):
0xe0000000R+S+O0x60000000S+O0xe0000000R+S+O0xc0000000R+S0xc0000000R+SFrame 83, the unicast Neighbor Solicitation (NS) that frame 84 answers, carries only the Reserved
field and the Target Address — no Source Link-Layer Address option. Frame 84 nevertheless carries
a Target Link-Layer Address option and its target
fe80::8aa:ff:fe00:2is an ordinary unicastaddress the home agent owns, so RFC 4861 Section 7.2.4 asks for Override = 1.
The Duplicate Address Detection (DAD) defence path needs a node that joins the link after
another node already holds the address permanently, which no example on master arranges. A small
purpose-built network reproduces it on master alone:
host1andhost2on one Ethernet switchwith the same MAC address,
host2held down and started by aScenarioManager<startup>att = 10 s, and a packet capture on
host1.origin/master::at t = 10.17990x00000000, Override 00x20000000, Override 1Router clear is correct (
host1is a host) and Solicited clear is correct (the probe came fromthe unspecified address). Override clear is the defect.
Not a regression
The condition appears to be original to the function;
git log -SoversourceLinkLayerAddress.isUnspecified()finds only file moves and the 2019 option-model redesign.