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