xref: /f-stack/dpdk/lib/librte_pdump/rte_pdump.c (revision 2d9fd380)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2018 Intel Corporation
3  */
4 
5 #include <rte_memcpy.h>
6 #include <rte_mbuf.h>
7 #include <rte_ethdev.h>
8 #include <rte_lcore.h>
9 #include <rte_log.h>
10 #include <rte_errno.h>
11 #include <rte_string_fns.h>
12 
13 #include "rte_pdump.h"
14 
15 #define DEVICE_ID_SIZE 64
16 
17 RTE_LOG_REGISTER(pdump_logtype, lib.pdump, NOTICE);
18 
19 /* Macro for printing using RTE_LOG */
20 #define PDUMP_LOG(level, fmt, args...)				\
21 	rte_log(RTE_LOG_ ## level, pdump_logtype, "%s(): " fmt,	\
22 		__func__, ## 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 enum pdump_version {
33 	V1 = 1
34 };
35 
36 struct pdump_request {
37 	uint16_t ver;
38 	uint16_t op;
39 	uint32_t flags;
40 	union pdump_data {
41 		struct enable_v1 {
42 			char device[DEVICE_ID_SIZE];
43 			uint16_t queue;
44 			struct rte_ring *ring;
45 			struct rte_mempool *mp;
46 			void *filter;
47 		} en_v1;
48 		struct disable_v1 {
49 			char device[DEVICE_ID_SIZE];
50 			uint16_t queue;
51 			struct rte_ring *ring;
52 			struct rte_mempool *mp;
53 			void *filter;
54 		} dis_v1;
55 	} data;
56 };
57 
58 struct pdump_response {
59 	uint16_t ver;
60 	uint16_t res_op;
61 	int32_t err_value;
62 };
63 
64 static struct pdump_rxtx_cbs {
65 	struct rte_ring *ring;
66 	struct rte_mempool *mp;
67 	const struct rte_eth_rxtx_callback *cb;
68 	void *filter;
69 } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
70 tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
71 
72 
73 static inline void
pdump_copy(struct rte_mbuf ** pkts,uint16_t nb_pkts,void * user_params)74 pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
75 {
76 	unsigned i;
77 	int ring_enq;
78 	uint16_t d_pkts = 0;
79 	struct rte_mbuf *dup_bufs[nb_pkts];
80 	struct pdump_rxtx_cbs *cbs;
81 	struct rte_ring *ring;
82 	struct rte_mempool *mp;
83 	struct rte_mbuf *p;
84 
85 	cbs  = user_params;
86 	ring = cbs->ring;
87 	mp = cbs->mp;
88 	for (i = 0; i < nb_pkts; i++) {
89 		p = rte_pktmbuf_copy(pkts[i], mp, 0, UINT32_MAX);
90 		if (p)
91 			dup_bufs[d_pkts++] = p;
92 	}
93 
94 	ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL);
95 	if (unlikely(ring_enq < d_pkts)) {
96 		PDUMP_LOG(DEBUG,
97 			"only %d of packets enqueued to ring\n", ring_enq);
98 		do {
99 			rte_pktmbuf_free(dup_bufs[ring_enq]);
100 		} while (++ring_enq < d_pkts);
101 	}
102 }
103 
104 static uint16_t
pdump_rx(uint16_t port __rte_unused,uint16_t qidx __rte_unused,struct rte_mbuf ** pkts,uint16_t nb_pkts,uint16_t max_pkts __rte_unused,void * user_params)105 pdump_rx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
106 	struct rte_mbuf **pkts, uint16_t nb_pkts,
107 	uint16_t max_pkts __rte_unused,
108 	void *user_params)
109 {
110 	pdump_copy(pkts, nb_pkts, user_params);
111 	return nb_pkts;
112 }
113 
114 static uint16_t
pdump_tx(uint16_t port __rte_unused,uint16_t qidx __rte_unused,struct rte_mbuf ** pkts,uint16_t nb_pkts,void * user_params)115 pdump_tx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
116 		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
117 {
118 	pdump_copy(pkts, nb_pkts, user_params);
119 	return nb_pkts;
120 }
121 
122 static int
pdump_register_rx_callbacks(uint16_t end_q,uint16_t port,uint16_t queue,struct rte_ring * ring,struct rte_mempool * mp,uint16_t operation)123 pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
124 				struct rte_ring *ring, struct rte_mempool *mp,
125 				uint16_t operation)
126 {
127 	uint16_t qid;
128 	struct pdump_rxtx_cbs *cbs = NULL;
129 
130 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
131 	for (; qid < end_q; qid++) {
132 		cbs = &rx_cbs[port][qid];
133 		if (cbs && operation == ENABLE) {
134 			if (cbs->cb) {
135 				PDUMP_LOG(ERR,
136 					"failed to add rx callback for port=%d "
137 					"and queue=%d, callback already exists\n",
138 					port, qid);
139 				return -EEXIST;
140 			}
141 			cbs->ring = ring;
142 			cbs->mp = mp;
143 			cbs->cb = rte_eth_add_first_rx_callback(port, qid,
144 								pdump_rx, cbs);
145 			if (cbs->cb == NULL) {
146 				PDUMP_LOG(ERR,
147 					"failed to add rx callback, errno=%d\n",
148 					rte_errno);
149 				return rte_errno;
150 			}
151 		}
152 		if (cbs && operation == DISABLE) {
153 			int ret;
154 
155 			if (cbs->cb == NULL) {
156 				PDUMP_LOG(ERR,
157 					"failed to delete non existing rx "
158 					"callback for port=%d and queue=%d\n",
159 					port, qid);
160 				return -EINVAL;
161 			}
162 			ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
163 			if (ret < 0) {
164 				PDUMP_LOG(ERR,
165 					"failed to remove rx callback, errno=%d\n",
166 					-ret);
167 				return ret;
168 			}
169 			cbs->cb = NULL;
170 		}
171 	}
172 
173 	return 0;
174 }
175 
176 static int
pdump_register_tx_callbacks(uint16_t end_q,uint16_t port,uint16_t queue,struct rte_ring * ring,struct rte_mempool * mp,uint16_t operation)177 pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
178 				struct rte_ring *ring, struct rte_mempool *mp,
179 				uint16_t operation)
180 {
181 
182 	uint16_t qid;
183 	struct pdump_rxtx_cbs *cbs = NULL;
184 
185 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
186 	for (; qid < end_q; qid++) {
187 		cbs = &tx_cbs[port][qid];
188 		if (cbs && operation == ENABLE) {
189 			if (cbs->cb) {
190 				PDUMP_LOG(ERR,
191 					"failed to add tx callback for port=%d "
192 					"and queue=%d, callback already exists\n",
193 					port, qid);
194 				return -EEXIST;
195 			}
196 			cbs->ring = ring;
197 			cbs->mp = mp;
198 			cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
199 								cbs);
200 			if (cbs->cb == NULL) {
201 				PDUMP_LOG(ERR,
202 					"failed to add tx callback, errno=%d\n",
203 					rte_errno);
204 				return rte_errno;
205 			}
206 		}
207 		if (cbs && operation == DISABLE) {
208 			int ret;
209 
210 			if (cbs->cb == NULL) {
211 				PDUMP_LOG(ERR,
212 					"failed to delete non existing tx "
213 					"callback for port=%d and queue=%d\n",
214 					port, qid);
215 				return -EINVAL;
216 			}
217 			ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
218 			if (ret < 0) {
219 				PDUMP_LOG(ERR,
220 					"failed to remove tx callback, errno=%d\n",
221 					-ret);
222 				return ret;
223 			}
224 			cbs->cb = NULL;
225 		}
226 	}
227 
228 	return 0;
229 }
230 
231 static int
set_pdump_rxtx_cbs(const struct pdump_request * p)232 set_pdump_rxtx_cbs(const struct pdump_request *p)
233 {
234 	uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
235 	uint16_t port;
236 	int ret = 0;
237 	uint32_t flags;
238 	uint16_t operation;
239 	struct rte_ring *ring;
240 	struct rte_mempool *mp;
241 
242 	flags = p->flags;
243 	operation = p->op;
244 	if (operation == ENABLE) {
245 		ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
246 				&port);
247 		if (ret < 0) {
248 			PDUMP_LOG(ERR,
249 				"failed to get port id for device id=%s\n",
250 				p->data.en_v1.device);
251 			return -EINVAL;
252 		}
253 		queue = p->data.en_v1.queue;
254 		ring = p->data.en_v1.ring;
255 		mp = p->data.en_v1.mp;
256 	} else {
257 		ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
258 				&port);
259 		if (ret < 0) {
260 			PDUMP_LOG(ERR,
261 				"failed to get port id for device id=%s\n",
262 				p->data.dis_v1.device);
263 			return -EINVAL;
264 		}
265 		queue = p->data.dis_v1.queue;
266 		ring = p->data.dis_v1.ring;
267 		mp = p->data.dis_v1.mp;
268 	}
269 
270 	/* validation if packet capture is for all queues */
271 	if (queue == RTE_PDUMP_ALL_QUEUES) {
272 		struct rte_eth_dev_info dev_info;
273 
274 		ret = rte_eth_dev_info_get(port, &dev_info);
275 		if (ret != 0) {
276 			PDUMP_LOG(ERR,
277 				"Error during getting device (port %u) info: %s\n",
278 				port, strerror(-ret));
279 			return ret;
280 		}
281 
282 		nb_rx_q = dev_info.nb_rx_queues;
283 		nb_tx_q = dev_info.nb_tx_queues;
284 		if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
285 			PDUMP_LOG(ERR,
286 				"number of rx queues cannot be 0\n");
287 			return -EINVAL;
288 		}
289 		if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
290 			PDUMP_LOG(ERR,
291 				"number of tx queues cannot be 0\n");
292 			return -EINVAL;
293 		}
294 		if ((nb_tx_q == 0 || nb_rx_q == 0) &&
295 			flags == RTE_PDUMP_FLAG_RXTX) {
296 			PDUMP_LOG(ERR,
297 				"both tx&rx queues must be non zero\n");
298 			return -EINVAL;
299 		}
300 	}
301 
302 	/* register RX callback */
303 	if (flags & RTE_PDUMP_FLAG_RX) {
304 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
305 		ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp,
306 							operation);
307 		if (ret < 0)
308 			return ret;
309 	}
310 
311 	/* register TX callback */
312 	if (flags & RTE_PDUMP_FLAG_TX) {
313 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
314 		ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp,
315 							operation);
316 		if (ret < 0)
317 			return ret;
318 	}
319 
320 	return ret;
321 }
322 
323 static int
pdump_server(const struct rte_mp_msg * mp_msg,const void * peer)324 pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
325 {
326 	struct rte_mp_msg mp_resp;
327 	const struct pdump_request *cli_req;
328 	struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
329 
330 	/* recv client requests */
331 	if (mp_msg->len_param != sizeof(*cli_req)) {
332 		PDUMP_LOG(ERR, "failed to recv from client\n");
333 		resp->err_value = -EINVAL;
334 	} else {
335 		cli_req = (const struct pdump_request *)mp_msg->param;
336 		resp->ver = cli_req->ver;
337 		resp->res_op = cli_req->op;
338 		resp->err_value = set_pdump_rxtx_cbs(cli_req);
339 	}
340 
341 	strlcpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
342 	mp_resp.len_param = sizeof(*resp);
343 	mp_resp.num_fds = 0;
344 	if (rte_mp_reply(&mp_resp, peer) < 0) {
345 		PDUMP_LOG(ERR, "failed to send to client:%s\n",
346 			  strerror(rte_errno));
347 		return -1;
348 	}
349 
350 	return 0;
351 }
352 
353 int
rte_pdump_init(void)354 rte_pdump_init(void)
355 {
356 	int ret = rte_mp_action_register(PDUMP_MP, pdump_server);
357 	if (ret && rte_errno != ENOTSUP)
358 		return -1;
359 	return 0;
360 }
361 
362 int
rte_pdump_uninit(void)363 rte_pdump_uninit(void)
364 {
365 	rte_mp_action_unregister(PDUMP_MP);
366 
367 	return 0;
368 }
369 
370 static int
pdump_validate_ring_mp(struct rte_ring * ring,struct rte_mempool * mp)371 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
372 {
373 	if (ring == NULL || mp == NULL) {
374 		PDUMP_LOG(ERR, "NULL ring or mempool\n");
375 		rte_errno = EINVAL;
376 		return -1;
377 	}
378 	if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
379 		PDUMP_LOG(ERR, "mempool with either SP or SC settings"
380 		" is not valid for pdump, should have MP and MC settings\n");
381 		rte_errno = EINVAL;
382 		return -1;
383 	}
384 	if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
385 		PDUMP_LOG(ERR, "ring with either SP or SC settings"
386 		" is not valid for pdump, should have MP and MC settings\n");
387 		rte_errno = EINVAL;
388 		return -1;
389 	}
390 
391 	return 0;
392 }
393 
394 static int
pdump_validate_flags(uint32_t flags)395 pdump_validate_flags(uint32_t flags)
396 {
397 	if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
398 		flags != RTE_PDUMP_FLAG_RXTX) {
399 		PDUMP_LOG(ERR,
400 			"invalid flags, should be either rx/tx/rxtx\n");
401 		rte_errno = EINVAL;
402 		return -1;
403 	}
404 
405 	return 0;
406 }
407 
408 static int
pdump_validate_port(uint16_t port,char * name)409 pdump_validate_port(uint16_t port, char *name)
410 {
411 	int ret = 0;
412 
413 	if (port >= RTE_MAX_ETHPORTS) {
414 		PDUMP_LOG(ERR, "Invalid port id %u\n", port);
415 		rte_errno = EINVAL;
416 		return -1;
417 	}
418 
419 	ret = rte_eth_dev_get_name_by_port(port, name);
420 	if (ret < 0) {
421 		PDUMP_LOG(ERR, "port %u to name mapping failed\n",
422 			  port);
423 		rte_errno = EINVAL;
424 		return -1;
425 	}
426 
427 	return 0;
428 }
429 
430 static int
pdump_prepare_client_request(char * device,uint16_t queue,uint32_t flags,uint16_t operation,struct rte_ring * ring,struct rte_mempool * mp,void * filter)431 pdump_prepare_client_request(char *device, uint16_t queue,
432 				uint32_t flags,
433 				uint16_t operation,
434 				struct rte_ring *ring,
435 				struct rte_mempool *mp,
436 				void *filter)
437 {
438 	int ret = -1;
439 	struct rte_mp_msg mp_req, *mp_rep;
440 	struct rte_mp_reply mp_reply;
441 	struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
442 	struct pdump_request *req = (struct pdump_request *)mp_req.param;
443 	struct pdump_response *resp;
444 
445 	req->ver = 1;
446 	req->flags = flags;
447 	req->op = operation;
448 	if ((operation & ENABLE) != 0) {
449 		strlcpy(req->data.en_v1.device, device,
450 			sizeof(req->data.en_v1.device));
451 		req->data.en_v1.queue = queue;
452 		req->data.en_v1.ring = ring;
453 		req->data.en_v1.mp = mp;
454 		req->data.en_v1.filter = filter;
455 	} else {
456 		strlcpy(req->data.dis_v1.device, device,
457 			sizeof(req->data.dis_v1.device));
458 		req->data.dis_v1.queue = queue;
459 		req->data.dis_v1.ring = NULL;
460 		req->data.dis_v1.mp = NULL;
461 		req->data.dis_v1.filter = NULL;
462 	}
463 
464 	strlcpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
465 	mp_req.len_param = sizeof(*req);
466 	mp_req.num_fds = 0;
467 	if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
468 		mp_rep = &mp_reply.msgs[0];
469 		resp = (struct pdump_response *)mp_rep->param;
470 		rte_errno = resp->err_value;
471 		if (!resp->err_value)
472 			ret = 0;
473 		free(mp_reply.msgs);
474 	}
475 
476 	if (ret < 0)
477 		PDUMP_LOG(ERR,
478 			"client request for pdump enable/disable failed\n");
479 	return ret;
480 }
481 
482 int
rte_pdump_enable(uint16_t port,uint16_t queue,uint32_t flags,struct rte_ring * ring,struct rte_mempool * mp,void * filter)483 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
484 			struct rte_ring *ring,
485 			struct rte_mempool *mp,
486 			void *filter)
487 {
488 
489 	int ret = 0;
490 	char name[DEVICE_ID_SIZE];
491 
492 	ret = pdump_validate_port(port, name);
493 	if (ret < 0)
494 		return ret;
495 	ret = pdump_validate_ring_mp(ring, mp);
496 	if (ret < 0)
497 		return ret;
498 	ret = pdump_validate_flags(flags);
499 	if (ret < 0)
500 		return ret;
501 
502 	ret = pdump_prepare_client_request(name, queue, flags,
503 						ENABLE, ring, mp, filter);
504 
505 	return ret;
506 }
507 
508 int
rte_pdump_enable_by_deviceid(char * device_id,uint16_t queue,uint32_t flags,struct rte_ring * ring,struct rte_mempool * mp,void * filter)509 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
510 				uint32_t flags,
511 				struct rte_ring *ring,
512 				struct rte_mempool *mp,
513 				void *filter)
514 {
515 	int ret = 0;
516 
517 	ret = pdump_validate_ring_mp(ring, mp);
518 	if (ret < 0)
519 		return ret;
520 	ret = pdump_validate_flags(flags);
521 	if (ret < 0)
522 		return ret;
523 
524 	ret = pdump_prepare_client_request(device_id, queue, flags,
525 						ENABLE, ring, mp, filter);
526 
527 	return ret;
528 }
529 
530 int
rte_pdump_disable(uint16_t port,uint16_t queue,uint32_t flags)531 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
532 {
533 	int ret = 0;
534 	char name[DEVICE_ID_SIZE];
535 
536 	ret = pdump_validate_port(port, name);
537 	if (ret < 0)
538 		return ret;
539 	ret = pdump_validate_flags(flags);
540 	if (ret < 0)
541 		return ret;
542 
543 	ret = pdump_prepare_client_request(name, queue, flags,
544 						DISABLE, NULL, NULL, NULL);
545 
546 	return ret;
547 }
548 
549 int
rte_pdump_disable_by_deviceid(char * device_id,uint16_t queue,uint32_t flags)550 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
551 				uint32_t flags)
552 {
553 	int ret = 0;
554 
555 	ret = pdump_validate_flags(flags);
556 	if (ret < 0)
557 		return ret;
558 
559 	ret = pdump_prepare_client_request(device_id, queue, flags,
560 						DISABLE, NULL, NULL, NULL);
561 
562 	return ret;
563 }
564