]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
xdp: add knot_xdp_socket_stats()
authorDaniel Salzman <daniel.salzman@nic.cz>
Thu, 25 Jan 2024 08:56:11 +0000 (09:56 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Wed, 3 Apr 2024 19:40:57 +0000 (21:40 +0200)
src/libknot/xdp/xdp.c
src/libknot/xdp/xdp.h

index fd4c88c285e3f8ea7bd302022fcaa7506c403d61..e7acadf35abd6ed407c59b4428c1d6eede5c3de4 100644 (file)
@@ -537,6 +537,9 @@ void knot_xdp_recv_finish(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[]
        xsk_ring_prod__submit(fq, count);
 }
 
+// The number of busy frames
+#define RING_BUSY(ring) ((*(ring)->producer - *(ring)->consumer) & (ring)->mask)
+
 _public_
 void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file)
 {
@@ -544,10 +547,6 @@ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file)
                return;
        }
 
-       // The number of busy frames
-       #define RING_BUSY(ring) \
-               ((*(ring)->producer - *(ring)->consumer) & (ring)->mask)
-
        #define RING_PRINFO(name, ring) \
                fprintf(file, "Ring %s: size %4d, busy %4d (prod %4d, cons %4d)\n", \
                        name, (unsigned)(ring)->size, \
@@ -567,3 +566,39 @@ void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file)
        RING_PRINFO("CQ", &socket->umem->cq);
        fprintf(file, "TX free frames: %4d\n", tx_freef);
 }
+
+_public_
+int knot_xdp_socket_stats(knot_xdp_socket_t *socket, knot_xdp_stats_t *stats)
+{
+       if (socket == NULL || stats == NULL) {
+               return KNOT_EINVAL;
+       }
+
+       memset(stats, 0, sizeof(*stats));
+
+       stats->if_name = socket->iface->if_name;
+       stats->if_index = socket->iface->if_index;
+       stats->if_queue = socket->iface->if_queue;
+
+       struct xdp_statistics xdp_stats;
+       socklen_t optlen = sizeof(xdp_stats);
+
+       int fd = knot_xdp_socket_fd(socket);
+       int ret = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &xdp_stats, &optlen);
+       if (ret != 0) {
+               return knot_map_errno();
+       } else if (optlen != sizeof(xdp_stats)) {
+               return KNOT_EINVAL;
+       }
+
+       size_t common_size = MIN(sizeof(xdp_stats), sizeof(stats->socket));
+       memcpy(&stats->socket, &xdp_stats, common_size);
+
+       stats->rings.tx_busy = socket->umem->ring_size - socket->umem->tx_free_count;
+       stats->rings.fq_fill = RING_BUSY(&socket->umem->fq);
+       stats->rings.rx_fill = RING_BUSY(&socket->rx);
+       stats->rings.tx_fill = RING_BUSY(&socket->tx);
+       stats->rings.cq_fill = RING_BUSY(&socket->umem->cq);
+
+       return KNOT_EOK;
+}
index cddb3ae572c374ba6c73754bec3e79a037b1f4c0..70a5045528c42d66352765a5c79945b9357b7ff7 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2024 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -60,6 +60,44 @@ struct knot_xdp_config {
 /*! \brief Configuration of XDP socket. */
 typedef struct knot_xdp_config knot_xdp_config_t;
 
+/*! \brief Various statistics of an XDP socket (optimally kernel >=5.9). */
+typedef struct {
+       /*! Interface name. */
+       const char *if_name;
+       /*! Interface name index (derived from ifname). */
+       int if_index;
+       /*! Network card queue id. */
+       unsigned if_queue;
+       /*! Counters (xdp_statistics) retrieved from the kernel via XDP_STATISTICS. */
+       struct {
+               /*! Dropped for other reasons. */
+               uint64_t rx_dropped;
+               /*! Dropped due to invalid descriptor. */
+               uint64_t rx_invalid;
+               /*! Dropped due to invalid descriptor. */
+               uint64_t tx_invalid;
+               /*! Dropped due to rx ring being full. */
+               uint64_t rx_full;
+               /*! Failed to retrieve item from fill ring. */
+               uint64_t fq_empty;
+               /*! Failed to retrieve item from tx ring. */
+               uint64_t tx_empty;
+       } socket;
+       /*! States of rings of the XDP socket. */
+       struct {
+               /*! Busy TX buffers. */
+               uint16_t tx_busy;
+               /*! Free buffers to consume from FQ ring. */
+               uint16_t fq_fill;
+               /*! Pending buffers in TX ring. */
+               uint16_t rx_fill;
+               /*! Pending buffers in RX ring. */
+               uint16_t tx_fill;
+               /*! Pending buffers in CQ ring. */
+               uint16_t cq_fill;
+       } rings;
+} knot_xdp_stats_t;
+
 /*!
  * \brief Initialize XDP socket.
  *
@@ -195,4 +233,14 @@ void knot_xdp_recv_finish(knot_xdp_socket_t *socket, const knot_xdp_msg_t msgs[]
  */
 void knot_xdp_socket_info(const knot_xdp_socket_t *socket, FILE *file);
 
+/*!
+ * \brief Gets various statistics of the XDP socket.
+ *
+ * \param socket  XDP socket.
+ * \param stats   Output structure.
+ *
+ * \return KNOT_E*
+ */
+int knot_xdp_socket_stats(knot_xdp_socket_t *socket, knot_xdp_stats_t *stats);
+
 /*! @} */