1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016-2018 Intel Corporation 3 */ 4 5 #include <rte_memcpy.h> 6 #include <rte_mbuf.h> 7 #include <rte_ethdev.h> 8 #include <rte_lcore.h> 9 #include <rte_log.h> 10 #include <rte_errno.h> 11 #include <rte_string_fns.h> 12 13 #include "rte_pdump.h" 14 15 RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE); 16 17 /* Macro for printing using RTE_LOG */ 18 #define PDUMP_LOG(level, fmt, args...) \ 19 rte_log(RTE_LOG_ ## level, pdump_logtype, "%s(): " fmt, \ 20 __func__, ## args) 21 22 /* Used for the multi-process communication */ 23 #define PDUMP_MP "mp_pdump" 24 25 enum pdump_operation { 26 DISABLE = 1, 27 ENABLE = 2 28 }; 29 30 enum pdump_version { 31 V1 = 1 32 }; 33 34 struct pdump_request { 35 uint16_t ver; 36 uint16_t op; 37 uint32_t flags; 38 union pdump_data { 39 struct enable_v1 { 40 char device[RTE_DEV_NAME_MAX_LEN]; 41 uint16_t queue; 42 struct rte_ring *ring; 43 struct rte_mempool *mp; 44 void *filter; 45 } en_v1; 46 struct disable_v1 { 47 char device[RTE_DEV_NAME_MAX_LEN]; 48 uint16_t queue; 49 struct rte_ring *ring; 50 struct rte_mempool *mp; 51 void *filter; 52 } dis_v1; 53 } data; 54 }; 55 56 struct pdump_response { 57 uint16_t ver; 58 uint16_t res_op; 59 int32_t err_value; 60 }; 61 62 static struct pdump_rxtx_cbs { 63 struct rte_ring *ring; 64 struct rte_mempool *mp; 65 const struct rte_eth_rxtx_callback *cb; 66 void *filter; 67 } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT], 68 tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT]; 69 70 71 static inline void 72 pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) 73 { 74 unsigned int i; 75 int ring_enq; 76 uint16_t d_pkts = 0; 77 struct rte_mbuf *dup_bufs[nb_pkts]; 78 struct pdump_rxtx_cbs *cbs; 79 struct rte_ring *ring; 80 struct rte_mempool *mp; 81 struct rte_mbuf *p; 82 83 cbs = user_params; 84 ring = cbs->ring; 85 mp = cbs->mp; 86 for (i = 0; i < nb_pkts; i++) { 87 p = rte_pktmbuf_copy(pkts[i], mp, 0, UINT32_MAX); 88 if (p) 89 dup_bufs[d_pkts++] = p; 90 } 91 92 ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL); 93 if (unlikely(ring_enq < d_pkts)) { 94 unsigned int drops = d_pkts - ring_enq; 95 96 PDUMP_LOG(DEBUG, 97 "only %d of packets enqueued to ring\n", ring_enq); 98 rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops); 99 } 100 } 101 102 static uint16_t 103 pdump_rx(uint16_t port __rte_unused, uint16_t qidx __rte_unused, 104 struct rte_mbuf **pkts, uint16_t nb_pkts, 105 uint16_t max_pkts __rte_unused, 106 void *user_params) 107 { 108 pdump_copy(pkts, nb_pkts, user_params); 109 return nb_pkts; 110 } 111 112 static uint16_t 113 pdump_tx(uint16_t port __rte_unused, uint16_t qidx __rte_unused, 114 struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) 115 { 116 pdump_copy(pkts, nb_pkts, user_params); 117 return nb_pkts; 118 } 119 120 static int 121 pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, 122 struct rte_ring *ring, struct rte_mempool *mp, 123 uint16_t operation) 124 { 125 uint16_t qid; 126 struct pdump_rxtx_cbs *cbs = NULL; 127 128 qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue; 129 for (; qid < end_q; qid++) { 130 cbs = &rx_cbs[port][qid]; 131 if (cbs && operation == ENABLE) { 132 if (cbs->cb) { 133 PDUMP_LOG(ERR, 134 "rx callback for port=%d queue=%d, already exists\n", 135 port, qid); 136 return -EEXIST; 137 } 138 cbs->ring = ring; 139 cbs->mp = mp; 140 cbs->cb = rte_eth_add_first_rx_callback(port, qid, 141 pdump_rx, cbs); 142 if (cbs->cb == NULL) { 143 PDUMP_LOG(ERR, 144 "failed to add rx callback, errno=%d\n", 145 rte_errno); 146 return rte_errno; 147 } 148 } 149 if (cbs && operation == DISABLE) { 150 int ret; 151 152 if (cbs->cb == NULL) { 153 PDUMP_LOG(ERR, 154 "no existing rx callback for port=%d queue=%d\n", 155 port, qid); 156 return -EINVAL; 157 } 158 ret = rte_eth_remove_rx_callback(port, qid, cbs->cb); 159 if (ret < 0) { 160 PDUMP_LOG(ERR, 161 "failed to remove rx callback, errno=%d\n", 162 -ret); 163 return ret; 164 } 165 cbs->cb = NULL; 166 } 167 } 168 169 return 0; 170 } 171 172 static int 173 pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, 174 struct rte_ring *ring, struct rte_mempool *mp, 175 uint16_t operation) 176 { 177 178 uint16_t qid; 179 struct pdump_rxtx_cbs *cbs = NULL; 180 181 qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue; 182 for (; qid < end_q; qid++) { 183 cbs = &tx_cbs[port][qid]; 184 if (cbs && operation == ENABLE) { 185 if (cbs->cb) { 186 PDUMP_LOG(ERR, 187 "tx callback for port=%d queue=%d, already exists\n", 188 port, qid); 189 return -EEXIST; 190 } 191 cbs->ring = ring; 192 cbs->mp = mp; 193 cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx, 194 cbs); 195 if (cbs->cb == NULL) { 196 PDUMP_LOG(ERR, 197 "failed to add tx callback, errno=%d\n", 198 rte_errno); 199 return rte_errno; 200 } 201 } 202 if (cbs && operation == DISABLE) { 203 int ret; 204 205 if (cbs->cb == NULL) { 206 PDUMP_LOG(ERR, 207 "no existing tx callback for port=%d queue=%d\n", 208 port, qid); 209 return -EINVAL; 210 } 211 ret = rte_eth_remove_tx_callback(port, qid, cbs->cb); 212 if (ret < 0) { 213 PDUMP_LOG(ERR, 214 "failed to remove tx callback, errno=%d\n", 215 -ret); 216 return ret; 217 } 218 cbs->cb = NULL; 219 } 220 } 221 222 return 0; 223 } 224 225 static int 226 set_pdump_rxtx_cbs(const struct pdump_request *p) 227 { 228 uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue; 229 uint16_t port; 230 int ret = 0; 231 uint32_t flags; 232 uint16_t operation; 233 struct rte_ring *ring; 234 struct rte_mempool *mp; 235 236 flags = p->flags; 237 operation = p->op; 238 if (operation == ENABLE) { 239 ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device, 240 &port); 241 if (ret < 0) { 242 PDUMP_LOG(ERR, 243 "failed to get port id for device id=%s\n", 244 p->data.en_v1.device); 245 return -EINVAL; 246 } 247 queue = p->data.en_v1.queue; 248 ring = p->data.en_v1.ring; 249 mp = p->data.en_v1.mp; 250 } else { 251 ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device, 252 &port); 253 if (ret < 0) { 254 PDUMP_LOG(ERR, 255 "failed to get port id for device id=%s\n", 256 p->data.dis_v1.device); 257 return -EINVAL; 258 } 259 queue = p->data.dis_v1.queue; 260 ring = p->data.dis_v1.ring; 261 mp = p->data.dis_v1.mp; 262 } 263 264 /* validation if packet capture is for all queues */ 265 if (queue == RTE_PDUMP_ALL_QUEUES) { 266 struct rte_eth_dev_info dev_info; 267 268 ret = rte_eth_dev_info_get(port, &dev_info); 269 if (ret != 0) { 270 PDUMP_LOG(ERR, 271 "Error during getting device (port %u) info: %s\n", 272 port, strerror(-ret)); 273 return ret; 274 } 275 276 nb_rx_q = dev_info.nb_rx_queues; 277 nb_tx_q = dev_info.nb_tx_queues; 278 if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) { 279 PDUMP_LOG(ERR, 280 "number of rx queues cannot be 0\n"); 281 return -EINVAL; 282 } 283 if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) { 284 PDUMP_LOG(ERR, 285 "number of tx queues cannot be 0\n"); 286 return -EINVAL; 287 } 288 if ((nb_tx_q == 0 || nb_rx_q == 0) && 289 flags == RTE_PDUMP_FLAG_RXTX) { 290 PDUMP_LOG(ERR, 291 "both tx&rx queues must be non zero\n"); 292 return -EINVAL; 293 } 294 } 295 296 /* register RX callback */ 297 if (flags & RTE_PDUMP_FLAG_RX) { 298 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1; 299 ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp, 300 operation); 301 if (ret < 0) 302 return ret; 303 } 304 305 /* register TX callback */ 306 if (flags & RTE_PDUMP_FLAG_TX) { 307 end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1; 308 ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp, 309 operation); 310 if (ret < 0) 311 return ret; 312 } 313 314 return ret; 315 } 316 317 static int 318 pdump_server(const struct rte_mp_msg *mp_msg, const void *peer) 319 { 320 struct rte_mp_msg mp_resp; 321 const struct pdump_request *cli_req; 322 struct pdump_response *resp = (struct pdump_response *)&mp_resp.param; 323 324 /* recv client requests */ 325 if (mp_msg->len_param != sizeof(*cli_req)) { 326 PDUMP_LOG(ERR, "failed to recv from client\n"); 327 resp->err_value = -EINVAL; 328 } else { 329 cli_req = (const struct pdump_request *)mp_msg->param; 330 resp->ver = cli_req->ver; 331 resp->res_op = cli_req->op; 332 resp->err_value = set_pdump_rxtx_cbs(cli_req); 333 } 334 335 strlcpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN); 336 mp_resp.len_param = sizeof(*resp); 337 mp_resp.num_fds = 0; 338 if (rte_mp_reply(&mp_resp, peer) < 0) { 339 PDUMP_LOG(ERR, "failed to send to client:%s\n", 340 strerror(rte_errno)); 341 return -1; 342 } 343 344 return 0; 345 } 346 347 int 348 rte_pdump_init(void) 349 { 350 int ret; 351 352 ret = rte_mp_action_register(PDUMP_MP, pdump_server); 353 if (ret && rte_errno != ENOTSUP) 354 return -1; 355 return 0; 356 } 357 358 int 359 rte_pdump_uninit(void) 360 { 361 rte_mp_action_unregister(PDUMP_MP); 362 363 return 0; 364 } 365 366 static int 367 pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp) 368 { 369 if (ring == NULL || mp == NULL) { 370 PDUMP_LOG(ERR, "NULL ring or mempool\n"); 371 rte_errno = EINVAL; 372 return -1; 373 } 374 if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) { 375 PDUMP_LOG(ERR, 376 "mempool with SP or SC set not valid for pdump," 377 "must have MP and MC set\n"); 378 rte_errno = EINVAL; 379 return -1; 380 } 381 if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) { 382 PDUMP_LOG(ERR, 383 "ring with SP or SC set is not valid for pdump," 384 "must have MP and MC set\n"); 385 rte_errno = EINVAL; 386 return -1; 387 } 388 389 return 0; 390 } 391 392 static int 393 pdump_validate_flags(uint32_t flags) 394 { 395 if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX && 396 flags != RTE_PDUMP_FLAG_RXTX) { 397 PDUMP_LOG(ERR, 398 "invalid flags, should be either rx/tx/rxtx\n"); 399 rte_errno = EINVAL; 400 return -1; 401 } 402 403 return 0; 404 } 405 406 static int 407 pdump_validate_port(uint16_t port, char *name) 408 { 409 int ret = 0; 410 411 if (port >= RTE_MAX_ETHPORTS) { 412 PDUMP_LOG(ERR, "Invalid port id %u\n", port); 413 rte_errno = EINVAL; 414 return -1; 415 } 416 417 ret = rte_eth_dev_get_name_by_port(port, name); 418 if (ret < 0) { 419 PDUMP_LOG(ERR, "port %u to name mapping failed\n", 420 port); 421 rte_errno = EINVAL; 422 return -1; 423 } 424 425 return 0; 426 } 427 428 static int 429 pdump_prepare_client_request(char *device, uint16_t queue, 430 uint32_t flags, 431 uint16_t operation, 432 struct rte_ring *ring, 433 struct rte_mempool *mp, 434 void *filter) 435 { 436 int ret = -1; 437 struct rte_mp_msg mp_req, *mp_rep; 438 struct rte_mp_reply mp_reply; 439 struct timespec ts = {.tv_sec = 5, .tv_nsec = 0}; 440 struct pdump_request *req = (struct pdump_request *)mp_req.param; 441 struct pdump_response *resp; 442 443 req->ver = 1; 444 req->flags = flags; 445 req->op = operation; 446 if ((operation & ENABLE) != 0) { 447 strlcpy(req->data.en_v1.device, device, 448 sizeof(req->data.en_v1.device)); 449 req->data.en_v1.queue = queue; 450 req->data.en_v1.ring = ring; 451 req->data.en_v1.mp = mp; 452 req->data.en_v1.filter = filter; 453 } else { 454 strlcpy(req->data.dis_v1.device, device, 455 sizeof(req->data.dis_v1.device)); 456 req->data.dis_v1.queue = queue; 457 req->data.dis_v1.ring = NULL; 458 req->data.dis_v1.mp = NULL; 459 req->data.dis_v1.filter = NULL; 460 } 461 462 strlcpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN); 463 mp_req.len_param = sizeof(*req); 464 mp_req.num_fds = 0; 465 if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) { 466 mp_rep = &mp_reply.msgs[0]; 467 resp = (struct pdump_response *)mp_rep->param; 468 rte_errno = resp->err_value; 469 if (!resp->err_value) 470 ret = 0; 471 free(mp_reply.msgs); 472 } 473 474 if (ret < 0) 475 PDUMP_LOG(ERR, 476 "client request for pdump enable/disable failed\n"); 477 return ret; 478 } 479 480 int 481 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, 482 struct rte_ring *ring, 483 struct rte_mempool *mp, 484 void *filter) 485 { 486 int ret; 487 char name[RTE_DEV_NAME_MAX_LEN]; 488 489 ret = pdump_validate_port(port, name); 490 if (ret < 0) 491 return ret; 492 ret = pdump_validate_ring_mp(ring, mp); 493 if (ret < 0) 494 return ret; 495 ret = pdump_validate_flags(flags); 496 if (ret < 0) 497 return ret; 498 499 ret = pdump_prepare_client_request(name, queue, flags, 500 ENABLE, ring, mp, filter); 501 502 return ret; 503 } 504 505 int 506 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue, 507 uint32_t flags, 508 struct rte_ring *ring, 509 struct rte_mempool *mp, 510 void *filter) 511 { 512 int ret = 0; 513 514 ret = pdump_validate_ring_mp(ring, mp); 515 if (ret < 0) 516 return ret; 517 ret = pdump_validate_flags(flags); 518 if (ret < 0) 519 return ret; 520 521 ret = pdump_prepare_client_request(device_id, queue, flags, 522 ENABLE, ring, mp, filter); 523 524 return ret; 525 } 526 527 int 528 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags) 529 { 530 int ret = 0; 531 char name[RTE_DEV_NAME_MAX_LEN]; 532 533 ret = pdump_validate_port(port, name); 534 if (ret < 0) 535 return ret; 536 ret = pdump_validate_flags(flags); 537 if (ret < 0) 538 return ret; 539 540 ret = pdump_prepare_client_request(name, queue, flags, 541 DISABLE, NULL, NULL, NULL); 542 543 return ret; 544 } 545 546 int 547 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue, 548 uint32_t flags) 549 { 550 int ret = 0; 551 552 ret = pdump_validate_flags(flags); 553 if (ret < 0) 554 return ret; 555 556 ret = pdump_prepare_client_request(device_id, queue, flags, 557 DISABLE, NULL, NULL, NULL); 558 559 return ret; 560 } 561