[Bug 296656] IPv6 ND SIOCSIFINFO_IN6 cannot raise stale nd_linkmtu above already-clamped in6_ifmtu()

[email protected] Fri, 10 Jul 2026 01:29:35 +0000
Newsgroups gmane.os.freebsd.bugs
Message-ID <[email protected]/bugzilla/>
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=296656

            Bug ID: 296656
           Summary: IPv6 ND SIOCSIFINFO_IN6 cannot raise stale nd_linkmtu
                    above already-clamped in6_ifmtu()
           Product: Base System
           Version: 16.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Many People
          Priority: ---
         Component: kern
          Assignee: [email protected]
          Reporter: [email protected]

Created attachment 272677
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=272677&action=edit
nd6_linkmtu_ioctl.patch

I found an IPv6 ND link-MTU recovery problem on FreeBSD 16.0-CURRENT.

  System:

  FreeBSD 16.0-CURRENT
  Interface: rge0
  Driver: if_rge
  Interface MTU: 4074

  The machine is directly connected to another FreeBSD machine over Ethernet.
The physical link and driver can pass larger frames; for example,
  large IPv6 pings succeed.

  Problem state:

  ifconfig rge0

  shows:

  rge0 ... mtu 4074

  but:

  ndp -i rge0

  shows:

  linkmtu=1500, maxmtu=4074

  This affects TCP. A packet capture of an IPv6 TCP handshake showed the peer
sending mss 4014, but this machine replied with:

  options [mss 1440,...]

  even though the interface MTU was 4074 and large IPv6 ping packets worked.

  I tried disabling RA, removing the autoconf global IPv6 address, flushing NDP
entries, flushing prefixes/default routers, disabling/re-enabling
  IPv6 on the interface, and changing MTU 1500 -> 4074 -> 9000 -> 4074. The
effective ND link MTU stayed stuck at 1500.

  The kernel source appears to contain a self-clamping validation problem in
sys/netinet6/nd6.c:

  if (ND.linkmtu < IPV6_MMTU ||
      ND.linkmtu > in6_ifmtu(ifp)) {
          error = EINVAL;
          break;
  }

  in6_ifmtu(ifp) already returns the lower stale nd_linkmtu when it is below
if_mtu, so once nd_linkmtu is 1500, userland cannot raise it to a
  valid value such as 4074 via SIOCSIFINFO_IN6.

  I tested the attached patch, which validates against the interface’s allowed
maximum MTU instead of the already-clamped effective MTU, and calls
  rt_updatemtu(ifp) when nd_linkmtu changes.

  Runtime test after patch:

  /tmp/set_nd_linkmtu rge0 1500
  rge0 linkmtu=1500 maxmtu=4074

  /tmp/set_nd_linkmtu rge0 4074
  rge0 linkmtu=4074 maxmtu=4074

  After raising linkmtu to 4074, tcpdump showed the IPv6 TCP SYN-ACK correctly
advertising:

  options [mss 4014,...]

  instead of mss 1440.

  IPv6 iperf also improved from about 2.0 Gbit/s to about 2.28 Gbit/s on this
direct 2.5G link.

  I am attaching the patch I tested.

-- 
You are receiving this mail because:
You are the assignee for the bug.