eal: set name when creating a control thread
[dpdk.git] / lib / librte_pdump / rte_pdump.c
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         snprintf(thread_name, sizeof(thread_name), "pdump-thread");
581         ret = rte_ctrl_thread_create(&pdump_thread, thread_name, NULL,
582                                 pdump_thread_main, NULL);
583         if (ret != 0) {
584                 RTE_LOG(ERR, PDUMP,
585                         "Failed to create the pdump thread:%s, %s:%d\n",
586                         strerror(-ret), __func__, __LINE__);
587                 return -1;
588         }
589
590         return 0;
591 }
592
593 int
594 rte_pdump_uninit(void)
595 {
596         int ret;
597
598         ret = pthread_cancel(pdump_thread);
599         if (ret != 0) {
600                 RTE_LOG(ERR, PDUMP,
601                         "Failed to cancel the pdump thread:%s, %s:%d\n",
602                         strerror(ret), __func__, __LINE__);
603                 return -1;
604         }
605
606         ret = close(pdump_socket_fd);
607         if (ret != 0) {
608                 RTE_LOG(ERR, PDUMP,
609                         "Failed to close server socket: %s, %s:%d\n",
610                         strerror(errno), __func__, __LINE__);
611                 return -1;
612         }
613
614         struct sockaddr_un addr;
615
616         ret = pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
617                                 RTE_PDUMP_SOCKET_SERVER);
618         if (ret != 0) {
619                 RTE_LOG(ERR, PDUMP,
620                         "Failed to get server socket path: %s:%d\n",
621                         __func__, __LINE__);
622                 return -1;
623         }
624         ret = unlink(addr.sun_path);
625         if (ret != 0) {
626                 RTE_LOG(ERR, PDUMP,
627                         "Failed to remove server socket addr: %s, %s:%d\n",
628                         strerror(errno), __func__, __LINE__);
629                 return -1;
630         }
631
632         return 0;
633 }
634
635 static int
636 pdump_create_client_socket(struct pdump_request *p)
637 {
638         int ret, socket_fd;
639         int pid;
640         int n;
641         struct pdump_response server_resp;
642         struct sockaddr_un addr, serv_addr, from;
643         socklen_t addr_len, serv_len;
644
645         pid = getpid();
646
647         socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
648         if (socket_fd < 0) {
649                 RTE_LOG(ERR, PDUMP,
650                         "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
651                         strerror(errno), pid, rte_sys_gettid(),
652                         __func__, __LINE__);
653                 rte_errno = errno;
654                 return -1;
655         }
656
657         ret = pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
658                                 RTE_PDUMP_SOCKET_CLIENT);
659         if (ret != 0) {
660                 RTE_LOG(ERR, PDUMP,
661                         "Failed to get client socket path: %s:%d\n",
662                         __func__, __LINE__);
663                 rte_errno = errno;
664                 goto exit;
665         }
666         addr.sun_family = AF_UNIX;
667         addr_len = sizeof(struct sockaddr_un);
668
669         do {
670                 ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
671                 if (ret) {
672                         RTE_LOG(ERR, PDUMP,
673                                 "client bind(): %s, %s:%d\n",
674                                 strerror(errno), __func__, __LINE__);
675                         rte_errno = errno;
676                         break;
677                 }
678
679                 serv_len = sizeof(struct sockaddr_un);
680                 memset(&serv_addr, 0, sizeof(serv_addr));
681                 ret = pdump_get_socket_path(serv_addr.sun_path,
682                                         sizeof(serv_addr.sun_path),
683                                         RTE_PDUMP_SOCKET_SERVER);
684                 if (ret != 0) {
685                         RTE_LOG(ERR, PDUMP,
686                                 "Failed to get server socket path: %s:%d\n",
687                                 __func__, __LINE__);
688                         rte_errno = errno;
689                         break;
690                 }
691                 serv_addr.sun_family = AF_UNIX;
692
693                 n =  sendto(socket_fd, p, sizeof(struct pdump_request), 0,
694                                 (struct sockaddr *)&serv_addr, serv_len);
695                 if (n < 0) {
696                         RTE_LOG(ERR, PDUMP,
697                                 "failed to send to server:%s, %s:%d\n",
698                                 strerror(errno), __func__, __LINE__);
699                         rte_errno = errno;
700                         ret = -1;
701                         break;
702                 }
703
704                 n = recvfrom(socket_fd, &server_resp,
705                                 sizeof(struct pdump_response), 0,
706                                 (struct sockaddr *)&from, &serv_len);
707                 if (n < 0) {
708                         RTE_LOG(ERR, PDUMP,
709                                 "failed to recv from server:%s, %s:%d\n",
710                                 strerror(errno), __func__, __LINE__);
711                         rte_errno = errno;
712                         ret = -1;
713                         break;
714                 }
715                 ret = server_resp.err_value;
716         } while (0);
717
718 exit:
719         close(socket_fd);
720         unlink(addr.sun_path);
721         return ret;
722 }
723
724 static int
725 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
726 {
727         if (ring == NULL || mp == NULL) {
728                 RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
729                         __func__, __LINE__);
730                 rte_errno = EINVAL;
731                 return -1;
732         }
733         if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
734                 RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
735                 " is not valid for pdump, should have MP and MC settings\n");
736                 rte_errno = EINVAL;
737                 return -1;
738         }
739         if (ring->prod.single || ring->cons.single) {
740                 RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
741                 " is not valid for pdump, should have MP and MC settings\n");
742                 rte_errno = EINVAL;
743                 return -1;
744         }
745
746         return 0;
747 }
748
749 static int
750 pdump_validate_flags(uint32_t flags)
751 {
752         if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
753                 flags != RTE_PDUMP_FLAG_RXTX) {
754                 RTE_LOG(ERR, PDUMP,
755                         "invalid flags, should be either rx/tx/rxtx\n");
756                 rte_errno = EINVAL;
757                 return -1;
758         }
759
760         return 0;
761 }
762
763 static int
764 pdump_validate_port(uint16_t port, char *name)
765 {
766         int ret = 0;
767
768         if (port >= RTE_MAX_ETHPORTS) {
769                 RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
770                         __func__, __LINE__);
771                 rte_errno = EINVAL;
772                 return -1;
773         }
774
775         ret = rte_eth_dev_get_name_by_port(port, name);
776         if (ret < 0) {
777                 RTE_LOG(ERR, PDUMP,
778                         "port id to name mapping failed for port id=%u, %s:%d\n",
779                         port, __func__, __LINE__);
780                 rte_errno = EINVAL;
781                 return -1;
782         }
783
784         return 0;
785 }
786
787 static int
788 pdump_prepare_client_request(char *device, uint16_t queue,
789                                 uint32_t flags,
790                                 uint16_t operation,
791                                 struct rte_ring *ring,
792                                 struct rte_mempool *mp,
793                                 void *filter)
794 {
795         int ret;
796         struct pdump_request req = {.ver = 1,};
797
798         req.flags = flags;
799         req.op =  operation;
800         if ((operation & ENABLE) != 0) {
801                 snprintf(req.data.en_v1.device, sizeof(req.data.en_v1.device),
802                                 "%s", device);
803                 req.data.en_v1.queue = queue;
804                 req.data.en_v1.ring = ring;
805                 req.data.en_v1.mp = mp;
806                 req.data.en_v1.filter = filter;
807         } else {
808                 snprintf(req.data.dis_v1.device, sizeof(req.data.dis_v1.device),
809                                 "%s", device);
810                 req.data.dis_v1.queue = queue;
811                 req.data.dis_v1.ring = NULL;
812                 req.data.dis_v1.mp = NULL;
813                 req.data.dis_v1.filter = NULL;
814         }
815
816         ret = pdump_create_client_socket(&req);
817         if (ret < 0) {
818                 RTE_LOG(ERR, PDUMP,
819                         "client request for pdump enable/disable failed\n");
820                 rte_errno = ret;
821                 return -1;
822         }
823
824         return 0;
825 }
826
827 int
828 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
829                         struct rte_ring *ring,
830                         struct rte_mempool *mp,
831                         void *filter)
832 {
833
834         int ret = 0;
835         char name[DEVICE_ID_SIZE];
836
837         ret = pdump_validate_port(port, name);
838         if (ret < 0)
839                 return ret;
840         ret = pdump_validate_ring_mp(ring, mp);
841         if (ret < 0)
842                 return ret;
843         ret = pdump_validate_flags(flags);
844         if (ret < 0)
845                 return ret;
846
847         ret = pdump_prepare_client_request(name, queue, flags,
848                                                 ENABLE, ring, mp, filter);
849
850         return ret;
851 }
852
853 int
854 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
855                                 uint32_t flags,
856                                 struct rte_ring *ring,
857                                 struct rte_mempool *mp,
858                                 void *filter)
859 {
860         int ret = 0;
861
862         ret = pdump_validate_ring_mp(ring, mp);
863         if (ret < 0)
864                 return ret;
865         ret = pdump_validate_flags(flags);
866         if (ret < 0)
867                 return ret;
868
869         ret = pdump_prepare_client_request(device_id, queue, flags,
870                                                 ENABLE, ring, mp, filter);
871
872         return ret;
873 }
874
875 int
876 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
877 {
878         int ret = 0;
879         char name[DEVICE_ID_SIZE];
880
881         ret = pdump_validate_port(port, name);
882         if (ret < 0)
883                 return ret;
884         ret = pdump_validate_flags(flags);
885         if (ret < 0)
886                 return ret;
887
888         ret = pdump_prepare_client_request(name, queue, flags,
889                                                 DISABLE, NULL, NULL, NULL);
890
891         return ret;
892 }
893
894 int
895 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
896                                 uint32_t flags)
897 {
898         int ret = 0;
899
900         ret = pdump_validate_flags(flags);
901         if (ret < 0)
902                 return ret;
903
904         ret = pdump_prepare_client_request(device_id, queue, flags,
905                                                 DISABLE, NULL, NULL, NULL);
906
907         return ret;
908 }
909
910 int
911 rte_pdump_set_socket_dir(const char *path, enum rte_pdump_socktype type)
912 {
913         int ret, count;
914
915         if (path != NULL) {
916                 if (type == RTE_PDUMP_SOCKET_SERVER) {
917                         count = sizeof(server_socket_dir);
918                         ret = snprintf(server_socket_dir, count, "%s", path);
919                 } else {
920                         count = sizeof(client_socket_dir);
921                         ret = snprintf(client_socket_dir, count, "%s", path);
922                 }
923
924                 if (ret < 0  || ret >= count) {
925                         RTE_LOG(ERR, PDUMP,
926                                         "Invalid socket path:%s:%d\n",
927                                         __func__, __LINE__);
928                         if (type == RTE_PDUMP_SOCKET_SERVER)
929                                 server_socket_dir[0] = 0;
930                         else
931                                 client_socket_dir[0] = 0;
932                         return -EINVAL;
933                 }
934         }
935
936         return 0;
937 }