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