RFC 4391 (IP over InfiniBand), section 9.3, lays the ND source/target
link-layer address option out as type, length (3), two reserved zero octets,
then the 20-octet IPoIB link-layer address. The ND code assumed the Ethernet
layout (RFC 4861, section 4.6.1) everywhere and read/wrote the address directly
after the option header, i.e. two octets early. The option-length sanity check
computes 24 for both layouts for a 20-octet address, so the mismatch was silent.
Against a conformant peer (e.g. Linux) this broke IPv6 over IPoIB in both
directions: the address parsed from a received NS/NA option was shifted by two
bytes, so the cached link-layer address embedded a GID that does not exist on
the fabric and replies were sent nowhere, and the options we built carried our
address at the wrong offset for the peer. IPv4/ARP was unaffected. This blocked
everything IPv6 over IPoIB against Linux, including rdma_cm's IP-to-GID
resolution and therefore NFS-over-RDMA-over-InfiniBand with IPv6.
Add nd6_lladdr_opt_pad(), the analog of Linux's ndisc_addr_option_pad(): the
number of reserved octets between the option header and the address (2 for
IFT_INFINIBAND and IFT_INFINIBANDLAG, 0 otherwise). Apply it at the option parse
sites (nd6_ns_input(), nd6_na_input(), nd6_rs_input(), nd6_ra_input(),
icmp6_redirect_input()) and the option build sites (nd6_ns_output_fib(),
nd6_na_output_fib(), icmp6_redirect_output()). Zero the redirect target option
before filling it; previously its trailing pad bytes were left uninitialized on
links with 20-octet addresses. No functional change for link types without
reserved octets.
This is a direct commit to stable/15, equivalent to main commit
bac4760524a2a15ce75e35251f0c9cdf31732f3f (D58096). It could not be cherry-picked
cleanly: the neighbor-discovery code diverged on main (the router advertisement
parse was refactored into helpers), so the same fix is reimplemented against the
stable/15 sources.
PR: 296585
Sponsored by: VersatusHPC