70efd96b46889ae199101575fc0273aef314dd53
[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 #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
63 enum pdump_operation {
64         DISABLE = 1,
65         ENABLE = 2
66 };
67
68 enum pdump_version {
69         V1 = 1
70 };
71
72 static pthread_t pdump_thread;
73 static int pdump_socket_fd;
74 static char server_socket_dir[PATH_MAX];
75 static char client_socket_dir[PATH_MAX];
76
77 struct 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
99 struct pdump_response {
100         uint16_t ver;
101         uint16_t res_op;
102         int32_t err_value;
103 };
104
105 static 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],
111 tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
112
113 static inline int
114 pdump_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
138 static inline struct rte_mbuf *
139 pdump_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
179 static inline void
180 pdump_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
210 static uint16_t
211 pdump_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
220 static uint16_t
221 pdump_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
228 static int
229 pdump_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
251 static int
252 pdump_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
305 static int
306 pdump_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
360 static int
361 set_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) */
446 static void
447 pdump_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                         snprintf(dpdk_dir, sizeof(dpdk_dir), "%s%s",
461                                         dir_home, DPDK_DIR);
462                 } else
463                         snprintf(dpdk_dir, sizeof(dpdk_dir), "%s%s",
464                                         SOCKET_PATH_VAR_RUN, DPDK_DIR);
465
466                 mkdir(dpdk_dir, 700);
467                 snprintf(dir, sizeof(dir), "%s%s",
468                                         dpdk_dir, SOCKET_DIR);
469         }
470
471         mkdir(dir, 700);
472         if (type == RTE_PDUMP_SOCKET_SERVER)
473                 snprintf(buffer, bufsz, SERVER_SOCKET, dir);
474         else
475                 snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
476                                 rte_sys_gettid());
477 }
478
479 static int
480 pdump_create_server_socket(void)
481 {
482         int ret, socket_fd;
483         struct sockaddr_un addr;
484         socklen_t addr_len;
485
486         pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
487                                 RTE_PDUMP_SOCKET_SERVER);
488         addr.sun_family = AF_UNIX;
489
490         /* remove if file already exists */
491         unlink(addr.sun_path);
492
493         /* set up a server socket */
494         socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
495         if (socket_fd < 0) {
496                 RTE_LOG(ERR, PDUMP,
497                         "Failed to create server socket: %s, %s:%d\n",
498                         strerror(errno), __func__, __LINE__);
499                 return -1;
500         }
501
502         addr_len = sizeof(struct sockaddr_un);
503         ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
504         if (ret) {
505                 RTE_LOG(ERR, PDUMP,
506                         "Failed to bind to server socket: %s, %s:%d\n",
507                         strerror(errno), __func__, __LINE__);
508                 close(socket_fd);
509                 return -1;
510         }
511
512         /* save the socket in local configuration */
513         pdump_socket_fd = socket_fd;
514
515         return 0;
516 }
517
518 static __attribute__((noreturn)) void *
519 pdump_thread_main(__rte_unused void *arg)
520 {
521         struct sockaddr_un cli_addr;
522         socklen_t cli_len;
523         struct pdump_request cli_req;
524         struct pdump_response resp;
525         int n;
526         int ret = 0;
527
528         /* host thread, never break out */
529         for (;;) {
530                 /* recv client requests */
531                 cli_len = sizeof(cli_addr);
532                 n = recvfrom(pdump_socket_fd, &cli_req,
533                                 sizeof(struct pdump_request), 0,
534                                 (struct sockaddr *)&cli_addr, &cli_len);
535                 if (n < 0) {
536                         RTE_LOG(ERR, PDUMP,
537                                 "failed to recv from client:%s, %s:%d\n",
538                                 strerror(errno), __func__, __LINE__);
539                         continue;
540                 }
541
542                 ret = set_pdump_rxtx_cbs(&cli_req);
543
544                 resp.ver = cli_req.ver;
545                 resp.res_op = cli_req.op;
546                 resp.err_value = ret;
547                 n = sendto(pdump_socket_fd, &resp,
548                                 sizeof(struct pdump_response),
549                                 0, (struct sockaddr *)&cli_addr, cli_len);
550                 if (n < 0) {
551                         RTE_LOG(ERR, PDUMP,
552                                 "failed to send to client:%s, %s:%d\n",
553                                 strerror(errno), __func__, __LINE__);
554                 }
555         }
556 }
557
558 int
559 rte_pdump_init(const char *path)
560 {
561         int ret = 0;
562         char thread_name[RTE_MAX_THREAD_NAME_LEN];
563
564         ret = rte_pdump_set_socket_dir(path, RTE_PDUMP_SOCKET_SERVER);
565         if (ret != 0)
566                 return -1;
567
568         ret = pdump_create_server_socket();
569         if (ret != 0) {
570                 RTE_LOG(ERR, PDUMP,
571                         "Failed to create server socket:%s:%d\n",
572                         __func__, __LINE__);
573                 return -1;
574         }
575
576         /* create the host thread to wait/handle pdump requests */
577         ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
578         if (ret != 0) {
579                 RTE_LOG(ERR, PDUMP,
580                         "Failed to create the pdump thread:%s, %s:%d\n",
581                         strerror(errno), __func__, __LINE__);
582                 return -1;
583         }
584         /* Set thread_name for aid in debugging. */
585         snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
586         ret = rte_thread_setname(pdump_thread, thread_name);
587         if (ret != 0) {
588                 RTE_LOG(DEBUG, PDUMP,
589                         "Failed to set thread name for pdump handling\n");
590         }
591
592         return 0;
593 }
594
595 int
596 rte_pdump_uninit(void)
597 {
598         int ret;
599
600         ret = pthread_cancel(pdump_thread);
601         if (ret != 0) {
602                 RTE_LOG(ERR, PDUMP,
603                         "Failed to cancel the pdump thread:%s, %s:%d\n",
604                         strerror(errno), __func__, __LINE__);
605                 return -1;
606         }
607
608         ret = close(pdump_socket_fd);
609         if (ret != 0) {
610                 RTE_LOG(ERR, PDUMP,
611                         "Failed to close server socket: %s, %s:%d\n",
612                         strerror(errno), __func__, __LINE__);
613                 return -1;
614         }
615
616         struct sockaddr_un addr;
617
618         pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
619                                 RTE_PDUMP_SOCKET_SERVER);
620         ret = unlink(addr.sun_path);
621         if (ret != 0) {
622                 RTE_LOG(ERR, PDUMP,
623                         "Failed to remove server socket addr: %s, %s:%d\n",
624                         strerror(errno), __func__, __LINE__);
625                 return -1;
626         }
627
628         return 0;
629 }
630
631 static int
632 pdump_create_client_socket(struct pdump_request *p)
633 {
634         int ret, socket_fd;
635         int pid;
636         int n;
637         struct pdump_response server_resp;
638         struct sockaddr_un addr, serv_addr, from;
639         socklen_t addr_len, serv_len;
640
641         pid = getpid();
642
643         socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
644         if (socket_fd < 0) {
645                 RTE_LOG(ERR, PDUMP,
646                         "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
647                         strerror(errno), pid, rte_sys_gettid(),
648                         __func__, __LINE__);
649                 ret = errno;
650                 return ret;
651         }
652
653         pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path),
654                                 RTE_PDUMP_SOCKET_CLIENT);
655         addr.sun_family = AF_UNIX;
656         addr_len = sizeof(struct sockaddr_un);
657
658         do {
659                 ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
660                 if (ret) {
661                         RTE_LOG(ERR, PDUMP,
662                                 "client bind(): %s, %s:%d\n",
663                                 strerror(errno), __func__, __LINE__);
664                         ret = errno;
665                         break;
666                 }
667
668                 serv_len = sizeof(struct sockaddr_un);
669                 memset(&serv_addr, 0, sizeof(serv_addr));
670                 pdump_get_socket_path(serv_addr.sun_path,
671                                         sizeof(serv_addr.sun_path),
672                                         RTE_PDUMP_SOCKET_SERVER);
673                 serv_addr.sun_family = AF_UNIX;
674
675                 n =  sendto(socket_fd, p, sizeof(struct pdump_request), 0,
676                                 (struct sockaddr *)&serv_addr, serv_len);
677                 if (n < 0) {
678                         RTE_LOG(ERR, PDUMP,
679                                 "failed to send to server:%s, %s:%d\n",
680                                 strerror(errno), __func__, __LINE__);
681                         ret =  errno;
682                         break;
683                 }
684
685                 n = recvfrom(socket_fd, &server_resp,
686                                 sizeof(struct pdump_response), 0,
687                                 (struct sockaddr *)&from, &serv_len);
688                 if (n < 0) {
689                         RTE_LOG(ERR, PDUMP,
690                                 "failed to recv from server:%s, %s:%d\n",
691                                 strerror(errno), __func__, __LINE__);
692                         ret = errno;
693                         break;
694                 }
695                 ret = server_resp.err_value;
696         } while (0);
697
698         close(socket_fd);
699         unlink(addr.sun_path);
700         return ret;
701 }
702
703 static int
704 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
705 {
706         if (ring == NULL || mp == NULL) {
707                 RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
708                         __func__, __LINE__);
709                 rte_errno = EINVAL;
710                 return -1;
711         }
712         if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
713                 RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
714                 " is not valid for pdump, should have MP and MC settings\n");
715                 rte_errno = EINVAL;
716                 return -1;
717         }
718         if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
719                 RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
720                 " is not valid for pdump, should have MP and MC settings\n");
721                 rte_errno = EINVAL;
722                 return -1;
723         }
724
725         return 0;
726 }
727
728 static int
729 pdump_validate_flags(uint32_t flags)
730 {
731         if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
732                 flags != RTE_PDUMP_FLAG_RXTX) {
733                 RTE_LOG(ERR, PDUMP,
734                         "invalid flags, should be either rx/tx/rxtx\n");
735                 rte_errno = EINVAL;
736                 return -1;
737         }
738
739         return 0;
740 }
741
742 static int
743 pdump_validate_port(uint8_t port, char *name)
744 {
745         int ret = 0;
746
747         if (port >= RTE_MAX_ETHPORTS) {
748                 RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
749                         __func__, __LINE__);
750                 rte_errno = EINVAL;
751                 return -1;
752         }
753
754         ret = rte_eth_dev_get_name_by_port(port, name);
755         if (ret < 0) {
756                 RTE_LOG(ERR, PDUMP,
757                         "port id to name mapping failed for port id=%u, %s:%d\n",
758                         port, __func__, __LINE__);
759                 rte_errno = EINVAL;
760                 return -1;
761         }
762
763         return 0;
764 }
765
766 static int
767 pdump_prepare_client_request(char *device, uint16_t queue,
768                                 uint32_t flags,
769                                 uint16_t operation,
770                                 struct rte_ring *ring,
771                                 struct rte_mempool *mp,
772                                 void *filter)
773 {
774         int ret;
775         struct pdump_request req = {.ver = 1,};
776
777         req.flags = flags;
778         req.op =  operation;
779         if ((operation & ENABLE) != 0) {
780                 strncpy(req.data.en_v1.device, device, strlen(device));
781                 req.data.en_v1.queue = queue;
782                 req.data.en_v1.ring = ring;
783                 req.data.en_v1.mp = mp;
784                 req.data.en_v1.filter = filter;
785         } else {
786                 strncpy(req.data.dis_v1.device, device, strlen(device));
787                 req.data.dis_v1.queue = queue;
788                 req.data.dis_v1.ring = NULL;
789                 req.data.dis_v1.mp = NULL;
790                 req.data.dis_v1.filter = NULL;
791         }
792
793         ret = pdump_create_client_socket(&req);
794         if (ret < 0) {
795                 RTE_LOG(ERR, PDUMP,
796                         "client request for pdump enable/disable failed\n");
797                 rte_errno = ret;
798                 return -1;
799         }
800
801         return 0;
802 }
803
804 int
805 rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
806                         struct rte_ring *ring,
807                         struct rte_mempool *mp,
808                         void *filter)
809 {
810
811         int ret = 0;
812         char name[DEVICE_ID_SIZE];
813
814         ret = pdump_validate_port(port, name);
815         if (ret < 0)
816                 return ret;
817         ret = pdump_validate_ring_mp(ring, mp);
818         if (ret < 0)
819                 return ret;
820         ret = pdump_validate_flags(flags);
821         if (ret < 0)
822                 return ret;
823
824         ret = pdump_prepare_client_request(name, queue, flags,
825                                                 ENABLE, ring, mp, filter);
826
827         return ret;
828 }
829
830 int
831 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
832                                 uint32_t flags,
833                                 struct rte_ring *ring,
834                                 struct rte_mempool *mp,
835                                 void *filter)
836 {
837         int ret = 0;
838         char domBDF[DEVICE_ID_SIZE];
839
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         if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
848                 ret = pdump_prepare_client_request(domBDF, queue, flags,
849                                                 ENABLE, ring, mp, filter);
850         else
851                 ret = pdump_prepare_client_request(device_id, queue, flags,
852                                                 ENABLE, ring, mp, filter);
853
854         return ret;
855 }
856
857 int
858 rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
859 {
860         int ret = 0;
861         char name[DEVICE_ID_SIZE];
862
863         ret = pdump_validate_port(port, name);
864         if (ret < 0)
865                 return ret;
866         ret = pdump_validate_flags(flags);
867         if (ret < 0)
868                 return ret;
869
870         ret = pdump_prepare_client_request(name, queue, flags,
871                                                 DISABLE, NULL, NULL, NULL);
872
873         return ret;
874 }
875
876 int
877 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
878                                 uint32_t flags)
879 {
880         int ret = 0;
881         char domBDF[DEVICE_ID_SIZE];
882
883         ret = pdump_validate_flags(flags);
884         if (ret < 0)
885                 return ret;
886
887         if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
888                 ret = pdump_prepare_client_request(domBDF, queue, flags,
889                                                 DISABLE, NULL, NULL, NULL);
890         else
891                 ret = pdump_prepare_client_request(device_id, queue, flags,
892                                                 DISABLE, NULL, NULL, NULL);
893
894         return ret;
895 }
896
897 int
898 rte_pdump_set_socket_dir(const char *path, enum rte_pdump_socktype type)
899 {
900         int ret, count;
901
902         if (path != NULL) {
903                 if (type == RTE_PDUMP_SOCKET_SERVER) {
904                         count = sizeof(server_socket_dir);
905                         ret = snprintf(server_socket_dir, count, "%s", path);
906                 } else {
907                         count = sizeof(client_socket_dir);
908                         ret = snprintf(client_socket_dir, count, "%s", path);
909                 }
910
911                 if (ret < 0  || ret >= count) {
912                         RTE_LOG(ERR, PDUMP,
913                                         "Invalid socket path:%s:%d\n",
914                                         __func__, __LINE__);
915                         if (type == RTE_PDUMP_SOCKET_SERVER)
916                                 server_socket_dir[0] = 0;
917                         else
918                                 client_socket_dir[0] = 0;
919                         return -EINVAL;
920                 }
921         }
922
923         return 0;
924 }