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.

tcp: shrink per-packet memset in __tcp_transmit_skb()

Use struct_group() to group the three fields in tcp_out_options that are
read unconditionally by tcp_options_write() and bpf_skops_write_hdr_opt()
(mss, bpf_opt_len, num_sack_blocks), then replace the full-struct memset
with a targeted memset of only that group.

struct tcp_out_options is 40 bytes without MPTCP and 96 bytes with
CONFIG_MPTCP=y (typical distro config). Every remaining field is either
assigned before first use by tcp_established_options()/tcp_syn_options(),
or gated behind its OPTION_* flag in tcp_options_write(). This memset
runs on every transmitted TCP packet, so shrinking it from 96 (or 40)
bytes to 4 bytes reduces per-packet overhead on the hot path.

Assembly comparison (x86-64, GCC 13, CONFIG_MPTCP=y):

Before: rep stos zeroing 96 bytes (5 instructions, 12 8-byte stores)
After: movl $0x0 zeroing 4 bytes (1 instruction, 1 store)

Also add opts->options = 0 at the top of tcp_syn_options(), which
already used |= without a prior clear. tcp_established_options() already
clears opts->options at its top.

Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Keita Morisaki <kmta1236@gmail.com>
Acked-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260304111517.2088694-1-kmta1236@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Keita Morisaki and committed by
Jakub Kicinski
cfcceb7a 752941e3

+11 -4
+11 -4
net/ipv4/tcp_output.c
··· 429 429 } 430 430 431 431 struct tcp_out_options { 432 + /* Following group is cleared in __tcp_transmit_skb() */ 433 + struct_group(cleared, 434 + u16 mss; /* 0 to disable */ 435 + u8 bpf_opt_len; /* length of BPF hdr option */ 436 + u8 num_sack_blocks; /* number of SACK blocks to include */ 437 + ); 438 + 439 + /* Caution: following fields are not cleared in __tcp_transmit_skb() */ 432 440 u16 options; /* bit field of OPTION_* */ 433 - u16 mss; /* 0 to disable */ 434 441 u8 ws; /* window scale, 0 to disable */ 435 - u8 num_sack_blocks; /* number of SACK blocks to include */ 436 442 u8 num_accecn_fields:7, /* number of AccECN fields needed */ 437 443 use_synack_ecn_bytes:1; /* Use synack_ecn_bytes or not */ 438 444 u8 hash_size; /* bytes in hash_location */ 439 - u8 bpf_opt_len; /* length of BPF hdr option */ 440 445 __u8 *hash_location; /* temporary pointer, overloaded */ 441 446 __u32 tsval, tsecr; /* need to include OPTION_TS */ 442 447 struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ ··· 969 964 unsigned int remaining = MAX_TCP_OPTION_SPACE; 970 965 struct tcp_fastopen_request *fastopen = tp->fastopen_req; 971 966 bool timestamps; 967 + 968 + opts->options = 0; 972 969 973 970 /* Better than switch (key.type) as it has static branches */ 974 971 if (tcp_key_is_md5(key)) { ··· 1572 1565 1573 1566 inet = inet_sk(sk); 1574 1567 tcb = TCP_SKB_CB(skb); 1575 - memset(&opts, 0, sizeof(opts)); 1568 + memset(&opts.cleared, 0, sizeof(opts.cleared)); 1576 1569 1577 1570 tcp_get_current_key(sk, &key); 1578 1571 if (unlikely(tcb->tcp_flags & TCPHDR_SYN)) {