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-drop-rx-socket-tracepoint'

Yan Zhai says:

====================
net: pass receive socket to drop tracepoint

We set up our production packet drop monitoring around the kfree_skb
tracepoint. While this tracepoint is extremely valuable for diagnosing
critical problems, it also has some limitation with drops on the local
receive path: this tracepoint can only inspect the dropped skb itself,
but such skb might not carry enough information to:

1. determine in which netns/container this skb gets dropped
2. determine by which socket/service this skb oughts to be received

The 1st issue is because skb->dev is the only member field with valid
netns reference. But skb->dev can get cleared or reused. For example,
tcp_v4_rcv will clear skb->dev and in later processing it might be reused
for OFO tree.

The 2nd issue is because there is no reference on an skb that reliably
points to a receiving socket. skb->sk usually points to the local
sending socket, and it only points to a receive socket briefly after
early demux stage, yet the socket can get stolen later. For certain drop
reason like TCP OFO_MERGE, Zerowindow, UDP at PROTO_MEM error, etc, it
is hard to infer which receiving socket is impacted. This cannot be
overcome by simply looking at the packet header, because of
complications like sk lookup programs. In the past, single purpose
tracepoints like trace_udp_fail_queue_rcv_skb, trace_sock_rcvqueue_full,
etc are added as needed to provide more visibility. This could be
handled in a more generic way.

In this change set we propose a new 'sk_skb_reason_drop' call as a drop-in
replacement for kfree_skb_reason at various local input path. It accepts
an extra receiving socket argument. Both issues above can be resolved
via this new argument.

V4->V5: rename rx_skaddr to rx_sk to be more clear visually, suggested
by Jesper Dangaard Brouer.

V3->V4: adjusted the TP_STRUCT field order to align better, suggested by
Steven Rostedt.

V2->V3: fixed drop_monitor function signatures; fixed a few uninitialized sks;
Added a few missing report tags from test bots (also noticed by Dan
Carpenter and Simon Horman).

