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 <da...@davemloft.net>
Signed-off-by: Paolo Abeni <pab...@redhat.com>
---
 include/linux/skbuff.h       | 18 ++++++++++--------
 include/net/flow_dissector.h |  7 ++++++-
 net/core/flow_dissector.c    | 17 +++++++++--------
 net/ethernet/eth.c           |  6 +++---
 4 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 908d66e55b14..693564a9a979 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -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_poff(const struct sk_buff *skb);
 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,
                            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);
 }
 
-static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow,
-                                                 void *data, __be16 proto,
-                                                 int nhoff, int hlen,
-                                                 unsigned int flags)
+static inline bool
+skb_flow_dissect_flow_keys_basic(const struct sk_buff *skb,
+                                struct flow_keys_basic *flow, void *data,
+                                __be16 proto, int nhoff, int hlen,
+                                unsigned int flags)
 {
        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);
 }
 
@@ -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,
                                              const int offset_hint)
 {
-       struct flow_keys keys;
+       struct flow_keys_basic keys;
 
        if (skb_transport_header_was_set(skb))
                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);
        else
                skb_set_transport_header(skb, offset_hint);
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index 9a074776f70b..e2f6e5c928bb 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -226,6 +226,11 @@ struct flow_dissector {
        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_dissector_key_control control;
 #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);
 
 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:
  *
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index d29f09bc5ff9..030d4ca177fb 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -1253,7 +1253,7 @@ __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 
perturb)
 EXPORT_SYMBOL(skb_get_hash_perturb);
 
 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;
 
@@ -1314,9 +1314,9 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
  */
 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 __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,
                .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;
 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)
 {
@@ -1427,9 +1428,9 @@ static int __init init_default_flow_dissectors(void)
        skb_flow_dissector_init(&flow_keys_dissector_symmetric,
                                flow_keys_dissector_symmetric_keys,
                                ARRAY_SIZE(flow_keys_dissector_symmetric_keys));
-       skb_flow_dissector_init(&flow_keys_buf_dissector,
-                               flow_keys_buf_dissector_keys,
-                               ARRAY_SIZE(flow_keys_buf_dissector_keys));
+       skb_flow_dissector_init(&flow_keys_basic_dissector,
+                               flow_keys_basic_dissector_keys,
+                               ARRAY_SIZE(flow_keys_basic_dissector_keys));
        return 0;
 }
 
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index eaeba9b99a73..ee28440f57c5 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -128,15 +128,15 @@ u32 eth_get_headlen(void *data, unsigned int len)
 {
        const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
        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 */
        if (unlikely(len < sizeof(*eth)))
                return len;
 
        /* parse any remaining L2/L3 headers, check for L4 */
-       if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto,
-                                           sizeof(*eth), len, flags))
+       if (!skb_flow_dissect_flow_keys_basic(NULL, &keys, data, eth->h_proto,
+                                             sizeof(*eth), len, flags))
                return max_t(u32, keys.control.thoff, sizeof(*eth));
 
        /* parse for any L4 headers */
-- 
2.14.3

Reply via email to