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