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: David Miller <davem@davemloft.net> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
62515f95b4
commit
72a338bcc6
|
@ -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,
|
||||||
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,
|
||||||
unsigned int flags)
|
__be16 proto, int nhoff, int hlen,
|
||||||
|
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)
|
||||||
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 {
|
||||||
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);
|
||||||
__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)
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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[] = {
|
||||||
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)
|
||||||
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,15 +128,15 @@ 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));
|
||||||
|
|
||||||
/* parse for any L4 headers */
|
/* parse for any L4 headers */
|
||||||
|
|
Loading…
Reference in New Issue