Skip to content

Commit 42aecaa

Browse files
tomratbertdavem330
authored andcommitted
net: Get skb hash over flow_keys structure
This patch changes flow hashing to use jhash2 over the flow_keys structure instead just doing jhash_3words over src, dst, and ports. This method will allow us take more input into the hashing function so that we can include full IPv6 addresses, VLAN, flow labels etc. without needing to resort to xor'ing which makes for a poor hash. Acked-by: Jiri Pirko <[email protected]> Signed-off-by: Tom Herbert <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c468efe commit 42aecaa

File tree

6 files changed

+66
-17
lines changed

6 files changed

+66
-17
lines changed

include/linux/skbuff.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1943,7 +1943,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb,
19431943
if (skb_transport_header_was_set(skb))
19441944
return;
19451945
else if (skb_flow_dissect_flow_keys(skb, &keys))
1946-
skb_set_transport_header(skb, keys.basic.thoff);
1946+
skb_set_transport_header(skb, keys.control.thoff);
19471947
else
19481948
skb_set_transport_header(skb, offset_hint);
19491949
}

include/net/flow_dissector.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@
66
#include <linux/in6.h>
77
#include <uapi/linux/if_ether.h>
88

9+
/**
10+
* struct flow_dissector_key_control:
11+
* @thoff: Transport header offset
12+
*/
13+
struct flow_dissector_key_control {
14+
u16 thoff;
15+
u16 padding;
16+
};
17+
918
/**
1019
* struct flow_dissector_key_basic:
1120
* @thoff: Transport header offset
1221
* @n_proto: Network header protocol (eg. IPv4/IPv6)
1322
* @ip_proto: Transport header protocol (eg. TCP/UDP)
1423
*/
1524
struct flow_dissector_key_basic {
16-
u16 thoff;
1725
__be16 n_proto;
1826
u8 ip_proto;
27+
u8 padding;
1928
};
2029

2130
/**
@@ -70,6 +79,7 @@ struct flow_dissector_key_eth_addrs {
7079
};
7180

7281
enum flow_dissector_key_id {
82+
FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */
7383
FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */
7484
FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */
7585
FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */
@@ -109,11 +119,16 @@ static inline bool skb_flow_dissect(const struct sk_buff *skb,
109119
}
110120

111121
struct flow_keys {
112-
struct flow_dissector_key_addrs addrs;
113-
struct flow_dissector_key_ports ports;
122+
struct flow_dissector_key_control control;
123+
#define FLOW_KEYS_HASH_START_FIELD basic
114124
struct flow_dissector_key_basic basic;
125+
struct flow_dissector_key_ports ports;
126+
struct flow_dissector_key_addrs addrs;
115127
};
116128

129+
#define FLOW_KEYS_HASH_OFFSET \
130+
offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD)
131+
117132
extern struct flow_dissector flow_keys_dissector;
118133
extern struct flow_dissector flow_keys_buf_dissector;
119134

include/net/ip.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ static inline void inet_set_txhash(struct sock *sk)
360360
struct inet_sock *inet = inet_sk(sk);
361361
struct flow_keys keys;
362362

363+
memset(&keys, 0, sizeof(keys));
364+
363365
keys.addrs.src = inet->inet_saddr;
364366
keys.addrs.dst = inet->inet_daddr;
365367
keys.ports.src = inet->inet_sport;

include/net/ipv6.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static inline void ip6_set_txhash(struct sock *sk)
699699
struct ipv6_pinfo *np = inet6_sk(sk);
700700
struct flow_keys keys;
701701

702+
memset(&keys, 0, sizeof(keys));
703+
702704
keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr);
703705
keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr);
704706
keys.ports.src = inet->inet_sport;

net/core/flow_dissector.c

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
5757
flow_dissector->offset[key->key_id] = key->offset;
5858
}
5959

60-
/* Ensure that the dissector always includes basic key. That way
61-
* we are able to avoid handling lack of it in fast path.
60+
/* Ensure that the dissector always includes control and basic key.
61+
* That way we are able to avoid handling lack of these in fast path.
6262
*/
63+
BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
64+
FLOW_DISSECTOR_KEY_CONTROL));
6365
BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
6466
FLOW_DISSECTOR_KEY_BASIC));
6567
}
@@ -120,6 +122,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
120122
void *target_container,
121123
void *data, __be16 proto, int nhoff, int hlen)
122124
{
125+
struct flow_dissector_key_control *key_control;
123126
struct flow_dissector_key_basic *key_basic;
124127
struct flow_dissector_key_addrs *key_addrs;
125128
struct flow_dissector_key_ports *key_ports;
@@ -132,6 +135,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
132135
hlen = skb_headlen(skb);
133136
}
134137

