Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2016-2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdlib.h>
6 : :
7 : : #include <rte_mbuf.h>
8 : : #include <rte_ethdev.h>
9 : : #include <rte_lcore.h>
10 : : #include <rte_log.h>
11 : : #include <rte_memzone.h>
12 : : #include <rte_errno.h>
13 : : #include <rte_string_fns.h>
14 : : #include <rte_pcapng.h>
15 : :
16 : : #include "rte_pdump.h"
17 : :
18 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE);
19 : : #define RTE_LOGTYPE_PDUMP pdump_logtype
20 : :
21 : : #define PDUMP_LOG_LINE(level, ...) \
22 : : RTE_LOG_LINE_PREFIX(level, PDUMP, "%s(): ", __func__, __VA_ARGS__)
23 : :
24 : : /* Used for the multi-process communication */
25 : : #define PDUMP_MP "mp_pdump"
26 : :
27 : : enum pdump_operation {
28 : : DISABLE = 1,
29 : : ENABLE = 2
30 : : };
31 : :
32 : : /* Internal version number in request */
33 : : enum pdump_version {
34 : : V1 = 1, /* no filtering or snap */
35 : : V2 = 2,
36 : : };
37 : :
38 : : struct pdump_request {
39 : : uint16_t ver;
40 : : uint16_t op;
41 : : uint32_t flags;
42 : : char device[RTE_DEV_NAME_MAX_LEN];
43 : : uint16_t queue;
44 : : struct rte_ring *ring;
45 : : struct rte_mempool *mp;
46 : :
47 : : const struct rte_bpf_prm *prm;
48 : : uint32_t snaplen;
49 : : };
50 : :
51 : : struct pdump_response {
52 : : uint16_t ver;
53 : : uint16_t res_op;
54 : : int32_t err_value;
55 : : };
56 : :
57 : : static struct pdump_rxtx_cbs {
58 : : struct rte_ring *ring;
59 : : struct rte_mempool *mp;
60 : : const struct rte_eth_rxtx_callback *cb;
61 : : const struct rte_bpf *filter;
62 : : enum pdump_version ver;
63 : : uint32_t snaplen;
64 : : } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
65 : : tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
66 : :
67 : :
68 : : /*
69 : : * The packet capture statistics keep track of packets
70 : : * accepted, filtered and dropped. These are per-queue
71 : : * and in memory between primary and secondary processes.
72 : : */
73 : : static const char MZ_RTE_PDUMP_STATS[] = "rte_pdump_stats";
74 : : static struct {
75 : : struct rte_pdump_stats rx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
76 : : struct rte_pdump_stats tx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
77 : : const struct rte_memzone *mz;
78 : : } *pdump_stats;
79 : :
80 : : /* Create a clone of mbuf to be placed into ring. */
81 : : static void
82 : 0 : pdump_copy(uint16_t port_id, uint16_t queue,
83 : : enum rte_pcapng_direction direction,
84 : : struct rte_mbuf **pkts, uint16_t nb_pkts,
85 : : const struct pdump_rxtx_cbs *cbs,
86 : : struct rte_pdump_stats *stats)
87 : 0 : {
88 : : unsigned int i;
89 : : int ring_enq;
90 : : uint16_t d_pkts = 0;
91 : 0 : struct rte_mbuf *dup_bufs[nb_pkts];
92 : : struct rte_ring *ring;
93 : : struct rte_mempool *mp;
94 : : struct rte_mbuf *p;
95 : 0 : uint64_t rcs[nb_pkts];
96 : :
97 [ # # ]: 0 : if (cbs->filter)
98 : 0 : rte_bpf_exec_burst(cbs->filter, (void **)pkts, rcs, nb_pkts);
99 : :
100 : 0 : ring = cbs->ring;
101 : 0 : mp = cbs->mp;
102 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
103 : : /*
104 : : * This uses same BPF return value convention as socket filter
105 : : * and pcap_offline_filter.
106 : : * if program returns zero
107 : : * then packet doesn't match the filter (will be ignored).
108 : : */
109 [ # # # # ]: 0 : if (cbs->filter && rcs[i] == 0) {
110 : 0 : rte_atomic_fetch_add_explicit(&stats->filtered,
111 : : 1, rte_memory_order_relaxed);
112 : 0 : continue;
113 : : }
114 : :
115 : : /*
116 : : * If using pcapng then want to wrap packets
117 : : * otherwise a simple copy.
118 : : */
119 [ # # ]: 0 : if (cbs->ver == V2)
120 : 0 : p = rte_pcapng_copy(port_id, queue,
121 : 0 : pkts[i], mp, cbs->snaplen,
122 : : direction, NULL);
123 : : else
124 : 0 : p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen);
125 : :
126 [ # # ]: 0 : if (unlikely(p == NULL))
127 : 0 : rte_atomic_fetch_add_explicit(&stats->nombuf, 1, rte_memory_order_relaxed);
128 : : else
129 : 0 : dup_bufs[d_pkts++] = p;
130 : : }
131 : :
132 : 0 : rte_atomic_fetch_add_explicit(&stats->accepted, d_pkts, rte_memory_order_relaxed);
133 : :
134 [ # # # # : 0 : ring_enq = rte_ring_enqueue_burst(ring, (void *)&dup_bufs[0], d_pkts, NULL);
# ]
135 [ # # ]: 0 : if (unlikely(ring_enq < d_pkts)) {
136 : 0 : unsigned int drops = d_pkts - ring_enq;
137 : :
138 : 0 : rte_atomic_fetch_add_explicit(&stats->ringfull, drops, rte_memory_order_relaxed);
139 : 0 : rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops);
140 : : }
141 : 0 : }
142 : :
143 : : static uint16_t
144 : 0 : pdump_rx(uint16_t port, uint16_t queue,
145 : : struct rte_mbuf **pkts, uint16_t nb_pkts,
146 : : uint16_t max_pkts __rte_unused, void *user_params)
147 : : {
148 : : const struct pdump_rxtx_cbs *cbs = user_params;
149 : 0 : struct rte_pdump_stats *stats = &pdump_stats->rx[port][queue];
150 : :
151 : 0 : pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN,
152 : : pkts, nb_pkts, cbs, stats);
153 : 0 : return nb_pkts;
154 : : }
155 : :
156 : : static uint16_t
157 : 0 : pdump_tx(uint16_t port, uint16_t queue,
158 : : struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
159 : : {
160 : : const struct pdump_rxtx_cbs *cbs = user_params;
161 : 0 : struct rte_pdump_stats *stats = &pdump_stats->tx[port][queue];
162 : :
163 : 0 : pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT,
164 : : pkts, nb_pkts, cbs, stats);
165 : 0 : return nb_pkts;
166 : : }
167 : :
168 : : static int
169 : 0 : pdump_register_rx_callbacks(enum pdump_version ver,
170 : : uint16_t end_q, uint16_t port, uint16_t queue,
171 : : struct rte_ring *ring, struct rte_mempool *mp,
172 : : struct rte_bpf *filter,
173 : : uint16_t operation, uint32_t snaplen)
174 : : {
175 : : uint16_t qid;
176 : :
177 [ # # ]: 0 : qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
178 [ # # ]: 0 : for (; qid < end_q; qid++) {
179 : 0 : struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid];
180 : :
181 [ # # ]: 0 : if (operation == ENABLE) {
182 [ # # ]: 0 : if (cbs->cb) {
183 : 0 : PDUMP_LOG_LINE(ERR,
184 : : "rx callback for port=%d queue=%d, already exists",
185 : : port, qid);
186 : 0 : return -EEXIST;
187 : : }
188 : 0 : cbs->ver = ver;
189 : 0 : cbs->ring = ring;
190 : 0 : cbs->mp = mp;
191 : 0 : cbs->snaplen = snaplen;
192 : 0 : cbs->filter = filter;
193 : :
194 : 0 : cbs->cb = rte_eth_add_first_rx_callback(port, qid,
195 : : pdump_rx, cbs);
196 [ # # ]: 0 : if (cbs->cb == NULL) {
197 : 0 : PDUMP_LOG_LINE(ERR,
198 : : "failed to add rx callback, errno=%d",
199 : : rte_errno);
200 : 0 : return rte_errno;
201 : : }
202 : :
203 : 0 : memset(&pdump_stats->rx[port][qid], 0, sizeof(struct rte_pdump_stats));
204 [ # # ]: 0 : } else if (operation == DISABLE) {
205 : : int ret;
206 : :
207 [ # # ]: 0 : if (cbs->cb == NULL) {
208 : 0 : PDUMP_LOG_LINE(ERR,
209 : : "no existing rx callback for port=%d queue=%d",
210 : : port, qid);
211 : 0 : return -EINVAL;
212 : : }
213 : 0 : ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
214 [ # # ]: 0 : if (ret < 0) {
215 : 0 : PDUMP_LOG_LINE(ERR,
216 : : "failed to remove rx callback, errno=%d",
217 : : -ret);
218 : 0 : return ret;
219 : : }
220 : 0 : cbs->cb = NULL;
221 : : }
222 : : }
223 : :
224 : : return 0;
225 : : }
226 : :
227 : : static int
228 : 0 : pdump_register_tx_callbacks(enum pdump_version ver,
229 : : uint16_t end_q, uint16_t port, uint16_t queue,
230 : : struct rte_ring *ring, struct rte_mempool *mp,
231 : : struct rte_bpf *filter,
232 : : uint16_t operation, uint32_t snaplen)
233 : : {
234 : :
235 : : uint16_t qid;
236 : :
237 [ # # ]: 0 : qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
238 [ # # ]: 0 : for (; qid < end_q; qid++) {
239 : 0 : struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
240 : :
241 [ # # ]: 0 : if (operation == ENABLE) {
242 [ # # ]: 0 : if (cbs->cb) {
243 : 0 : PDUMP_LOG_LINE(ERR,
244 : : "tx callback for port=%d queue=%d, already exists",
245 : : port, qid);
246 : 0 : return -EEXIST;
247 : : }
248 : 0 : cbs->ver = ver;
249 : 0 : cbs->ring = ring;
250 : 0 : cbs->mp = mp;
251 : 0 : cbs->snaplen = snaplen;
252 : 0 : cbs->filter = filter;
253 : :
254 : 0 : cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
255 : : cbs);
256 [ # # ]: 0 : if (cbs->cb == NULL) {
257 : 0 : PDUMP_LOG_LINE(ERR,
258 : : "failed to add tx callback, errno=%d",
259 : : rte_errno);
260 : 0 : return rte_errno;
261 : : }
262 : 0 : memset(&pdump_stats->tx[port][qid], 0, sizeof(struct rte_pdump_stats));
263 [ # # ]: 0 : } else if (operation == DISABLE) {
264 : : int ret;
265 : :
266 [ # # ]: 0 : if (cbs->cb == NULL) {
267 : 0 : PDUMP_LOG_LINE(ERR,
268 : : "no existing tx callback for port=%d queue=%d",
269 : : port, qid);
270 : 0 : return -EINVAL;
271 : : }
272 : 0 : ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
273 [ # # ]: 0 : if (ret < 0) {
274 : 0 : PDUMP_LOG_LINE(ERR,
275 : : "failed to remove tx callback, errno=%d",
276 : : -ret);
277 : 0 : return ret;
278 : : }
279 : 0 : cbs->cb = NULL;
280 : : }
281 : : }
282 : :
283 : : return 0;
284 : : }
285 : :
286 : : static int
287 : 0 : set_pdump_rxtx_cbs(const struct pdump_request *p)
288 : : {
289 : : uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
290 : : uint16_t port;
291 : : int ret = 0;
292 : : struct rte_bpf *filter = NULL;
293 : : uint32_t flags;
294 : : uint16_t operation;
295 : : struct rte_ring *ring;
296 : : struct rte_mempool *mp;
297 : :
298 : : /* Check for possible DPDK version mismatch */
299 [ # # ]: 0 : if (!(p->ver == V1 || p->ver == V2)) {
300 : 0 : PDUMP_LOG_LINE(ERR,
301 : : "incorrect client version %u", p->ver);
302 : 0 : return -EINVAL;
303 : : }
304 : :
305 [ # # ]: 0 : if (p->prm) {
306 [ # # ]: 0 : if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
307 : 0 : PDUMP_LOG_LINE(ERR,
308 : : "invalid BPF program type: %u",
309 : : p->prm->prog_arg.type);
310 : 0 : return -EINVAL;
311 : : }
312 : :
313 : 0 : filter = rte_bpf_load(p->prm);
314 [ # # ]: 0 : if (filter == NULL) {
315 : 0 : PDUMP_LOG_LINE(ERR, "cannot load BPF filter: %s",
316 : : rte_strerror(rte_errno));
317 : 0 : return -rte_errno;
318 : : }
319 : : }
320 : :
321 : 0 : flags = p->flags;
322 : 0 : operation = p->op;
323 : 0 : queue = p->queue;
324 : 0 : ring = p->ring;
325 : 0 : mp = p->mp;
326 : :
327 : 0 : ret = rte_eth_dev_get_port_by_name(p->device, &port);
328 [ # # ]: 0 : if (ret < 0) {
329 : 0 : PDUMP_LOG_LINE(ERR,
330 : : "failed to get port id for device id=%s",
331 : : p->device);
332 : 0 : return -EINVAL;
333 : : }
334 : :
335 : : /* validation if packet capture is for all queues */
336 [ # # ]: 0 : if (queue == RTE_PDUMP_ALL_QUEUES) {
337 : : struct rte_eth_dev_info dev_info;
338 : :
339 : 0 : ret = rte_eth_dev_info_get(port, &dev_info);
340 [ # # ]: 0 : if (ret != 0) {
341 : 0 : PDUMP_LOG_LINE(ERR,
342 : : "Error during getting device (port %u) info: %s",
343 : : port, strerror(-ret));
344 : 0 : return ret;
345 : : }
346 : :
347 : 0 : nb_rx_q = dev_info.nb_rx_queues;
348 : 0 : nb_tx_q = dev_info.nb_tx_queues;
349 [ # # # # ]: 0 : if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
350 : 0 : PDUMP_LOG_LINE(ERR,
351 : : "number of rx queues cannot be 0");
352 : 0 : return -EINVAL;
353 : : }
354 [ # # # # ]: 0 : if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
355 : 0 : PDUMP_LOG_LINE(ERR,
356 : : "number of tx queues cannot be 0");
357 : 0 : return -EINVAL;
358 : : }
359 [ # # # # ]: 0 : if ((nb_tx_q == 0 || nb_rx_q == 0) &&
360 : : flags == RTE_PDUMP_FLAG_RXTX) {
361 : 0 : PDUMP_LOG_LINE(ERR,
362 : : "both tx&rx queues must be non zero");
363 : 0 : return -EINVAL;
364 : : }
365 : : }
366 : :
367 : : /* register RX callback */
368 [ # # ]: 0 : if (flags & RTE_PDUMP_FLAG_RX) {
369 [ # # ]: 0 : end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
370 : 0 : ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
371 : : ring, mp, filter,
372 : 0 : operation, p->snaplen);
373 [ # # ]: 0 : if (ret < 0)
374 : : return ret;
375 : : }
376 : :
377 : : /* register TX callback */
378 [ # # ]: 0 : if (flags & RTE_PDUMP_FLAG_TX) {
379 [ # # ]: 0 : end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
380 : 0 : ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
381 : : ring, mp, filter,
382 : 0 : operation, p->snaplen);
383 : : if (ret < 0)
384 : : return ret;
385 : : }
386 : :
387 : : return ret;
388 : : }
389 : :
390 : : static int
391 : 0 : pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
392 : : {
393 : : struct rte_mp_msg mp_resp;
394 : : const struct pdump_request *cli_req;
395 : : struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
396 : :
397 : : /* recv client requests */
398 [ # # ]: 0 : if (mp_msg->len_param != sizeof(*cli_req)) {
399 : 0 : PDUMP_LOG_LINE(ERR, "failed to recv from client");
400 : 0 : resp->err_value = -EINVAL;
401 : : } else {
402 : 0 : cli_req = (const struct pdump_request *)mp_msg->param;
403 : 0 : resp->ver = cli_req->ver;
404 : 0 : resp->res_op = cli_req->op;
405 : 0 : resp->err_value = set_pdump_rxtx_cbs(cli_req);
406 : : }
407 : :
408 : 0 : rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
409 : 0 : mp_resp.len_param = sizeof(*resp);
410 : 0 : mp_resp.num_fds = 0;
411 [ # # ]: 0 : if (rte_mp_reply(&mp_resp, peer) < 0) {
412 : 0 : PDUMP_LOG_LINE(ERR, "failed to send to client:%s",
413 : : strerror(rte_errno));
414 : 0 : return -1;
415 : : }
416 : :
417 : : return 0;
418 : : }
419 : :
420 : : int
421 : 1 : rte_pdump_init(void)
422 : : {
423 : : const struct rte_memzone *mz;
424 : : int ret;
425 : :
426 : 1 : mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
427 : 1 : rte_socket_id(), 0);
428 [ - + ]: 1 : if (mz == NULL) {
429 : 0 : PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics");
430 : 0 : rte_errno = ENOMEM;
431 : 0 : return -1;
432 : : }
433 : 1 : pdump_stats = mz->addr;
434 : 1 : pdump_stats->mz = mz;
435 : :
436 : 1 : ret = rte_mp_action_register(PDUMP_MP, pdump_server);
437 [ - + - - ]: 1 : if (ret && rte_errno != ENOTSUP)
438 : 0 : return -1;
439 : : return 0;
440 : : }
441 : :
442 : : int
443 : 1 : rte_pdump_uninit(void)
444 : : {
445 : 1 : rte_mp_action_unregister(PDUMP_MP);
446 : :
447 [ + - ]: 1 : if (pdump_stats != NULL) {
448 : 1 : rte_memzone_free(pdump_stats->mz);
449 : 1 : pdump_stats = NULL;
450 : : }
451 : :
452 : 1 : return 0;
453 : : }
454 : :
455 : : static int
456 : 0 : pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
457 : : {
458 [ # # ]: 0 : if (ring == NULL || mp == NULL) {
459 : 0 : PDUMP_LOG_LINE(ERR, "NULL ring or mempool");
460 : 0 : rte_errno = EINVAL;
461 : 0 : return -1;
462 : : }
463 [ # # ]: 0 : if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
464 : : mp->flags & RTE_MEMPOOL_F_SC_GET) {
465 : 0 : PDUMP_LOG_LINE(ERR,
466 : : "mempool with SP or SC set not valid for pdump,"
467 : : "must have MP and MC set");
468 : 0 : rte_errno = EINVAL;
469 : 0 : return -1;
470 : : }
471 [ # # # # ]: 0 : if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
472 : 0 : PDUMP_LOG_LINE(ERR,
473 : : "ring with SP or SC set is not valid for pdump,"
474 : : "must have MP and MC set");
475 : 0 : rte_errno = EINVAL;
476 : 0 : return -1;
477 : : }
478 : :
479 : : return 0;
480 : : }
481 : :
482 : : static int
483 : 0 : pdump_validate_flags(uint32_t flags)
484 : : {
485 [ # # ]: 0 : if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
486 : 0 : PDUMP_LOG_LINE(ERR,
487 : : "invalid flags, should be either rx/tx/rxtx");
488 : 0 : rte_errno = EINVAL;
489 : 0 : return -1;
490 : : }
491 : :
492 : : /* mask off the flags we know about */
493 [ # # ]: 0 : if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
494 : 0 : PDUMP_LOG_LINE(ERR,
495 : : "unknown flags: %#x", flags);
496 : 0 : rte_errno = ENOTSUP;
497 : 0 : return -1;
498 : : }
499 : :
500 : : return 0;
501 : : }
502 : :
503 : : static int
504 : 0 : pdump_validate_port(uint16_t port, char *name)
505 : : {
506 : : int ret = 0;
507 : :
508 [ # # ]: 0 : if (port >= RTE_MAX_ETHPORTS) {
509 : 0 : PDUMP_LOG_LINE(ERR, "Invalid port id %u", port);
510 : 0 : rte_errno = EINVAL;
511 : 0 : return -1;
512 : : }
513 : :
514 : 0 : ret = rte_eth_dev_get_name_by_port(port, name);
515 [ # # ]: 0 : if (ret < 0) {
516 : 0 : PDUMP_LOG_LINE(ERR, "port %u to name mapping failed",
517 : : port);
518 : 0 : rte_errno = EINVAL;
519 : 0 : return -1;
520 : : }
521 : :
522 : : return 0;
523 : : }
524 : :
525 : : static int
526 : 0 : pdump_prepare_client_request(const char *device, uint16_t queue,
527 : : uint32_t flags, uint32_t snaplen,
528 : : uint16_t operation,
529 : : struct rte_ring *ring,
530 : : struct rte_mempool *mp,
531 : : const struct rte_bpf_prm *prm)
532 : : {
533 : : int ret = -1;
534 : : struct rte_mp_msg mp_req, *mp_rep;
535 : : struct rte_mp_reply mp_reply;
536 : 0 : struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
537 : : struct pdump_request *req = (struct pdump_request *)mp_req.param;
538 : : struct pdump_response *resp;
539 : :
540 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
541 : 0 : PDUMP_LOG_LINE(ERR,
542 : : "pdump enable/disable not allowed in primary process");
543 : 0 : return -EINVAL;
544 : : }
545 : :
546 : : memset(req, 0, sizeof(*req));
547 : :
548 [ # # ]: 0 : req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
549 : 0 : req->flags = flags & RTE_PDUMP_FLAG_RXTX;
550 : 0 : req->op = operation;
551 : 0 : req->queue = queue;
552 : 0 : rte_strscpy(req->device, device, sizeof(req->device));
553 : :
554 [ # # ]: 0 : if ((operation & ENABLE) != 0) {
555 : 0 : req->ring = ring;
556 : 0 : req->mp = mp;
557 : 0 : req->prm = prm;
558 : 0 : req->snaplen = snaplen;
559 : : }
560 : :
561 : 0 : rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
562 : 0 : mp_req.len_param = sizeof(*req);
563 : 0 : mp_req.num_fds = 0;
564 [ # # ]: 0 : if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
565 : 0 : mp_rep = &mp_reply.msgs[0];
566 : : resp = (struct pdump_response *)mp_rep->param;
567 [ # # ]: 0 : if (resp->err_value == 0)
568 : : ret = 0;
569 : : else
570 : 0 : rte_errno = -resp->err_value;
571 : 0 : free(mp_reply.msgs);
572 : : }
573 : :
574 [ # # ]: 0 : if (ret < 0)
575 : 0 : PDUMP_LOG_LINE(ERR,
576 : : "client request for pdump enable/disable failed");
577 : : return ret;
578 : : }
579 : :
580 : : /*
581 : : * There are two versions of this function, because although original API
582 : : * left place holder for future filter, it never checked the value.
583 : : * Therefore the API can't depend on application passing a non
584 : : * bogus value.
585 : : */
586 : : static int
587 : 0 : pdump_enable(uint16_t port, uint16_t queue,
588 : : uint32_t flags, uint32_t snaplen,
589 : : struct rte_ring *ring, struct rte_mempool *mp,
590 : : const struct rte_bpf_prm *prm)
591 : : {
592 : : int ret;
593 : : char name[RTE_DEV_NAME_MAX_LEN];
594 : :
595 : 0 : ret = pdump_validate_port(port, name);
596 [ # # ]: 0 : if (ret < 0)
597 : : return ret;
598 : 0 : ret = pdump_validate_ring_mp(ring, mp);
599 [ # # ]: 0 : if (ret < 0)
600 : : return ret;
601 : 0 : ret = pdump_validate_flags(flags);
602 [ # # ]: 0 : if (ret < 0)
603 : : return ret;
604 : :
605 [ # # ]: 0 : if (snaplen == 0)
606 : : snaplen = UINT32_MAX;
607 : :
608 : 0 : return pdump_prepare_client_request(name, queue, flags, snaplen,
609 : : ENABLE, ring, mp, prm);
610 : : }
611 : :
612 : : int
613 : 0 : rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
614 : : struct rte_ring *ring,
615 : : struct rte_mempool *mp,
616 : : void *filter __rte_unused)
617 : : {
618 : 0 : return pdump_enable(port, queue, flags, 0,
619 : : ring, mp, NULL);
620 : : }
621 : :
622 : : int
623 : 0 : rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
624 : : uint32_t flags, uint32_t snaplen,
625 : : struct rte_ring *ring,
626 : : struct rte_mempool *mp,
627 : : const struct rte_bpf_prm *prm)
628 : : {
629 : 0 : return pdump_enable(port, queue, flags, snaplen,
630 : : ring, mp, prm);
631 : : }
632 : :
633 : : static int
634 : 0 : pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
635 : : uint32_t flags, uint32_t snaplen,
636 : : struct rte_ring *ring,
637 : : struct rte_mempool *mp,
638 : : const struct rte_bpf_prm *prm)
639 : : {
640 : : int ret;
641 : :
642 : 0 : ret = pdump_validate_ring_mp(ring, mp);
643 [ # # ]: 0 : if (ret < 0)
644 : : return ret;
645 : 0 : ret = pdump_validate_flags(flags);
646 [ # # ]: 0 : if (ret < 0)
647 : : return ret;
648 : :
649 [ # # ]: 0 : if (snaplen == 0)
650 : : snaplen = UINT32_MAX;
651 : :
652 : 0 : return pdump_prepare_client_request(device_id, queue, flags, snaplen,
653 : : ENABLE, ring, mp, prm);
654 : : }
655 : :
656 : : int
657 : 0 : rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
658 : : uint32_t flags,
659 : : struct rte_ring *ring,
660 : : struct rte_mempool *mp,
661 : : void *filter __rte_unused)
662 : : {
663 : 0 : return pdump_enable_by_deviceid(device_id, queue, flags, 0,
664 : : ring, mp, NULL);
665 : : }
666 : :
667 : : int
668 : 0 : rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
669 : : uint32_t flags, uint32_t snaplen,
670 : : struct rte_ring *ring,
671 : : struct rte_mempool *mp,
672 : : const struct rte_bpf_prm *prm)
673 : : {
674 : 0 : return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
675 : : ring, mp, prm);
676 : : }
677 : :
678 : : int
679 : 0 : rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
680 : : {
681 : : int ret = 0;
682 : : char name[RTE_DEV_NAME_MAX_LEN];
683 : :
684 : 0 : ret = pdump_validate_port(port, name);
685 [ # # ]: 0 : if (ret < 0)
686 : : return ret;
687 : 0 : ret = pdump_validate_flags(flags);
688 [ # # ]: 0 : if (ret < 0)
689 : : return ret;
690 : :
691 : 0 : ret = pdump_prepare_client_request(name, queue, flags, 0,
692 : : DISABLE, NULL, NULL, NULL);
693 : :
694 : 0 : return ret;
695 : : }
696 : :
697 : : int
698 : 0 : rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
699 : : uint32_t flags)
700 : : {
701 : : int ret = 0;
702 : :
703 : 0 : ret = pdump_validate_flags(flags);
704 [ # # ]: 0 : if (ret < 0)
705 : : return ret;
706 : :
707 : 0 : ret = pdump_prepare_client_request(device_id, queue, flags, 0,
708 : : DISABLE, NULL, NULL, NULL);
709 : :
710 : 0 : return ret;
711 : : }
712 : :
713 : : static void
714 : 0 : pdump_sum_stats(uint16_t port, uint16_t nq,
715 : : struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
716 : : struct rte_pdump_stats *total)
717 : : {
718 : : uint64_t *sum = (uint64_t *)total;
719 : : unsigned int i;
720 : : uint64_t val;
721 : : uint16_t qid;
722 : :
723 [ # # ]: 0 : for (qid = 0; qid < nq; qid++) {
724 : 0 : const RTE_ATOMIC(uint64_t) *perq = (const uint64_t __rte_atomic *)&stats[port][qid];
725 : :
726 [ # # ]: 0 : for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
727 : 0 : val = rte_atomic_load_explicit(&perq[i], rte_memory_order_relaxed);
728 : 0 : sum[i] += val;
729 : : }
730 : : }
731 : 0 : }
732 : :
733 : : int
734 : 0 : rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
735 : : {
736 : : struct rte_eth_dev_info dev_info;
737 : : const struct rte_memzone *mz;
738 : : int ret;
739 : :
740 : : memset(stats, 0, sizeof(*stats));
741 : 0 : ret = rte_eth_dev_info_get(port, &dev_info);
742 [ # # ]: 0 : if (ret != 0) {
743 : 0 : PDUMP_LOG_LINE(ERR,
744 : : "Error during getting device (port %u) info: %s",
745 : : port, strerror(-ret));
746 : 0 : return ret;
747 : : }
748 : :
749 [ # # ]: 0 : if (pdump_stats == NULL) {
750 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
751 : : /* rte_pdump_init was not called */
752 : 0 : PDUMP_LOG_LINE(ERR, "pdump stats not initialized");
753 : 0 : rte_errno = EINVAL;
754 : 0 : return -1;
755 : : }
756 : :
757 : : /* secondary process looks up the memzone */
758 : 0 : mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
759 [ # # ]: 0 : if (mz == NULL) {
760 : : /* rte_pdump_init was not called in primary process?? */
761 : 0 : PDUMP_LOG_LINE(ERR, "can not find pdump stats");
762 : 0 : rte_errno = EINVAL;
763 : 0 : return -1;
764 : : }
765 : 0 : pdump_stats = mz->addr;
766 : : }
767 : :
768 : 0 : pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
769 : 0 : pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
770 : 0 : return 0;
771 : : }
|