1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 */ 4 #include <stdint.h> 5 #include <string.h> 6 7 #include <rte_mbuf.h> 8 #include <rte_mempool.h> 9 #include <rte_malloc.h> 10 #include <rte_memcpy.h> 11 12 #ifdef RTE_PORT_PCAP 13 #include <rte_ether.h> 14 #include <pcap.h> 15 #endif 16 17 #include "rte_port_source_sink.h" 18 19 /* 20 * Port SOURCE 21 */ 22 #ifdef RTE_PORT_STATS_COLLECT 23 24 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) \ 25 port->stats.n_pkts_in += val 26 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) \ 27 port->stats.n_pkts_drop += val 28 29 #else 30 31 #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) 32 #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) 33 34 #endif 35 36 struct rte_port_source { 37 struct rte_port_in_stats stats; 38 39 struct rte_mempool *mempool; 40 41 /* PCAP buffers and indices */ 42 uint8_t **pkts; 43 uint8_t *pkt_buff; 44 uint32_t *pkt_len; 45 uint32_t n_pkts; 46 uint32_t pkt_index; 47 }; 48 49 #ifdef RTE_PORT_PCAP 50 51 static int 52 pcap_source_load(struct rte_port_source *port, 53 const char *file_name, 54 uint32_t n_bytes_per_pkt, 55 int socket_id) 56 { 57 uint32_t n_pkts = 0; 58 uint32_t i; 59 uint32_t *pkt_len_aligns = NULL; 60 size_t total_buff_len = 0; 61 pcap_t *pcap_handle; 62 char pcap_errbuf[PCAP_ERRBUF_SIZE]; 63 uint32_t max_len; 64 struct pcap_pkthdr pcap_hdr; 65 const uint8_t *pkt; 66 uint8_t *buff = NULL; 67 uint32_t pktmbuf_maxlen = (uint32_t) 68 (rte_pktmbuf_data_room_size(port->mempool) - 69 RTE_PKTMBUF_HEADROOM); 70 71 if (n_bytes_per_pkt == 0) 72 max_len = pktmbuf_maxlen; 73 else 74 max_len = RTE_MIN(n_bytes_per_pkt, pktmbuf_maxlen); 75 76 /* first time open, get packet number */ 77 pcap_handle = pcap_open_offline(file_name, pcap_errbuf); 78 if (pcap_handle == NULL) { 79 RTE_LOG(ERR, PORT, "Failed to open pcap file " 80 "'%s' for reading\n", file_name); 81 goto error_exit; 82 } 83 84 while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL) 85 n_pkts++; 86 87 pcap_close(pcap_handle); 88 89 port->pkt_len = rte_zmalloc_socket("PCAP", 90 (sizeof(*port->pkt_len) * n_pkts), 0, socket_id); 91 if (port->pkt_len == NULL) { 92 RTE_LOG(ERR, PORT, "No enough memory\n"); 93 goto error_exit; 94 } 95 96 pkt_len_aligns = rte_malloc("PCAP", 97 (sizeof(*pkt_len_aligns) * n_pkts), 0); 98 if (pkt_len_aligns == NULL) { 99 RTE_LOG(ERR, PORT, "No enough memory\n"); 100 goto error_exit; 101 } 102 103 port->pkts = rte_zmalloc_socket("PCAP", 104 (sizeof(*port->pkts) * n_pkts), 0, socket_id); 105 if (port->pkts == NULL) { 106 RTE_LOG(ERR, PORT, "No enough memory\n"); 107 goto error_exit; 108 } 109 110 /* open 2nd time, get pkt_len */ 111 pcap_handle = pcap_open_offline(file_name, pcap_errbuf); 112 if (pcap_handle == NULL) { 113 RTE_LOG(ERR, PORT, "Failed to open pcap file " 114 "'%s' for reading\n", file_name); 115 goto error_exit; 116 } 117 118 for (i = 0; i < n_pkts; i++) { 119 pcap_next(pcap_handle, &pcap_hdr); 120 port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len); 121 pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP( 122 port->pkt_len[i]); 123 total_buff_len += pkt_len_aligns[i]; 124 } 125 126 pcap_close(pcap_handle); 127 128 /* allocate a big trunk of data for pcap file load */ 129 buff = rte_zmalloc_socket("PCAP", 130 total_buff_len, 0, socket_id); 131 if (buff == NULL) { 132 RTE_LOG(ERR, PORT, "No enough memory\n"); 133 goto error_exit; 134 } 135 136 port->pkt_buff = buff; 137 138 /* open file one last time to copy the pkt content */ 139 pcap_handle = pcap_open_offline(file_name, pcap_errbuf); 140 if (pcap_handle == NULL) { 141 RTE_LOG(ERR, PORT, "Failed to open pcap file " 142 "'%s' for reading\n", file_name); 143 goto error_exit; 144 } 145 146 for (i = 0; i < n_pkts; i++) { 147 pkt = pcap_next(pcap_handle, &pcap_hdr); 148 rte_memcpy(buff, pkt, port->pkt_len[i]); 149 port->pkts[i] = buff; 150 buff += pkt_len_aligns[i]; 151 } 152 153 pcap_close(pcap_handle); 154 155 port->n_pkts = n_pkts; 156 157 rte_free(pkt_len_aligns); 158 159 RTE_LOG(INFO, PORT, "Successfully load pcap file " 160 "'%s' with %u pkts\n", 161 file_name, port->n_pkts); 162 163 return 0; 164 165 error_exit: 166 if (pkt_len_aligns) 167 rte_free(pkt_len_aligns); 168 if (port->pkt_len) 169 rte_free(port->pkt_len); 170 if (port->pkts) 171 rte_free(port->pkts); 172 if (port->pkt_buff) 173 rte_free(port->pkt_buff); 174 175 return -1; 176 } 177 178 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \ 179 pcap_source_load(port, file_name, n_bytes, socket_id) 180 181 #else /* RTE_PORT_PCAP */ 182 183 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \ 184 ({ \ 185 int _ret = 0; \ 186 \ 187 if (file_name) { \ 188 RTE_LOG(ERR, PORT, "Source port field " \ 189 "\"file_name\" is not NULL.\n"); \ 190 _ret = -1; \ 191 } \ 192 \ 193 _ret; \ 194 }) 195 196 #endif /* RTE_PORT_PCAP */ 197 198 static void * 199 rte_port_source_create(void *params, int socket_id) 200 { 201 struct rte_port_source_params *p = 202 params; 203 struct rte_port_source *port; 204 205 /* Check input arguments*/ 206 if ((p == NULL) || (p->mempool == NULL)) { 207 RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__); 208 return NULL; 209 } 210 211 /* Memory allocation */ 212 port = rte_zmalloc_socket("PORT", sizeof(*port), 213 RTE_CACHE_LINE_SIZE, socket_id); 214 if (port == NULL) { 215 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__); 216 return NULL; 217 } 218 219 /* Initialization */ 220 port->mempool = (struct rte_mempool *) p->mempool; 221 222 if (p->file_name) { 223 int status = PCAP_SOURCE_LOAD(port, p->file_name, 224 p->n_bytes_per_pkt, socket_id); 225 226 if (status < 0) { 227 rte_free(port); 228 port = NULL; 229 } 230 } 231 232 return port; 233 } 234 235 static int 236 rte_port_source_free(void *port) 237 { 238 struct rte_port_source *p = 239 port; 240 241 /* Check input parameters */ 242 if (p == NULL) 243 return 0; 244 245 if (p->pkt_len) 246 rte_free(p->pkt_len); 247 if (p->pkts) 248 rte_free(p->pkts); 249 if (p->pkt_buff) 250 rte_free(p->pkt_buff); 251 252 rte_free(p); 253 254 return 0; 255 } 256 257 static int 258 rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts) 259 { 260 struct rte_port_source *p = port; 261 uint32_t i; 262 263 if (rte_pktmbuf_alloc_bulk(p->mempool, pkts, n_pkts) != 0) 264 return 0; 265 266 if (p->pkt_buff != NULL) { 267 for (i = 0; i < n_pkts; i++) { 268 uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i], 269 uint8_t *); 270 271 rte_memcpy(pkt_data, p->pkts[p->pkt_index], 272 p->pkt_len[p->pkt_index]); 273 pkts[i]->data_len = p->pkt_len[p->pkt_index]; 274 pkts[i]->pkt_len = pkts[i]->data_len; 275 276 p->pkt_index++; 277 if (p->pkt_index >= p->n_pkts) 278 p->pkt_index = 0; 279 } 280 } 281 282 RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts); 283 284 return n_pkts; 285 } 286 287 static int 288 rte_port_source_stats_read(void *port, 289 struct rte_port_in_stats *stats, int clear) 290 { 291 struct rte_port_source *p = 292 port; 293 294 if (stats != NULL) 295 memcpy(stats, &p->stats, sizeof(p->stats)); 296 297 if (clear) 298 memset(&p->stats, 0, sizeof(p->stats)); 299 300 return 0; 301 } 302 303 /* 304 * Port SINK 305 */ 306 #ifdef RTE_PORT_STATS_COLLECT 307 308 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \ 309 (port->stats.n_pkts_in += val) 310 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \ 311 (port->stats.n_pkts_drop += val) 312 313 #else 314 315 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) 316 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) 317 318 #endif 319 320 struct rte_port_sink { 321 struct rte_port_out_stats stats; 322 323 /* PCAP dumper handle and pkts number */ 324 void *dumper; 325 uint32_t max_pkts; 326 uint32_t pkt_index; 327 uint32_t dump_finish; 328 }; 329 330 #ifdef RTE_PORT_PCAP 331 332 static int 333 pcap_sink_open(struct rte_port_sink *port, 334 const char *file_name, 335 uint32_t max_n_pkts) 336 { 337 pcap_t *tx_pcap; 338 pcap_dumper_t *pcap_dumper; 339 340 /** Open a dead pcap handler for opening dumper file */ 341 tx_pcap = pcap_open_dead(DLT_EN10MB, 65535); 342 if (tx_pcap == NULL) { 343 RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n"); 344 return -1; 345 } 346 347 /* The dumper is created using the previous pcap_t reference */ 348 pcap_dumper = pcap_dump_open(tx_pcap, file_name); 349 if (pcap_dumper == NULL) { 350 RTE_LOG(ERR, PORT, "Failed to open pcap file " 351 "\"%s\" for writing\n", file_name); 352 return -1; 353 } 354 355 port->dumper = pcap_dumper; 356 port->max_pkts = max_n_pkts; 357 port->pkt_index = 0; 358 port->dump_finish = 0; 359 360 RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n", 361 file_name); 362 363 return 0; 364 } 365 366 static void 367 pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf) 368 { 369 uint8_t *pcap_dumper = (port->dumper); 370 struct pcap_pkthdr pcap_hdr; 371 uint8_t jumbo_pkt_buf[RTE_ETHER_MAX_JUMBO_FRAME_LEN]; 372 uint8_t *pkt; 373 374 /* Maximum num packets already reached */ 375 if (port->dump_finish) 376 return; 377 378 pkt = rte_pktmbuf_mtod(mbuf, uint8_t *); 379 380 pcap_hdr.len = mbuf->pkt_len; 381 pcap_hdr.caplen = pcap_hdr.len; 382 gettimeofday(&(pcap_hdr.ts), NULL); 383 384 if (mbuf->nb_segs > 1) { 385 struct rte_mbuf *jumbo_mbuf; 386 uint32_t pkt_index = 0; 387 388 /* if packet size longer than RTE_ETHER_MAX_JUMBO_FRAME_LEN, 389 * ignore it. 390 */ 391 if (mbuf->pkt_len > RTE_ETHER_MAX_JUMBO_FRAME_LEN) 392 return; 393 394 for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL; 395 jumbo_mbuf = jumbo_mbuf->next) { 396 rte_memcpy(&jumbo_pkt_buf[pkt_index], 397 rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *), 398 jumbo_mbuf->data_len); 399 pkt_index += jumbo_mbuf->data_len; 400 } 401 402 jumbo_pkt_buf[pkt_index] = '\0'; 403 404 pkt = jumbo_pkt_buf; 405 } 406 407 pcap_dump(pcap_dumper, &pcap_hdr, pkt); 408 409 port->pkt_index++; 410 411 if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) { 412 port->dump_finish = 1; 413 RTE_LOG(INFO, PORT, "Dumped %u packets to file\n", 414 port->pkt_index); 415 } 416 417 } 418 419 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts) \ 420 pcap_sink_open(port, file_name, max_n_pkts) 421 422 #define PCAP_SINK_WRITE_PKT(port, mbuf) \ 423 pcap_sink_write_pkt(port, mbuf) 424 425 #define PCAP_SINK_FLUSH_PKT(dumper) \ 426 do { \ 427 if (dumper) \ 428 pcap_dump_flush((pcap_dumper_t *)dumper); \ 429 } while (0) 430 431 #define PCAP_SINK_CLOSE(dumper) \ 432 do { \ 433 if (dumper) \ 434 pcap_dump_close((pcap_dumper_t *)dumper); \ 435 } while (0) 436 437 #else 438 439 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts) \ 440 ({ \ 441 int _ret = 0; \ 442 \ 443 if (file_name) { \ 444 RTE_LOG(ERR, PORT, "Sink port field " \ 445 "\"file_name\" is not NULL.\n"); \ 446 _ret = -1; \ 447 } \ 448 \ 449 _ret; \ 450 }) 451 452 #define PCAP_SINK_WRITE_PKT(port, mbuf) {} 453 454 #define PCAP_SINK_FLUSH_PKT(dumper) 455 456 #define PCAP_SINK_CLOSE(dumper) 457 458 #endif 459 460 static void * 461 rte_port_sink_create(void *params, int socket_id) 462 { 463 struct rte_port_sink *port; 464 struct rte_port_sink_params *p = params; 465 466 /* Memory allocation */ 467 port = rte_zmalloc_socket("PORT", sizeof(*port), 468 RTE_CACHE_LINE_SIZE, socket_id); 469 if (port == NULL) { 470 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__); 471 return NULL; 472 } 473 474 if (!p) 475 return port; 476 477 if (p->file_name) { 478 int status = PCAP_SINK_OPEN(port, p->file_name, 479 p->max_n_pkts); 480 481 if (status < 0) { 482 rte_free(port); 483 port = NULL; 484 } 485 } 486 487 return port; 488 } 489 490 static int 491 rte_port_sink_tx(void *port, struct rte_mbuf *pkt) 492 { 493 struct rte_port_sink *p = port; 494 495 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1); 496 if (p->dumper != NULL) 497 PCAP_SINK_WRITE_PKT(p, pkt); 498 rte_pktmbuf_free(pkt); 499 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1); 500 501 return 0; 502 } 503 504 static int 505 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts, 506 uint64_t pkts_mask) 507 { 508 struct rte_port_sink *p = port; 509 510 if ((pkts_mask & (pkts_mask + 1)) == 0) { 511 uint64_t n_pkts = __builtin_popcountll(pkts_mask); 512 uint32_t i; 513 514 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts); 515 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts); 516 517 if (p->dumper) { 518 for (i = 0; i < n_pkts; i++) 519 PCAP_SINK_WRITE_PKT(p, pkts[i]); 520 } 521 522 for (i = 0; i < n_pkts; i++) { 523 struct rte_mbuf *pkt = pkts[i]; 524 525 rte_pktmbuf_free(pkt); 526 } 527 528 } else { 529 if (p->dumper) { 530 uint64_t dump_pkts_mask = pkts_mask; 531 uint32_t pkt_index; 532 533 for ( ; dump_pkts_mask; ) { 534 pkt_index = __builtin_ctzll( 535 dump_pkts_mask); 536 PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]); 537 dump_pkts_mask &= ~(1LLU << pkt_index); 538 } 539 } 540 541 for ( ; pkts_mask; ) { 542 uint32_t pkt_index = __builtin_ctzll(pkts_mask); 543 uint64_t pkt_mask = 1LLU << pkt_index; 544 struct rte_mbuf *pkt = pkts[pkt_index]; 545 546 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1); 547 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1); 548 rte_pktmbuf_free(pkt); 549 pkts_mask &= ~pkt_mask; 550 } 551 } 552 553 return 0; 554 } 555 556 static int 557 rte_port_sink_flush(void *port) 558 { 559 struct rte_port_sink *p = 560 port; 561 562 if (p == NULL) 563 return 0; 564 565 PCAP_SINK_FLUSH_PKT(p->dumper); 566 567 return 0; 568 } 569 570 static int 571 rte_port_sink_free(void *port) 572 { 573 struct rte_port_sink *p = 574 port; 575 576 if (p == NULL) 577 return 0; 578 579 PCAP_SINK_CLOSE(p->dumper); 580 581 rte_free(p); 582 583 return 0; 584 } 585 586 static int 587 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats, 588 int clear) 589 { 590 struct rte_port_sink *p = 591 port; 592 593 if (stats != NULL) 594 memcpy(stats, &p->stats, sizeof(p->stats)); 595 596 if (clear) 597 memset(&p->stats, 0, sizeof(p->stats)); 598 599 return 0; 600 } 601 602 /* 603 * Summary of port operations 604 */ 605 struct rte_port_in_ops rte_port_source_ops = { 606 .f_create = rte_port_source_create, 607 .f_free = rte_port_source_free, 608 .f_rx = rte_port_source_rx, 609 .f_stats = rte_port_source_stats_read, 610 }; 611 612 struct rte_port_out_ops rte_port_sink_ops = { 613 .f_create = rte_port_sink_create, 614 .f_free = rte_port_sink_free, 615 .f_tx = rte_port_sink_tx, 616 .f_tx_bulk = rte_port_sink_tx_bulk, 617 .f_flush = rte_port_sink_flush, 618 .f_stats = rte_port_sink_stats_read, 619 }; 620