V1->V2: instead of using skb->cb, directly add the needed argument to
trace_kfree_skb tracepoint. Also renamed functions as Eric Dumazet
suggested.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+65 -51
+8 -2
include/linux/skbuff.h
··· 1251 1251 return true; 1252 1252 } 1253 1253 1254 - void __fix_address 1255 - kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason); 1254 + void __fix_address sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb, 1255 + enum skb_drop_reason reason); 1256 + 1257 + static inline void 1258 + kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason) 1259 + { 1260 + sk_skb_reason_drop(NULL, skb, reason); 1261 + } 1256 1262 1257 1263 /** 1258 1264 * kfree_skb - free an sk_buff with 'NOT_SPECIFIED' reason
+7 -4
include/trace/events/skb.h
··· 24 24 TRACE_EVENT(kfree_skb, 25 25 26 26 TP_PROTO(struct sk_buff *skb, void *location, 27 - enum skb_drop_reason reason), 27 + enum skb_drop_reason reason, struct sock *rx_sk), 28 28 29 - TP_ARGS(skb, location, reason), 29 + TP_ARGS(skb, location, reason, rx_sk), 30 30 31 31 TP_STRUCT__entry( 32 32 __field(void *, skbaddr) 33 33 __field(void *, location) 34 + __field(void *, rx_sk) 34 35 __field(unsigned short, protocol) 35 36 __field(enum skb_drop_reason, reason) 36 37 ), ··· 39 38 TP_fast_assign( 40 39 __entry->skbaddr = skb; 41 40 __entry->location = location; 41 + __entry->rx_sk = rx_sk; 42 42 __entry->protocol = ntohs(skb->protocol); 43 43 __entry->reason = reason; 44 44 ), 45 45 46 - TP_printk("skbaddr=%p protocol=%u location=%pS reason: %s", 47 - __entry->skbaddr, __entry->protocol, __entry->location, 46 + TP_printk("skbaddr=%p rx_sk=%p protocol=%u location=%pS reason: %s", 47 + __entry->skbaddr, __entry->rx_sk, __entry->protocol, 48 + __entry->location, 48 49 __print_symbolic(__entry->reason, 49 50 DEFINE_DROP_REASON(FN, FNe))) 50 51 );
+1 -1
net/core/dev.c
··· 5234 5234 trace_consume_skb(skb, net_tx_action); 5235 5235 else 5236 5236 trace_kfree_skb(skb, net_tx_action, 5237 - get_kfree_skb_cb(skb)->reason); 5237 + get_kfree_skb_cb(skb)->reason, NULL); 5238 5238 5239 5239 if (skb->fclone != SKB_FCLONE_UNAVAILABLE) 5240 5240 __kfree_skb(skb);
+6 -3
net/core/drop_monitor.c
··· 109 109 struct net_dm_alert_ops { 110 110 void (*kfree_skb_probe)(void *ignore, struct sk_buff *skb, 111 111 void *location, 112 - enum skb_drop_reason reason); 112 + enum skb_drop_reason reason, 113 + struct sock *rx_sk); 113 114 void (*napi_poll_probe)(void *ignore, struct napi_struct *napi, 114 115 int work, int budget); 115 116 void (*work_item_func)(struct work_struct *work); ··· 265 264 266 265 static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, 267 266 void *location, 268 - enum skb_drop_reason reason) 267 + enum skb_drop_reason reason, 268 + struct sock *rx_sk) 269 269 { 270 270 trace_drop_common(skb, location); 271 271 } ··· 493 491 static void net_dm_packet_trace_kfree_skb_hit(void *ignore, 494 492 struct sk_buff *skb, 495 493 void *location, 496 - enum skb_drop_reason reason) 494 + enum skb_drop_reason reason, 495 + struct sock *rx_sk) 497 496 { 498 497 ktime_t tstamp = ktime_get_real(); 499 498 struct per_cpu_dm_data *data;
+12 -10
net/core/skbuff.c
··· 1190 1190 EXPORT_SYMBOL(__kfree_skb); 1191 1191 1192 1192 static __always_inline 1193 - bool __kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason) 1193 + bool __sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb, 1194 + enum skb_drop_reason reason) 1194 1195 { 1195 1196 if (unlikely(!skb_unref(skb))) 1196 1197 return false; ··· 1204 1203 if (reason == SKB_CONSUMED) 1205 1204 trace_consume_skb(skb, __builtin_return_address(0)); 1206 1205 else 1207 - trace_kfree_skb(skb, __builtin_return_address(0), reason); 1206 + trace_kfree_skb(skb, __builtin_return_address(0), reason, sk); 1208 1207 return true; 1209 1208 } 1210 1209 1211 1210 /** 1212 - * kfree_skb_reason - free an sk_buff with special reason 1211 + * sk_skb_reason_drop - free an sk_buff with special reason 1212 + * @sk: the socket to receive @skb, or NULL if not applicable 1213 1213 * @skb: buffer to free 1214 1214 * @reason: reason why this skb is dropped 1215 1215 * 1216 - * Drop a reference to the buffer and free it if the usage count has 1217 - * hit zero. Meanwhile, pass the drop reason to 'kfree_skb' 1218 - * tracepoint. 1216 + * Drop a reference to the buffer and free it if the usage count has hit 1217 + * zero. Meanwhile, pass the receiving socket and drop reason to 1218 + * 'kfree_skb' tracepoint. 1219 1219 */ 1220 1220 void __fix_address 1221 - kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason) 1221 + sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb, enum skb_drop_reason reason) 1222 1222 { 1223 - if (__kfree_skb_reason(skb, reason)) 1223 + if (__sk_skb_reason_drop(sk, skb, reason)) 1224 1224 __kfree_skb(skb); 1225 1225 } 1226 - EXPORT_SYMBOL(kfree_skb_reason); 1226 + EXPORT_SYMBOL(sk_skb_reason_drop); 1227 1227 1228 1228 #define KFREE_SKB_BULK_SIZE 16 1229 1229 ··· 1263 1261 while (segs) { 1264 1262 struct sk_buff *next = segs->next; 1265 1263 1266 - if (__kfree_skb_reason(segs, reason)) { 1264 + if (__sk_skb_reason_drop(NULL, segs, reason)) { 1267 1265 skb_poison_list(segs); 1268 1266 kfree_skb_add_bulk(segs, &sa, reason); 1269 1267 }
+1 -1
net/ipv4/ping.c
··· 946 946 pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", 947 947 inet_sk(sk), inet_sk(sk)->inet_num, skb); 948 948 if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 949 - kfree_skb_reason(skb, reason); 949 + sk_skb_reason_drop(sk, skb, reason); 950 950 pr_debug("ping_queue_rcv_skb -> failed\n"); 951 951 return reason; 952 952 }
+2 -2
net/ipv4/raw.c
··· 301 301 302 302 ipv4_pktinfo_prepare(sk, skb, true); 303 303 if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 304 - kfree_skb_reason(skb, reason); 304 + sk_skb_reason_drop(sk, skb, reason); 305 305 return NET_RX_DROP; 306 306 } 307 307 ··· 312 312 { 313 313 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { 314 314 atomic_inc(&sk->sk_drops); 315 - kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY); 315 + sk_skb_reason_drop(sk, skb, SKB_DROP_REASON_XFRM_POLICY); 316 316 return NET_RX_DROP; 317 317 } 318 318 nf_reset_ct(skb);
+1 -1
net/ipv4/syncookies.c
··· 496 496 out_free: 497 497 reqsk_free(req); 498 498 out_drop: 499 - kfree_skb_reason(skb, reason); 499 + sk_skb_reason_drop(sk, skb, reason); 500 500 return NULL; 501 501 }
+1 -1
net/ipv4/tcp_input.c
··· 4860 4860 enum skb_drop_reason reason) 4861 4861 { 4862 4862 sk_drops_add(sk, skb); 4863 - kfree_skb_reason(skb, reason); 4863 + sk_skb_reason_drop(sk, skb, reason); 4864 4864 } 4865 4865 4866 4866 /* This one checks to see if we can put data from the
+3 -3
net/ipv4/tcp_ipv4.c
··· 1932 1932 reset: 1933 1933 tcp_v4_send_reset(rsk, skb, sk_rst_convert_drop_reason(reason)); 1934 1934 discard: 1935 - kfree_skb_reason(skb, reason); 1935 + sk_skb_reason_drop(sk, skb, reason); 1936 1936 /* Be careful here. If this function gets more complicated and 1937 1937 * gcc suffers from register pressure on the x86, sk (in %ebx) 1938 1938 * might be destroyed here. This current version compiles correctly, ··· 2168 2168 int dif = inet_iif(skb); 2169 2169 const struct iphdr *iph; 2170 2170 const struct tcphdr *th; 2171 + struct sock *sk = NULL; 2171 2172 bool refcounted; 2172 - struct sock *sk; 2173 2173 int ret; 2174 2174 u32 isn; 2175 2175 ··· 2368 2368 discard_it: 2369 2369 SKB_DR_OR(drop_reason, NOT_SPECIFIED); 2370 2370 /* Discard frame. */ 2371 - kfree_skb_reason(skb, drop_reason); 2371 + sk_skb_reason_drop(sk, skb, drop_reason); 2372 2372 return 0; 2373 2373 2374 2374 discard_and_relse:
+5 -5
net/ipv4/udp.c
··· 2074 2074 } 2075 2075 UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 2076 2076 trace_udp_fail_queue_rcv_skb(rc, sk, skb); 2077 - kfree_skb_reason(skb, drop_reason); 2077 + sk_skb_reason_drop(sk, skb, drop_reason); 2078 2078 return -1; 2079 2079 } 2080 2080 ··· 2196 2196 drop: 2197 2197 __UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 2198 2198 atomic_inc(&sk->sk_drops); 2199 - kfree_skb_reason(skb, drop_reason); 2199 + sk_skb_reason_drop(sk, skb, drop_reason); 2200 2200 return -1; 2201 2201 } 2202 2202 ··· 2383 2383 int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, 2384 2384 int proto) 2385 2385 { 2386 - struct sock *sk; 2386 + struct sock *sk = NULL; 2387 2387 struct udphdr *uh; 2388 2388 unsigned short ulen; 2389 2389 struct rtable *rt = skb_rtable(skb); ··· 2460 2460 * Hmm. We got an UDP packet to a port to which we 2461 2461 * don't wanna listen. Ignore it. 2462 2462 */ 2463 - kfree_skb_reason(skb, drop_reason); 2463 + sk_skb_reason_drop(sk, skb, drop_reason); 2464 2464 return 0; 2465 2465 2466 2466 short_packet: ··· 2485 2485 __UDP_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); 2486 2486 drop: 2487 2487 __UDP_INC_STATS(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); 2488 - kfree_skb_reason(skb, drop_reason); 2488 + sk_skb_reason_drop(sk, skb, drop_reason); 2489 2489 return 0; 2490 2490 } 2491 2491
+4 -4
net/ipv6/raw.c
··· 362 362 if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) && 363 363 skb_checksum_complete(skb)) { 364 364 atomic_inc(&sk->sk_drops); 365 - kfree_skb_reason(skb, SKB_DROP_REASON_SKB_CSUM); 365 + sk_skb_reason_drop(sk, skb, SKB_DROP_REASON_SKB_CSUM); 366 366 return NET_RX_DROP; 367 367 } 368 368 369 369 /* Charge it to the socket. */ 370 370 skb_dst_drop(skb); 371 371 if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 372 - kfree_skb_reason(skb, reason); 372 + sk_skb_reason_drop(sk, skb, reason); 373 373 return NET_RX_DROP; 374 374 } 375 375 ··· 390 390 391 391 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { 392 392 atomic_inc(&sk->sk_drops); 393 - kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY); 393 + sk_skb_reason_drop(sk, skb, SKB_DROP_REASON_XFRM_POLICY); 394 394 return NET_RX_DROP; 395 395 } 396 396 nf_reset_ct(skb); ··· 415 415 if (inet_test_bit(HDRINCL, sk)) { 416 416 if (skb_checksum_complete(skb)) { 417 417 atomic_inc(&sk->sk_drops); 418 - kfree_skb_reason(skb, SKB_DROP_REASON_SKB_CSUM); 418 + sk_skb_reason_drop(sk, skb, SKB_DROP_REASON_SKB_CSUM); 419 419 return NET_RX_DROP; 420 420 } 421 421 }
+1 -1
net/ipv6/syncookies.c
··· 275 275 out_free: 276 276 reqsk_free(req); 277 277 out_drop: 278 - kfree_skb_reason(skb, reason); 278 + sk_skb_reason_drop(sk, skb, reason); 279 279 return NULL; 280 280 }
+3 -3
net/ipv6/tcp_ipv6.c
··· 1674 1674 discard: 1675 1675 if (opt_skb) 1676 1676 __kfree_skb(opt_skb); 1677 - kfree_skb_reason(skb, reason); 1677 + sk_skb_reason_drop(sk, skb, reason); 1678 1678 return 0; 1679 1679 csum_err: 1680 1680 reason = SKB_DROP_REASON_TCP_CSUM; ··· 1747 1747 int dif = inet6_iif(skb); 1748 1748 const struct tcphdr *th; 1749 1749 const struct ipv6hdr *hdr; 1750 + struct sock *sk = NULL; 1750 1751 bool refcounted; 1751 - struct sock *sk; 1752 1752 int ret; 1753 1753 u32 isn; 1754 1754 struct net *net = dev_net(skb->dev); ··· 1940 1940 1941 1941 discard_it: 1942 1942 SKB_DR_OR(drop_reason, NOT_SPECIFIED); 1943 - kfree_skb_reason(skb, drop_reason); 1943 + sk_skb_reason_drop(sk, skb, drop_reason); 1944 1944 return 0; 1945 1945 1946 1946 discard_and_relse:
+5 -5
net/ipv6/udp.c
··· 673 673 } 674 674 UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 675 675 trace_udp_fail_queue_rcv_skb(rc, sk, skb); 676 - kfree_skb_reason(skb, drop_reason); 676 + sk_skb_reason_drop(sk, skb, drop_reason); 677 677 return -1; 678 678 } 679 679 ··· 776 776 drop: 777 777 __UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 778 778 atomic_inc(&sk->sk_drops); 779 - kfree_skb_reason(skb, drop_reason); 779 + sk_skb_reason_drop(sk, skb, drop_reason); 780 780 return -1; 781 781 } 782 782 ··· 940 940 enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 941 941 const struct in6_addr *saddr, *daddr; 942 942 struct net *net = dev_net(skb->dev); 943 + struct sock *sk = NULL; 943 944 struct udphdr *uh; 944 - struct sock *sk; 945 945 bool refcounted; 946 946 u32 ulen = 0; 947 947 ··· 1033 1033 __UDP6_INC_STATS(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); 1034 1034 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 1035 1035 1036 - kfree_skb_reason(skb, reason); 1036 + sk_skb_reason_drop(sk, skb, reason); 1037 1037 return 0; 1038 1038 1039 1039 short_packet: ··· 1054 1054 __UDP6_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); 1055 1055 discard: 1056 1056 __UDP6_INC_STATS(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); 1057 - kfree_skb_reason(skb, reason); 1057 + sk_skb_reason_drop(sk, skb, reason); 1058 1058 return 0; 1059 1059 } 1060 1060
+5 -5
net/packet/af_packet.c
··· 2121 2121 struct packet_type *pt, struct net_device *orig_dev) 2122 2122 { 2123 2123 enum skb_drop_reason drop_reason = SKB_CONSUMED; 2124 - struct sock *sk; 2124 + struct sock *sk = NULL; 2125 2125 struct sockaddr_ll *sll; 2126 2126 struct packet_sock *po; 2127 2127 u8 *skb_head = skb->data; ··· 2226 2226 skb->len = skb_len; 2227 2227 } 2228 2228 drop: 2229 - kfree_skb_reason(skb, drop_reason); 2229 + sk_skb_reason_drop(sk, skb, drop_reason); 2230 2230 return 0; 2231 2231 } 2232 2232 ··· 2234 2234 struct packet_type *pt, struct net_device *orig_dev) 2235 2235 { 2236 2236 enum skb_drop_reason drop_reason = SKB_CONSUMED; 2237 - struct sock *sk; 2237 + struct sock *sk = NULL; 2238 2238 struct packet_sock *po; 2239 2239 struct sockaddr_ll *sll; 2240 2240 union tpacket_uhdr h; ··· 2494 2494 skb->len = skb_len; 2495 2495 } 2496 2496 drop: 2497 - kfree_skb_reason(skb, drop_reason); 2497 + sk_skb_reason_drop(sk, skb, drop_reason); 2498 2498 return 0; 2499 2499 2500 2500 drop_n_account: ··· 2503 2503 drop_reason = SKB_DROP_REASON_PACKET_SOCK_ERROR; 2504 2504 2505 2505 sk->sk_data_ready(sk); 2506 - kfree_skb_reason(copy_skb, drop_reason); 2506 + sk_skb_reason_drop(sk, copy_skb, drop_reason); 2507 2507 goto drop_n_restore; 2508 2508 } 2509 2509