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