kfree_skb_list() calls kfree_skb(), thus triggering as many dropwatch events as the number of skbs in the list. This can disturb the analysis of packet drops, e.g. with fragmented echo requests generated by ICMP sockets, or with regular SCTP packets: when consume_skb() frees them, the kernel's drop monitor may wrongly account for several packet drops: consume skb() skb_release_data() kfree_skb_list() kfree_skb() <-- false dropwatch event don't call kfree_skb() when freeing a skb list, use a dedicated tracepoint instead. By printing "cur" and "next", it also becomes possible to reconstruct the skb list from its members. Signed-off-by: Davide Caratti <dcaratti@xxxxxxxxxx> --- include/trace/events/skb.h | 19 +++++++++++++++++++ net/core/skbuff.c | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 9e92f22eb086..b16e3544bbbe 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -51,6 +51,25 @@ TRACE_EVENT(consume_skb, TP_printk("skbaddr=%p", __entry->skbaddr) ); +TRACE_EVENT(kfree_skb_list, + + TP_PROTO(struct sk_buff *cur, struct sk_buff *next), + + TP_ARGS(cur, next), + + TP_STRUCT__entry( + __field( void *, cur_addr ) + __field( void *, next_addr ) + ), + + TP_fast_assign( + __entry->cur_addr = cur; + __entry->next_addr = next; + ), + + TP_printk("cur=%p next=%p", __entry->cur_addr, __entry->next_addr) +); + TRACE_EVENT(skb_copy_datagram_iovec, TP_PROTO(const struct sk_buff *skb, int len), diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1ba8f0163744..7ed6bfc5dfd0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -702,7 +702,11 @@ void kfree_skb_list(struct sk_buff *segs) while (segs) { struct sk_buff *next = segs->next; - kfree_skb(segs); + if (!skb_unref(segs)) + continue; + + trace_kfree_skb_list(segs, next); + __kfree_skb(segs); segs = next; } } -- 2.26.2