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 rte_free(pkt_len_aligns); 167 rte_free(port->pkt_len); 168 rte_free(port->pkts); 169 rte_free(port->pkt_buff); 170 171 return -1; 172 } 173 174 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \ 175 pcap_source_load(port, file_name, n_bytes, socket_id) 176 177 #else /* RTE_PORT_PCAP */ 178 179 #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id) \ 180 ({ \ 181 int _ret = 0; \ 182 \ 183 if (file_name) { \ 184 RTE_LOG(ERR, PORT, "Source port field " \ 185 "\"file_name\" is not NULL.\n"); \ 186 _ret = -1; \ 187 } \ 188 \ 189 _ret; \ 190 }) 191 192 #endif /* RTE_PORT_PCAP */ 193 194 static void * 195 rte_port_source_create(void *params, int socket_id) 196 { 197 struct rte_port_source_params *p = 198 params; 199 struct rte_port_source *port; 200 201 /* Check input arguments*/ 202 if ((p == NULL) || (p->mempool == NULL)) { 203 RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__); 204 return NULL; 205 } 206 207 /* Memory allocation */ 208 port = rte_zmalloc_socket("PORT", sizeof(*port), 209 RTE_CACHE_LINE_SIZE, socket_id); 210 if (port == NULL) { 211 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__); 212 return NULL; 213 } 214 215 /* Initialization */ 216 port->mempool = (struct rte_mempool *) p->mempool; 217 218 if (p->file_name) { 219 int status = PCAP_SOURCE_LOAD(port, p->file_name, 220 p->n_bytes_per_pkt, socket_id); 221 222 if (status < 0) { 223 rte_free(port); 224 port = NULL; 225 } 226 } 227 228 return port; 229 } 230 231 static int 232 rte_port_source_free(void *port) 233 { 234 struct rte_port_source *p = 235 port; 236 237 /* Check input parameters */ 238 if (p == NULL) 239 return 0; 240 241 rte_free(p->pkt_len); 242 rte_free(p->pkts); 243 rte_free(p->pkt_buff); 244 245 rte_free(p); 246 247 return 0; 248 } 249 250 static int 251 rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts) 252 { 253 struct rte_port_source *p = port; 254 uint32_t i; 255 256 if (rte_pktmbuf_alloc_bulk(p->mempool, pkts, n_pkts) != 0) 257 return 0; 258 259 if (p->pkt_buff != NULL) { 260 for (i = 0; i < n_pkts; i++) { 261 uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i], 262 uint8_t *); 263 264 rte_memcpy(pkt_data, p->pkts[p->pkt_index], 265 p->pkt_len[p->pkt_index]); 266 pkts[i]->data_len = p->pkt_len[p->pkt_index]; 267 pkts[i]->pkt_len = pkts[i]->data_len; 268 269 p->pkt_index++; 270 if (p->pkt_index >= p->n_pkts) 271 p->pkt_index = 0; 272 } 273 } 274 275 RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts); 276 277 return n_pkts; 278 } 279 280 static int 281 rte_port_source_stats_read(void *port, 282 struct rte_port_in_stats *stats, int clear) 283 { 284 struct rte_port_source *p = 285 port; 286 287 if (stats != NULL) 288 memcpy(stats, &p->stats, sizeof(p->stats)); 289 290 if (clear) 291 memset(&p->stats, 0, sizeof(p->stats)); 292 293 return 0; 294 } 295 296 /* 297 * Port SINK 298 */ 299 #ifdef RTE_PORT_STATS_COLLECT 300 301 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \ 302 (port->stats.n_pkts_in += val) 303 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \ 304 (port->stats.n_pkts_drop += val) 305 306 #else 307 308 #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) 309 #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) 310 311 #endif 312 313 struct rte_port_sink { 314 struct rte_port_out_stats stats; 315 316 /* PCAP dumper handle and pkts number */ 317 void *dumper; 318 uint32_t max_pkts; 319 uint32_t pkt_index; 320 uint32_t dump_finish; 321 }; 322 323 #ifdef RTE_PORT_PCAP 324 325 static int 326 pcap_sink_open(struct rte_port_sink *port, 327 const char *file_name, 328 uint32_t max_n_pkts) 329 { 330 pcap_t *tx_pcap; 331 pcap_dumper_t *pcap_dumper; 332 333 /** Open a dead pcap handler for opening dumper file */ 334 tx_pcap = pcap_open_dead(DLT_EN10MB, 65535); 335 if (tx_pcap == NULL) { 336 RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n"); 337 return -1; 338 } 339 340 /* The dumper is created using the previous pcap_t reference */ 341 pcap_dumper = pcap_dump_open(tx_pcap, file_name); 342 if (pcap_dumper == NULL) { 343 RTE_LOG(ERR, PORT, "Failed to open pcap file " 344 "\"%s\" for writing\n", file_name); 345 return -1; 346 } 347 348 port->dumper = pcap_dumper; 349 port->max_pkts = max_n_pkts; 350 port->pkt_index = 0; 351 port->dump_finish = 0; 352 353 RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n", 354 file_name); 355 356 return 0; 357 } 358 359 static void 360 pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf) 361 { 362 uint8_t *pcap_dumper = (port->dumper); 363 struct pcap_pkthdr pcap_hdr; 364 uint8_t jumbo_pkt_buf[RTE_ETHER_MAX_JUMBO_FRAME_LEN]; 365 uint8_t *pkt; 366 367 /* Maximum num packets already reached */ 368 if (port->dump_finish) 369 return; 370 371 pkt = rte_pktmbuf_mtod(mbuf, uint8_t *); 372 373 pcap_hdr.len = mbuf->pkt_len; 374 pcap_hdr.caplen = pcap_hdr.len; 375 gettimeofday(&(pcap_hdr.ts), NULL); 376 377 if (mbuf->nb_segs > 1) { 378 struct rte_mbuf *jumbo_mbuf; 379 uint32_t pkt_index = 0; 380 381 /* if packet size longer than RTE_ETHER_MAX_JUMBO_FRAME_LEN, 382 * ignore it. 383 */ 384 if (mbuf->pkt_len > RTE_ETHER_MAX_JUMBO_FRAME_LEN) 385 return; 386 387 for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL; 388 jumbo_mbuf = jumbo_mbuf->next) { 389 rte_memcpy(&jumbo_pkt_buf[pkt_index], 390 rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *), 391 jumbo_mbuf->data_len); 392 pkt_index += jumbo_mbuf->data_len; 393 } 394 395 jumbo_pkt_buf[pkt_index] = '\0'; 396 397 pkt = jumbo_pkt_buf; 398 } 399 400 pcap_dump(pcap_dumper, &pcap_hdr, pkt); 401 402 port->pkt_index++; 403 404 if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) { 405 port->dump_finish = 1; 406 RTE_LOG(INFO, PORT, "Dumped %u packets to file\n", 407 port->pkt_index); 408 } 409 410 } 411 412 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts) \ 413 pcap_sink_open(port, file_name, max_n_pkts) 414 415 #define PCAP_SINK_WRITE_PKT(port, mbuf) \ 416 pcap_sink_write_pkt(port, mbuf) 417 418 #define PCAP_SINK_FLUSH_PKT(dumper) \ 419 do { \ 420 if (dumper) \ 421 pcap_dump_flush((pcap_dumper_t *)dumper); \ 422 } while (0) 423 424 #define PCAP_SINK_CLOSE(dumper) \ 425 do { \ 426 if (dumper) \ 427 pcap_dump_close((pcap_dumper_t *)dumper); \ 428 } while (0) 429 430 #else 431 432 #define PCAP_SINK_OPEN(port, file_name, max_n_pkts) \ 433 ({ \ 434 int _ret = 0; \ 435 \ 436 if (file_name) { \ 437 RTE_LOG(ERR, PORT, "Sink port field " \ 438 "\"file_name\" is not NULL.\n"); \ 439 _ret = -1; \ 440 } \ 441 \ 442 _ret; \ 443 }) 444 445 #define PCAP_SINK_WRITE_PKT(port, mbuf) {} 446 447 #define PCAP_SINK_FLUSH_PKT(dumper) 448 449 #define PCAP_SINK_CLOSE(dumper) 450 451 #endif 452 453 static void * 454 rte_port_sink_create(void *params, int socket_id) 455 { 456 struct rte_port_sink *port; 457 struct rte_port_sink_params *p = params; 458 459 /* Memory allocation */ 460 port = rte_zmalloc_socket("PORT", sizeof(*port), 461 RTE_CACHE_LINE_SIZE, socket_id); 462 if (port == NULL) { 463 RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__); 464 return NULL; 465 } 466 467 if (!p) 468 return port; 469 470 if (p->file_name) { 471 int status = PCAP_SINK_OPEN(port, p->file_name, 472 p->max_n_pkts); 473 474 if (status < 0) { 475 rte_free(port); 476 port = NULL; 477 } 478 } 479 480 return port; 481 } 482 483 static int 484 rte_port_sink_tx(void *port, struct rte_mbuf *pkt) 485 { 486 struct rte_port_sink *p = port; 487 488 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1); 489 if (p->dumper != NULL) 490 PCAP_SINK_WRITE_PKT(p, pkt); 491 rte_pktmbuf_free(pkt); 492 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1); 493 494 return 0; 495 } 496 497 static int 498 rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts, 499 uint64_t pkts_mask) 500 { 501 struct rte_port_sink *p = port; 502 503 if ((pkts_mask & (pkts_mask + 1)) == 0) { 504 uint64_t n_pkts = __builtin_popcountll(pkts_mask); 505 uint32_t i; 506 507 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts); 508 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts); 509 510 if (p->dumper) { 511 for (i = 0; i < n_pkts; i++) 512 PCAP_SINK_WRITE_PKT(p, pkts[i]); 513 } 514 515 for (i = 0; i < n_pkts; i++) { 516 struct rte_mbuf *pkt = pkts[i]; 517 518 rte_pktmbuf_free(pkt); 519 } 520 521 } else { 522 if (p->dumper) { 523 uint64_t dump_pkts_mask = pkts_mask; 524 uint32_t pkt_index; 525 526 for ( ; dump_pkts_mask; ) { 527 pkt_index = __builtin_ctzll( 528 dump_pkts_mask); 529 PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]); 530 dump_pkts_mask &= ~(1LLU << pkt_index); 531 } 532 } 533 534 for ( ; pkts_mask; ) { 535 uint32_t pkt_index = __builtin_ctzll(pkts_mask); 536 uint64_t pkt_mask = 1LLU << pkt_index; 537 struct rte_mbuf *pkt = pkts[pkt_index]; 538 539 RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1); 540 RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1); 541 rte_pktmbuf_free(pkt); 542 pkts_mask &= ~pkt_mask; 543 } 544 } 545 546 return 0; 547 } 548 549 static int 550 rte_port_sink_flush(void *port) 551 { 552 struct rte_port_sink *p = 553 port; 554 555 if (p == NULL) 556 return 0; 557 558 PCAP_SINK_FLUSH_PKT(p->dumper); 559 560 return 0; 561 } 562 563 static int 564 rte_port_sink_free(void *port) 565 { 566 struct rte_port_sink *p = 567 port; 568 569 if (p == NULL) 570 return 0; 571 572 PCAP_SINK_CLOSE(p->dumper); 573 574 rte_free(p); 575 576 return 0; 577 } 578 579 static int 580 rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats, 581 int clear) 582 { 583 struct rte_port_sink *p = 584 port; 585 586 if (stats != NULL) 587 memcpy(stats, &p->stats, sizeof(p->stats)); 588 589 if (clear) 590 memset(&p->stats, 0, sizeof(p->stats)); 591 592 return 0; 593 } 594 595 /* 596 * Summary of port operations 597 */ 598 struct rte_port_in_ops rte_port_source_ops = { 599 .f_create = rte_port_source_create, 600 .f_free = rte_port_source_free, 601 .f_rx = rte_port_source_rx, 602 .f_stats = rte_port_source_stats_read, 603 }; 604 605 struct rte_port_out_ops rte_port_sink_ops = { 606 .f_create = rte_port_sink_create, 607 .f_free = rte_port_sink_free, 608 .f_tx = rte_port_sink_tx, 609 .f_tx_bulk = rte_port_sink_tx_bulk, 610 .f_flush = rte_port_sink_flush, 611 .f_stats = rte_port_sink_stats_read, 612 }; 613