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