Bill Fischofer(Bill-Fischofer-Linaro) replied on github web page: platform/linux-generic/odp_packet_io.c line 237 @@ -89,6 +96,274 @@ int odp_pktio_init_local(void) return odp_pktio_ops_init_local(true); } +static int write_pcapng_hdr(pktio_entry_t *entry, int qidx) +{ + size_t len; + pcapng_section_hdr_block_t shb; + pcapng_interface_description_block_s idb; + int fd = entry->s.pcapng_info.pcapng_fd[qidx]; + + memset(&shb, 0, sizeof(shb)); + memset(&idb, 0, sizeof(idb)); + + shb.block_type = PCAPNG_BLOCK_TYPE_SHB; + shb.block_total_length = sizeof(shb); + shb.block_total_length2 = sizeof(shb); + shb.magic = PCAPNG_ENDIAN_MAGIC; + shb.version_major = 0x1; + shb.version_minor = 0x0; + shb.section_len = -1; + + len = write(fd, &shb, sizeof(shb)); + fsync(fd); + /* fail to write shb/idb means the pcapng is unreadable */ + if (!len) { + ODP_ERR("Failed to write pcapng section hdr\n"); + close(fd); + return -1; + } + + idb.block_type = PCAPNG_BLOCK_TYPE_IDB; + idb.block_total_length = sizeof(idb); + idb.block_total_length2 = sizeof(idb); + idb.linktype = 0x1; /* LINKTYPE_ETHERNET */ + idb.snaplen = 0x0; /* unlimited */ + len = write(fd, &idb, sizeof(idb)); + if (!len) { + ODP_ERR("Failed to write pcapng interface description\n"); + close(fd); + return -1; + } + fsync(fd); + + entry->s.pcapng_info.state[qidx] = PCAPNG_WR_HDR; + + return 0; +} + +static int write_pcapng_pkts(pktio_entry_t *entry, int qidx, + const odp_packet_t packets[], int num) +{ + int i = 0; + struct iovec packet_iov[3 * num]; + pcapng_enhanced_packet_block_t epb; + int iovcnt = 0; + ssize_t len = 0; + int fd = entry->s.pcapng_info.pcapng_fd[qidx]; + + for (i = 0; i < num; i++) { + odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(packets[i]); + uint32_t pkt_len = _odp_packet_len(packets[i]); + char *buf = (char *)odp_packet_data(packets[i]); + + epb.block_type = PCAPNG_BLOCK_TYPE_EPB; + epb.block_total_length = sizeof(epb) + + ROUNDUP_ALIGN(pkt_len, PCAP_DATA_ALIGN) + + PCAP_DATA_ALIGN; + epb.interface_idx = 0; + epb.timestamp_high = (uint32_t)(pkt_hdr->timestamp.u64 >> 32); + epb.timestamp_low = (uint32_t)(pkt_hdr->timestamp.u64); + epb.captured_len = pkt_len; + epb.packet_len = pkt_len; + + /* epb */ + packet_iov[iovcnt].iov_base = &epb; + packet_iov[iovcnt].iov_len = sizeof(epb); + iovcnt++; + + /* data */ + packet_iov[iovcnt].iov_base = buf; + packet_iov[iovcnt].iov_len = + ROUNDUP_ALIGN(pkt_len, PCAP_DATA_ALIGN); + iovcnt++; + + /* trailing */ + packet_iov[iovcnt].iov_base = &epb.block_total_length; + packet_iov[iovcnt].iov_len = sizeof(uint32_t); + iovcnt++; + } + + /* we don't really care if we manage to write *all* data */ + len = writev(fd, packet_iov, iovcnt); + if (!len) + ODP_ERR("Failed to write pcapng data\n"); + fsync(fd); + + return len; +} + +static void pcapng_drain_fifo(int fd) +{ + char c; + ssize_t len; + + do { + len = read(fd, &c, sizeof(c)); + } while (len > 0 && len != -1); + ODP_DBG("Drain pcap fifo %d\n", len); +} + +static void *inotify_update(void *arg) +{ + pktio_entry_t *entry = (pktio_entry_t *)arg; + struct timeval time; + int ret; + ssize_t rdlen; + int i; + char buffer[INOTIFY_BUF_LEN]; + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + fd_set rfds; + + while (1) { + i = 0; + FD_ZERO(&rfds); + FD_SET(entry->s.pcapng_info.inotify_pcapng_fd, &rfds); + time.tv_sec = 2; + time.tv_usec = 0; + select(entry->s.pcapng_info.inotify_pcapng_fd + 1, &rfds, NULL, + NULL, &time); + if (FD_ISSET(entry->s.pcapng_info.inotify_pcapng_fd, &rfds)) { + rdlen = read(entry->s.pcapng_info.inotify_pcapng_fd, + buffer, INOTIFY_BUF_LEN); + while (i < rdlen) { + char *e; + unsigned int qidx; + struct inotify_event *event = + (struct inotify_event *)(void *) + &buffer[i]; + + e = strrchr(event->name, '-'); + e++; + if (!e) + continue; + qidx = atoi(e); + if (qidx > max_queue) { + ODP_ERR("Invalid queue number\n"); + i += INOTIFY_EVENT_SIZE + event->len; + continue; + } + + if (entry->s.pcapng_info.state[qidx] == + PCAPNG_WR_INVALID) + continue; + + if (event->mask & IN_OPEN) { + int fd = entry->s.pcapng_info.pcapng_fd[qidx]; + + pcapng_drain_fifo(fd); + ret = write_pcapng_hdr(entry, i); + if (ret) + entry->s.pcapng_info.state[qidx] = + PCAPNG_WR_STOP; + else + entry->s.pcapng_info.state[qidx] = + PCAPNG_WR_PKT; + ODP_DBG("Open %s for pcap tracing\n", + event->name); + } else if (event->mask & IN_CLOSE) { + entry->s.pcapng_info.state[qidx] = + PCAPNG_WR_STOP; + ODP_DBG("Close %s for pcap tracing\n", + event->name); + } else { + ODP_ERR("Unknown inotify event 0x%08x\n", + event->mask); + } + i += INOTIFY_EVENT_SIZE + event->len; + } + } + } + + return NULL; +} + +static void pcapng_destroy(pktio_entry_t *entry) +{ + int ret; + unsigned int i; + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + + ret = pthread_cancel(entry->s.pcapng_info.inotify_thread); + if (ret) + ODP_ERR("can't cancel inotify thread %s\n", strerror(errno)); + + /* fd's will be -1 in case of any failure */ + ret = inotify_rm_watch(entry->s.pcapng_info.inotify_pcapng_fd, + entry->s.pcapng_info.inotify_watch_fd); + if (ret) + ODP_ERR("can't deregister inotify %s\n", strerror(errno)); + + close(entry->s.pcapng_info.inotify_pcapng_fd); + + for (i = 0; i < max_queue; i++) { + entry->s.pcapng_info.state[i] = PCAPNG_WR_INVALID; + close(entry->s.pcapng_info.pcapng_fd[i]); + } +} + +static int pcapng_prepare(pktio_entry_t *entry) +{ + int ret = -1, fd; + pthread_attr_t attr; + unsigned int i; + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + + for (i = 0; i < max_queue; i++) { + char pcap_entry[256]; + + snprintf(pcap_entry, sizeof(pcap_entry), + "%s/%s-flow-%d", PCAPNG_WATCH_DIR, entry->s.name, i);
Comment: @apalos No, start and stop are good times for this as well. An application can stop a device, reconfigure it, and then restart it, so having that be the trigger for capture file cleanup and close makes sense. > Ilias Apalodimas(apalos) wrote: > wireshark re-defines them in every c file they want to use them. Keeping in > mind this is the pcapng file format specification, these are high unlikely to > change. > > The only relevant library i found is > ntar(https://www.winpcap.org/ntar/changelog.htm) but it seems abandoned for > many many years. >> Ilias Apalodimas(apalos) wrote: >> @Bill-Fischofer-Linaro pcapng_destroy() is called from _pktio_stop() which >> is called from odp_pktio_term_global(). >> pcapng_prepare() on the other hand is called from odp_pktio_start(). Want me >> to move it in odp_pktio_init_global()? >>> Ilias Apalodimas(apalos) wrote: >>> This essentially "reads" the inotify triggers for opening/closing the fifos >>> and sets the appropriate variables for starting/stopping the pcapng dump on >>> fifos. Will try to make it easier to read on the final PR >>>> Ilias Apalodimas(apalos) wrote: >>>> will fix >>>>> Ilias Apalodimas(apalos) wrote: >>>>> will fix >>>>>> Ilias Apalodimas(apalos) wrote: >>>>>> I'll check and update for the final PR >>>>>>> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >>>>>>> General cleanup should be part of `odp_term_global()` processing. >>>>>>> Presumably `odp_pktio_close()` should also do cleanup for specific >>>>>>> pktios. >>>>>>>> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >>>>>>>> A few comments about what this routine is doing would be very helpful >>>>>>>> here. This is not easy code to follow. Modularizing it into some >>>>>>>> `static inline` helpers might also make the logic simpler. >>>>>>>>> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >>>>>>>>> This is redundant. If `len > 0` then by definition `len != -1`. >>>>>>>>>> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >>>>>>>>>> This fails for multi-segment packets. `odp_packet_data(pkt)` is >>>>>>>>>> shorthand for `odp_packet_offset(pkt, 0, NULL, NULL)` so you don't >>>>>>>>>> know how long the first segment really is. First cut would be to >>>>>>>>>> only dump the first segment, so correct code is: >>>>>>>>>> ``` >>>>>>>>>> uint32_t seg_len; >>>>>>>>>> char *buf = (char *)odp_packet_offset(packets[i], 0, &seg_len, NULL); >>>>>>>>>> ``` >>>>>>>>>> And use `seg_len` rather than `pkt_len` in this routine. >>>>>>>>>>> Bill Fischofer(Bill-Fischofer-Linaro) wrote: >>>>>>>>>>> Does pcapng not supply a `.h` file for these "magic numbers" and >>>>>>>>>>> associated structs? >>>>>>>>>>>> Ilias Apalodimas(apalos) wrote: >>>>>>>>>>>> Will fix. This will also remove the requirement of manually >>>>>>>>>>>> deleting the fifos >>>>>>>>>>>>> muvarov wrote >>>>>>>>>>>>> odp_global_data_s->main_pid needs to be here. https://github.com/Linaro/odp/pull/435#discussion_r166085233 updated_at 2018-02-05 19:25:22