Tunnel mode encapsulation leaves the flow label of the outer IPv6 header
zero. ESP and AH have no transport ports (UDP-encapsulated ESP has them, but
the same pair for every SA), so devices that hash IPv6 headers to spread
traffic, link aggregates and ECMP routers alike, see no difference between
the security associations of two gateways and put all of their tunnels on
one path. lagg(4)'s own header hash does the same: for IPv6 its layer 4
input is the flow label.
Set the label to the low 20 bits of the SA's flow ID, the hash of its SPI
that the previous change introduced. Each SA then carries one label for its
lifetime; SPIs are unique within the SADB, so distinct SAs carry distinct
labels unless the 20-bit hashes collide. A hasher that includes the flow
label then spreads SAs over its paths while keeping the packets of each SA
on one, which avoids reordering their sequence numbers across paths. A rekey
starts a new SA and a new label. The label is set whether or not
net.inet.ipsec.sa_flowid is enabled: that sysctl governs the local transmit
queue selection, this label what the network sees. In a bundle whose tunnel
mode SA is followed by transport mode SAs the outer header stays in place;
relabel it from the outermost SA when the packet leaves, as that SA's
sequence numbers are the first the path choice reorders and the previous
change already took the flow ID from it. One transport SA shared by several
tunnel SAs then stays on one path.
RFC 6437 leaves the definition of a flow to the source and recommends a
stateless hash as the label. RFC 6438 describes labelling at a tunnel entry
point from the inner flow, which gre(4) and Linux IPsec do, so that one
tunnel spreads over several paths. ESP carries sequence numbers, so that
spreading reorders them and a receiver with a small anti-replay window drops
the late packets; keying the label on the SA is the choice that fits.
RFC 6437 asks that a hash-derived label be hard to predict; this one is a
function of the SPI in the same packet, so keying the hash would hide
nothing, and the label is meant to stay the same for the life of the SA.
AH treats the flow label as mutable and zeroes it before computing and
verifying the ICV, so the label does not affect AH. Transport mode and SAs
offloaded to a NIC are not affected. ip6_output() leaves the label of
packets without socket options alone.
Document the label in ipsec(4).
MFC after: 2 weeks
Sponsored by: Rubicon Communications, LLC ("Netgate")