1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019 Microsoft Corporation 3 */ 4 5 #include <errno.h> 6 #include <net/if.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <sys/uio.h> 11 #include <time.h> 12 #include <unistd.h> 13 14 #include <bus_driver.h> 15 #include <rte_common.h> 16 #include <rte_cycles.h> 17 #include <dev_driver.h> 18 #include <rte_errno.h> 19 #include <rte_ethdev.h> 20 #include <rte_ether.h> 21 #include <rte_mbuf.h> 22 #include <rte_pcapng.h> 23 #include <rte_reciprocal.h> 24 #include <rte_time.h> 25 26 #include "pcapng_proto.h" 27 28 /* conversion from DPDK speed to PCAPNG */ 29 #define PCAPNG_MBPS_SPEED 1000000ull 30 31 /* Format of the capture file handle */ 32 struct rte_pcapng { 33 int outfd; /* output file */ 34 /* DPDK port id to interface index in file */ 35 uint32_t port_index[RTE_MAX_ETHPORTS]; 36 }; 37 38 /* For converting TSC cycles to PCAPNG ns format */ 39 static struct pcapng_time { 40 uint64_t ns; 41 uint64_t cycles; 42 uint64_t tsc_hz; 43 struct rte_reciprocal_u64 tsc_hz_inverse; 44 } pcapng_time; 45 46 static inline void 47 pcapng_init(void) 48 { 49 struct timespec ts; 50 51 pcapng_time.cycles = rte_get_tsc_cycles(); 52 clock_gettime(CLOCK_REALTIME, &ts); 53 pcapng_time.cycles = (pcapng_time.cycles + rte_get_tsc_cycles()) / 2; 54 pcapng_time.ns = rte_timespec_to_ns(&ts); 55 56 pcapng_time.tsc_hz = rte_get_tsc_hz(); 57 pcapng_time.tsc_hz_inverse = rte_reciprocal_value_u64(pcapng_time.tsc_hz); 58 } 59 60 /* PCAPNG timestamps are in nanoseconds */ 61 static uint64_t pcapng_tsc_to_ns(uint64_t cycles) 62 { 63 uint64_t delta, secs; 64 65 if (!pcapng_time.tsc_hz) 66 pcapng_init(); 67 68 /* In essence the calculation is: 69 * delta = (cycles - pcapng_time.cycles) * NSEC_PRE_SEC / rte_get_tsc_hz() 70 * but this overflows within 4 to 8 seconds depending on TSC frequency. 71 * Instead, if delta >= pcapng_time.tsc_hz: 72 * Increase pcapng_time.ns and pcapng_time.cycles by the number of 73 * whole seconds in delta and reduce delta accordingly. 74 * delta will therefore always lie in the interval [0, pcapng_time.tsc_hz), 75 * which will not overflow when multiplied by NSEC_PER_SEC provided the 76 * TSC frequency < approx 18.4GHz. 77 * 78 * Currently all TSCs operate below 5GHz. 79 */ 80 delta = cycles - pcapng_time.cycles; 81 if (unlikely(delta >= pcapng_time.tsc_hz)) { 82 if (likely(delta < pcapng_time.tsc_hz * 2)) { 83 delta -= pcapng_time.tsc_hz; 84 pcapng_time.cycles += pcapng_time.tsc_hz; 85 pcapng_time.ns += NSEC_PER_SEC; 86 } else { 87 secs = rte_reciprocal_divide_u64(delta, &pcapng_time.tsc_hz_inverse); 88 delta -= secs * pcapng_time.tsc_hz; 89 pcapng_time.cycles += secs * pcapng_time.tsc_hz; 90 pcapng_time.ns += secs * NSEC_PER_SEC; 91 } 92 } 93 94 return pcapng_time.ns + rte_reciprocal_divide_u64(delta * NSEC_PER_SEC, 95 &pcapng_time.tsc_hz_inverse); 96 } 97 98 /* length of option including padding */ 99 static uint16_t pcapng_optlen(uint16_t len) 100 { 101 return RTE_ALIGN(sizeof(struct pcapng_option) + len, 102 sizeof(uint32_t)); 103 } 104 105 /* build TLV option and return location of next */ 106 static struct pcapng_option * 107 pcapng_add_option(struct pcapng_option *popt, uint16_t code, 108 const void *data, uint16_t len) 109 { 110 popt->code = code; 111 popt->length = len; 112 memcpy(popt->data, data, len); 113 114 return (struct pcapng_option *)((uint8_t *)popt + pcapng_optlen(len)); 115 } 116 117 /* 118 * Write required initial section header describing the capture 119 */ 120 static int 121 pcapng_section_block(rte_pcapng_t *self, 122 const char *os, const char *hw, 123 const char *app, const char *comment) 124 { 125 struct pcapng_section_header *hdr; 126 struct pcapng_option *opt; 127 void *buf; 128 uint32_t len; 129 ssize_t cc; 130 131 len = sizeof(*hdr); 132 if (hw) 133 len += pcapng_optlen(strlen(hw)); 134 if (os) 135 len += pcapng_optlen(strlen(os)); 136 if (app) 137 len += pcapng_optlen(strlen(app)); 138 if (comment) 139 len += pcapng_optlen(strlen(comment)); 140 141 /* reserve space for OPT_END */ 142 len += pcapng_optlen(0); 143 len += sizeof(uint32_t); 144 145 buf = calloc(1, len); 146 if (!buf) 147 return -1; 148 149 hdr = (struct pcapng_section_header *)buf; 150 *hdr = (struct pcapng_section_header) { 151 .block_type = PCAPNG_SECTION_BLOCK, 152 .block_length = len, 153 .byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC, 154 .major_version = PCAPNG_MAJOR_VERS, 155 .minor_version = PCAPNG_MINOR_VERS, 156 .section_length = UINT64_MAX, 157 }; 158 159 /* After the section header insert variable length options. */ 160 opt = (struct pcapng_option *)(hdr + 1); 161 if (comment) 162 opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, 163 comment, strlen(comment)); 164 if (hw) 165 opt = pcapng_add_option(opt, PCAPNG_SHB_HARDWARE, 166 hw, strlen(hw)); 167 if (os) 168 opt = pcapng_add_option(opt, PCAPNG_SHB_OS, 169 os, strlen(os)); 170 if (app) 171 opt = pcapng_add_option(opt, PCAPNG_SHB_USERAPPL, 172 app, strlen(app)); 173 174 /* The standard requires last option to be OPT_END */ 175 opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 176 177 /* clone block_length after option */ 178 memcpy(opt, &hdr->block_length, sizeof(uint32_t)); 179 180 cc = write(self->outfd, buf, len); 181 free(buf); 182 183 return cc; 184 } 185 186 /* Write an interface block for a DPDK port */ 187 static int 188 pcapng_add_interface(rte_pcapng_t *self, uint16_t port) 189 { 190 struct pcapng_interface_block *hdr; 191 struct rte_eth_dev_info dev_info; 192 struct rte_ether_addr *ea, macaddr; 193 const struct rte_device *dev; 194 struct rte_eth_link link; 195 struct pcapng_option *opt; 196 const uint8_t tsresol = 9; /* nanosecond resolution */ 197 uint32_t len; 198 void *buf; 199 char ifname[IF_NAMESIZE]; 200 char ifhw[256]; 201 uint64_t speed = 0; 202 203 if (rte_eth_dev_info_get(port, &dev_info) < 0) 204 return -1; 205 206 /* make something like an interface name */ 207 if (if_indextoname(dev_info.if_index, ifname) == NULL) 208 snprintf(ifname, IF_NAMESIZE, "dpdk:%u", port); 209 210 /* make a useful device hardware string */ 211 dev = dev_info.device; 212 if (dev) 213 snprintf(ifhw, sizeof(ifhw), 214 "%s-%s", dev->bus->name, dev->name); 215 216 /* DPDK reports in units of Mbps */ 217 if (rte_eth_link_get(port, &link) == 0 && 218 link.link_status == RTE_ETH_LINK_UP) 219 speed = link.link_speed * PCAPNG_MBPS_SPEED; 220 221 if (rte_eth_macaddr_get(port, &macaddr) < 0) 222 ea = NULL; 223 else 224 ea = &macaddr; 225 226 /* Compute length of interface block options */ 227 len = sizeof(*hdr); 228 229 len += pcapng_optlen(sizeof(tsresol)); /* timestamp */ 230 len += pcapng_optlen(strlen(ifname)); /* ifname */ 231 232 if (ea) 233 len += pcapng_optlen(RTE_ETHER_ADDR_LEN); /* macaddr */ 234 if (speed != 0) 235 len += pcapng_optlen(sizeof(uint64_t)); 236 if (dev) 237 len += pcapng_optlen(strlen(ifhw)); 238 239 len += pcapng_optlen(0); 240 len += sizeof(uint32_t); 241 242 buf = alloca(len); 243 if (!buf) 244 return -1; 245 246 hdr = (struct pcapng_interface_block *)buf; 247 *hdr = (struct pcapng_interface_block) { 248 .block_type = PCAPNG_INTERFACE_BLOCK, 249 .link_type = 1, /* DLT_EN10MB - Ethernet */ 250 .block_length = len, 251 }; 252 253 opt = (struct pcapng_option *)(hdr + 1); 254 opt = pcapng_add_option(opt, PCAPNG_IFB_TSRESOL, 255 &tsresol, sizeof(tsresol)); 256 opt = pcapng_add_option(opt, PCAPNG_IFB_NAME, 257 ifname, strlen(ifname)); 258 if (ea) 259 opt = pcapng_add_option(opt, PCAPNG_IFB_MACADDR, 260 ea, RTE_ETHER_ADDR_LEN); 261 if (speed != 0) 262 opt = pcapng_add_option(opt, PCAPNG_IFB_SPEED, 263 &speed, sizeof(uint64_t)); 264 if (dev) 265 opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE, 266 ifhw, strlen(ifhw)); 267 opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 268 269 /* clone block_length after optionsa */ 270 memcpy(opt, &hdr->block_length, sizeof(uint32_t)); 271 272 return write(self->outfd, buf, len); 273 } 274 275 /* 276 * Write the list of possible interfaces at the start 277 * of the file. 278 */ 279 static int 280 pcapng_interfaces(rte_pcapng_t *self) 281 { 282 uint16_t port_id; 283 uint16_t index = 0; 284 285 RTE_ETH_FOREACH_DEV(port_id) { 286 /* The list if ports in pcapng needs to be contiguous */ 287 self->port_index[port_id] = index++; 288 if (pcapng_add_interface(self, port_id) < 0) 289 return -1; 290 } 291 return 0; 292 } 293 294 /* 295 * Write an Interface statistics block at the end of capture. 296 */ 297 ssize_t 298 rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id, 299 const char *comment, 300 uint64_t start_time, uint64_t end_time, 301 uint64_t ifrecv, uint64_t ifdrop) 302 { 303 struct pcapng_statistics *hdr; 304 struct pcapng_option *opt; 305 uint32_t optlen, len; 306 uint8_t *buf; 307 uint64_t ns; 308 309 RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); 310 311 optlen = 0; 312 313 if (ifrecv != UINT64_MAX) 314 optlen += pcapng_optlen(sizeof(ifrecv)); 315 if (ifdrop != UINT64_MAX) 316 optlen += pcapng_optlen(sizeof(ifdrop)); 317 if (start_time != 0) 318 optlen += pcapng_optlen(sizeof(start_time)); 319 if (end_time != 0) 320 optlen += pcapng_optlen(sizeof(end_time)); 321 if (comment) 322 optlen += pcapng_optlen(strlen(comment)); 323 if (optlen != 0) 324 optlen += pcapng_optlen(0); 325 326 len = sizeof(*hdr) + optlen + sizeof(uint32_t); 327 buf = alloca(len); 328 if (buf == NULL) 329 return -1; 330 331 hdr = (struct pcapng_statistics *)buf; 332 opt = (struct pcapng_option *)(hdr + 1); 333 334 if (comment) 335 opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, 336 comment, strlen(comment)); 337 if (start_time != 0) 338 opt = pcapng_add_option(opt, PCAPNG_ISB_STARTTIME, 339 &start_time, sizeof(start_time)); 340 if (end_time != 0) 341 opt = pcapng_add_option(opt, PCAPNG_ISB_ENDTIME, 342 &end_time, sizeof(end_time)); 343 if (ifrecv != UINT64_MAX) 344 opt = pcapng_add_option(opt, PCAPNG_ISB_IFRECV, 345 &ifrecv, sizeof(ifrecv)); 346 if (ifdrop != UINT64_MAX) 347 opt = pcapng_add_option(opt, PCAPNG_ISB_IFDROP, 348 &ifdrop, sizeof(ifdrop)); 349 if (optlen != 0) 350 opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 351 352 hdr->block_type = PCAPNG_INTERFACE_STATS_BLOCK; 353 hdr->block_length = len; 354 hdr->interface_id = self->port_index[port_id]; 355 356 ns = pcapng_tsc_to_ns(rte_get_tsc_cycles()); 357 hdr->timestamp_hi = ns >> 32; 358 hdr->timestamp_lo = (uint32_t)ns; 359 360 /* clone block_length after option */ 361 memcpy(opt, &len, sizeof(uint32_t)); 362 363 return write(self->outfd, buf, len); 364 } 365 366 uint32_t 367 rte_pcapng_mbuf_size(uint32_t length) 368 { 369 /* The VLAN and EPB header must fit in the mbuf headroom. */ 370 RTE_ASSERT(sizeof(struct pcapng_enhance_packet_block) + 371 sizeof(struct rte_vlan_hdr) <= RTE_PKTMBUF_HEADROOM); 372 373 /* The flags and queue information are added at the end. */ 374 return sizeof(struct rte_mbuf) 375 + RTE_ALIGN(length, sizeof(uint32_t)) 376 + pcapng_optlen(sizeof(uint32_t)) /* flag option */ 377 + pcapng_optlen(sizeof(uint32_t)) /* queue option */ 378 + sizeof(uint32_t); /* length */ 379 } 380 381 /* More generalized version rte_vlan_insert() */ 382 static int 383 pcapng_vlan_insert(struct rte_mbuf *m, uint16_t ether_type, uint16_t tci) 384 { 385 struct rte_ether_hdr *nh, *oh; 386 struct rte_vlan_hdr *vh; 387 388 if (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1) 389 return -EINVAL; 390 391 if (rte_pktmbuf_data_len(m) < sizeof(*oh)) 392 return -EINVAL; 393 394 oh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 395 nh = (struct rte_ether_hdr *) 396 rte_pktmbuf_prepend(m, sizeof(struct rte_vlan_hdr)); 397 if (nh == NULL) 398 return -ENOSPC; 399 400 memmove(nh, oh, 2 * RTE_ETHER_ADDR_LEN); 401 nh->ether_type = rte_cpu_to_be_16(ether_type); 402 403 vh = (struct rte_vlan_hdr *) (nh + 1); 404 vh->vlan_tci = rte_cpu_to_be_16(tci); 405 406 return 0; 407 } 408 409 /* 410 * The mbufs created use the Pcapng standard enhanced packet block. 411 * 412 * 1 2 3 413 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 414 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 415 * 0 | Block Type = 0x00000006 | 416 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 417 * 4 | Block Total Length | 418 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 419 * 8 | Interface ID | 420 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 421 * 12 | Timestamp (High) | 422 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 423 * 16 | Timestamp (Low) | 424 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 425 * 20 | Captured Packet Length | 426 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 427 * 24 | Original Packet Length | 428 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 429 * 28 / / 430 * / Packet Data / 431 * / variable length, padded to 32 bits / 432 * / / 433 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 434 * | Option Code = 0x0002 | Option Length = 0x004 | 435 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 436 * | Flags (direction) | 437 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 438 * | Option Code = 0x0006 | Option Length = 0x002 | 439 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 440 * | Queue id | 441 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 442 * | Block Total Length | 443 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 444 */ 445 446 /* Make a copy of original mbuf with pcapng header and options */ 447 struct rte_mbuf * 448 rte_pcapng_copy(uint16_t port_id, uint32_t queue, 449 const struct rte_mbuf *md, 450 struct rte_mempool *mp, 451 uint32_t length, uint64_t cycles, 452 enum rte_pcapng_direction direction) 453 { 454 struct pcapng_enhance_packet_block *epb; 455 uint32_t orig_len, data_len, padding, flags; 456 struct pcapng_option *opt; 457 const uint16_t optlen = pcapng_optlen(sizeof(flags)) + pcapng_optlen(sizeof(queue)); 458 struct rte_mbuf *mc; 459 uint64_t ns; 460 461 #ifdef RTE_LIBRTE_ETHDEV_DEBUG 462 RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, NULL); 463 #endif 464 ns = pcapng_tsc_to_ns(cycles); 465 466 orig_len = rte_pktmbuf_pkt_len(md); 467 468 /* Take snapshot of the data */ 469 mc = rte_pktmbuf_copy(md, mp, 0, length); 470 if (unlikely(mc == NULL)) 471 return NULL; 472 473 /* Expand any offloaded VLAN information */ 474 if ((direction == RTE_PCAPNG_DIRECTION_IN && 475 (md->ol_flags & RTE_MBUF_F_RX_VLAN_STRIPPED)) || 476 (direction == RTE_PCAPNG_DIRECTION_OUT && 477 (md->ol_flags & RTE_MBUF_F_TX_VLAN))) { 478 if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_VLAN, 479 md->vlan_tci) != 0) 480 goto fail; 481 } 482 483 if ((direction == RTE_PCAPNG_DIRECTION_IN && 484 (md->ol_flags & RTE_MBUF_F_RX_QINQ_STRIPPED)) || 485 (direction == RTE_PCAPNG_DIRECTION_OUT && 486 (md->ol_flags & RTE_MBUF_F_TX_QINQ))) { 487 if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_QINQ, 488 md->vlan_tci_outer) != 0) 489 goto fail; 490 } 491 492 /* pad the packet to 32 bit boundary */ 493 data_len = rte_pktmbuf_data_len(mc); 494 padding = RTE_ALIGN(data_len, sizeof(uint32_t)) - data_len; 495 if (padding > 0) { 496 void *tail = rte_pktmbuf_append(mc, padding); 497 498 if (tail == NULL) 499 goto fail; 500 memset(tail, 0, padding); 501 } 502 503 /* reserve trailing options and block length */ 504 opt = (struct pcapng_option *) 505 rte_pktmbuf_append(mc, optlen + sizeof(uint32_t)); 506 if (unlikely(opt == NULL)) 507 goto fail; 508 509 switch (direction) { 510 case RTE_PCAPNG_DIRECTION_IN: 511 flags = PCAPNG_IFB_INBOUND; 512 break; 513 case RTE_PCAPNG_DIRECTION_OUT: 514 flags = PCAPNG_IFB_OUTBOUND; 515 break; 516 default: 517 flags = 0; 518 } 519 520 opt = pcapng_add_option(opt, PCAPNG_EPB_FLAGS, 521 &flags, sizeof(flags)); 522 523 opt = pcapng_add_option(opt, PCAPNG_EPB_QUEUE, 524 &queue, sizeof(queue)); 525 526 /* Note: END_OPT necessary here. Wireshark doesn't do it. */ 527 528 /* Add PCAPNG packet header */ 529 epb = (struct pcapng_enhance_packet_block *) 530 rte_pktmbuf_prepend(mc, sizeof(*epb)); 531 if (unlikely(epb == NULL)) 532 goto fail; 533 534 epb->block_type = PCAPNG_ENHANCED_PACKET_BLOCK; 535 epb->block_length = rte_pktmbuf_data_len(mc); 536 537 /* Interface index is filled in later during write */ 538 mc->port = port_id; 539 540 epb->timestamp_hi = ns >> 32; 541 epb->timestamp_lo = (uint32_t)ns; 542 epb->capture_length = data_len; 543 epb->original_length = orig_len; 544 545 /* set trailer of block length */ 546 *(uint32_t *)opt = epb->block_length; 547 548 return mc; 549 550 fail: 551 rte_pktmbuf_free(mc); 552 return NULL; 553 } 554 555 /* Count how many segments are in this array of mbufs */ 556 static unsigned int 557 mbuf_burst_segs(struct rte_mbuf *pkts[], unsigned int n) 558 { 559 unsigned int i, iovcnt; 560 561 for (iovcnt = 0, i = 0; i < n; i++) { 562 const struct rte_mbuf *m = pkts[i]; 563 564 __rte_mbuf_sanity_check(m, 1); 565 566 iovcnt += m->nb_segs; 567 } 568 return iovcnt; 569 } 570 571 /* Write pre-formatted packets to file. */ 572 ssize_t 573 rte_pcapng_write_packets(rte_pcapng_t *self, 574 struct rte_mbuf *pkts[], uint16_t nb_pkts) 575 { 576 int iovcnt = mbuf_burst_segs(pkts, nb_pkts); 577 struct iovec iov[iovcnt]; 578 unsigned int i, cnt; 579 ssize_t ret; 580 581 for (i = cnt = 0; i < nb_pkts; i++) { 582 struct rte_mbuf *m = pkts[i]; 583 struct pcapng_enhance_packet_block *epb; 584 585 /* sanity check that is really a pcapng mbuf */ 586 epb = rte_pktmbuf_mtod(m, struct pcapng_enhance_packet_block *); 587 if (unlikely(epb->block_type != PCAPNG_ENHANCED_PACKET_BLOCK || 588 epb->block_length != rte_pktmbuf_data_len(m))) { 589 rte_errno = EINVAL; 590 return -1; 591 } 592 593 /* 594 * The DPDK port is recorded during pcapng_copy. 595 * Map that to PCAPNG interface in file. 596 */ 597 epb->interface_id = self->port_index[m->port]; 598 do { 599 iov[cnt].iov_base = rte_pktmbuf_mtod(m, void *); 600 iov[cnt].iov_len = rte_pktmbuf_data_len(m); 601 ++cnt; 602 } while ((m = m->next)); 603 } 604 605 ret = writev(self->outfd, iov, iovcnt); 606 if (unlikely(ret < 0)) 607 rte_errno = errno; 608 return ret; 609 } 610 611 /* Create new pcapng writer handle */ 612 rte_pcapng_t * 613 rte_pcapng_fdopen(int fd, 614 const char *osname, const char *hardware, 615 const char *appname, const char *comment) 616 { 617 rte_pcapng_t *self; 618 619 self = malloc(sizeof(*self)); 620 if (!self) { 621 rte_errno = ENOMEM; 622 return NULL; 623 } 624 625 self->outfd = fd; 626 627 if (pcapng_section_block(self, osname, hardware, appname, comment) < 0) 628 goto fail; 629 630 if (pcapng_interfaces(self) < 0) 631 goto fail; 632 633 return self; 634 fail: 635 free(self); 636 return NULL; 637 } 638 639 void 640 rte_pcapng_close(rte_pcapng_t *self) 641 { 642 close(self->outfd); 643 free(self); 644 } 645