Repository navigation
mipv6: intercept packets for an absent mobile node on its home link - #1268
adamgeorge309 wants to merge 3 commits into
Conversation
isOnLinkAddress() scans the interfaces for one whose prefix advertisement list covers the address, then discards which interface that was. The Mobile IPv6 home agent needs that interface to intercept packets on the home link: it joins a multicast group and sends a Neighbor Advertisement there. Return the interface from findOnLinkInterface() and answer the boolean question from it. The scan itself is unchanged. Change: src.networklayer.ipv6.Ipv6RoutingTable | refactor | - | home-agent-proxy-nd
A node that answers Neighbor Solicitations for an address it does not hold -- a proxy, in the sense of RFC 4861 Section 7.2.4 -- had no way to say so: processNsPacket() discards every solicitation whose target is not assigned to the receiving interface. A Mobile IPv6 home agent needs a proxy to intercept packets for an absent mobile node (RFC 6275 Section 10.4.1). For a proxied target, the existing unspecified-source path of processNsPacket() also answers another node's Duplicate Address Detection probe for the address. Solicitations for the address go to its solicited-node multicast address. A node that does not hold the address is not a member of that group, so Ipv6::routeMulticastPacket() would discard them before Neighbor Discovery sees them. addProxyAddress() therefore joins the group, and removeProxyAddress() leaves the group that addProxyAddress() recorded, not one the caller names: leaving a group that was never joined trips an assertion in Ipv6InterfaceData, and the caller may no longer know which interface it named. Two advertisement fields depend on who owns the target: - The Router flag describes the target, not the sender, so for a proxied address it follows what the caller says the proxied node is. A home agent is a router, but the mobile node it proxies for is a host. - The Override flag of a solicited advertisement is cleared for a proxied target, as RFC 4861 Section 7.2.4 says it SHOULD be, so that the owner's own advertisement wins over the proxy's. The code quoted that sentence above a condition that did not implement it. An unsolicited advertisement keeps its set Override flag. sendUnsolicitedNa() uses the target address as the IPv6 source address. For a proxied target that is an address the node does not hold, so it now sources those advertisements from the interface's preferred address, which RFC 6275 Section 10.4.1 requires for the home agent's advertisement. Each unsolicited advertisement is now logged at info level, so that a proxied one can be told apart in the log; nothing logged it before. When a node stops, Ipv6RoutingTable removes only its routes; the interfaces keep their Ipv6InterfaceData and its multicast memberships. So stop() withdraws the proxy records too: one that survived would leave the restarted node answering for an address nothing stands behind. No module calls addProxyAddress() yet, so no simulation changes: the full fingerprint suite (without the graphical tyf ingredient) and the module suite give the same results as before this commit. The first caller, the Mobile IPv6 home agent, is tested with its own change. That module test checks the service end to end: solicitations for the proxied address are answered, and neighbors that cached another link-layer address switch to the proxy's. No test asserts the individual field values (the Router flag, the cleared Override flag of a solicited advertisement, the source address of an unsolicited one), the answer to a Duplicate Address Detection probe, or the withdrawal in stop(). Change: src.networklayer.icmpv6.Ipv6NeighbourDiscovery | behavior.add | test whatsnew | home-agent-proxy-nd
A host on the home link could not reach a mobile node that was away, although the home agent one hop away held a valid binding for it. The host solicited the home address, nobody answered, and its address resolution failed every 3 s. Only off-link traffic reached the mobile node, because it passes through the home agent as the home link's router anyway. No shipped example puts a host on the home link, which hid the defect. RFC 6275 Section 10.4.1: While a node is serving as a home agent for some mobile node, the home agent uses IPv6 Neighbor Discovery [18] to intercept unicast packets on the home link addressed to the mobile node. In order to intercept packets in this way, the home agent MUST act as a proxy for this mobile node and reply to any received Neighbor Solicitations for it. The same section requires the home agent, when it begins serving, to multicast a Neighbor Advertisement onto the home link on the mobile node's behalf, with its own link-layer address, the Router flag cleared and the Override flag set. Mipv6 did neither. Register the home address for proxy service when a home registration is accepted, next to the tunnel that carries the traffic already reaching the home agent, and withdraw it when the binding is de-registered or expires. Only a home registration: the standard keys the proxy check on a Binding Cache entry marked as a home registration. The home link is the interface on which the home address is on-link; a home agent that serves no prefix covering the home address logs a warning and does not proxy. The multicast advertisement goes out only for a binding that did not exist before. A refreshed binding, or one moved to a new care-of address, changes nothing on the home link. The advertisement's set Override flag replaces the mobile node's link-layer address in the home link's neighbor caches at once. Reproduce with the new module test against the unfixed source (check out this commit's parent's src/ with the test file in place, and rebuild): cd tests/module && inet_run_module_tests -m release -f MIPv6_home_agent_proxy_nd It puts two hosts on the home link of tests/module/lib/Mipv6Network and counts the ping replies for requests sent while the mobile node is away and registered (from t=36 s or, for the later host, t=40 s, to t=75.5 s). EarlyHost starts before the mobile node leaves and so caches its link-layer address; LateHost starts afterwards with an empty cache. Unfixed: EarlyHost 0 of 80 replies, LateHost 0 of 72, and LateHost reports "Address Resolution has failed". Fixed: 80 of 80 and 72 of 72. The test also asserts the multicast advertisement and the withdrawal when the mobile node comes home. The three Mobile IPv6 example fingerprint rows (Handover, RouteOptimizationTwoCNs, Roaming) move on every packet-level ingredient (tplx, ~tNl and ~tND in examples.csv, ~tNlb in mipv6-refactoring.csv). The cause is the multicast advertisement, one per new binding: with only the sendUnsolicitedNa() call removed, all four ingredients return to their recorded values. The home access point bridges the advertisement onto the wireless medium, so IEEE 802.11 timing moves and everything after it shifts. The graphical tyf values of these rows were already stale on master: a run there gives 04da-4143, 2f8e-79f9 and a8a6-63b4 against the recorded 44ef-1a45, ed3e-17fa and afae-2b3c. With the sendUnsolicitedNa() call removed, tyf also returns to exactly these master values, so this commit moves tyf from them to the new values. tyf is not maintained on master (the suites run with -F tyf), so the stale values get no commit of their own. The Proxy Mobile IPv6 example row does not move, so its stale tyf is left as it is. Not repaired here: RFC 6275 Section 10.3.1 also requires Duplicate Address Detection for the home address before the Binding Acknowledgement (#1194), and Section 10.4.1 requires proxying for the mobile node's link-local address when the Binding Update sets the Link-Layer Address Compatibility flag. Change: src.networklayer.mipv6.Mipv6 | behavior.change.fix | fingerprint test whatsnew | home-agent-proxy-nd
There was a problem hiding this comment.
Devin Review found 3 potential issues.
2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)
| if (!existingBinding) | ||
| ipv6nd->sendUnsolicitedNa(homeLink, HoA); |
There was a problem hiding this comment.
🔴 Home-link takeover advertisement skipped after registration change
When a home registration replaces a non-home binding, existingBinding suppresses the takeover advertisement. The binding cache also stores non-home registrations. Neighbors retain the absent mobile node's link-layer address and cannot reach it until their caches recover.
Learn more
A home agent accepts a Binding Update without the Home Registration flag and stores it through addOrUpdateBC. existingBinding tests only whether that address exists in the cache, not whether its entry already represents a home registration. When a later home registration arrives for the same address, it creates the proxy but skips the advertisement that replaces the mobile node's old link-layer address in neighbors' caches.
Example: A home-link host caches mobile node M's MAC. The home agent first receives a non-home binding for M's address, then M registers that address as its home address while away. The proxy answers new solicitations, but the host continues sending to M's old MAC.
Recommended fix: Capture the previous entry's getHomeRegistration(HoA) before addOrUpdateBC, and announce when the prior entry was not a home registration. Preserve the existing refresh behavior for an already active home registration.
Was this helpful? React with 👍 or 👎 to provide feedback.
| return; | ||
| } | ||
|
|
||
| ipv6nd->addProxyAddress(homeLink, HoA); |
There was a problem hiding this comment.
🟡 Old home link keeps proxying moved address
When a home prefix moves between interfaces, startInterceptingForHomeAddress adds the new proxy without withdrawing the old one. The home agent keeps answering solicitations on the former home link, where its tunnel still intercepts traffic.
Learn more
Proxy registrations are keyed by interface and address in proxyAddresses. findOnLinkInterface can select a different interface after advertised prefixes are changed. A refreshed Binding Update calls addProxyAddress for the new interface, but the previous registration and multicast membership remain; the home agent answers Neighbor Solicitations on both links.
Example: The home agent initially advertises M's home prefix on eth1 and later moves it to eth2. A subsequent Binding Update adds proxying on eth2 while eth1 still answers solicitations for M's address.
Recommended fix: Before changing the home-link proxy, withdraw the previous interface's proxy registration for that address, or make the proxy update operation atomically move the registration to the selected interface. Retain the no-extra-advertisement behavior only when the existing proxy is already on the selected interface.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (!existingBinding) | ||
| ipv6nd->sendUnsolicitedNa(homeLink, HoA); |
There was a problem hiding this comment.
🟡 Takeover advertisement precedes home-address verification
For a new binding, startInterceptingForHomeAddress multicasts the override advertisement before the delayed acknowledgement and any address check. Neighbors can replace a resident node's MAC with the home agent's before it establishes that the address is free.
Learn more
A new home binding takes the existingBinding == false path. processBUMessage delays its Binding Acknowledgement by one second for the intended duplicate-address check, while the new proxy registration and unsolicited Neighbor Advertisement happen immediately. The advertisement sets Override, so a home-link neighbor with an existing cache entry can replace its entry before the address has been checked. The duplicate-address check is not implemented yet, but the new takeover action makes this pre-existing gap affect neighbors.
Example: A second node still owns the requested home address on the home link. The home agent announces its own MAC for that address immediately, and a neighbor replaces its existing MAC mapping before the delayed acknowledgement.
Recommended fix: Defer starting proxy service and sending the takeover advertisement until the new binding's home-link duplicate check has completed successfully. Keep the acceptance and failure paths consistent so a failed check does not leave a proxy or tunnel behind.
Was this helpful? React with 👍 or 👎 to provide feedback.
A Mobile IPv6 (MIPv6) home agent now acts as a Neighbor Discovery proxy for an absent mobile node's home address, as RFC 6275 Section 10.4.1 requires, so hosts on the home link reach the mobile node while it is away. INET had no proxy Neighbor Discovery, so the fix needs a new service in
Ipv6NeighbourDiscoverybefore the home agent can use it. That service is a new feature.Closes #1267
The problem
Ipv6NeighbourDiscovery::processNsPacket()discards a Neighbor Solicitation whose target is not an address of the receiving interface, and the home agent is not a member of the home address's solicited-node multicast group. Off-link traffic reaches the mobile node only because the home agent is also the home link's router. A host on the home link resolves the home address with Neighbor Discovery, gets no answer, and cannot send at all.examples/ipv6/mipv6Handoverwith oneStandardHost6added on the home link, pinging the home address while the mobile node is away (t=25 s to 39 s, run 0; the files are in the issue):CN[0](off-link) repliesOn master the home-link host's address resolution fails at t=28, 31, 34, 37 and 40 s. The one-reply difference for
CN[0]is the timing shift described under Verification.The commits
ipv6: refactor:extractsIpv6RoutingTable::findOnLinkInterface()fromisOnLinkAddress(), which found the interface and discarded it. Behavior-preserving.icmpv6: add:addsIpv6NeighbourDiscovery::addProxyAddress()andremoveProxyAddress(), proxy service in the sense of RFC 4861 Section 7.2.4. No module callsaddProxyAddress()in this commit, and no fingerprint moves.mipv6: fix:starts the proxy service when the home agent accepts a home registration, multicasts one Neighbor Advertisement (Override set, Router cleared) for a new binding, and stops the service when the binding is de-registered or expires.Architectural surface
Ipv6NeighbourDiscovery::addProxyAddress()/removeProxyAddress()and non-virtualIpv6RoutingTable::findOnLinkInterface(); protected virtualisProxyAddress()/isProxyTargetRouter(). The virtuals follow the class, whose other members are virtual too. All additions; nothing existing changes signature.Relationship to open pull requests
Ipv6NeighbourDiscovery::sendSolicitedNa(). icmpv6: set the Override flag of a solicited Neighbor Advertisement #1245 always sets the flag and states that proxy service is not modelled. Resolution: keep icmpv6: set the Override flag of a solicited Neighbor Advertisement #1245's comment, setna->setOverrideFlag(!proxy)and drop its sentence about proxy service.startInterceptingForHomeAddress()into mipv6: verify the home address before acknowledging a home registration #1195's successful-probe path;stopInterceptingForHomeAddress()on its status-134 path;findHomeLinkInterface()withfindOnLinkInterface(), as mipv6: verify the home address before acknowledging a home registration #1195's comment on that function anticipates.Proposed landing order: #1245 and #1195 first, then this branch rebased as described. #1247 is independent.
Verification
The new module test
tests/module/MIPv6_home_agent_proxy_nd.testputs two hosts on the home link ofMipv6Networkintests/module/lib, a copy of the example network kept for the module tests. It counts ping replies for requests sent while the mobile node is away and registered (EarlyHost from t=36 s, LateHost from its start at t=40 s, both to t=75.5 s), and asserts the multicast advertisement and the withdrawal on return.Commands, run on master 4eb3bb4 and on this branch unless marked; the builds exit 0:
Results compared by name against the same commands on unmodified master 4eb3bb4:
-F tyf): master 1711 pass, 0 failures, 63 errors (disabled optional features and the ethernet-nonstandardspeed row). This branch: the same 63 errors, and the 3 rows below move; after re-recording, the-m mipv6run passes them.-f MIPv6: 12 of 12 pass on this branch, the new test included.tests/protocol/ipv6: 26 of 27 on both (Rfc8200OverlappingFragmentsfails on master).tests/protocol/nd: 22 of 37 on both, the same 15 failures.check-architecture.sh src/inet/networklayer: PASS (exit 0) on both, identical output.check-architecture.sh,check-naming.shandcheck-interfaces.shexit 1 on master and on this branch with byte-identical output; none of their hits is in a file this branch touches.check-source-seals.sh: passed (exit 0), no sealed file touched.check-commits.shandcheck-classification.sh: PASS (exit 0).-F tyf) and release module suites give master's results by name. Commits 1 and 2 build, and the-m mipv6run gives master's values at each.Fingerprint rows re-recorded in commit 3:
examples/ipv6/mipv6HandoverandRouteOptimizationTwoCNsandexamples/ipv6/mipv6roamingRoaming, inexamples.csv(packet-level ingredients tplx, ~tNl, ~tND and the graphical ingredient tyf) andmipv6-refactoring.csv(~tNlb). With only thesendUnsolicitedNa()call removed, every packet-level ingredient of the three rows returns to its recorded value, so the multicast advertisement is the whole cause. The home access point bridges it onto the wireless medium, which shifts IEEE 802.11 timing and everything after it.The tyf values of the three rows were already stale on master: the
-m mipv6run measures 04da-4143, 2f8e-79f9 and a8a6-63b4 there against the recorded 44ef-1a45, ed3e-17fa and afae-2b3c. With thesendUnsolicitedNa()call removed, tyf returns to exactly these master values too, so commit 3 moves tyf from them to 1ccb-c62a, 38b5-3e5d and 0da4-da9b, recorded from the same run on this branch. tyf is not maintained on master (the suites run with-F tyf), so the stale values get no commit of their own; they are re-recorded with the rest of each cell. The Proxy Mobile IPv6 example row does not move, so its stale tyf (05f8-fee3 against 0277-d784 on master) is left as it is.The module test checks the proxy service end to end. No test asserts its individual field values (the Router flag, the cleared Override flag of a solicited advertisement, the source address of an unsolicited one), the answer to a Duplicate Address Detection probe, or the withdrawal in
stop().Not addressed here