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 & RTE_MEMPOOL_F_SP_PUT || 375 mp->flags & RTE_MEMPOOL_F_SC_GET) { 376 PDUMP_LOG(ERR, 377 "mempool with SP or SC set not valid for pdump," 378 "must have MP and MC set\n"); 379 rte_errno = EINVAL; 380 return -1; 381 } 382 if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) { 383 PDUMP_LOG(ERR, 384 "ring with SP or SC set is not valid for pdump," 385 "must have MP and MC set\n"); 386 rte_errno = EINVAL; 387 return -1; 388 } 389 390 return 0; 391 } 392 393 static int 394 pdump_validate_flags(uint32_t flags) 395 { 396 if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX && 397 flags != RTE_PDUMP_FLAG_RXTX) { 398 PDUMP_LOG(ERR, 399 "invalid flags, should be either rx/tx/rxtx\n"); 400 rte_errno = EINVAL; 401 return -1; 402 } 403 404 return 0; 405 } 406 407 static int 408 pdump_validate_port(uint16_t port, char *name) 409 { 410 int ret = 0; 411 412 if (port >= RTE_MAX_ETHPORTS) { 413 PDUMP_LOG(ERR, "Invalid port id %u\n", port); 414 rte_errno = EINVAL; 415 return -1; 416 } 417 418 ret = rte_eth_dev_get_name_by_port(port, name); 419 if (ret < 0) { 420 PDUMP_LOG(ERR, "port %u to name mapping failed\n", 421 port); 422 rte_errno = EINVAL; 423 return -1; 424 } 425 426 return 0; 427 } 428 429 static int 430 pdump_prepare_client_request(char *device, uint16_t queue, 431 uint32_t flags, 432 uint16_t operation, 433 struct rte_ring *ring, 434 struct rte_mempool *mp, 435 void *filter) 436 { 437 int ret = -1; 438 struct rte_mp_msg mp_req, *mp_rep; 439 struct rte_mp_reply mp_reply; 440 struct timespec ts = {.tv_sec = 5, .tv_nsec = 0}; 441 struct pdump_request *req = (struct pdump_request *)mp_req.param; 442 struct pdump_response *resp; 443 444 req->ver = 1; 445 req->flags = flags; 446 req->op = operation; 447 if ((operation & ENABLE) != 0) { 448 strlcpy(req->data.en_v1.device, device, 449 sizeof(req->data.en_v1.device)); 450 req->data.en_v1.queue = queue; 451 req->data.en_v1.ring = ring; 452 req->data.en_v1.mp = mp; 453 req->data.en_v1.filter = filter; 454 } else { 455 strlcpy(req->data.dis_v1.device, device, 456 sizeof(req->data.dis_v1.device)); 457 req->data.dis_v1.queue = queue; 458 req->data.dis_v1.ring = NULL; 459 req->data.dis_v1.mp = NULL; 460 req->data.dis_v1.filter = NULL; 461 } 462 463 strlcpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN); 464 mp_req.len_param = sizeof(*req); 465 mp_req.num_fds = 0; 466 if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) { 467 mp_rep = &mp_reply.msgs[0]; 468 resp = (struct pdump_response *)mp_rep->param; 469 rte_errno = resp->err_value; 470 if (!resp->err_value) 471 ret = 0; 472 free(mp_reply.msgs); 473 } 474 475 if (ret < 0) 476 PDUMP_LOG(ERR, 477 "client request for pdump enable/disable failed\n"); 478 return ret; 479 } 480 481 int 482 rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, 483 struct rte_ring *ring, 484 struct rte_mempool *mp, 485 void *filter) 486 { 487 int ret; 488 char name[RTE_DEV_NAME_MAX_LEN]; 489 490 ret = pdump_validate_port(port, name); 491 if (ret < 0) 492 return ret; 493 ret = pdump_validate_ring_mp(ring, mp); 494 if (ret < 0) 495 return ret; 496 ret = pdump_validate_flags(flags); 497 if (ret < 0) 498 return ret; 499 500 ret = pdump_prepare_client_request(name, queue, flags, 501 ENABLE, ring, mp, filter); 502 503 return ret; 504 } 505 506 int 507 rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue, 508 uint32_t flags, 509 struct rte_ring *ring, 510 struct rte_mempool *mp, 511 void *filter) 512 { 513 int ret = 0; 514 515 ret = pdump_validate_ring_mp(ring, mp); 516 if (ret < 0) 517 return ret; 518 ret = pdump_validate_flags(flags); 519 if (ret < 0) 520 return ret; 521 522 ret = pdump_prepare_client_request(device_id, queue, flags, 523 ENABLE, ring, mp, filter); 524 525 return ret; 526 } 527 528 int 529 rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags) 530 { 531 int ret = 0; 532 char name[RTE_DEV_NAME_MAX_LEN]; 533 534 ret = pdump_validate_port(port, name); 535 if (ret < 0) 536 return ret; 537 ret = pdump_validate_flags(flags); 538 if (ret < 0) 539 return ret; 540 541 ret = pdump_prepare_client_request(name, queue, flags, 542 DISABLE, NULL, NULL, NULL); 543 544 return ret; 545 } 546 547 int 548 rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue, 549 uint32_t flags) 550 { 551 int ret = 0; 552 553 ret = pdump_validate_flags(flags); 554 if (ret < 0) 555 return ret; 556 557 ret = pdump_prepare_client_request(device_id, queue, flags, 558 DISABLE, NULL, NULL, NULL); 559 560 return ret; 561 } 562