138+
/* It is ensured by skb_flow_dissector_init() that control key will
139+
* be always present.
140+
*/
141+
key_control = skb_flow_dissector_target(flow_dissector,
142+
FLOW_DISSECTOR_KEY_CONTROL,
143+
target_container);
144+
135145
/* It is ensured by skb_flow_dissector_init() that basic key will
136146
* be always present.
137147
*/
@@ -219,7 +229,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
219229

220230
key_basic->n_proto = proto;
221231
key_basic->ip_proto = ip_proto;
222-
key_basic->thoff = (u16)nhoff;
232+
key_control->thoff = (u16)nhoff;
223233

224234
if (skb_flow_dissector_uses_key(flow_dissector,
225235
FLOW_DISSECTOR_KEY_PORTS)) {
@@ -275,7 +285,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
275285
if (!hdr)
276286
return false;
277287
key_basic->n_proto = proto;
278-
key_basic->thoff = (u16)nhoff;
288+
key_control->thoff = (u16)nhoff;
279289

280290
if (skb_flow_dissector_uses_key(flow_dissector,
281291
FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) {
@@ -288,7 +298,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
288298
return true;
289299
}
290300
case htons(ETH_P_FCOE):
291-
key_basic->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
301+
key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
292302
/* fall through */
293303
default:
294304
return false;
@@ -345,7 +355,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
345355

346356
key_basic->n_proto = proto;
347357
key_basic->ip_proto = ip_proto;
348-
key_basic->thoff = (u16) nhoff;
358+
key_control->thoff = (u16)nhoff;
349359

350360
if (skb_flow_dissector_uses_key(flow_dissector,
351361
FLOW_DISSECTOR_KEY_PORTS)) {
@@ -366,9 +376,21 @@ static __always_inline void __flow_hash_secret_init(void)
366376
net_get_random_once(&hashrnd, sizeof(hashrnd));
367377
}
368378

369-
static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c, u32 keyval)
379+
static __always_inline u32 __flow_hash_words(u32 *words, u32 length, u32 keyval)
380+
{
381+
return jhash2(words, length, keyval);
382+
}
383+
384+
static inline void *flow_keys_hash_start(struct flow_keys *flow)
370385
{
371-
return jhash_3words(a, b, c, keyval);
386+
BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
387+
return (void *)flow + FLOW_KEYS_HASH_OFFSET;
388+
}
389+
390+
static inline size_t flow_keys_hash_length(struct flow_keys *flow)
391+
{
392+
BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
393+
return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32);
372394
}
373395

374396
static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
@@ -383,10 +405,8 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
383405
swap(keys->ports.src, keys->ports.dst);
384406
}
385407

386-
hash = __flow_hash_3words((__force u32)keys->addrs.dst,
387-
(__force u32)keys->addrs.src,
388-
(__force u32)keys->ports.ports,
389-
keyval);
408+
hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys),
409+
flow_keys_hash_length(keys), keyval);
390410
if (!hash)
391411
hash = 1;
392412

@@ -473,7 +493,7 @@ EXPORT_SYMBOL(skb_get_hash_perturb);
473493
u32 __skb_get_poff(const struct sk_buff *skb, void *data,
474494
const struct flow_keys *keys, int hlen)
475495
{
476-
u32 poff = keys->basic.thoff;
496+
u32 poff = keys->control.thoff;
477497

478498
switch (keys->basic.ip_proto) {
479499
case IPPROTO_TCP: {
@@ -536,6 +556,10 @@ u32 skb_get_poff(const struct sk_buff *skb)
536556
}
537557

538558
static const struct flow_dissector_key flow_keys_dissector_keys[] = {
559+
{
560+
.key_id = FLOW_DISSECTOR_KEY_CONTROL,
561+
.offset = offsetof(struct flow_keys, control),
562+
},
539563
{
540564
.key_id = FLOW_DISSECTOR_KEY_BASIC,
541565
.offset = offsetof(struct flow_keys, basic),
@@ -555,6 +579,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = {
555579
};
556580

557581
static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = {
582+
{
583+
.key_id = FLOW_DISSECTOR_KEY_CONTROL,
584+
.offset = offsetof(struct flow_keys, control),
585+
},
558586
{
559587
.key_id = FLOW_DISSECTOR_KEY_BASIC,
560588
.offset = offsetof(struct flow_keys, basic),

net/sched/cls_flower.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
struct fl_flow_key {
2727
int indev_ifindex;
28+
struct flow_dissector_key_control control;
2829
struct flow_dissector_key_basic basic;
2930
struct flow_dissector_key_eth_addrs eth;
3031
union {
@@ -347,6 +348,7 @@ static void fl_init_dissector(struct cls_fl_head *head,
347348
struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
348349
size_t cnt = 0;
349350

351+
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
350352
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
351353
FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
352354
FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);

0 commit comments

Comments
 (0)