Skip to content

Commit b73c3d0

Browse files
Tom Herbertdavem330
authored andcommitted
net: Save TX flow hash in sock and set in skbuf on xmit
For a connected socket we can precompute the flow hash for setting in skb->hash on output. This is a performance advantage over calculating the skb->hash for every packet on the connection. The computation is done using the common hash algorithm to be consistent with computations done for packets of the connection in other states where thers is no socket (e.g. time-wait, syn-recv, syn-cookies). This patch adds sk_txhash to the sock structure. inet_set_txhash and ip6_set_txhash functions are added which are called from points in TCP and UDP where socket moves to established state. skb_set_hash_from_sk is a function which sets skb->hash from the sock txhash value. This is called in UDP and TCP transmit path when transmitting within the context of a socket. Tested: ran super_netperf with 200 TCP_RR streams over a vxlan interface (in this case skb_get_hash called on every TX packet to create a UDP source port). Before fix: 95.02% CPU utilization 154/256/505 90/95/99% latencies 1.13042e+06 tps Time in functions: 0.28% skb_flow_dissect 0.21% __skb_get_hash After fix: 94.95% CPU utilization 156/254/485 90/95/99% latencies 1.15447e+06 Neither __skb_get_hash nor skb_flow_dissect appear in perf Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 5ed20a6 commit b73c3d0

File tree

8 files changed

+50
-0
lines changed

8 files changed

+50
-0
lines changed

include/net/ip.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <net/route.h>
3232
#include <net/snmp.h>
3333
#include <net/flow.h>
34+
#include <net/flow_keys.h>
3435

3536
struct sock;
3637

@@ -353,6 +354,19 @@ static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto)
353354
skb->len, proto, 0);
354355
}
355356

357+
static inline void inet_set_txhash(struct sock *sk)
358+
{
359+
struct inet_sock *inet = inet_sk(sk);
360+
struct flow_keys keys;
361+
362+
keys.src = inet->inet_saddr;
363+
keys.dst = inet->inet_daddr;
364+
keys.port16[0] = inet->inet_sport;
365+
keys.port16[1] = inet->inet_dport;
366+
367+
sk->sk_txhash = flow_hash_from_keys(&keys);
368+
}
369+
356370
/*
357371
* Map a multicast IP onto multicast MAC for type ethernet.
358372
*/

include/net/ipv6.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <net/if_inet6.h>
2020
#include <net/ndisc.h>
2121
#include <net/flow.h>
22+
#include <net/flow_keys.h>
2223
#include <net/snmp.h>
2324

2425
#define SIN6_LEN_RFC2133 24
@@ -684,6 +685,20 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
684685
return hlimit;
685686
}
686687

688+
static inline void ip6_set_txhash(struct sock *sk)
689+
{
690+
struct inet_sock *inet = inet_sk(sk);
691+
struct ipv6_pinfo *np = inet6_sk(sk);
692+
struct flow_keys keys;
693+
694+
keys.src = (__force __be32)ipv6_addr_hash(&np->saddr);
695+
keys.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr);
696+
keys.port16[0] = inet->inet_sport;
697+
keys.port16[1] = inet->inet_dport;
698+
699+
sk->sk_txhash = flow_hash_from_keys(&keys);
700+
}
701+
687702
/*
688703
* Header manipulation
689704
*/

include/net/sock.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ struct cg_proto;
273273
* @sk_rcvtimeo: %SO_RCVTIMEO setting
274274
* @sk_sndtimeo: %SO_SNDTIMEO setting
275275
* @sk_rxhash: flow hash received from netif layer
276+
* @sk_txhash: computed flow hash for use on transmit
276277
* @sk_filter: socket filtering instructions
277278
* @sk_protinfo: private area, net family specific, when not using slab
278279
* @sk_timer: sock cleanup timer
@@ -347,6 +348,7 @@ struct sock {
347348
#ifdef CONFIG_RPS
348349
__u32 sk_rxhash;
349350
#endif
351+
__u32 sk_txhash;
350352
#ifdef CONFIG_NET_RX_BUSY_POLL
351353
unsigned int sk_napi_id;
352354
unsigned int sk_ll_usec;
@@ -1980,6 +1982,14 @@ static inline void sock_poll_wait(struct file *filp,
19801982
}
19811983
}
19821984

1985+
static inline void skb_set_hash_from_sk(struct sk_buff *skb, struct sock *sk)
1986+
{
1987+
if (sk->sk_txhash) {
1988+
skb->l4_hash = 1;
1989+
skb->hash = sk->sk_txhash;
1990+
}
1991+
}
1992+
19831993
/*
19841994
* Queue a received datagram if it will fit. Stream and sequenced
19851995
* protocols can't normally use this as they need to fit buffers in
@@ -1994,6 +2004,7 @@ static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
19942004
skb_orphan(skb);
19952005
skb->sk = sk;
19962006
skb->destructor = sock_wfree;
2007+
skb_set_hash_from_sk(skb, sk);
19972008
/*
19982009
* We used to take a refcount on sk, but following operation
19992010
* is enough to guarantee sk_free() wont free this sock until

net/ipv4/datagram.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
7676
inet->inet_daddr = fl4->daddr;
7777
inet->inet_dport = usin->sin_port;
7878
sk->sk_state = TCP_ESTABLISHED;
79+
inet_set_txhash(sk);
7980
inet->inet_id = jiffies;
8081

8182
sk_dst_set(sk, &rt->dst);

net/ipv4/tcp_ipv4.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
208208
inet->inet_dport = usin->sin_port;
209209
inet->inet_daddr = daddr;
210210

211+
inet_set_txhash(sk);
212+
211213
inet_csk(sk)->icsk_ext_hdr_len = 0;
212214
if (inet_opt)
213215
inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
@@ -1334,6 +1336,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
13341336
newinet->mc_ttl = ip_hdr(skb)->ttl;
13351337
newinet->rcv_tos = ip_hdr(skb)->tos;
13361338
inet_csk(newsk)->icsk_ext_hdr_len = 0;
1339+
inet_set_txhash(newsk);
13371340
if (inet_opt)
13381341
inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
13391342
newinet->inet_id = newtp->write_seq ^ jiffies;

net/ipv4/tcp_output.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
916916
skb_orphan(skb);
917917
skb->sk = sk;
918918
skb->destructor = tcp_wfree;
919+
skb_set_hash_from_sk(skb, sk);
919920
atomic_add(skb->truesize, &sk->sk_wmem_alloc);
920921

921922
/* Build TCP header and checksum it. */

net/ipv6/datagram.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
199199
NULL);
200200

201201
sk->sk_state = TCP_ESTABLISHED;
202+
ip6_set_txhash(sk);
202203
out:
203204
fl6_sock_release(flowlabel);
204205
return err;

net/ipv6/tcp_ipv6.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
198198
sk->sk_v6_daddr = usin->sin6_addr;
199199
np->flow_label = fl6.flowlabel;
200200

201+
ip6_set_txhash(sk);
202+
201203
/*
202204
* TCP over IPv4
203205
*/
@@ -1132,6 +1134,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
11321134
newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
11331135
newsk->sk_bound_dev_if = ireq->ir_iif;
11341136

1137+
ip6_set_txhash(newsk);
1138+
11351139
/* Now IPv6 options...
11361140
11371141
First: no IPv4 options.

0 commit comments

Comments
 (0)