Skip to content

ipv6: a host copies the Router Advertisement MTU option into LinkMTU but never sends with it #1248

Description

@adamgeorge309

Summary

A host copies the MTU option of a Router Advertisement (RA) into the LinkMTU host variable and then never reads LinkMTU when it sends. The copy is in Ipv6NeighbourDiscovery::processRaForRouterUpdates():

// src/inet/networklayer/icmpv6/Ipv6NeighbourDiscovery.cc:1532
    if (auto mtuOption = check_and_cast_nullable<const Ipv6NdMtu *>(ra->getOptions().findOption(IPv6ND_MTU))) {
        uint32_t mtu = mtuOption->getMtu();
        if (mtu >= IPv6_MIN_MTU) {
            EV_INFO << "RA MTU option: setting link MTU to " << mtu << "\n";
            ie->getProtocolDataForUpdate<Ipv6InterfaceData>()->setLinkMtu(mtu);
        }

Ipv6InterfaceData::getLinkMtu() (src/inet/networklayer/ipv6/Ipv6InterfaceData.h:638) has no caller in src or tests. The IPv6 output path fragments to the interface MTU only:

// src/inet/networklayer/ipv6/Ipv6.cc:1059
    int mtu = ie->getMtu();

    // check if datagram does not require fragmentation
    if (packet->getDataLength() <= B(mtu)) {
        sendDatagramToOutput(packet, ie, nextHopAddr);
        return;
    }

The copy also checks only the lower bound (mtu >= IPv6_MIN_MTU), not the upper bound that RFC 4861 sets.

Two defaults make the obvious fix unsafe. Every INET router advertises 1280 bytes, and every host starts LinkMTU at 1280 bytes before any RA arrives:

// src/inet/networklayer/ipv6/Ipv6RoutingTable.ned:101
        int advLinkMtu = default(1280); // MTU option in RAs (1280 = IPv6 minimum MTU, 0 = don't include)
// src/inet/networklayer/ipv6/Ipv6InterfaceData.cc:201
    hostVars.linkMTU = IPv6_MIN_MTU;
// src/inet/networklayer/ipv6/Ipv6InterfaceData.cc:214
    rtrVars.advLinkMTU = IPv6_MIN_MTU;

The RA sender also appends the MTU option unconditionally (Ipv6NeighbourDiscovery.cc:1307-1311), so advLinkMtu = 0 does not omit it, contrary to the NED comment.

What the standard says

RFC 4861 (Neighbor Discovery for IP version 6), Section 6.3.4, Processing Received Router Advertisements:

If the MTU option is present, hosts SHOULD copy the option's value
into LinkMTU so long as the value is greater than or equal to the
minimum link MTU [IPv6] and does not exceed the maximum LinkMTU value
specified in the link-type-specific document (e.g., [IPv6-ETHER]).

Section 6.3.2, Host Variables:

LinkMTU The MTU of the link.
Default: The valued defined in the specific
document that describes how IPv6 operates over
the particular link layer (e.g., [IPv6-ETHER]).

Section 4.6.4, MTU, on the purpose of the option:

The MTU option is used in Router Advertisement
messages to ensure that all nodes on a link use the
same MTU value in those cases where the link MTU is
not well known.

Section 6.2.1, Router Configuration Variables:

AdvLinkMTU The value to be placed in MTU options sent by the
router. A value of zero indicates that no MTU
options are sent.

           Default: 0

Section 6.2.3, Router Advertisement Message Content:

o MTU option: the interface's configured AdvLinkMTU value if
the value is non-zero. If AdvLinkMTU is zero, the MTU
option is not sent.

LinkMTU is the MTU of the link, which a host sends with. It starts at the link-type value, not at 1280, and an advertised value is accepted only between the IPv6 minimum and the link maximum. By default a router sends no MTU option.

Why it matters

A router cannot lower the MTU its hosts use, which is the case the option exists for. The log line and the module test suggest the opposite: tests/module/IPv6_RA_MTU_option.test checks only for the text RA MTU option: setting link MTU to.

Reproduction on master (49e1fa0945, release build): the network of tests/module/IPv6_RA_MTU_option.test (one Router6, one StandardHost6, Ethernet with a 1500-byte interface MTU), plus a ping from the host with a 1400-byte payload, started at 4 s:

*.host.numApps = 1
*.host.app[0].typename = "PingApp"
*.host.app[0].destAddr = "router(ipv6)"
*.host.app[0].packetSize = 1400B
*.host.app[0].startTime = 4s
*.host.app[0].count = 1
3.097265257161 MtuTestNetwork.host.ipv6.neighbourDiscovery: RA MTU option: setting link MTU to 1280
4 MtuTestNetwork.host.ipv6.neighbourDiscovery: Packet (inet::Packet)ping0 (1448 B) (inet::SequenceChunk) length = 1448 B arrived from Ipv6 module.
4.534852467138 MtuTestNetwork.host.eth[0].mac: Received (inet::Packet)ping0 (1466 B) (inet::SequenceChunk) length = 1466 B from upper layer.
4.537211067138 MtuTestNetwork.host.app[0]: Ping reply #0 arrived, rtt=0.537211067138

The host sets LinkMTU to 1280 and then sends a 1448-byte IPv6 datagram unfragmented; the run logs no IPv6 fragmentation. With *.router.ipv6.routingTable.advLinkMtu = 9000, the host logs setting link MTU to 9000 on the same 1500-byte Ethernet link, so an advertised value above the link maximum is also accepted.

Fix options

Both options include the same host-side changes:

  • start LinkMTU at the interface MTU instead of IPv6_MIN_MTU (Ipv6InterfaceData.cc:201);
  • in processRaForRouterUpdates(), ignore an advertised value above the interface MTU;
  • in Ipv6::fragmentAndSend(), let a host (not a router) fragment to the smaller of the interface MTU and LinkMTU;
  • extend tests/module/IPv6_RA_MTU_option.test to check that a large datagram is fragmented to an advertised value below the interface MTU, and that a value above it is ignored.

They differ in what a router advertises by default.

(A) Change the default to 0, the RFC 4861 Section 6.2.1 default. advLinkMtu = default(0) and rtrVars.advLinkMTU = 0, and the RA sender omits the MTU option when the value is 0 (Section 6.2.3). Packet sizes do not change: without an MTU option, hosts keep sending at the interface MTU as they do today. Every RA becomes 8 bytes shorter, so fingerprints move in every simulation where an IPv6 router sends RAs (the IPv6, Mobile IPv6 (MIPv6) and Proxy Mobile IPv6 (PMIPv6) suites among them). Only configurations that set advLinkMtu get the new host behaviour.

(B) Keep the default of 1280 and let hosts honour it. RAs are unchanged, but every IPv6 host behind an INET router then fragments every datagram above 1280 bytes, on every link type. Packet counts, sizes and timing change wherever a host sends datagrams larger than 1280 bytes, so fingerprints and statistical results move across the suites. This keeps a default that differs from the one RFC 4861 specifies.

Neither blast radius has been measured. A pull request will follow once the maintainers choose an option.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions