Currently, we only dump a few selected skb fields in netdev_rx_csum_fault(). It is not suffient for debugging checksum fault. This patch introduces skb_dump() which dumps skb mac header, network header and its whole skb->data too.
Cc: Herbert Xu <herb...@gondor.apana.org.au> Cc: Eric Dumazet <eduma...@google.com> Cc: David Miller <da...@davemloft.net> Signed-off-by: Cong Wang <xiyou.wangc...@gmail.com> --- include/linux/skbuff.h | 5 +++++ net/core/dev.c | 6 +----- net/core/skbuff.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index afddb5c17ce5..844c0a7ff52f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4218,5 +4218,10 @@ static inline __wsum lco_csum(struct sk_buff *skb) return csum_partial(l4_hdr, csum_start - l4_hdr, partial); } +#ifdef CONFIG_BUG +void skb_dump(const char *level, const struct sk_buff *skb, bool dump_header, + bool dump_mac_header, bool dump_network_header); +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/core/dev.c b/net/core/dev.c index f2bfd2eda7b2..dc54c89fb4b1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3097,11 +3097,7 @@ void netdev_rx_csum_fault(struct net_device *dev, struct sk_buff *skb) pr_err("%s: hw csum failure\n", dev ? dev->name : "<unknown>"); if (dev) pr_err("dev features: %pNF\n", &dev->features); - pr_err("skb len=%u data_len=%u pkt_type=%u gso_size=%u gso_type=%u nr_frags=%u ip_summed=%u csum=%x csum_complete_sw=%d csum_valid=%d csum_level=%u\n", - skb->len, skb->data_len, skb->pkt_type, - skb_shinfo(skb)->gso_size, skb_shinfo(skb)->gso_type, - skb_shinfo(skb)->nr_frags, skb->ip_summed, skb->csum, - skb->csum_complete_sw, skb->csum_valid, skb->csum_level); + skb_dump(KERN_ERR, skb, true, true, true); dump_stack(); } } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b6ba923e7dc7..21aaef3f6a4a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -5555,3 +5555,52 @@ void skb_condense(struct sk_buff *skb) */ skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); } + +#ifdef CONFIG_BUG +void skb_dump(const char *level, const struct sk_buff *skb, bool dump_header, + bool dump_mac_header, bool dump_network_header) +{ + struct sk_buff *frag_iter; + int i; + + if (dump_header) + printk("%sskb len=%u data_len=%u pkt_type=%u gso_size=%u gso_type=%u nr_frags=%u ip_summed=%u csum=%x csum_complete_sw=%d csum_valid=%d csum_level=%u\n", + level, skb->len, skb->data_len, skb->pkt_type, + skb_shinfo(skb)->gso_size, skb_shinfo(skb)->gso_type, + skb_shinfo(skb)->nr_frags, skb->ip_summed, skb->csum, + skb->csum_complete_sw, skb->csum_valid, skb->csum_level); + + if (dump_mac_header && skb_mac_header_was_set(skb)) + print_hex_dump(level, "mac header: ", DUMP_PREFIX_OFFSET, 16, 1, + skb_mac_header(skb), skb_mac_header_len(skb), + false); + + if (dump_network_header && skb_network_header_was_set(skb)) + print_hex_dump(level, "network header: ", DUMP_PREFIX_OFFSET, + 16, 1, skb_network_header(skb), + skb_network_header_len(skb), false); + + print_hex_dump(level, "skb data: ", DUMP_PREFIX_OFFSET, 16, 1, + skb->data, skb->len, false); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 p_off, p_len, copied; + struct page *p; + u8 *vaddr; + + skb_frag_foreach_page(frag, frag->page_offset, skb_frag_size(frag), + p, p_off, p_len, copied) { + vaddr = kmap_atomic(p); + print_hex_dump(level, "skb frag: ", DUMP_PREFIX_OFFSET, + 16, 1, vaddr + p_off, p_len, false); + kunmap_atomic(vaddr); + } + } + + if (skb_has_frag_list(skb)) + printk("%sskb frags list:\n", level); + skb_walk_frags(skb, frag_iter) + skb_dump(level, frag_iter, false, false, false); +} +#endif -- 2.19.1