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