Commit 736f16de authored by Dongli Zhang's avatar Dongli Zhang Committed by David S. Miller
Browse files

net: tap: track dropped skb via kfree_skb_reason()



The TAP can be used as vhost-net backend. E.g., the tap_handle_frame() is
the interface to forward the skb from TAP to vhost-net/virtio-net.

However, there are many "goto drop" in the TAP driver. Therefore, the
kfree_skb_reason() is involved at each "goto drop" to help userspace
ftrace/ebpf to track the reason for the loss of packets.

The below reasons are introduced:

- SKB_DROP_REASON_SKB_CSUM
- SKB_DROP_REASON_SKB_GSO_SEG
- SKB_DROP_REASON_SKB_UCOPY_FAULT
- SKB_DROP_REASON_DEV_HDR
- SKB_DROP_REASON_FULL_RING

Cc: Joao Martins <joao.m.martins@oracle.com>
Cc: Joe Jin <joe.jin@oracle.com>
Signed-off-by: default avatarDongli Zhang <dongli.zhang@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 925a2421
Loading
Loading
Loading
Loading
+25 −10
Original line number Diff line number Diff line
@@ -322,6 +322,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
	struct tap_dev *tap;
	struct tap_queue *q;
	netdev_features_t features = TAP_FEATURES;
	enum skb_drop_reason drop_reason;

	tap = tap_dev_get_rcu(dev);
	if (!tap)
@@ -343,12 +344,16 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
		struct sk_buff *segs = __skb_gso_segment(skb, features, false);
		struct sk_buff *next;

		if (IS_ERR(segs))
		if (IS_ERR(segs)) {
			drop_reason = SKB_DROP_REASON_SKB_GSO_SEG;
			goto drop;
		}

		if (!segs) {
			if (ptr_ring_produce(&q->ring, skb))
			if (ptr_ring_produce(&q->ring, skb)) {
				drop_reason = SKB_DROP_REASON_FULL_RING;
				goto drop;
			}
			goto wake_up;
		}

@@ -356,8 +361,9 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
		skb_list_walk_safe(segs, skb, next) {
			skb_mark_not_on_list(skb);
			if (ptr_ring_produce(&q->ring, skb)) {
				kfree_skb(skb);
				kfree_skb_list(next);
				drop_reason = SKB_DROP_REASON_FULL_RING;
				kfree_skb_reason(skb, drop_reason);
				kfree_skb_list_reason(next, drop_reason);
				break;
			}
		}
@@ -369,11 +375,15 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
		 */
		if (skb->ip_summed == CHECKSUM_PARTIAL &&
		    !(features & NETIF_F_CSUM_MASK) &&
		    skb_checksum_help(skb))
		    skb_checksum_help(skb)) {
			drop_reason = SKB_DROP_REASON_SKB_CSUM;
			goto drop;
		if (ptr_ring_produce(&q->ring, skb))
		}
		if (ptr_ring_produce(&q->ring, skb)) {
			drop_reason = SKB_DROP_REASON_FULL_RING;
			goto drop;
		}
	}

wake_up:
	wake_up_interruptible_poll(sk_sleep(&q->sk), EPOLLIN | EPOLLRDNORM | EPOLLRDBAND);
@@ -383,7 +393,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
	/* Count errors/drops only here, thus don't care about args. */
	if (tap->count_rx_dropped)
		tap->count_rx_dropped(tap);
	kfree_skb(skb);
	kfree_skb_reason(skb, drop_reason);
	return RX_HANDLER_CONSUMED;
}
EXPORT_SYMBOL_GPL(tap_handle_frame);
@@ -632,6 +642,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
	int depth;
	bool zerocopy = false;
	size_t linear;
	enum skb_drop_reason drop_reason;

	if (q->flags & IFF_VNET_HDR) {
		vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
@@ -696,8 +707,10 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
	else
		err = skb_copy_datagram_from_iter(skb, 0, from, len);

	if (err)
	if (err) {
		drop_reason = SKB_DROP_REASON_SKB_UCOPY_FAULT;
		goto err_kfree;
	}

	skb_set_network_header(skb, ETH_HLEN);
	skb_reset_mac_header(skb);
@@ -706,9 +719,11 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
	if (vnet_hdr_len) {
		err = virtio_net_hdr_to_skb(skb, &vnet_hdr,
					    tap_is_little_endian(q));
		if (err)
		if (err) {
			drop_reason = SKB_DROP_REASON_DEV_HDR;
			goto err_kfree;
		}
	}

	skb_probe_transport_header(skb);

@@ -738,7 +753,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
	return total_len;

err_kfree:
	kfree_skb(skb);
	kfree_skb_reason(skb, drop_reason);

err:
	rcu_read_lock();
+13 −0
Original line number Diff line number Diff line
@@ -412,6 +412,19 @@ enum skb_drop_reason {
					 * this means that L3 protocol is
					 * not supported
					 */
	SKB_DROP_REASON_SKB_CSUM,	/* sk_buff checksum computation
					 * error
					 */
	SKB_DROP_REASON_SKB_GSO_SEG,	/* gso segmentation error */
	SKB_DROP_REASON_SKB_UCOPY_FAULT,	/* failed to copy data from
						 * user space, e.g., via
						 * zerocopy_sg_from_iter()
						 * or skb_orphan_frags_rx()
						 */
	SKB_DROP_REASON_DEV_HDR,	/* device driver specific
					 * header/metadata is invalid
					 */
	SKB_DROP_REASON_FULL_RING,	/* ring buffer is full */
	SKB_DROP_REASON_MAX,
};

+5 −0
Original line number Diff line number Diff line
@@ -51,6 +51,11 @@
	EM(SKB_DROP_REASON_XDP, XDP)				\
	EM(SKB_DROP_REASON_TC_INGRESS, TC_INGRESS)		\
	EM(SKB_DROP_REASON_PTYPE_ABSENT, PTYPE_ABSENT)		\
	EM(SKB_DROP_REASON_SKB_CSUM, SKB_CSUM)			\
	EM(SKB_DROP_REASON_SKB_GSO_SEG, SKB_GSO_SEG)		\
	EM(SKB_DROP_REASON_SKB_UCOPY_FAULT, SKB_UCOPY_FAULT)	\
	EM(SKB_DROP_REASON_DEV_HDR, DEV_HDR)			\
	EM(SKB_DROP_REASON_FULL_RING, FULL_RING)		\
	EMe(SKB_DROP_REASON_MAX, MAX)

#undef EM