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

Configure Feed

Select the types of activity you want to include in your feed.

net: add vlan_get_protocol_offset_inline() helper

skb_protocol() is bloated, and forces slow stack canaries in many
fast paths.

Add vlan_get_protocol_offset_inline() which deals with the non-vlan
common cases.

__vlan_get_protocol_offset() is now out of line.

It returns a vlan_type_depth struct to avoid stack canaries in callers.

struct vlan_type_depth {
__be16 type;
u16 depth;
};

$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new
add/remove: 0/2 grow/shrink: 0/22 up/down: 0/-6320 (-6320)
Function old new delta
vlan_get_protocol_dgram 61 59 -2
__pfx_skb_protocol 16 - -16
__vlan_get_protocol_offset 307 273 -34
tap_get_user 1374 1207 -167
ip_md_tunnel_xmit 1625 1452 -173
tap_sendmsg 940 753 -187
netif_skb_features 1079 866 -213
netem_enqueue 3017 2800 -217
vlan_parse_protocol 271 50 -221
tso_start 567 344 -223
fq_dequeue 1908 1685 -223
skb_network_protocol 434 205 -229
ip6_tnl_xmit 2639 2409 -230
br_dev_queue_push_xmit 474 236 -238
skb_protocol 258 - -258
packet_parse_headers 621 357 -264
__ip6_tnl_rcv 1306 1039 -267
skb_csum_hwoffload_help 515 224 -291
ip_tunnel_xmit 2635 2339 -296
sch_frag_xmit_hook 1582 1233 -349
bpf_skb_ecn_set_ce 868 457 -411
IP6_ECN_decapsulate 1297 768 -529
ip_tunnel_rcv 2121 1489 -632
ipip6_rcv 2572 1922 -650
Total: Before=24892803, After=24886483, chg -0.03%

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260204053023.1622775-1-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Eric Dumazet and committed by
Paolo Abeni
7a4cd71f 770e1126

+61 -31
+22 -29
include/linux/if_vlan.h
··· 594 594 } 595 595 } 596 596 597 + struct vlan_type_depth { 598 + __be16 type; 599 + u16 depth; 600 + }; 601 + 602 + struct vlan_type_depth __vlan_get_protocol_offset(const struct sk_buff *skb, 603 + __be16 type, 604 + int mac_offset); 605 + 597 606 /** 598 - * __vlan_get_protocol_offset() - get protocol EtherType. 607 + * vlan_get_protocol_offset_inline() - get protocol EtherType. 599 608 * @skb: skbuff to query 600 609 * @type: first vlan protocol 601 610 * @mac_offset: MAC offset ··· 613 604 * Returns: the EtherType of the packet, regardless of whether it is 614 605 * vlan encapsulated (normal or hardware accelerated) or not. 615 606 */ 616 - static inline __be16 __vlan_get_protocol_offset(const struct sk_buff *skb, 617 - __be16 type, 618 - int mac_offset, 619 - int *depth) 607 + static inline 608 + __be16 vlan_get_protocol_offset_inline(const struct sk_buff *skb, 609 + __be16 type, 610 + int mac_offset, 611 + int *depth) 620 612 { 621 - unsigned int vlan_depth = skb->mac_len, parse_depth = VLAN_MAX_DEPTH; 622 - 623 - /* if type is 802.1Q/AD then the header should already be 624 - * present at mac_len - VLAN_HLEN (if mac_len > 0), or at 625 - * ETH_HLEN otherwise 626 - */ 627 613 if (eth_type_vlan(type)) { 628 - if (vlan_depth) { 629 - if (WARN_ON(vlan_depth < VLAN_HLEN)) 630 - return 0; 631 - vlan_depth -= VLAN_HLEN; 632 - } else { 633 - vlan_depth = ETH_HLEN; 634 - } 635 - do { 636 - struct vlan_hdr vhdr, *vh; 614 + struct vlan_type_depth res; 637 615 638 - vh = skb_header_pointer(skb, mac_offset + vlan_depth, 639 - sizeof(vhdr), &vhdr); 640 - if (unlikely(!vh || !--parse_depth)) 641 - return 0; 616 + res = __vlan_get_protocol_offset(skb, type, mac_offset); 642 617 643 - type = vh->h_vlan_encapsulated_proto; 644 - vlan_depth += VLAN_HLEN; 645 - } while (eth_type_vlan(type)); 618 + if (depth && res.type) 619 + *depth = res.depth; 620 + return res.type; 646 621 } 647 622 648 623 if (depth) 649 - *depth = vlan_depth; 624 + *depth = skb->mac_len; 650 625 651 626 return type; 652 627 } ··· 638 645 static inline __be16 __vlan_get_protocol(const struct sk_buff *skb, __be16 type, 639 646 int *depth) 640 647 { 641 - return __vlan_get_protocol_offset(skb, type, 0, depth); 648 + return vlan_get_protocol_offset_inline(skb, type, 0, depth); 642 649 } 643 650 644 651 /**
+36
net/core/skbuff.c
··· 7444 7444 net_devmem_put_net_iov(netmem_to_net_iov(netmem)); 7445 7445 } 7446 7446 EXPORT_SYMBOL(__put_netmem); 7447 + 7448 + struct vlan_type_depth __vlan_get_protocol_offset(const struct sk_buff *skb, 7449 + __be16 type, 7450 + int mac_offset) 7451 + { 7452 + unsigned int vlan_depth = skb->mac_len, parse_depth = VLAN_MAX_DEPTH; 7453 + 7454 + /* if type is 802.1Q/AD then the header should already be 7455 + * present at mac_len - VLAN_HLEN (if mac_len > 0), or at 7456 + * ETH_HLEN otherwise 7457 + */ 7458 + if (vlan_depth) { 7459 + if (WARN_ON_ONCE(vlan_depth < VLAN_HLEN)) 7460 + return (struct vlan_type_depth) { 0 }; 7461 + vlan_depth -= VLAN_HLEN; 7462 + } else { 7463 + vlan_depth = ETH_HLEN; 7464 + } 7465 + do { 7466 + struct vlan_hdr vhdr, *vh; 7467 + 7468 + vh = skb_header_pointer(skb, mac_offset + vlan_depth, 7469 + sizeof(vhdr), &vhdr); 7470 + if (unlikely(!vh || !--parse_depth)) 7471 + return (struct vlan_type_depth) { 0 }; 7472 + 7473 + type = vh->h_vlan_encapsulated_proto; 7474 + vlan_depth += VLAN_HLEN; 7475 + } while (eth_type_vlan(type)); 7476 + 7477 + return (struct vlan_type_depth) { 7478 + .type = type, 7479 + .depth = vlan_depth 7480 + }; 7481 + } 7482 + EXPORT_SYMBOL(__vlan_get_protocol_offset);
+3 -2
net/packet/af_packet.c
··· 572 572 __be16 proto = skb->protocol; 573 573 574 574 if (unlikely(eth_type_vlan(proto))) 575 - proto = __vlan_get_protocol_offset(skb, proto, 576 - skb_mac_offset(skb), NULL); 575 + proto = vlan_get_protocol_offset_inline(skb, proto, 576 + skb_mac_offset(skb), 577 + NULL); 577 578 578 579 return proto; 579 580 }