mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:04:51 +01:00
psp: use sk->sk_hash in psp_write_headers()
udp_flow_src_port() is indirectly using sk->sk_txhash as a base,
because __tcp_transmit_skb() uses skb_set_hash_from_sk().
This is problematic because this field can change over the
lifetime of a TCP flow, thanks to calls to sk_rethink_txhash().
Problem is that some NIC might (ab)use the PSP UDP source port in their
RSS computation, and PSP packets for a given flow could jump
from one queue to another.
In order to avoid surprises, it is safer to let Protective Load
Balancing (PLB) get its entropy from the IPv6 flowlabel,
and change psp_write_headers() to use sk->sk_hash which
does not change for the duration of the flow.
We might add a sysctl to select the behavior, if there
is a need for it.
Fixes: fc72451574 ("psp: provide encapsulation helper for drivers")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-By: Daniel Zahka <daniel.zahka@gmail.com>
Link: https://patch.msgid.link/20260218141337.999945-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
858d2a4f67
commit
f891007ab1
1 changed files with 38 additions and 1 deletions
|
|
@ -166,9 +166,46 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi,
|
|||
{
|
||||
struct udphdr *uh = udp_hdr(skb);
|
||||
struct psphdr *psph = (struct psphdr *)(uh + 1);
|
||||
const struct sock *sk = skb->sk;
|
||||
|
||||
uh->dest = htons(PSP_DEFAULT_UDP_PORT);
|
||||
uh->source = udp_flow_src_port(net, skb, 0, 0, false);
|
||||
|
||||
/* A bit of theory: Selection of the source port.
|
||||
*
|
||||
* We need some entropy, so that multiple flows use different
|
||||
* source ports for better RSS spreading at the receiver.
|
||||
*
|
||||
* We also need that all packets belonging to one TCP flow
|
||||
* use the same source port through their duration,
|
||||
* so that all these packets land in the same receive queue.
|
||||
*
|
||||
* udp_flow_src_port() is using sk_txhash, inherited from
|
||||
* skb_set_hash_from_sk() call in __tcp_transmit_skb().
|
||||
* This field is subject to reshuffling, thanks to
|
||||
* sk_rethink_txhash() calls in various TCP functions.
|
||||
*
|
||||
* Instead, use sk->sk_hash which is constant through
|
||||
* the whole flow duration.
|
||||
*/
|
||||
if (likely(sk)) {
|
||||
u32 hash = sk->sk_hash;
|
||||
int min, max;
|
||||
|
||||
/* These operations are cheap, no need to cache the result
|
||||
* in another socket field.
|
||||
*/
|
||||
inet_get_local_port_range(net, &min, &max);
|
||||
/* Since this is being sent on the wire obfuscate hash a bit
|
||||
* to minimize possibility that any useful information to an
|
||||
* attacker is leaked. Only upper 16 bits are relevant in the
|
||||
* computation for 16 bit port value because we use a
|
||||
* reciprocal divide.
|
||||
*/
|
||||
hash ^= hash << 16;
|
||||
uh->source = htons((((u64)hash * (max - min)) >> 32) + min);
|
||||
} else {
|
||||
uh->source = udp_flow_src_port(net, skb, 0, 0, false);
|
||||
}
|
||||
uh->check = 0;
|
||||
uh->len = htons(udp_len);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue