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