xref: /f-stack/dpdk/lib/librte_pdump/rte_pdump.c (revision 031be553)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <pthread.h>
40 #include <stdbool.h>
41 #include <stdio.h>
42 
43 #include <rte_memcpy.h>
44 #include <rte_mbuf.h>
45 #include <rte_ethdev.h>
46 #include <rte_lcore.h>
47 #include <rte_log.h>
48 #include <rte_errno.h>
49 
50 #include "rte_pdump.h"
51 
52 #define SOCKET_PATH_VAR_RUN "/var/run"
53 #define SOCKET_PATH_HOME "HOME"
54 #define DPDK_DIR         "/.dpdk"
55 #define SOCKET_DIR       "/pdump_sockets"
56 #define SERVER_SOCKET "%s/pdump_server_socket"
57 #define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
58 #define DEVICE_ID_SIZE 64
59 /* Macros for printing using RTE_LOG */
60 #define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
61 
62 enum pdump_operation {
63 	DISABLE = 1,
64 	ENABLE = 2
65 };
66 
67 enum pdump_version {
68 	V1 = 1
69 };
70 
71 static pthread_t pdump_thread;
72 static int pdump_socket_fd;
73 static char server_socket_dir[PATH_MAX];
74 static char client_socket_dir[PATH_MAX];
75 
76 struct pdump_request {
77 	uint16_t ver;
78 	uint16_t op;
79 	uint32_t flags;
80 	union pdump_data {
81 		struct enable_v1 {
82 			char device[DEVICE_ID_SIZE];
83 			uint16_t queue;
84 			struct rte_ring *ring;
85 			struct rte_mempool *mp;
86 			void *filter;
87 		} en_v1;
88 		struct disable_v1 {
89 			char device[DEVICE_ID_SIZE];
90 			uint16_t queue;
91 			struct rte_ring *ring;
92 			struct rte_mempool *mp;
93 			void *filter;
94 		} dis_v1;
95 	} data;
96 };
97 
98 struct pdump_response {
99 	uint16_t ver;
100 	uint16_t res_op;
101 	int32_t err_value;
102 };
103 
104 static struct pdump_rxtx_cbs {
105 	struct rte_ring *ring;
106 	struct rte_mempool *mp;
107 	struct rte_eth_rxtx_callback *cb;
108 	void *filter;
109 } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
110 tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
111 
112 static inline int
113 pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
114 {
115 	if (rte_pktmbuf_tailroom(seg) < m->data_len) {
116 		RTE_LOG(ERR, PDUMP,
117 			"User mempool: insufficient data_len of mbuf\n");
118 		return -EINVAL;
119 	}
120 
121 	seg->port = m->port;
122 	seg->vlan_tci = m->vlan_tci;
123 	seg->hash = m->hash;
124 	seg->tx_offload = m->tx_offload;
125 	seg->ol_flags = m->ol_flags;
126 	seg->packet_type = m->packet_type;
127 	seg->vlan_tci_outer = m->vlan_tci_outer;
128 	seg->data_len = m->data_len;
129 	seg->pkt_len = seg->data_len;
130 	rte_memcpy(rte_pktmbuf_mtod(seg, void *),
131 			rte_pktmbuf_mtod(m, void *),
132 			rte_pktmbuf_data_len(seg));
133 
134 	return 0;
135 }
136 
137 static inline struct rte_mbuf *
138 pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
139 {
140 	struct rte_mbuf *m_dup, *seg, **prev;
141 	uint32_t pktlen;
142 	uint16_t nseg;
143 
144 	m_dup = rte_pktmbuf_alloc(mp);
145 	if (unlikely(m_dup == NULL))
146 		return NULL;
147 
148 	seg = m_dup;
149 	prev = &seg->next;
150 	pktlen = m->pkt_len;
151 	nseg = 0;
152 
153 	do {
154 		nseg++;
155 		if (pdump_pktmbuf_copy_data(seg, m) < 0) {
156 			if (seg != m_dup)
157 				rte_pktmbuf_free_seg(seg);
158 			rte_pktmbuf_free(m_dup);
159 			return NULL;
160 		}
161 		*prev = seg;
162 		prev = &seg->next;
163 	} while ((m = m->next) != NULL &&
164 			(seg = rte_pktmbuf_alloc(mp)) != NULL);
165 
166 	*prev = NULL;
167 	m_dup->nb_segs = nseg;
168 	m_dup->pkt_len = pktlen;
169 
170 	/* Allocation of new indirect segment failed */
171 	if (unlikely(seg == NULL)) {
172 		rte_pktmbuf_free(m_dup);
173 		return NULL;
174 	}
175 
176 	__rte_mbuf_sanity_check(m_dup, 1);
177 	return m_dup;
178 }
179 
180 static inline void
181 pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
182 {
183 	unsigned i;
184 	int ring_enq;
185 	uint16_t d_pkts = 0;
186 	struct rte_mbuf *dup_bufs[nb_pkts];
187 	struct pdump_rxtx_cbs *cbs;
188 	struct rte_ring *ring;
189 	struct rte_mempool *mp;
190 	struct rte_mbuf *p;
191 
192 	cbs  = user_params;
193 	ring = cbs->ring;
194 	mp = cbs->mp;
195 	for (i = 0; i < nb_pkts; i++) {
196 		p = pdump_pktmbuf_copy(pkts[i], mp);
197 		if (p)
198 			dup_bufs[d_pkts++] = p;
199 	}
200 
201 	ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL);
202 	if (unlikely(ring_enq < d_pkts)) {
203 		RTE_LOG(DEBUG, PDUMP,
204 			"only %d of packets enqueued to ring\n", ring_enq);
205 		do {
206 			rte_pktmbuf_free(dup_bufs[ring_enq]);
207 		} while (++ring_enq < d_pkts);
208 	}
209 }
210 
211 static uint16_t
212 pdump_rx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
213 	struct rte_mbuf **pkts, uint16_t nb_pkts,
214 	uint16_t max_pkts __rte_unused,
215 	void *user_params)
216 {
217 	pdump_copy(pkts, nb_pkts, user_params);
218 	return nb_pkts;
219 }
220 
221 static uint16_t
222 pdump_tx(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
223 		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
224 {
225 	pdump_copy(pkts, nb_pkts, user_params);
226 	return nb_pkts;
227 }
228 
229 static int
230 pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
231 				struct rte_ring *ring, struct rte_mempool *mp,
232 				uint16_t operation)
233 {
234 	uint16_t qid;
235 	struct pdump_rxtx_cbs *cbs = NULL;
236 
237 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
238 	for (; qid < end_q; qid++) {
239 		cbs = &rx_cbs[port][qid];
240 		if (cbs && operation == ENABLE) {
241 			if (cbs->cb) {
242 				RTE_LOG(ERR, PDUMP,
243 					"failed to add rx callback for port=%d "
244 					"and queue=%d, callback already exists\n",
245 					port, qid);
246 				return -EEXIST;
247 			}
248 			cbs->ring = ring;
249 			cbs->mp = mp;
250 			cbs->cb = rte_eth_add_first_rx_callback(port, qid,
251 								pdump_rx, cbs);
252 			if (cbs->cb == NULL) {
253 				RTE_LOG(ERR, PDUMP,
254 					"failed to add rx callback, errno=%d\n",
255 					rte_errno);
256 				return rte_errno;
257 			}
258 		}
259 		if (cbs && operation == DISABLE) {
260 			int ret;
261 
262 			if (cbs->cb == NULL) {
263 				RTE_LOG(ERR, PDUMP,
264 					"failed to delete non existing rx "
265 					"callback for port=%d and queue=%d\n",
266 					port, qid);
267 				return -EINVAL;
268 			}
269 			ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
270 			if (ret < 0) {
271 				RTE_LOG(ERR, PDUMP,
272 					"failed to remove rx callback, errno=%d\n",
273 					-ret);
274 				return ret;
275 			}
276 			cbs->cb = NULL;
277 		}
278 	}
279 
280 	return 0;
281 }
282 
283 static int
284 pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue,
285 				struct rte_ring *ring, struct rte_mempool *mp,
286 				uint16_t operation)
287 {
288 
289 	uint16_t qid;
290 	struct pdump_rxtx_cbs *cbs = NULL;
291 
292 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
293 	for (; qid < end_q; qid++) {
294 		cbs = &tx_cbs[port][qid];
295 		if (cbs && operation == ENABLE) {
296 			if (cbs->cb) {
297 				RTE_LOG(ERR, PDUMP,
298 					"failed to add tx callback for port=%d "
299 					"and queue=%d, callback already exists\n",
300 					port, qid);
301 				return -EEXIST;
302 			}
303 			cbs->ring = ring;
304 			cbs->mp = mp;
305 			cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
306 								cbs);
307 			if (cbs->cb == NULL) {
308 				RTE_LOG(ERR, PDUMP,
309 					"failed to add tx callback, errno=%d\n",
310 					rte_errno);
311 				return rte_errno;
312 			}
313 		}
314 		if (cbs && operation == DISABLE) {
315 			int ret;
316 
317 			if (cbs->cb == NULL) {
318 				RTE_LOG(ERR, PDUMP,
319 					"failed to delete non existing tx "
320 					"callback for port=%d and queue=%d\n",
321 					port, qid);
322 				return -EINVAL;
323 			}
324 			ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
325 			if (ret < 0) {
326 				RTE_LOG(ERR, PDUMP,
327 					"failed to remove tx callback, errno=%d\n",
328 					-ret);
329 				return ret;
330 			}
331 			cbs->cb = NULL;
332 		}
333 	}
334 
335 	return 0;
336 }
337 
338 static int
339 set_pdump_rxtx_cbs(struct pdump_request *p)
340 {
341 	uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
342 	uint16_t port;
343 	int ret = 0;
344 	uint32_t flags;
345 	uint16_t operation;
346 	struct rte_ring *ring;
347 	struct rte_mempool *mp;
348 
349 	flags = p->flags;
350 	operation = p->op;
351 	if (operation == ENABLE) {
352 		ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
353 				&port);
354 		if (ret < 0) {
355 			RTE_LOG(ERR, PDUMP,
356 				"failed to get port id for device id=%s\n",
357 				p->data.en_v1.device);
358 			return -EINVAL;
359 		}
360 		queue = p->data.en_v1.queue;
361 		ring = p->data.en_v1.ring;
362 		mp = p->data.en_v1.mp;
363 	} else {
364 		ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
365 				&port);
366 		if (ret < 0) {
367 			RTE_LOG(ERR, PDUMP,
368 				"failed to get port id for device id=%s\n",
369 				p->data.dis_v1.device);
370 			return -EINVAL;
371 		}
372 		queue = p->data.dis_v1.queue;
373 		ring = p->data.dis_v1.ring;
374 		mp = p->data.dis_v1.mp;
375 	}
376 
377 	/* validation if packet capture is for all queues */
378 	if (queue == RTE_PDUMP_ALL_QUEUES) {
379 		struct rte_eth_dev_info dev_info;
380 
381 		rte_eth_dev_info_get(port, &dev_info);
382 		nb_rx_q = dev_info.nb_rx_queues;
383 		nb_tx_q = dev_info.nb_tx_queues;
384 		if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
385 			RTE_LOG(ERR, PDUMP,
386 				"number of rx queues cannot be 0\n");
387 			return -EINVAL;
388 		}
389 		if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
390 			RTE_LOG(ERR, PDUMP,
391 				"number of tx queues cannot be 0\n");
392 			return -EINVAL;
393 		}
394 		if ((nb_tx_q == 0 || nb_rx_q == 0) &&
395 			flags == RTE_PDUMP_FLAG_RXTX) {
396 			RTE_LOG(ERR, PDUMP,
397 				"both tx&rx queues must be non zero\n");
398 			return -EINVAL;
399 		}
400 	}
401 
402 	/* register RX callback */
403 	if (flags & RTE_PDUMP_FLAG_RX) {
404 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
405 		ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp,
406 							operation);
407 		if (ret < 0)
408 			return ret;
409 	}
410 
411 	/* register TX callback */
412 	if (flags & RTE_PDUMP_FLAG_TX) {
413 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
414 		ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp,
415 							operation);
416 		if (ret < 0)
417 			return ret;
418 	}
419 
420 	return ret;
421 }
422 
423 /* get socket path (/var/run if root, $HOME otherwise) */
424 static int
425 pdump_get_socket_path(char *buffer, int bufsz, enum rte_pdump_socktype type)
426 {
427 	char dpdk_dir[PATH_MAX] = {0};
428 	char dir[PATH_MAX] = {0};
429 	char *dir_home = NULL;
430 	int ret = 0;
431 
432 	if (type == RTE_PDUMP_SOCKET_SERVER && server_socket_dir[0] != 0)
433 		snprintf(dir, sizeof(dir), "%s", server_socket_dir);
434 	else if (type == RTE_PDUMP_SOCKET_CLIENT && client_socket_dir[0] != 0)
435 		snprintf(dir, sizeof(dir), "%s", client_socket_dir);
436 	else {
437 		if (getuid() != 0) {
438 			dir_home = getenv(SOCKET_PATH_HOME);
439 			if (!dir_home) {
440 				RTE_LOG(ERR, PDUMP,
441 					"Failed to get environment variable"
442 					" value for %s, %s:%d\n",
443 					SOCKET_PATH_HOME, __func__, __LINE__);
444 				return -1;
445 			}
446 			snprintf(dpdk_dir, sizeof(dpdk_dir), "%s%s",
447 					dir_home, DPDK_DIR);
448 		} else
449 			snprintf(dpdk_dir, sizeof(dpdk_dir), "%s%s",
450 					SOCKET_PATH_VAR_RUN, DPDK_DIR);
451 
452 		mkdir(dpdk_dir, 0700);
453 		snprintf(dir, sizeof(dir), "%s%s",
454 					dpdk_dir, SOCKET_DIR);
455 	}
456 
457 	ret =  mkdir(dir, 0700);
458 	/* if user passed socket path is invalid, return immediately */
459 	if (ret < 0 && errno != EEXIST) {
460 		RTE_LOG(ERR, PDUMP,
461 			"Failed to create dir:%s:%s\n", dir,
462 			strerror(errno));
463 		rte_errno = errno;
464 		return -1;
465 	}
466 
467 	if (type == RTE_PDUMP_SOCKET_SERVER)
468 		snprintf(buffer, bufsz, SERVER_SOCKET, dir);
469 	else
470 		snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
471 				rte_sys_gettid());
472 
473 	return 0;
474 }
475 
476 static int
477 pdump_create_server_socket(void)
478 {
479 	int ret, socket_fd;
480 	struct sockaddr_un addr;
481 	socklen_t addr_len;
482 
483 	ret = pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
484 				RTE_PDUMP_SOCKET_SERVER);
485 	if (ret != 0) {
486 		RTE_LOG(ERR, PDUMP,
487 			"Failed to get server socket path: %s:%d\n",
488 			__func__, __LINE__);
489 		return -1;
490 	}
491 	addr.sun_family = AF_UNIX;
492 
493 	/* remove if file already exists */
494 	unlink(addr.sun_path);
495 
496 	/* set up a server socket */
497 	socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
498 	if (socket_fd < 0) {
499 		RTE_LOG(ERR, PDUMP,
500 			"Failed to create server socket: %s, %s:%d\n",
501 			strerror(errno), __func__, __LINE__);
502 		return -1;
503 	}
504 
505 	addr_len = sizeof(struct sockaddr_un);
506 	ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
507 	if (ret) {
508 		RTE_LOG(ERR, PDUMP,
509 			"Failed to bind to server socket: %s, %s:%d\n",
510 			strerror(errno), __func__, __LINE__);
511 		close(socket_fd);
512 		return -1;
513 	}
514 
515 	/* save the socket in local configuration */
516 	pdump_socket_fd = socket_fd;
517 
518 	return 0;
519 }
520 
521 static __attribute__((noreturn)) void *
522 pdump_thread_main(__rte_unused void *arg)
523 {
524 	struct sockaddr_un cli_addr;
525 	socklen_t cli_len;
526 	struct pdump_request cli_req;
527 	struct pdump_response resp;
528 	int n;
529 	int ret = 0;
530 
531 	/* host thread, never break out */
532 	for (;;) {
533 		/* recv client requests */
534 		cli_len = sizeof(cli_addr);
535 		n = recvfrom(pdump_socket_fd, &cli_req,
536 				sizeof(struct pdump_request), 0,
537 				(struct sockaddr *)&cli_addr, &cli_len);
538 		if (n < 0) {
539 			RTE_LOG(ERR, PDUMP,
540 				"failed to recv from client:%s, %s:%d\n",
541 				strerror(errno), __func__, __LINE__);
542 			continue;
543 		}
544 
545 		ret = set_pdump_rxtx_cbs(&cli_req);
546 
547 		resp.ver = cli_req.ver;
548 		resp.res_op = cli_req.op;
549 		resp.err_value = ret;
550 		n = sendto(pdump_socket_fd, &resp,
551 				sizeof(struct pdump_response),
552 				0, (struct sockaddr *)&cli_addr, cli_len);
553 		if (n < 0) {
554 			RTE_LOG(ERR, PDUMP,
555 				"failed to send to client:%s, %s:%d\n",
556 				strerror(errno), __func__, __LINE__);
557 		}
558 	}
559 }
560 
561 int
562 rte_pdump_init(const char *path)
563 {
564 	int ret = 0;
565 	char thread_name[RTE_MAX_THREAD_NAME_LEN];
566 
567 	ret = rte_pdump_set_socket_dir(path, RTE_PDUMP_SOCKET_SERVER);
568 	if (ret != 0)
569 		return -1;
570 
571 	ret = pdump_create_server_socket();
572 	if (ret != 0) {
573 		RTE_LOG(ERR, PDUMP,
574 			"Failed to create server socket:%s:%d\n",
575 			__func__, __LINE__);
576 		return -1;
577 	}
578 
579 	/* create the host thread to wait/handle pdump requests */
580 	ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
581 	if (ret != 0) {
582 		RTE_LOG(ERR, PDUMP,
583 			"Failed to create the pdump thread:%s, %s:%d\n",
584 			strerror(ret), __func__, __LINE__);
585 		return -1;
586 	}
587 	/* Set thread_name for aid in debugging. */
588 	snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
589 	ret = rte_thread_setname(pdump_thread, thread_name);
590 	if (ret != 0) {
591 		RTE_LOG(DEBUG, PDUMP,
592 			"Failed to set thread name for pdump handling\n");
593 	}
594 
595 	return 0;
596 }
597 
598 int
599 rte_pdump_uninit(void)
600 {
601 	int ret;
602 
603 	ret = pthread_cancel(pdump_thread);
604 	if (ret != 0) {
605 		RTE_LOG(ERR, PDUMP,
606 			"Failed to cancel the pdump thread:%s, %s:%d\n",
607 			strerror(ret), __func__, __LINE__);
608 		return -1;
609 	}
610 
611 	ret = close(pdump_socket_fd);
612 	if (ret != 0) {
613 		RTE_LOG(ERR, PDUMP,
614 			"Failed to close server socket: %s, %s:%d\n",
615 			strerror(errno), __func__, __LINE__);
616 		return -1;
617 	}
618 
619 	struct sockaddr_un addr;
620 
621 	ret = pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
622 				RTE_PDUMP_SOCKET_SERVER);
623 	if (ret != 0) {
624 		RTE_LOG(ERR, PDUMP,
625 			"Failed to get server socket path: %s:%d\n",
626 			__func__, __LINE__);
627 		return -1;
628 	}
629 	ret = unlink(addr.sun_path);
630 	if (ret != 0) {
631 		RTE_LOG(ERR, PDUMP,
632 			"Failed to remove server socket addr: %s, %s:%d\n",
633 			strerror(errno), __func__, __LINE__);
634 		return -1;
635 	}
636 
637 	return 0;
638 }
639 
640 static int
641 pdump_create_client_socket(struct pdump_request *p)
642 {
643 	int ret, socket_fd;
644 	int pid;
645 	int n;
646 	struct pdump_response server_resp;
647 	struct sockaddr_un addr, serv_addr, from;
648 	socklen_t addr_len, serv_len;
649 
650 	pid = getpid();
651 
652 	socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
653 	if (socket_fd < 0) {
654 		RTE_LOG(ERR, PDUMP,
655 			"client socket(): %s:pid(%d):tid(%u), %s:%d\n",
656 			strerror(errno), pid, rte_sys_gettid(),
657 			__func__, __LINE__);
658 		rte_errno = errno;
659 		return -1;
660 	}
661 
662 	ret = pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
663 				RTE_PDUMP_SOCKET_CLIENT);
664 	if (ret != 0) {
665 		RTE_LOG(ERR, PDUMP,
666 			"Failed to get client socket path: %s:%d\n",
667 			__func__, __LINE__);
668 		rte_errno = errno;
669 		goto exit;
670 	}
671 	addr.sun_family = AF_UNIX;
672 	addr_len = sizeof(struct sockaddr_un);
673 
674 	do {
675 		ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
676 		if (ret) {
677 			RTE_LOG(ERR, PDUMP,
678 				"client bind(): %s, %s:%d\n",
679 				strerror(errno), __func__, __LINE__);
680 			rte_errno = errno;
681 			break;
682 		}
683 
684 		serv_len = sizeof(struct sockaddr_un);
685 		memset(&serv_addr, 0, sizeof(serv_addr));
686 		ret = pdump_get_socket_path(serv_addr.sun_path,
687 					sizeof(serv_addr.sun_path),
688 					RTE_PDUMP_SOCKET_SERVER);
689 		if (ret != 0) {
690 			RTE_LOG(ERR, PDUMP,
691 				"Failed to get server socket path: %s:%d\n",
692 				__func__, __LINE__);
693 			rte_errno = errno;
694 			break;
695 		}
696 		serv_addr.sun_family = AF_UNIX;
697 
698 		n =  sendto(socket_fd, p, sizeof(struct pdump_request), 0,
699 				(struct sockaddr *)&serv_addr, serv_len);
700 		if (n < 0) {
701 			RTE_LOG(ERR, PDUMP,
702 				"failed to send to server:%s, %s:%d\n",
703 				strerror(errno), __func__, __LINE__);
704 			rte_errno = errno;
705 			ret = -1;
706 			break;
707 		}
708 
709 		n = recvfrom(socket_fd, &server_resp,
710 				sizeof(struct pdump_response), 0,
711 				(struct sockaddr *)&from, &serv_len);
712 		if (n < 0) {
713 			RTE_LOG(ERR, PDUMP,
714 				"failed to recv from server:%s, %s:%d\n",
715 				strerror(errno), __func__, __LINE__);
716 			rte_errno = errno;
717 			ret = -1;
718 			break;
719 		}
720 		ret = server_resp.err_value;
721 	} while (0);
722 
723 exit:
724 	close(socket_fd);
725 	unlink(addr.sun_path);
726 	return ret;
727 }
728 
729 static int
730 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
731 {
732 	if (ring == NULL || mp == NULL) {
733 		RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
734 			__func__, __LINE__);
735 		rte_errno = EINVAL;
736 		return -1;
737 	}
738 	if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
739 		RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
740 		" is not valid for pdump, should have MP and MC settings\n");
741 		rte_errno = EINVAL;
742 		return -1;
743 	}
744 	if (ring->prod.single || ring->cons.single) {
745 		RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
746 		" is not valid for pdump, should have MP and MC settings\n");
747 		rte_errno = EINVAL;
748 		return -1;
749 	}
750 
751 	return 0;
752 }
753 
754 static int
755 pdump_validate_flags(uint32_t flags)
756 {
757 	if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
758 		flags != RTE_PDUMP_FLAG_RXTX) {
759 		RTE_LOG(ERR, PDUMP,
760 			"invalid flags, should be either rx/tx/rxtx\n");
761 		rte_errno = EINVAL;
762 		return -1;
763 	}
764 
765 	return 0;
766 }
767 
768 static int
769 pdump_validate_port(uint16_t port, char *name)
770 {
771 	int ret = 0;
772 
773 	if (port >= RTE_MAX_ETHPORTS) {
774 		RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
775 			__func__, __LINE__);
776 		rte_errno = EINVAL;
777 		return -1;
778 	}
779 
780 	ret = rte_eth_dev_get_name_by_port(port, name);
781 	if (ret < 0) {
782 		RTE_LOG(ERR, PDUMP,
783 			"port id to name mapping failed for port id=%u, %s:%d\n",
784 			port, __func__, __LINE__);
785 		rte_errno = EINVAL;
786 		return -1;
787 	}
788 
789 	return 0;
790 }
791 
792 static int
793 pdump_prepare_client_request(char *device, uint16_t queue,
794 				uint32_t flags,
795 				uint16_t operation,
796 				struct rte_ring *ring,
797 				struct rte_mempool *mp,
798 				void *filter)
799 {
800 	int ret;
801 	struct pdump_request req = {.ver = 1,};
802 
803 	req.flags = flags;
804 	req.op =  operation;
805 	if ((operation & ENABLE) != 0) {
806 		snprintf(req.data.en_v1.device, sizeof(req.data.en_v1.device),
807 				"%s", device);
808 		req.data.en_v1.queue = queue;
809 		req.data.en_v1.ring = ring;
810 		req.data.en_v1.mp = mp;
811 		req.data.en_v1.filter = filter;
812 	} else {
813 		snprintf(req.data.dis_v1.device, sizeof(req.data.dis_v1.device),
814 				"%s", device);
815 		req.data.dis_v1.queue = queue;
816 		req.data.dis_v1.ring = NULL;
817 		req.data.dis_v1.mp = NULL;
818 		req.data.dis_v1.filter = NULL;
819 	}
820 
821 	ret = pdump_create_client_socket(&req);
822 	if (ret < 0) {
823 		RTE_LOG(ERR, PDUMP,
824 			"client request for pdump enable/disable failed\n");
825 		rte_errno = ret;
826 		return -1;
827 	}
828 
829 	return 0;
830 }
831 
832 int
833 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
834 			struct rte_ring *ring,
835 			struct rte_mempool *mp,
836 			void *filter)
837 {
838 
839 	int ret = 0;
840 	char name[DEVICE_ID_SIZE];
841 
842 	ret = pdump_validate_port(port, name);
843 	if (ret < 0)
844 		return ret;
845 	ret = pdump_validate_ring_mp(ring, mp);
846 	if (ret < 0)
847 		return ret;
848 	ret = pdump_validate_flags(flags);
849 	if (ret < 0)
850 		return ret;
851 
852 	ret = pdump_prepare_client_request(name, queue, flags,
853 						ENABLE, ring, mp, filter);
854 
855 	return ret;
856 }
857 
858 int
859 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
860 				uint32_t flags,
861 				struct rte_ring *ring,
862 				struct rte_mempool *mp,
863 				void *filter)
864 {
865 	int ret = 0;
866 
867 	ret = pdump_validate_ring_mp(ring, mp);
868 	if (ret < 0)
869 		return ret;
870 	ret = pdump_validate_flags(flags);
871 	if (ret < 0)
872 		return ret;
873 
874 	ret = pdump_prepare_client_request(device_id, queue, flags,
875 						ENABLE, ring, mp, filter);
876 
877 	return ret;
878 }
879 
880 int
881 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
882 {
883 	int ret = 0;
884 	char name[DEVICE_ID_SIZE];
885 
886 	ret = pdump_validate_port(port, name);
887 	if (ret < 0)
888 		return ret;
889 	ret = pdump_validate_flags(flags);
890 	if (ret < 0)
891 		return ret;
892 
893 	ret = pdump_prepare_client_request(name, queue, flags,
894 						DISABLE, NULL, NULL, NULL);
895 
896 	return ret;
897 }
898 
899 int
900 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
901 				uint32_t flags)
902 {
903 	int ret = 0;
904 
905 	ret = pdump_validate_flags(flags);
906 	if (ret < 0)
907 		return ret;
908 
909 	ret = pdump_prepare_client_request(device_id, queue, flags,
910 						DISABLE, NULL, NULL, NULL);
911 
912 	return ret;
913 }
914 
915 int
916 rte_pdump_set_socket_dir(const char *path, enum rte_pdump_socktype type)
917 {
918 	int ret, count;
919 
920 	if (path != NULL) {
921 		if (type == RTE_PDUMP_SOCKET_SERVER) {
922 			count = sizeof(server_socket_dir);
923 			ret = snprintf(server_socket_dir, count, "%s", path);
924 		} else {
925 			count = sizeof(client_socket_dir);
926 			ret = snprintf(client_socket_dir, count, "%s", path);
927 		}
928 
929 		if (ret < 0  || ret >= count) {
930 			RTE_LOG(ERR, PDUMP,
931 					"Invalid socket path:%s:%d\n",
932 					__func__, __LINE__);
933 			if (type == RTE_PDUMP_SOCKET_SERVER)
934 				server_socket_dir[0] = 0;
935 			else
936 				client_socket_dir[0] = 0;
937 			return -EINVAL;
938 		}
939 	}
940 
941 	return 0;
942 }
943