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.

Merge branch 'net-reduce-sk_filter-and-friends-bloat'

Eric Dumazet says:

====================
net: reduce sk_filter() (and friends) bloat

Some functions return an error by value, and a drop_reason
by an output parameter. This extra parameter can force stack canaries.

A drop_reason is enough and more efficient.

This series reduces bloat by 678 bytes on x86_64:

$ scripts/bloat-o-meter -t vmlinux.old vmlinux.final
add/remove: 0/0 grow/shrink: 3/18 up/down: 79/-757 (-678)
Function old new delta
vsock_queue_rcv_skb 50 79 +29
ipmr_cache_report 1290 1315 +25
ip6mr_cache_report 1322 1347 +25
tcp_v6_rcv 3169 3167 -2
packet_rcv_spkt 329 327 -2
unix_dgram_sendmsg 1731 1726 -5
netlink_unicast 957 945 -12
netlink_dump 1372 1359 -13
sk_filter_trim_cap 889 858 -31
netlink_broadcast_filtered 1633 1595 -38
tcp_v4_rcv 3152 3111 -41
raw_rcv_skb 122 80 -42
ping_queue_rcv_skb 109 61 -48
ping_rcv 215 162 -53
rawv6_rcv_skb 278 224 -54
__sk_receive_skb 690 632 -58
raw_rcv 591 527 -64
udpv6_queue_rcv_one_skb 935 869 -66
udp_queue_rcv_one_skb 919 853 -66
tun_net_xmit 1146 1074 -72
sock_queue_rcv_skb_reason 166 76 -90
Total: Before=29722890, After=29722212, chg -0.00%

Future conversions from sock_queue_rcv_skb() to sock_queue_rcv_skb_reason()
can be done later.
====================

