diff --git a/config.ini b/config.ini index 304f89ad6..416867629 100644 --- a/config.ini +++ b/config.ini @@ -98,11 +98,16 @@ nb_bond=0 # Each core write into own pcap file, which is open one time, close one time if enough. # Support dump the first snaplen bytes of each packet. # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. +# timestamp_precision: 0 = microseconds (default, standard pcap magic 0xA1B2C3D4), +# 1 = nanoseconds (nanosecond pcap magic 0xA1B23C4D). +# Nanosecond mode uses clock_gettime(CLOCK_REALTIME) for ns-level timestamps. +# Wireshark and tcpdump >= 4.0 can parse nanosecond pcap files automatically. [pcap] enable=0 snaplen=96 savelen=16777216 savepath=. +timestamp_precision=0 # Port config section # Correspond to dpdk.port_list's index: port0, port1... diff --git a/lib/ff_config.c b/lib/ff_config.c index 14c193a3b..191c6589f 100644 --- a/lib/ff_config.c +++ b/lib/ff_config.c @@ -1033,6 +1033,8 @@ ini_parse_handler(void* user, const char* section, const char* name, pconfig->pcap.enable = (uint16_t)atoi(value); } else if (strcmp(name, "savepath") == 0) { pconfig->pcap.save_path = strdup(value); + } else if (strcmp(name, "timestamp_precision") == 0) { + pconfig->pcap.timestamp_precision = (uint8_t)atoi(value); } } else if (strcmp(section, "rss_check") == 0) { return rss_check_cfg_handler(pconfig, section, name, value); diff --git a/lib/ff_config.h b/lib/ff_config.h index 52c4729f8..f462b0761 100644 --- a/lib/ff_config.h +++ b/lib/ff_config.h @@ -338,6 +338,7 @@ struct ff_config { uint16_t snap_len; uint32_t save_len; char* save_path; + uint8_t timestamp_precision; /* 0=usec (default), 1=nsec */ } pcap; }; diff --git a/lib/ff_dpdk_if.c b/lib/ff_dpdk_if.c index 162cc4bdc..ed9e79d7e 100644 --- a/lib/ff_dpdk_if.c +++ b/lib/ff_dpdk_if.c @@ -317,7 +317,7 @@ init_lcore_conf(void) /* Enable pcap dump */ if (ff_global_cfg.pcap.enable) { - ff_enable_pcap(ff_global_cfg.pcap.save_path, ff_global_cfg.pcap.snap_len); + ff_enable_pcap(ff_global_cfg.pcap.save_path, ff_global_cfg.pcap.snap_len, ff_global_cfg.pcap.timestamp_precision); } lcore_conf.nb_queue_list[port_id] = pconf->nb_lcores; @@ -1651,7 +1651,7 @@ process_packets(uint16_t port_id, uint16_t queue_id, struct rte_mbuf **bufs, if (unlikely( ff_global_cfg.pcap.enable)) { if (!pkts_from_ring) { - ff_dump_packets( ff_global_cfg.pcap.save_path, rtem, ff_global_cfg.pcap.snap_len, ff_global_cfg.pcap.save_len); + ff_dump_packets(ff_global_cfg.pcap.save_path, rtem, ff_global_cfg.pcap.snap_len, ff_global_cfg.pcap.save_len, ff_global_cfg.pcap.timestamp_precision); } } @@ -2048,8 +2048,8 @@ send_burst(struct lcore_conf *qconf, uint16_t n, uint8_t port) if (unlikely(ff_global_cfg.pcap.enable)) { uint16_t i; for (i = 0; i < n; i++) { - ff_dump_packets( ff_global_cfg.pcap.save_path, m_table[i], - ff_global_cfg.pcap.snap_len, ff_global_cfg.pcap.save_len); + ff_dump_packets(ff_global_cfg.pcap.save_path, m_table[i], + ff_global_cfg.pcap.snap_len, ff_global_cfg.pcap.save_len, ff_global_cfg.pcap.timestamp_precision); } } diff --git a/lib/ff_dpdk_pcap.c b/lib/ff_dpdk_pcap.c index 59b90ff40..7615eb8ea 100644 --- a/lib/ff_dpdk_pcap.c +++ b/lib/ff_dpdk_pcap.c @@ -25,12 +25,15 @@ */ #include +#include #include #include #include "ff_dpdk_pcap.h" #define FILE_PATH_LEN 64 #define PCAP_FILE_NUM 10 +#define PCAP_MAGIC_USEC 0xA1B2C3D4 +#define PCAP_MAGIC_NSEC 0xA1B23C4D struct pcap_file_header { uint32_t magic; @@ -44,7 +47,7 @@ struct pcap_file_header { struct pcap_pkthdr { uint32_t sec; /* time stamp */ - uint32_t usec; /* struct timeval time_t, in linux64: 8*2=16, in cap: 4 */ + uint32_t usec_or_nsec; /* usec when magic=0xA1B2C3D4, nsec when magic=0xA1B23C4D */ uint32_t caplen; /* length of portion present */ uint32_t len; /* length this packet (off wire) */ }; @@ -53,7 +56,7 @@ static __thread FILE* g_pcap_fp = NULL; static __thread uint32_t seq = 0; static __thread uint32_t g_flen = 0; -int ff_enable_pcap(const char* dump_path, uint16_t snap_len) +int ff_enable_pcap(const char* dump_path, uint16_t snap_len, uint8_t timestamp_precision) { char pcap_f_path[FILE_PATH_LEN] = {0}; @@ -68,7 +71,7 @@ int ff_enable_pcap(const char* dump_path, uint16_t snap_len) struct pcap_file_header pcap_file_hdr; void* file_hdr = &pcap_file_hdr; - pcap_file_hdr.magic = 0xA1B2C3D4; + pcap_file_hdr.magic = timestamp_precision ? PCAP_MAGIC_NSEC : PCAP_MAGIC_USEC; pcap_file_hdr.version_major = 0x0002; pcap_file_hdr.version_minor = 0x0004; pcap_file_hdr.thiszone = 0x00000000; @@ -83,21 +86,30 @@ int ff_enable_pcap(const char* dump_path, uint16_t snap_len) } int -ff_dump_packets(const char* dump_path, struct rte_mbuf* pkt, uint16_t snap_len, uint32_t f_maxlen) +ff_dump_packets(const char* dump_path, struct rte_mbuf* pkt, uint16_t snap_len, uint32_t f_maxlen, uint8_t timestamp_precision) { unsigned int out_len = 0, wr_len = 0; struct pcap_pkthdr pcap_hdr; void* hdr = &pcap_hdr; - struct timeval ts; char pcap_f_path[FILE_PATH_LEN] = {0}; if (g_pcap_fp == NULL) { return -1; } snap_len = pkt->pkt_len < snap_len ? pkt->pkt_len : snap_len; - gettimeofday(&ts, NULL); - pcap_hdr.sec = ts.tv_sec; - pcap_hdr.usec = ts.tv_usec; + + if (timestamp_precision) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + pcap_hdr.sec = ts.tv_sec; + pcap_hdr.usec_or_nsec = ts.tv_nsec; + } else { + struct timeval ts; + gettimeofday(&ts, NULL); + pcap_hdr.sec = ts.tv_sec; + pcap_hdr.usec_or_nsec = ts.tv_usec; + } + pcap_hdr.caplen = snap_len; pcap_hdr.len = pkt->pkt_len; fwrite(hdr, sizeof(struct pcap_pkthdr), 1, g_pcap_fp); @@ -117,7 +129,7 @@ ff_dump_packets(const char* dump_path, struct rte_mbuf* pkt, uint16_t snap_len, if ( ++seq >= PCAP_FILE_NUM ) seq = 0; - ff_enable_pcap(dump_path, snap_len); + ff_enable_pcap(dump_path, snap_len, timestamp_precision); } return 0; diff --git a/lib/ff_dpdk_pcap.h b/lib/ff_dpdk_pcap.h index 42399f682..6a6369019 100644 --- a/lib/ff_dpdk_pcap.h +++ b/lib/ff_dpdk_pcap.h @@ -30,8 +30,8 @@ #include #include -int ff_enable_pcap(const char* dump_path, uint16_t snap_len); -int ff_dump_packets(const char* dump_path, struct rte_mbuf *pkt, uint16_t snap_len, uint32_t f_maxlen); +int ff_enable_pcap(const char* dump_path, uint16_t snap_len, uint8_t timestamp_precision); +int ff_dump_packets(const char* dump_path, struct rte_mbuf *pkt, uint16_t snap_len, uint32_t f_maxlen, uint8_t timestamp_precision); #endif /* ifndef _FSTACK_DPDK_PCAP_H */