dpdk: collect port stats before device stop

Some drivers (e.g. BNXT) fail to report stats after the device is
stopped. Move stats collection (DPDKDumpCounters and PrintDPDKPortXstats)
to run before rte_eth_dev_stop() in HandleShutdown.

Also change PrintDPDKPortXstats error handling from FatalError to
graceful return since stats collection failures during shutdown
should not crash the application.

The commit removes ThreadExitPrintStats callback as the function had no
useful features after the stats were moved.

Ticket: 8251
pull/14712/head
Lukas Sismis 3 months ago committed by Victor Julien
parent 0fe0390a2f
commit 27f398b5f2

@ -140,7 +140,6 @@ typedef struct DPDKThreadVars_ {
} DPDKThreadVars;
static TmEcode ReceiveDPDKThreadInit(ThreadVars *, const void *, void **);
static void ReceiveDPDKThreadExitStats(ThreadVars *, void *);
static TmEcode ReceiveDPDKThreadDeinit(ThreadVars *, void *);
static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot);
@ -257,7 +256,7 @@ void TmModuleReceiveDPDKRegister(void)
tmm_modules[TMM_RECEIVEDPDK].Func = NULL;
tmm_modules[TMM_RECEIVEDPDK].PktAcqLoop = ReceiveDPDKLoop;
tmm_modules[TMM_RECEIVEDPDK].PktAcqBreakLoop = NULL;
tmm_modules[TMM_RECEIVEDPDK].ThreadExitPrintStats = ReceiveDPDKThreadExitStats;
tmm_modules[TMM_RECEIVEDPDK].ThreadExitPrintStats = NULL;
tmm_modules[TMM_RECEIVEDPDK].ThreadDeinit = ReceiveDPDKThreadDeinit;
tmm_modules[TMM_RECEIVEDPDK].cap_flags = SC_CAP_NET_RAW;
tmm_modules[TMM_RECEIVEDPDK].flags = TM_FLAG_RECEIVE_TM;
@ -481,6 +480,54 @@ static inline void DPDKSegmentedMbufWarning(struct rte_mbuf *mbuf)
}
}
static void PrintDPDKPortXstats(uint16_t port_id, const char *port_name)
{
struct rte_eth_xstat *xstats;
struct rte_eth_xstat_name *xstats_names;
int32_t ret = rte_eth_xstats_get(port_id, NULL, 0);
if (ret < 0) {
SCLogPerf("%s: unable to obtain rte_eth_xstats (%s)", port_name, rte_strerror(-ret));
return;
}
uint16_t len = (uint16_t)ret;
xstats = SCCalloc(len, sizeof(*xstats));
if (xstats == NULL) {
SCLogWarning("Failed to allocate memory for the rte_eth_xstat structure");
return;
}
ret = rte_eth_xstats_get(port_id, xstats, len);
if (ret < 0 || ret > len) {
SCFree(xstats);
SCLogPerf("%s: unable to obtain rte_eth_xstats (%s)", port_name, rte_strerror(-ret));
return;
}
xstats_names = SCCalloc(len, sizeof(*xstats_names));
if (xstats_names == NULL) {
SCFree(xstats);
SCLogWarning("Failed to allocate memory for the rte_eth_xstat_name array");
return;
}
ret = rte_eth_xstats_get_names(port_id, xstats_names, len);
if (ret < 0 || ret > len) {
SCFree(xstats);
SCFree(xstats_names);
SCLogPerf(
"%s: unable to obtain names of rte_eth_xstats (%s)", port_name, rte_strerror(-ret));
return;
}
for (int32_t i = 0; i < len; i++) {
if (xstats[i].value > 0)
SCLogPerf("Port %u (%s) - %s: %" PRIu64, port_id, port_name, xstats_names[i].name,
xstats[i].value);
}
SCFree(xstats);
SCFree(xstats_names);
}
static void HandleShutdown(DPDKThreadVars *ptv)
{
SCLogDebug("Stopping Suricata!");
@ -488,7 +535,11 @@ static void HandleShutdown(DPDKThreadVars *ptv)
while (SC_ATOMIC_GET(ptv->workers_sync->worker_checked_in) < ptv->workers_sync->worker_cnt) {
rte_delay_us(10);
}
// Dump counters while device is still running - some drivers (e.g. BNXT) fail
// to report stats after the device is stopped
DPDKDumpCounters(ptv);
if (ptv->queue_id == 0) {
PrintDPDKPortXstats(ptv->port_id, ptv->livedev->dev);
rte_delay_us(20); // wait for all threads to get out of the sync loop
SC_ATOMIC_SET(ptv->workers_sync->worker_checked_in, 0);
// If Suricata runs in peered mode, the peer threads might still want to send
@ -501,7 +552,6 @@ static void HandleShutdown(DPDKThreadVars *ptv)
rte_eth_dev_stop(ptv->port_id);
}
}
DPDKDumpCounters(ptv);
}
static void PeriodicDPDKDumpCounters(DPDKThreadVars *ptv)
@ -707,82 +757,6 @@ fail:
SCReturnInt(TM_ECODE_FAILED);
}
static void PrintDPDKPortXstats(uint16_t port_id, const char *port_name)
{
struct rte_eth_xstat *xstats;
struct rte_eth_xstat_name *xstats_names;
int32_t ret = rte_eth_xstats_get(port_id, NULL, 0);
if (ret < 0) {
FatalError("Error (%s) getting count of rte_eth_xstats failed on port %s",
rte_strerror(-ret), port_name);
}
uint16_t len = (uint16_t)ret;
xstats = SCCalloc(len, sizeof(*xstats));
if (xstats == NULL)
FatalError("Failed to allocate memory for the rte_eth_xstat structure");
ret = rte_eth_xstats_get(port_id, xstats, len);
if (ret < 0 || ret > len) {
SCFree(xstats);
FatalError("Error (%s) getting rte_eth_xstats failed on port %s", rte_strerror(-ret),
port_name);
}
xstats_names = SCCalloc(len, sizeof(*xstats_names));
if (xstats_names == NULL) {
SCFree(xstats);
FatalError("Failed to allocate memory for the rte_eth_xstat_name array");
}
ret = rte_eth_xstats_get_names(port_id, xstats_names, len);
if (ret < 0 || ret > len) {
SCFree(xstats);
SCFree(xstats_names);
FatalError("Error (%s) getting names of rte_eth_xstats failed on port %s",
rte_strerror(-ret), port_name);
}
for (int32_t i = 0; i < len; i++) {
if (xstats[i].value > 0)
SCLogPerf("Port %u (%s) - %s: %" PRIu64, port_id, port_name, xstats_names[i].name,
xstats[i].value);
}
SCFree(xstats);
SCFree(xstats_names);
}
/**
* \brief This function prints stats to the screen at exit.
* \param tv pointer to ThreadVars
* \param data pointer that gets cast into DPDKThreadVars for ptv
*/
static void ReceiveDPDKThreadExitStats(ThreadVars *tv, void *data)
{
SCEnter();
int retval;
DPDKThreadVars *ptv = (DPDKThreadVars *)data;
if (ptv->queue_id == 0) {
struct rte_eth_stats eth_stats;
PrintDPDKPortXstats(ptv->port_id, ptv->livedev->dev);
retval = rte_eth_stats_get(ptv->port_id, &eth_stats);
if (unlikely(retval != 0)) {
SCLogError("%s: failed to get stats (%s)", ptv->livedev->dev, strerror(-retval));
SCReturn;
}
SCLogPerf("%s: total RX stats: packets %" PRIu64 " bytes: %" PRIu64 " missed: %" PRIu64
" errors: %" PRIu64 " nombufs: %" PRIu64,
ptv->livedev->dev, eth_stats.ipackets, eth_stats.ibytes, eth_stats.imissed,
eth_stats.ierrors, eth_stats.rx_nombuf);
if (ptv->copy_mode == DPDK_COPY_MODE_TAP || ptv->copy_mode == DPDK_COPY_MODE_IPS)
SCLogPerf("%s: total TX stats: packets %" PRIu64 " bytes: %" PRIu64 " errors: %" PRIu64,
ptv->livedev->dev, eth_stats.opackets, eth_stats.obytes, eth_stats.oerrors);
}
DPDKDumpCounters(ptv);
SCLogPerf("(%s) received packets %" PRIu64, tv->name, ptv->pkts);
}
/**
* \brief DeInit function closes dpdk at exit.
* \param tv pointer to ThreadVars

Loading…
Cancel
Save