Link: https://patch.msgid.link/20260409145625.2306224-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+81 -68
+5 -3
drivers/net/tun.c
··· 1031 1031 goto drop; 1032 1032 } 1033 1033 1034 - if (tfile->socket.sk->sk_filter && 1035 - sk_filter_reason(tfile->socket.sk, skb, &drop_reason)) 1036 - goto drop; 1034 + if (tfile->socket.sk->sk_filter) { 1035 + drop_reason = sk_filter_reason(tfile->socket.sk, skb); 1036 + if (drop_reason) 1037 + goto drop; 1038 + } 1037 1039 1038 1040 len = run_ebpf_filter(tun, skb, len); 1039 1041 if (len == 0) {
+8 -7
include/linux/filter.h
··· 1092 1092 return set_memory_rox((unsigned long)hdr, hdr->size >> PAGE_SHIFT); 1093 1093 } 1094 1094 1095 - int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap, 1096 - enum skb_drop_reason *reason); 1095 + enum skb_drop_reason 1096 + sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap); 1097 1097 1098 1098 static inline int sk_filter(struct sock *sk, struct sk_buff *skb) 1099 1099 { 1100 - enum skb_drop_reason ignore_reason; 1100 + enum skb_drop_reason drop_reason; 1101 1101 1102 - return sk_filter_trim_cap(sk, skb, 1, &ignore_reason); 1102 + drop_reason = sk_filter_trim_cap(sk, skb, 1); 1103 + return drop_reason ? -EPERM : 0; 1103 1104 } 1104 1105 1105 - static inline int sk_filter_reason(struct sock *sk, struct sk_buff *skb, 1106 - enum skb_drop_reason *reason) 1106 + static inline enum skb_drop_reason 1107 + sk_filter_reason(struct sock *sk, struct sk_buff *skb) 1107 1108 { 1108 - return sk_filter_trim_cap(sk, skb, 1, reason); 1109 + return sk_filter_trim_cap(sk, skb, 1); 1109 1110 } 1110 1111 1111 1112 struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
+14 -3
include/net/sock.h
··· 2502 2502 struct sk_buff *skb)); 2503 2503 int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); 2504 2504 2505 - int sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb, 2506 - enum skb_drop_reason *reason); 2505 + enum skb_drop_reason 2506 + sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb); 2507 2507 2508 2508 static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 2509 2509 { 2510 - return sock_queue_rcv_skb_reason(sk, skb, NULL); 2510 + enum skb_drop_reason drop_reason = sock_queue_rcv_skb_reason(sk, skb); 2511 + 2512 + switch (drop_reason) { 2513 + case SKB_DROP_REASON_SOCKET_RCVBUFF: 2514 + return -ENOMEM; 2515 + case SKB_DROP_REASON_PROTO_MEM: 2516 + return -ENOBUFS; 2517 + case 0: 2518 + return 0; 2519 + default: 2520 + return -EPERM; 2521 + } 2511 2522 } 2512 2523 2513 2524 int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
+3 -3
include/net/tcp.h
··· 1682 1682 1683 1683 enum skb_drop_reason tcp_add_backlog(struct sock *sk, struct sk_buff *skb); 1684 1684 1685 - static inline int tcp_filter(struct sock *sk, struct sk_buff *skb, 1686 - enum skb_drop_reason *reason) 1685 + static inline enum skb_drop_reason 1686 + tcp_filter(struct sock *sk, struct sk_buff *skb) 1687 1687 { 1688 1688 const struct tcphdr *th = (const struct tcphdr *)skb->data; 1689 1689 1690 - return sk_filter_trim_cap(sk, skb, __tcp_hdrlen(th), reason); 1690 + return sk_filter_trim_cap(sk, skb, __tcp_hdrlen(th)); 1691 1691 } 1692 1692 1693 1693 void tcp_set_state(struct sock *sk, int state);
+2 -3
net/can/bcm.c
··· 363 363 struct sockaddr_can *addr; 364 364 struct sock *sk = op->sk; 365 365 unsigned int datalen = head->nframes * op->cfsiz; 366 - int err; 367 366 unsigned int *pflags; 368 367 enum skb_drop_reason reason; 369 368 ··· 419 420 addr->can_family = AF_CAN; 420 421 addr->can_ifindex = op->rx_ifindex; 421 422 422 - err = sock_queue_rcv_skb_reason(sk, skb, &reason); 423 - if (err < 0) { 423 + reason = sock_queue_rcv_skb_reason(sk, skb); 424 + if (reason) { 424 425 struct bcm_sock *bo = bcm_sk(sk); 425 426 426 427 sk_skb_reason_drop(sk, skb, reason);
+2 -1
net/can/isotp.c
··· 291 291 addr->can_family = AF_CAN; 292 292 addr->can_ifindex = skb->dev->ifindex; 293 293 294 - if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) 294 + reason = sock_queue_rcv_skb_reason(sk, skb); 295 + if (reason) 295 296 sk_skb_reason_drop(sk, skb, reason); 296 297 } 297 298
+2 -1
net/can/j1939/socket.c
··· 333 333 if (skb->sk) 334 334 skcb->msg_flags |= MSG_DONTROUTE; 335 335 336 - if (sock_queue_rcv_skb_reason(&jsk->sk, skb, &reason) < 0) 336 + reason = sock_queue_rcv_skb_reason(&jsk->sk, skb); 337 + if (reason) 337 338 sk_skb_reason_drop(&jsk->sk, skb, reason); 338 339 } 339 340
+2 -1
net/can/raw.c
··· 207 207 if (oskb->sk == sk) 208 208 *pflags |= MSG_CONFIRM; 209 209 210 - if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) 210 + reason = sock_queue_rcv_skb_reason(sk, skb); 211 + if (reason) 211 212 sk_skb_reason_drop(sk, skb, reason); 212 213 } 213 214
+13 -17
net/core/filter.c
··· 121 121 * @sk: sock associated with &sk_buff 122 122 * @skb: buffer to filter 123 123 * @cap: limit on how short the eBPF program may trim the packet 124 - * @reason: record drop reason on errors (negative return value) 125 124 * 126 125 * Run the eBPF program and then cut skb->data to correct size returned by 127 126 * the program. If pkt_len is 0 we toss packet. If skb->len is smaller 128 127 * than pkt_len we keep whole skb->data. This is the socket level 129 128 * wrapper to bpf_prog_run. It returns 0 if the packet should 130 - * be accepted or -EPERM if the packet should be tossed. 129 + * be accepted or a drop_reason if the packet should be tossed. 131 130 * 132 131 */ 133 - int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, 134 - unsigned int cap, enum skb_drop_reason *reason) 132 + enum skb_drop_reason 133 + sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) 135 134 { 136 - int err; 135 + enum skb_drop_reason drop_reason; 137 136 struct sk_filter *filter; 137 + int err; 138 138 139 139 /* 140 140 * If the skb was allocated from pfmemalloc reserves, only ··· 143 143 */ 144 144 if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) { 145 145 NET_INC_STATS(sock_net(sk), LINUX_MIB_PFMEMALLOCDROP); 146 - *reason = SKB_DROP_REASON_PFMEMALLOC; 147 - return -ENOMEM; 146 + return SKB_DROP_REASON_PFMEMALLOC; 148 147 } 149 148 err = BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb); 150 - if (err) { 151 - *reason = SKB_DROP_REASON_SOCKET_FILTER; 152 - return err; 153 - } 149 + if (err) 150 + return SKB_DROP_REASON_SOCKET_FILTER; 154 151 155 152 err = security_sock_rcv_skb(sk, skb); 156 - if (err) { 157 - *reason = SKB_DROP_REASON_SECURITY_HOOK; 158 - return err; 159 - } 153 + if (err) 154 + return SKB_DROP_REASON_SECURITY_HOOK; 160 155 156 + drop_reason = 0; 161 157 rcu_read_lock(); 162 158 filter = rcu_dereference(sk->sk_filter); 163 159 if (filter) { ··· 165 169 skb->sk = save_sk; 166 170 err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; 167 171 if (err) 168 - *reason = SKB_DROP_REASON_SOCKET_FILTER; 172 + drop_reason = SKB_DROP_REASON_SOCKET_FILTER; 169 173 } 170 174 rcu_read_unlock(); 171 175 172 - return err; 176 + return drop_reason; 173 177 } 174 178 EXPORT_SYMBOL(sk_filter_trim_cap); 175 179
+11 -18
net/core/sock.c
··· 520 520 } 521 521 EXPORT_SYMBOL(__sock_queue_rcv_skb); 522 522 523 - int sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb, 524 - enum skb_drop_reason *reason) 523 + enum skb_drop_reason 524 + sock_queue_rcv_skb_reason(struct sock *sk, struct sk_buff *skb) 525 525 { 526 526 enum skb_drop_reason drop_reason; 527 527 int err; 528 528 529 - err = sk_filter_reason(sk, skb, &drop_reason); 530 - if (err) 531 - goto out; 529 + drop_reason = sk_filter_reason(sk, skb); 530 + if (drop_reason) 531 + return drop_reason; 532 532 533 533 err = __sock_queue_rcv_skb(sk, skb); 534 534 switch (err) { 535 535 case -ENOMEM: 536 - drop_reason = SKB_DROP_REASON_SOCKET_RCVBUFF; 537 - break; 536 + return SKB_DROP_REASON_SOCKET_RCVBUFF; 538 537 case -ENOBUFS: 539 - drop_reason = SKB_DROP_REASON_PROTO_MEM; 540 - break; 541 - default: 542 - drop_reason = SKB_NOT_DROPPED_YET; 543 - break; 538 + return SKB_DROP_REASON_PROTO_MEM; 544 539 } 545 - out: 546 - if (reason) 547 - *reason = drop_reason; 548 - return err; 540 + return SKB_NOT_DROPPED_YET; 549 541 } 550 542 EXPORT_SYMBOL(sock_queue_rcv_skb_reason); 551 543 552 544 int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, 553 545 const int nested, unsigned int trim_cap, bool refcounted) 554 546 { 555 - enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 547 + enum skb_drop_reason reason; 556 548 int rc = NET_RX_SUCCESS; 557 549 int err; 558 550 559 - if (sk_filter_trim_cap(sk, skb, trim_cap, &reason)) 551 + reason = sk_filter_trim_cap(sk, skb, trim_cap); 552 + if (reason) 560 553 goto discard_and_relse; 561 554 562 555 skb->dev = NULL;
+2 -1
net/ipv4/ping.c
··· 935 935 936 936 pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", 937 937 inet_sk(sk), inet_sk(sk)->inet_num, skb); 938 - if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 938 + reason = sock_queue_rcv_skb_reason(sk, skb); 939 + if (reason) { 939 940 sk_skb_reason_drop(sk, skb, reason); 940 941 pr_debug("ping_queue_rcv_skb -> failed\n"); 941 942 return reason;
+2 -1
net/ipv4/raw.c
··· 300 300 /* Charge it to the socket. */ 301 301 302 302 ipv4_pktinfo_prepare(sk, skb, true); 303 - if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 303 + reason = sock_queue_rcv_skb_reason(sk, skb); 304 + if (reason) { 304 305 sk_skb_reason_drop(sk, skb, reason); 305 306 return NET_RX_DROP; 306 307 }
+4 -2
net/ipv4/tcp_ipv4.c
··· 2160 2160 } 2161 2161 refcounted = true; 2162 2162 nsk = NULL; 2163 - if (!tcp_filter(sk, skb, &drop_reason)) { 2163 + drop_reason = tcp_filter(sk, skb); 2164 + if (!drop_reason) { 2164 2165 th = (const struct tcphdr *)skb->data; 2165 2166 iph = ip_hdr(skb); 2166 2167 tcp_v4_fill_cb(skb, iph, th); ··· 2222 2221 2223 2222 nf_reset_ct(skb); 2224 2223 2225 - if (tcp_filter(sk, skb, &drop_reason)) 2224 + drop_reason = tcp_filter(sk, skb); 2225 + if (drop_reason) 2226 2226 goto discard_and_relse; 2227 2227 2228 2228 th = (const struct tcphdr *)skb->data;
+2 -1
net/ipv4/udp.c
··· 2392 2392 udp_lib_checksum_complete(skb)) 2393 2393 goto csum_error; 2394 2394 2395 - if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr), &drop_reason)) 2395 + drop_reason = sk_filter_trim_cap(sk, skb, sizeof(struct udphdr)); 2396 + if (drop_reason) 2396 2397 goto drop; 2397 2398 2398 2399 udp_csum_pull_header(skb);
+2 -1
net/ipv6/raw.c
··· 369 369 370 370 /* Charge it to the socket. */ 371 371 skb_dst_drop(skb); 372 - if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 372 + reason = sock_queue_rcv_skb_reason(sk, skb); 373 + if (reason) { 373 374 sk_skb_reason_drop(sk, skb, reason); 374 375 return NET_RX_DROP; 375 376 }
+4 -2
net/ipv6/tcp_ipv6.c
··· 1794 1794 } 1795 1795 refcounted = true; 1796 1796 nsk = NULL; 1797 - if (!tcp_filter(sk, skb, &drop_reason)) { 1797 + drop_reason = tcp_filter(sk, skb); 1798 + if (!drop_reason) { 1798 1799 th = (const struct tcphdr *)skb->data; 1799 1800 hdr = ipv6_hdr(skb); 1800 1801 tcp_v6_fill_cb(skb, hdr, th); ··· 1856 1855 1857 1856 nf_reset_ct(skb); 1858 1857 1859 - if (tcp_filter(sk, skb, &drop_reason)) 1858 + drop_reason = tcp_filter(sk, skb); 1859 + if (drop_reason) 1860 1860 goto discard_and_relse; 1861 1861 1862 1862 th = (const struct tcphdr *)skb->data;
+2 -1
net/ipv6/udp.c
··· 853 853 udp_lib_checksum_complete(skb)) 854 854 goto csum_error; 855 855 856 - if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr), &drop_reason)) 856 + drop_reason = sk_filter_trim_cap(sk, skb, sizeof(struct udphdr)); 857 + if (drop_reason) 857 858 goto drop; 858 859 859 860 udp_csum_pull_header(skb);
+1 -2
net/rose/rose_in.c
··· 101 101 */ 102 102 static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m) 103 103 { 104 - enum skb_drop_reason dr; /* ignored */ 105 104 struct rose_sock *rose = rose_sk(sk); 106 105 int queued = 0; 107 106 ··· 162 163 rose_frames_acked(sk, nr); 163 164 if (ns == rose->vr) { 164 165 rose_start_idletimer(sk); 165 - if (!sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN, &dr) && 166 + if (!sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) && 166 167 __sock_queue_rcv_skb(sk, skb) == 0) { 167 168 rose->vr = (rose->vr + 1) % ROSE_MODULUS; 168 169 queued = 1;