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