Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Paolo Abeni and committed by
David S. Miller
72a338bc 62515f95

+28 -20
+10 -8
include/linux/skbuff.h
··· 1171 1171 u32 __skb_get_hash_symmetric(const struct sk_buff *skb); 1172 1172 u32 skb_get_poff(const struct sk_buff *skb); 1173 1173 u32 __skb_get_poff(const struct sk_buff *skb, void *data, 1174 - const struct flow_keys *keys, int hlen); 1174 + const struct flow_keys_basic *keys, int hlen); 1175 1175 __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, 1176 1176 void *data, int hlen_proto); 1177 1177 ··· 1208 1208 NULL, 0, 0, 0, flags); 1209 1209 } 1210 1210 1211 - static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, 1212 - void *data, __be16 proto, 1213 - int nhoff, int hlen, 1214 - unsigned int flags) 1211 + static inline bool 1212 + skb_flow_dissect_flow_keys_basic(const struct sk_buff *skb, 1213 + struct flow_keys_basic *flow, void *data, 1214 + __be16 proto, int nhoff, int hlen, 1215 + unsigned int flags) 1215 1216 { 1216 1217 memset(flow, 0, sizeof(*flow)); 1217 - return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, 1218 + return __skb_flow_dissect(skb, &flow_keys_basic_dissector, flow, 1218 1219 data, proto, nhoff, hlen, flags); 1219 1220 } 1220 1221 ··· 2351 2350 static inline void skb_probe_transport_header(struct sk_buff *skb, 2352 2351 const int offset_hint) 2353 2352 { 2354 - struct flow_keys keys; 2353 + struct flow_keys_basic keys; 2355 2354 2356 2355 if (skb_transport_header_was_set(skb)) 2357 2356 return; 2358 - else if (skb_flow_dissect_flow_keys(skb, &keys, 0)) 2357 + 2358 + if (skb_flow_dissect_flow_keys_basic(skb, &keys, 0, 0, 0, 0, 0)) 2359 2359 skb_set_transport_header(skb, keys.control.thoff); 2360 2360 else 2361 2361 skb_set_transport_header(skb, offset_hint);
+6 -1
include/net/flow_dissector.h
··· 226 226 unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; 227 227 }; 228 228 229 + struct flow_keys_basic { 230 + struct flow_dissector_key_control control; 231 + struct flow_dissector_key_basic basic; 232 + }; 233 + 229 234 struct flow_keys { 230 235 struct flow_dissector_key_control control; 231 236 #define FLOW_KEYS_HASH_START_FIELD basic ··· 249 244 __be32 flow_get_u32_dst(const struct flow_keys *flow); 250 245 251 246 extern struct flow_dissector flow_keys_dissector; 252 - extern struct flow_dissector flow_keys_buf_dissector; 247 + extern struct flow_dissector flow_keys_basic_dissector; 253 248 254 249 /* struct flow_keys_digest: 255 250 *
+9 -8
net/core/flow_dissector.c
··· 1253 1253 EXPORT_SYMBOL(skb_get_hash_perturb); 1254 1254 1255 1255 u32 __skb_get_poff(const struct sk_buff *skb, void *data, 1256 - const struct flow_keys *keys, int hlen) 1256 + const struct flow_keys_basic *keys, int hlen) 1257 1257 { 1258 1258 u32 poff = keys->control.thoff; 1259 1259 ··· 1314 1314 */ 1315 1315 u32 skb_get_poff(const struct sk_buff *skb) 1316 1316 { 1317 - struct flow_keys keys; 1317 + struct flow_keys_basic keys; 1318 1318 1319 - if (!skb_flow_dissect_flow_keys(skb, &keys, 0)) 1319 + if (!skb_flow_dissect_flow_keys_basic(skb, &keys, 0, 0, 0, 0, 0)) 1320 1320 return 0; 1321 1321 1322 1322 return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); ··· 1403 1403 }, 1404 1404 }; 1405 1405 1406 - static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { 1406 + static const struct flow_dissector_key flow_keys_basic_dissector_keys[] = { 1407 1407 { 1408 1408 .key_id = FLOW_DISSECTOR_KEY_CONTROL, 1409 1409 .offset = offsetof(struct flow_keys, control), ··· 1417 1417 struct flow_dissector flow_keys_dissector __read_mostly; 1418 1418 EXPORT_SYMBOL(flow_keys_dissector); 1419 1419 1420 - struct flow_dissector flow_keys_buf_dissector __read_mostly; 1420 + struct flow_dissector flow_keys_basic_dissector __read_mostly; 1421 + EXPORT_SYMBOL(flow_keys_basic_dissector); 1421 1422 1422 1423 static int __init init_default_flow_dissectors(void) 1423 1424 { ··· 1428 1427 skb_flow_dissector_init(&flow_keys_dissector_symmetric, 1429 1428 flow_keys_dissector_symmetric_keys, 1430 1429 ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); 1431 - skb_flow_dissector_init(&flow_keys_buf_dissector, 1432 - flow_keys_buf_dissector_keys, 1433 - ARRAY_SIZE(flow_keys_buf_dissector_keys)); 1430 + skb_flow_dissector_init(&flow_keys_basic_dissector, 1431 + flow_keys_basic_dissector_keys, 1432 + ARRAY_SIZE(flow_keys_basic_dissector_keys)); 1434 1433 return 0; 1435 1434 } 1436 1435
+3 -3
net/ethernet/eth.c
··· 128 128 { 129 129 const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG; 130 130 const struct ethhdr *eth = (const struct ethhdr *)data; 131 - struct flow_keys keys; 131 + struct flow_keys_basic keys; 132 132 133 133 /* this should never happen, but better safe than sorry */ 134 134 if (unlikely(len < sizeof(*eth))) 135 135 return len; 136 136 137 137 /* parse any remaining L2/L3 headers, check for L4 */ 138 - if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, 139 - sizeof(*eth), len, flags)) 138 + if (!skb_flow_dissect_flow_keys_basic(NULL, &keys, data, eth->h_proto, 139 + sizeof(*eth), len, flags)) 140 140 return max_t(u32, keys.control.thoff, sizeof(*eth)); 141 141 142 142 /* parse for any L4 headers */