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)
{
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, \
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;
+}
-/* 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
/*! \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.
*
*/
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);
+
/*! @} */