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 [ - + ]: 251 : 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 [ # # ]: 0 : } else if (operation == DISABLE) {
203 : : int ret;
204 : :
205 [ # # ]: 0 : if (cbs->cb == NULL) {
206 : 0 : PDUMP_LOG_LINE(ERR,
207 : : "no existing rx callback for port=%d queue=%d",
208 : : port, qid);
209 : 0 : return -EINVAL;
210 : : }
211 : 0 : ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
212 [ # # ]: 0 : if (ret < 0) {
213 : 0 : PDUMP_LOG_LINE(ERR,
214 : : "failed to remove rx callback, errno=%d",
215 : : -ret);
216 : 0 : return ret;
217 : : }
218 : 0 : cbs->cb = NULL;
219 : : }
220 : : }
221 : :
222 : : return 0;
223 : : }
224 : :
225 : : static int
226 : 0 : pdump_register_tx_callbacks(enum pdump_version ver,
227 : : uint16_t end_q, uint16_t port, uint16_t queue,
228 : : struct rte_ring *ring, struct rte_mempool *mp,
229 : : struct rte_bpf *filter,
230 : : uint16_t operation, uint32_t snaplen)
231 : : {
232 : :
233 : : uint16_t qid;
234 : :
235 [ # # ]: 0 : qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
236 [ # # ]: 0 : for (; qid < end_q; qid++) {
237 : 0 : struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
238 : :
239 [ # # ]: 0 : if (operation == ENABLE) {
240 [ # # ]: 0 : if (cbs->cb) {
241 : 0 : PDUMP_LOG_LINE(ERR,
242 : : "tx callback for port=%d queue=%d, already exists",
243 : : port, qid);
244 : 0 : return -EEXIST;
245 : : }
246 : 0 : cbs->ver = ver;
247 : 0 : cbs->ring = ring;
248 : 0 : cbs->mp = mp;
249 : 0 : cbs->snaplen = snaplen;
250 : 0 : cbs->filter = filter;
251 : :
252 : 0 : cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
253 : : cbs);
254 [ # # ]: 0 : if (cbs->cb == NULL) {
255 : 0 : PDUMP_LOG_LINE(ERR,
256 : : "failed to add tx callback, errno=%d",
257 : : rte_errno);
258 : 0 : return rte_errno;
259 : : }
260 [ # # ]: 0 : } else if (operation == DISABLE) {
261 : : int ret;
262 : :
263 [ # # ]: 0 : if (cbs->cb == NULL) {
264 : 0 : PDUMP_LOG_LINE(ERR,
265 : : "no existing tx callback for port=%d queue=%d",
266 : : port, qid);
267 : 0 : return -EINVAL;
268 : : }
269 : 0 : ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
270 [ # # ]: 0 : if (ret < 0) {
271 : 0 : PDUMP_LOG_LINE(ERR,
272 : : "failed to remove tx callback, errno=%d",
273 : : -ret);
274 : 0 : return ret;
275 : : }
276 : 0 : cbs->cb = NULL;
277 : : }
278 : : }
279 : :
280 : : return 0;
281 : : }
282 : :
283 : : static int
284 : 0 : set_pdump_rxtx_cbs(const struct pdump_request *p)
285 : : {
286 : : uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
287 : : uint16_t port;
288 : : int ret = 0;
289 : : struct rte_bpf *filter = NULL;
290 : : uint32_t flags;
291 : : uint16_t operation;
292 : : struct rte_ring *ring;
293 : : struct rte_mempool *mp;
294 : :
295 : : /* Check for possible DPDK version mismatch */
296 [ # # ]: 0 : if (!(p->ver == V1 || p->ver == V2)) {
297 : 0 : PDUMP_LOG_LINE(ERR,
298 : : "incorrect client version %u", p->ver);
299 : 0 : return -EINVAL;
300 : : }
301 : :
302 [ # # ]: 0 : if (p->prm) {
303 [ # # ]: 0 : if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
304 : 0 : PDUMP_LOG_LINE(ERR,
305 : : "invalid BPF program type: %u",
306 : : p->prm->prog_arg.type);
307 : 0 : return -EINVAL;
308 : : }
309 : :
310 : 0 : filter = rte_bpf_load(p->prm);
311 [ # # ]: 0 : if (filter == NULL) {
312 : 0 : PDUMP_LOG_LINE(ERR, "cannot load BPF filter: %s",
313 : : rte_strerror(rte_errno));
314 : 0 : return -rte_errno;
315 : : }
316 : : }
317 : :
318 : 0 : flags = p->flags;
319 : 0 : operation = p->op;
320 : 0 : queue = p->queue;
321 : 0 : ring = p->ring;
322 : 0 : mp = p->mp;
323 : :
324 : 0 : ret = rte_eth_dev_get_port_by_name(p->device, &port);
325 [ # # ]: 0 : if (ret < 0) {
326 : 0 : PDUMP_LOG_LINE(ERR,
327 : : "failed to get port id for device id=%s",
328 : : p->device);
329 : 0 : return -EINVAL;
330 : : }
331 : :
332 : : /* validation if packet capture is for all queues */
333 [ # # ]: 0 : if (queue == RTE_PDUMP_ALL_QUEUES) {
334 : : struct rte_eth_dev_info dev_info;
335 : :
336 : 0 : ret = rte_eth_dev_info_get(port, &dev_info);
337 [ # # ]: 0 : if (ret != 0) {
338 : 0 : PDUMP_LOG_LINE(ERR,
339 : : "Error during getting device (port %u) info: %s",
340 : : port, strerror(-ret));
341 : 0 : return ret;
342 : : }
343 : :
344 : 0 : nb_rx_q = dev_info.nb_rx_queues;
345 : 0 : nb_tx_q = dev_info.nb_tx_queues;
346 [ # # # # ]: 0 : if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
347 : 0 : PDUMP_LOG_LINE(ERR,
348 : : "number of rx queues cannot be 0");
349 : 0 : return -EINVAL;
350 : : }
351 [ # # # # ]: 0 : if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
352 : 0 : PDUMP_LOG_LINE(ERR,
353 : : "number of tx queues cannot be 0");
354 : 0 : return -EINVAL;
355 : : }
356 [ # # # # ]: 0 : if ((nb_tx_q == 0 || nb_rx_q == 0) &&
357 : : flags == RTE_PDUMP_FLAG_RXTX) {
358 : 0 : PDUMP_LOG_LINE(ERR,
359 : : "both tx&rx queues must be non zero");
360 : 0 : return -EINVAL;
361 : : }
362 : : }
363 : :
364 : : /* register RX callback */
365 [ # # ]: 0 : if (flags & RTE_PDUMP_FLAG_RX) {
366 [ # # ]: 0 : end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
367 : 0 : ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
368 : : ring, mp, filter,
369 : 0 : operation, p->snaplen);
370 [ # # ]: 0 : if (ret < 0)
371 : : return ret;
372 : : }
373 : :
374 : : /* register TX callback */
375 [ # # ]: 0 : if (flags & RTE_PDUMP_FLAG_TX) {
376 [ # # ]: 0 : end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
377 : 0 : ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
378 : : ring, mp, filter,
379 : 0 : operation, p->snaplen);
380 : : if (ret < 0)
381 : : return ret;
382 : : }
383 : :
384 : : return ret;
385 : : }
386 : :
387 : : static int
388 : 0 : pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
389 : : {
390 : : struct rte_mp_msg mp_resp;
391 : : const struct pdump_request *cli_req;
392 : : struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
393 : :
394 : : /* recv client requests */
395 [ # # ]: 0 : if (mp_msg->len_param != sizeof(*cli_req)) {
396 : 0 : PDUMP_LOG_LINE(ERR, "failed to recv from client");
397 : 0 : resp->err_value = -EINVAL;
398 : : } else {
399 : 0 : cli_req = (const struct pdump_request *)mp_msg->param;
400 : 0 : resp->ver = cli_req->ver;
401 : 0 : resp->res_op = cli_req->op;
402 : 0 : resp->err_value = set_pdump_rxtx_cbs(cli_req);
403 : : }
404 : :
405 : 0 : rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
406 : 0 : mp_resp.len_param = sizeof(*resp);
407 : 0 : mp_resp.num_fds = 0;
408 [ # # ]: 0 : if (rte_mp_reply(&mp_resp, peer) < 0) {
409 : 0 : PDUMP_LOG_LINE(ERR, "failed to send to client:%s",
410 : : strerror(rte_errno));
411 : 0 : return -1;
412 : : }
413 : :
414 : : return 0;
415 : : }
416 : :
417 : : int
418 : 1 : rte_pdump_init(void)
419 : : {
420 : : const struct rte_memzone *mz;
421 : : int ret;
422 : :
423 : 1 : mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
424 : 1 : rte_socket_id(), 0);
425 [ - + ]: 1 : if (mz == NULL) {
426 : 0 : PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics");
427 : 0 : rte_errno = ENOMEM;
428 : 0 : return -1;
429 : : }
430 : 1 : pdump_stats = mz->addr;
431 : 1 : pdump_stats->mz = mz;
432 : :
433 : 1 : ret = rte_mp_action_register(PDUMP_MP, pdump_server);
434 [ - + - - ]: 1 : if (ret && rte_errno != ENOTSUP)
435 : 0 : return -1;
436 : : return 0;
437 : : }
438 : :
439 : : int
440 : 1 : rte_pdump_uninit(void)
441 : : {
442 : 1 : rte_mp_action_unregister(PDUMP_MP);
443 : :
444 [ + - ]: 1 : if (pdump_stats != NULL) {
445 : 1 : rte_memzone_free(pdump_stats->mz);
446 : 1 : pdump_stats = NULL;
447 : : }
448 : :
449 : 1 : return 0;
450 : : }
451 : :
452 : : static int
453 : 0 : pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
454 : : {
455 [ # # ]: 0 : if (ring == NULL || mp == NULL) {
456 : 0 : PDUMP_LOG_LINE(ERR, "NULL ring or mempool");
457 : 0 : rte_errno = EINVAL;
458 : 0 : return -1;
459 : : }
460 [ # # ]: 0 : if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
461 : : mp->flags & RTE_MEMPOOL_F_SC_GET) {
462 : 0 : PDUMP_LOG_LINE(ERR,
463 : : "mempool with SP or SC set not valid for pdump,"
464 : : "must have MP and MC set");
465 : 0 : rte_errno = EINVAL;
466 : 0 : return -1;
467 : : }
468 [ # # # # ]: 0 : if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
469 : 0 : PDUMP_LOG_LINE(ERR,
470 : : "ring with SP or SC set is not valid for pdump,"
471 : : "must have MP and MC set");
472 : 0 : rte_errno = EINVAL;
473 : 0 : return -1;
474 : : }
475 : :
476 : : return 0;
477 : : }
478 : :
479 : : static int
480 : 0 : pdump_validate_flags(uint32_t flags)
481 : : {
482 [ # # ]: 0 : if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
483 : 0 : PDUMP_LOG_LINE(ERR,
484 : : "invalid flags, should be either rx/tx/rxtx");
485 : 0 : rte_errno = EINVAL;
486 : 0 : return -1;
487 : : }
488 : :
489 : : /* mask off the flags we know about */
490 [ # # ]: 0 : if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
491 : 0 : PDUMP_LOG_LINE(ERR,
492 : : "unknown flags: %#x", flags);
493 : 0 : rte_errno = ENOTSUP;
494 : 0 : return -1;
495 : : }
496 : :
497 : : return 0;
498 : : }
499 : :
500 : : static int
501 : 0 : pdump_validate_port(uint16_t port, char *name)
502 : : {
503 : : int ret = 0;
504 : :
505 [ # # ]: 0 : if (port >= RTE_MAX_ETHPORTS) {
506 : 0 : PDUMP_LOG_LINE(ERR, "Invalid port id %u", port);
507 : 0 : rte_errno = EINVAL;
508 : 0 : return -1;
509 : : }
510 : :
511 : 0 : ret = rte_eth_dev_get_name_by_port(port, name);
512 [ # # ]: 0 : if (ret < 0) {
513 : 0 : PDUMP_LOG_LINE(ERR, "port %u to name mapping failed",
514 : : port);
515 : 0 : rte_errno = EINVAL;
516 : 0 : return -1;
517 : : }
518 : :
519 : : return 0;
520 : : }
521 : :
522 : : static int
523 : 0 : pdump_prepare_client_request(const char *device, uint16_t queue,
524 : : uint32_t flags, uint32_t snaplen,
525 : : uint16_t operation,
526 : : struct rte_ring *ring,
527 : : struct rte_mempool *mp,
528 : : const struct rte_bpf_prm *prm)
529 : : {
530 : : int ret = -1;
531 : : struct rte_mp_msg mp_req, *mp_rep;
532 : : struct rte_mp_reply mp_reply;
533 : 0 : struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
534 : : struct pdump_request *req = (struct pdump_request *)mp_req.param;
535 : : struct pdump_response *resp;
536 : :
537 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
538 : 0 : PDUMP_LOG_LINE(ERR,
539 : : "pdump enable/disable not allowed in primary process");
540 : 0 : return -EINVAL;
541 : : }
542 : :
543 : : memset(req, 0, sizeof(*req));
544 : :
545 [ # # ]: 0 : req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
546 : 0 : req->flags = flags & RTE_PDUMP_FLAG_RXTX;
547 : 0 : req->op = operation;
548 : 0 : req->queue = queue;
549 : 0 : rte_strscpy(req->device, device, sizeof(req->device));
550 : :
551 [ # # ]: 0 : if ((operation & ENABLE) != 0) {
552 : 0 : req->ring = ring;
553 : 0 : req->mp = mp;
554 : 0 : req->prm = prm;
555 : 0 : req->snaplen = snaplen;
556 : : }
557 : :
558 : 0 : rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
559 : 0 : mp_req.len_param = sizeof(*req);
560 : 0 : mp_req.num_fds = 0;
561 [ # # ]: 0 : if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
562 : 0 : mp_rep = &mp_reply.msgs[0];
563 : : resp = (struct pdump_response *)mp_rep->param;
564 [ # # ]: 0 : if (resp->err_value == 0)
565 : : ret = 0;
566 : : else
567 : 0 : rte_errno = -resp->err_value;
568 : 0 : free(mp_reply.msgs);
569 : : }
570 : :
571 [ # # ]: 0 : if (ret < 0)
572 : 0 : PDUMP_LOG_LINE(ERR,
573 : : "client request for pdump enable/disable failed");
574 : : return ret;
575 : : }
576 : :
577 : : /*
578 : : * There are two versions of this function, because although original API
579 : : * left place holder for future filter, it never checked the value.
580 : : * Therefore the API can't depend on application passing a non
581 : : * bogus value.
582 : : */
583 : : static int
584 : 0 : pdump_enable(uint16_t port, uint16_t queue,
585 : : uint32_t flags, uint32_t snaplen,
586 : : struct rte_ring *ring, struct rte_mempool *mp,
587 : : const struct rte_bpf_prm *prm)
588 : : {
589 : : int ret;
590 : : char name[RTE_DEV_NAME_MAX_LEN];
591 : :
592 : 0 : ret = pdump_validate_port(port, name);
593 [ # # ]: 0 : if (ret < 0)
594 : : return ret;
595 : 0 : ret = pdump_validate_ring_mp(ring, mp);
596 [ # # ]: 0 : if (ret < 0)
597 : : return ret;
598 : 0 : ret = pdump_validate_flags(flags);
599 [ # # ]: 0 : if (ret < 0)
600 : : return ret;
601 : :
602 [ # # ]: 0 : if (snaplen == 0)
603 : : snaplen = UINT32_MAX;
604 : :
605 : 0 : return pdump_prepare_client_request(name, queue, flags, snaplen,
606 : : ENABLE, ring, mp, prm);
607 : : }
608 : :
609 : : int
610 : 0 : rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
611 : : struct rte_ring *ring,
612 : : struct rte_mempool *mp,
613 : : void *filter __rte_unused)
614 : : {
615 : 0 : return pdump_enable(port, queue, flags, 0,
616 : : ring, mp, NULL);
617 : : }
618 : :
619 : : int
620 : 0 : rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
621 : : uint32_t flags, uint32_t snaplen,
622 : : struct rte_ring *ring,
623 : : struct rte_mempool *mp,
624 : : const struct rte_bpf_prm *prm)
625 : : {
626 : 0 : return pdump_enable(port, queue, flags, snaplen,
627 : : ring, mp, prm);
628 : : }
629 : :
630 : : static int
631 : 0 : pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
632 : : uint32_t flags, uint32_t snaplen,
633 : : struct rte_ring *ring,
634 : : struct rte_mempool *mp,
635 : : const struct rte_bpf_prm *prm)
636 : : {
637 : : int ret;
638 : :
639 : 0 : ret = pdump_validate_ring_mp(ring, mp);
640 [ # # ]: 0 : if (ret < 0)
641 : : return ret;
642 : 0 : ret = pdump_validate_flags(flags);
643 [ # # ]: 0 : if (ret < 0)
644 : : return ret;
645 : :
646 [ # # ]: 0 : if (snaplen == 0)
647 : : snaplen = UINT32_MAX;
648 : :
649 : 0 : return pdump_prepare_client_request(device_id, queue, flags, snaplen,
650 : : ENABLE, ring, mp, prm);
651 : : }
652 : :
653 : : int
654 : 0 : rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
655 : : uint32_t flags,
656 : : struct rte_ring *ring,
657 : : struct rte_mempool *mp,
658 : : void *filter __rte_unused)
659 : : {
660 : 0 : return pdump_enable_by_deviceid(device_id, queue, flags, 0,
661 : : ring, mp, NULL);
662 : : }
663 : :
664 : : int
665 : 0 : rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
666 : : uint32_t flags, uint32_t snaplen,
667 : : struct rte_ring *ring,
668 : : struct rte_mempool *mp,
669 : : const struct rte_bpf_prm *prm)
670 : : {
671 : 0 : return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
672 : : ring, mp, prm);
673 : : }
674 : :
675 : : int
676 : 0 : rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
677 : : {
678 : : int ret = 0;
679 : : char name[RTE_DEV_NAME_MAX_LEN];
680 : :
681 : 0 : ret = pdump_validate_port(port, name);
682 [ # # ]: 0 : if (ret < 0)
683 : : return ret;
684 : 0 : ret = pdump_validate_flags(flags);
685 [ # # ]: 0 : if (ret < 0)
686 : : return ret;
687 : :
688 : 0 : ret = pdump_prepare_client_request(name, queue, flags, 0,
689 : : DISABLE, NULL, NULL, NULL);
690 : :
691 : 0 : return ret;
692 : : }
693 : :
694 : : int
695 : 0 : rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
696 : : uint32_t flags)
697 : : {
698 : : int ret = 0;
699 : :
700 : 0 : ret = pdump_validate_flags(flags);
701 [ # # ]: 0 : if (ret < 0)
702 : : return ret;
703 : :
704 : 0 : ret = pdump_prepare_client_request(device_id, queue, flags, 0,
705 : : DISABLE, NULL, NULL, NULL);
706 : :
707 : 0 : return ret;
708 : : }
709 : :
710 : : static void
711 : 0 : pdump_sum_stats(uint16_t port, uint16_t nq,
712 : : struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
713 : : struct rte_pdump_stats *total)
714 : : {
715 : : uint64_t *sum = (uint64_t *)total;
716 : : unsigned int i;
717 : : uint64_t val;
718 : : uint16_t qid;
719 : :
720 [ # # ]: 0 : for (qid = 0; qid < nq; qid++) {
721 : 0 : const RTE_ATOMIC(uint64_t) *perq = (const uint64_t __rte_atomic *)&stats[port][qid];
722 : :
723 [ # # ]: 0 : for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
724 : 0 : val = rte_atomic_load_explicit(&perq[i], rte_memory_order_relaxed);
725 : 0 : sum[i] += val;
726 : : }
727 : : }
728 : 0 : }
729 : :
730 : : int
731 : 0 : rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
732 : : {
733 : : struct rte_eth_dev_info dev_info;
734 : : const struct rte_memzone *mz;
735 : : int ret;
736 : :
737 : : memset(stats, 0, sizeof(*stats));
738 : 0 : ret = rte_eth_dev_info_get(port, &dev_info);
739 [ # # ]: 0 : if (ret != 0) {
740 : 0 : PDUMP_LOG_LINE(ERR,
741 : : "Error during getting device (port %u) info: %s",
742 : : port, strerror(-ret));
743 : 0 : return ret;
744 : : }
745 : :
746 [ # # ]: 0 : if (pdump_stats == NULL) {
747 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
748 : : /* rte_pdump_init was not called */
749 : 0 : PDUMP_LOG_LINE(ERR, "pdump stats not initialized");
750 : 0 : rte_errno = EINVAL;
751 : 0 : return -1;
752 : : }
753 : :
754 : : /* secondary process looks up the memzone */
755 : 0 : mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
756 [ # # ]: 0 : if (mz == NULL) {
757 : : /* rte_pdump_init was not called in primary process?? */
758 : 0 : PDUMP_LOG_LINE(ERR, "can not find pdump stats");
759 : 0 : rte_errno = EINVAL;
760 : 0 : return -1;
761 : : }
762 : 0 : pdump_stats = mz->addr;
763 : : }
764 : :
765 : 0 : pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
766 : 0 : pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
767 : 0 : return 0;
768 : : }
|