Commit 7c4bf5fe authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'af_xdp-stats'



Ciara Loftus says:

====================
This series introduces new statistics for af_xdp:
1. drops due to rx ring being full
2. drops due to fill ring being empty
3. failures pulling an item from the tx ring

These statistics should assist users debugging and troubleshooting
peformance issues and packet drops.

The statistics are made available though the getsockopt and xsk_diag
interfaces, and the ability to dump these extended statistics is made
available in the xdpsock application via the --extra-stats or -x flag.

A separate patch which will add ss/iproute2 support will follow.
====================

Acked-by: default avatarBjörn Töpel <bjorn.topel@intel.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 24a38b7c 0d80cb46
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -69,7 +69,11 @@ struct xdp_sock {
	spinlock_t tx_completion_lock;
	/* Protects generic receive. */
	spinlock_t rx_lock;

	/* Statistics */
	u64 rx_dropped;
	u64 rx_queue_full;

	struct list_head map_list;
	/* Protects map_list */
	spinlock_t map_list_lock;
+4 −1
Original line number Diff line number Diff line
@@ -73,9 +73,12 @@ struct xdp_umem_reg {
};

struct xdp_statistics {
	__u64 rx_dropped; /* Dropped for reasons other than invalid desc */
	__u64 rx_dropped; /* Dropped for other reasons */
	__u64 rx_invalid_descs; /* Dropped due to invalid descriptor */
	__u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
	__u64 rx_ring_full; /* Dropped due to rx ring being full */
	__u64 rx_fill_ring_empty_descs; /* Failed to retrieve item from fill ring */
	__u64 tx_ring_empty_descs; /* Failed to retrieve item from tx ring */
};

struct xdp_options {
+11 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ struct xdp_diag_msg {
#define XDP_SHOW_RING_CFG	(1 << 1)
#define XDP_SHOW_UMEM		(1 << 2)
#define XDP_SHOW_MEMINFO	(1 << 3)
#define XDP_SHOW_STATS		(1 << 4)

enum {
	XDP_DIAG_NONE,
@@ -41,6 +42,7 @@ enum {
	XDP_DIAG_UMEM_FILL_RING,
	XDP_DIAG_UMEM_COMPLETION_RING,
	XDP_DIAG_MEMINFO,
	XDP_DIAG_STATS,
	__XDP_DIAG_MAX,
};

@@ -69,4 +71,13 @@ struct xdp_diag_umem {
	__u32	refs;
};

struct xdp_diag_stats {
	__u64	n_rx_dropped;
	__u64	n_rx_invalid;
	__u64	n_rx_full;
	__u64	n_fill_ring_empty;
	__u64	n_tx_invalid;
	__u64	n_tx_ring_empty;
};

#endif /* _LINUX_XDP_DIAG_H */
+31 −5
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
	addr = xp_get_handle(xskb);
	err = xskq_prod_reserve_desc(xs->rx, addr, len);
	if (err) {
		xs->rx_dropped++;
		xs->rx_queue_full++;
		return err;
	}

@@ -274,8 +274,10 @@ bool xsk_umem_consume_tx(struct xdp_umem *umem, struct xdp_desc *desc)

	rcu_read_lock();
	list_for_each_entry_rcu(xs, &umem->xsk_tx_list, list) {
		if (!xskq_cons_peek_desc(xs->tx, desc, umem))
		if (!xskq_cons_peek_desc(xs->tx, desc, umem)) {
			xs->tx->queue_empty_descs++;
			continue;
		}

		/* This is the backpressure mechanism for the Tx path.
		 * Reserve space in the completion queue and only proceed
@@ -387,6 +389,8 @@ static int xsk_generic_xmit(struct sock *sk)
		sent_frame = true;
	}

	xs->tx->queue_empty_descs++;

out:
	if (sent_frame)
		sk->sk_write_space(sk);
@@ -812,6 +816,12 @@ static void xsk_enter_umem_offsets(struct xdp_ring_offset_v1 *ring)
	ring->desc = offsetof(struct xdp_umem_ring, desc);
}

struct xdp_statistics_v1 {
	__u64 rx_dropped;
	__u64 rx_invalid_descs;
	__u64 tx_invalid_descs;
};

static int xsk_getsockopt(struct socket *sock, int level, int optname,
			  char __user *optval, int __user *optlen)
{
@@ -831,19 +841,35 @@ static int xsk_getsockopt(struct socket *sock, int level, int optname,
	case XDP_STATISTICS:
	{
		struct xdp_statistics stats;
		bool extra_stats = true;
		size_t stats_size;

		if (len < sizeof(stats))
		if (len < sizeof(struct xdp_statistics_v1)) {
			return -EINVAL;
		} else if (len < sizeof(stats)) {
			extra_stats = false;
			stats_size = sizeof(struct xdp_statistics_v1);
		} else {
			stats_size = sizeof(stats);
		}

		mutex_lock(&xs->mutex);
		stats.rx_dropped = xs->rx_dropped;
		if (extra_stats) {
			stats.rx_ring_full = xs->rx_queue_full;
			stats.rx_fill_ring_empty_descs =
				xs->umem ? xskq_nb_queue_empty_descs(xs->umem->fq) : 0;
			stats.tx_ring_empty_descs = xskq_nb_queue_empty_descs(xs->tx);
		} else {
			stats.rx_dropped += xs->rx_queue_full;
		}
		stats.rx_invalid_descs = xskq_nb_invalid_descs(xs->rx);
		stats.tx_invalid_descs = xskq_nb_invalid_descs(xs->tx);
		mutex_unlock(&xs->mutex);

		if (copy_to_user(optval, &stats, sizeof(stats)))
		if (copy_to_user(optval, &stats, stats_size))
			return -EFAULT;
		if (put_user(sizeof(stats), optlen))
		if (put_user(stats_size, optlen))
			return -EFAULT;

		return 0;
+1 −0
Original line number Diff line number Diff line
@@ -235,6 +235,7 @@ static struct xdp_buff_xsk *__xp_alloc(struct xsk_buff_pool *pool)

	for (;;) {
		if (!xskq_cons_peek_addr_unchecked(pool->fq, &addr)) {
			pool->fq->queue_empty_descs++;
			xp_release(xskb);
			return NULL;
		}
Loading