Commit 72a338bc authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

net: core: rework basic flow dissection helper

When the core networking needs to detect the transport offset in a given
packet and parse it explicitly, a full-blown flow_keys struct is used for
storage.
This patch introduces a smaller keys store, rework the basic flow dissect
helper to use it, and apply this new helper where possible - namely in
skb_probe_transport_header(). The used flow dissector data structures
are renamed to match more closely the new role.

The above gives ~50% performance improvement in micro benchmarking around
skb_probe_transport_header() and ~30% around eth_get_headlen(), mostly due
to the smaller memset. Small, but measurable improvement is measured also
in macro benchmarking.

v1 -> v2: use the new helper in eth_get_headlen() and skb_get_poff(),
  as per DaveM suggestion
Suggested-by: default avatarDavid Miller <davem@davemloft.net>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 62515f95
...@@ -1171,7 +1171,7 @@ void __skb_get_hash(struct sk_buff *skb); ...@@ -1171,7 +1171,7 @@ void __skb_get_hash(struct sk_buff *skb);
u32 __skb_get_hash_symmetric(const struct sk_buff *skb); u32 __skb_get_hash_symmetric(const struct sk_buff *skb);
u32 skb_get_poff(const struct sk_buff *skb); u32 skb_get_poff(const struct sk_buff *skb);
u32 __skb_get_poff(const struct sk_buff *skb, void *data, u32 __skb_get_poff(const struct sk_buff *skb, void *data,
const struct flow_keys *keys, int hlen); const struct flow_keys_basic *keys, int hlen);
__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
void *data, int hlen_proto); void *data, int hlen_proto);
...@@ -1208,13 +1208,14 @@ static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, ...@@ -1208,13 +1208,14 @@ static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb,
NULL, 0, 0, 0, flags); NULL, 0, 0, 0, flags);
} }
static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, static inline bool
void *data, __be16 proto, skb_flow_dissect_flow_keys_basic(const struct sk_buff *skb,
int nhoff, int hlen, struct flow_keys_basic *flow, void *data,
__be16 proto, int nhoff, int hlen,
unsigned int flags) unsigned int flags)
{ {
memset(flow, 0, sizeof(*flow)); memset(flow, 0, sizeof(*flow));
return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, return __skb_flow_dissect(skb, &flow_keys_basic_dissector, flow,
data, proto, nhoff, hlen, flags); data, proto, nhoff, hlen, flags);
} }
...@@ -2350,11 +2351,12 @@ static inline void skb_pop_mac_header(struct sk_buff *skb) ...@@ -2350,11 +2351,12 @@ static inline void skb_pop_mac_header(struct sk_buff *skb)
static inline void skb_probe_transport_header(struct sk_buff *skb, static inline void skb_probe_transport_header(struct sk_buff *skb,
const int offset_hint) const int offset_hint)
{ {
struct flow_keys keys; struct flow_keys_basic keys;
if (skb_transport_header_was_set(skb)) if (skb_transport_header_was_set(skb))
return; return;
else if (skb_flow_dissect_flow_keys(skb, &keys, 0))
if (skb_flow_dissect_flow_keys_basic(skb, &keys, 0, 0, 0, 0, 0))
skb_set_transport_header(skb, keys.control.thoff); skb_set_transport_header(skb, keys.control.thoff);
else else
skb_set_transport_header(skb, offset_hint); skb_set_transport_header(skb, offset_hint);
......
...@@ -226,6 +226,11 @@ struct flow_dissector { ...@@ -226,6 +226,11 @@ struct flow_dissector {
unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; unsigned short int offset[FLOW_DISSECTOR_KEY_MAX];
}; };
struct flow_keys_basic {
struct flow_dissector_key_control control;
struct flow_dissector_key_basic basic;
};
struct flow_keys { struct flow_keys {
struct flow_dissector_key_control control; struct flow_dissector_key_control control;
#define FLOW_KEYS_HASH_START_FIELD basic #define FLOW_KEYS_HASH_START_FIELD basic
...@@ -244,7 +249,7 @@ __be32 flow_get_u32_src(const struct flow_keys *flow); ...@@ -244,7 +249,7 @@ __be32 flow_get_u32_src(const struct flow_keys *flow);
__be32 flow_get_u32_dst(const struct flow_keys *flow); __be32 flow_get_u32_dst(const struct flow_keys *flow);
extern struct flow_dissector flow_keys_dissector; extern struct flow_dissector flow_keys_dissector;
extern struct flow_dissector flow_keys_buf_dissector; extern struct flow_dissector flow_keys_basic_dissector;
/* struct flow_keys_digest: /* struct flow_keys_digest:
* *
......
...@@ -1253,7 +1253,7 @@ __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) ...@@ -1253,7 +1253,7 @@ __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb)
EXPORT_SYMBOL(skb_get_hash_perturb); EXPORT_SYMBOL(skb_get_hash_perturb);
u32 __skb_get_poff(const struct sk_buff *skb, void *data, u32 __skb_get_poff(const struct sk_buff *skb, void *data,
const struct flow_keys *keys, int hlen) const struct flow_keys_basic *keys, int hlen)
{ {
u32 poff = keys->control.thoff; u32 poff = keys->control.thoff;
...@@ -1314,9 +1314,9 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data, ...@@ -1314,9 +1314,9 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
*/ */
u32 skb_get_poff(const struct sk_buff *skb) u32 skb_get_poff(const struct sk_buff *skb)
{ {
struct flow_keys keys; struct flow_keys_basic keys;
if (!skb_flow_dissect_flow_keys(skb, &keys, 0)) if (!skb_flow_dissect_flow_keys_basic(skb, &keys, 0, 0, 0, 0, 0))
return 0; return 0;
return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
...@@ -1403,7 +1403,7 @@ static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = { ...@@ -1403,7 +1403,7 @@ static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = {
}, },
}; };
static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { static const struct flow_dissector_key flow_keys_basic_dissector_keys[] = {
{ {
.key_id = FLOW_DISSECTOR_KEY_CONTROL, .key_id = FLOW_DISSECTOR_KEY_CONTROL,
.offset = offsetof(struct flow_keys, control), .offset = offsetof(struct flow_keys, control),
...@@ -1417,7 +1417,8 @@ static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { ...@@ -1417,7 +1417,8 @@ static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = {
struct flow_dissector flow_keys_dissector __read_mostly; struct flow_dissector flow_keys_dissector __read_mostly;
EXPORT_SYMBOL(flow_keys_dissector); EXPORT_SYMBOL(flow_keys_dissector);
struct flow_dissector flow_keys_buf_dissector __read_mostly; struct flow_dissector flow_keys_basic_dissector __read_mostly;
EXPORT_SYMBOL(flow_keys_basic_dissector);
static int __init init_default_flow_dissectors(void) static int __init init_default_flow_dissectors(void)
{ {
...@@ -1427,9 +1428,9 @@ static int __init init_default_flow_dissectors(void) ...@@ -1427,9 +1428,9 @@ static int __init init_default_flow_dissectors(void)
skb_flow_dissector_init(&flow_keys_dissector_symmetric, skb_flow_dissector_init(&flow_keys_dissector_symmetric,
flow_keys_dissector_symmetric_keys, flow_keys_dissector_symmetric_keys,
ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); ARRAY_SIZE(flow_keys_dissector_symmetric_keys));
skb_flow_dissector_init(&flow_keys_buf_dissector, skb_flow_dissector_init(&flow_keys_basic_dissector,
flow_keys_buf_dissector_keys, flow_keys_basic_dissector_keys,
ARRAY_SIZE(flow_keys_buf_dissector_keys)); ARRAY_SIZE(flow_keys_basic_dissector_keys));
return 0; return 0;
} }
......
...@@ -128,14 +128,14 @@ u32 eth_get_headlen(void *data, unsigned int len) ...@@ -128,14 +128,14 @@ u32 eth_get_headlen(void *data, unsigned int len)
{ {
const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG; const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
const struct ethhdr *eth = (const struct ethhdr *)data; const struct ethhdr *eth = (const struct ethhdr *)data;
struct flow_keys keys; struct flow_keys_basic keys;
/* this should never happen, but better safe than sorry */ /* this should never happen, but better safe than sorry */
if (unlikely(len < sizeof(*eth))) if (unlikely(len < sizeof(*eth)))
return len; return len;
/* parse any remaining L2/L3 headers, check for L4 */ /* parse any remaining L2/L3 headers, check for L4 */
if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, if (!skb_flow_dissect_flow_keys_basic(NULL, &keys, data, eth->h_proto,
sizeof(*eth), len, flags)) sizeof(*eth), len, flags))
return max_t(u32, keys.control.thoff, sizeof(*eth)); return max_t(u32, keys.control.thoff, sizeof(*eth));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment