xsk: Add new statistics
authorCiara Loftus <ciara.loftus@intel.com>
Wed, 8 Jul 2020 07:28:33 +0000 (07:28 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 13 Jul 2020 22:32:56 +0000 (15:32 -0700)
It can be useful for the user to know the reason behind a dropped packet.
Introduce new counters which track drops on the receive path caused by:
1. rx ring being full
2. fill ring being empty

Also, on the tx path introduce a counter which tracks the number of times
we attempt pull from the tx ring when it is empty.

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200708072835.4427-2-ciara.loftus@intel.com
include/net/xdp_sock.h
include/uapi/linux/if_xdp.h
net/xdp/xsk.c
net/xdp/xsk_buff_pool.c
net/xdp/xsk_queue.h
tools/include/uapi/linux/if_xdp.h

index 96bfc5f..c9d87cc 100644 (file)
@@ -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;
index be328c5..a78a809 100644 (file)
@@ -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 {
index 3700266..26e3bba 100644 (file)
@@ -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;
index 540ed75..89cf355 100644 (file)
@@ -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;
                }
index 5b5d24d..bf42cfd 100644 (file)
@@ -38,6 +38,7 @@ struct xsk_queue {
        u32 cached_cons;
        struct xdp_ring *ring;
        u64 invalid_descs;
+       u64 queue_empty_descs;
 };
 
 /* The structure of the shared state of the rings are the same as the
@@ -354,6 +355,11 @@ static inline u64 xskq_nb_invalid_descs(struct xsk_queue *q)
        return q ? q->invalid_descs : 0;
 }
 
+static inline u64 xskq_nb_queue_empty_descs(struct xsk_queue *q)
+{
+       return q ? q->queue_empty_descs : 0;
+}
+
 struct xsk_queue *xskq_create(u32 nentries, bool umem_queue);
 void xskq_destroy(struct xsk_queue *q_ops);
 
index be328c5..a78a809 100644 (file)
@@ -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 {