From 026a575a984b094ddc09be5fe46692b336f41f51 Mon Sep 17 00:00:00 2001 From: Denis Ivaykin Date: Thu, 20 Apr 2017 00:41:07 +1000 Subject: [PATCH 1/5] prepare for multi-interface capture --- util/exanic-capture.c | 56 +++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/util/exanic-capture.c b/util/exanic-capture.c index c1ae063..adf5712 100644 --- a/util/exanic-capture.c +++ b/util/exanic-capture.c @@ -445,15 +445,23 @@ static int set_promiscuous_mode(exanic_t *exanic, int port_number, int enable) return 0; } -int main(int argc, char *argv[]) +struct exanic_capture_ctx { - const char *interface = NULL; - const char *savefile = NULL; - FILE *savefp = NULL; char device[16]; int port_number; exanic_t *exanic; exanic_rx_t *rx; +}; + +#define EXA_MAX_IFACES 8 + +int main(int argc, char *argv[]) +{ + const char *interface = NULL; + const char *savefile = NULL; + FILE *savefp = NULL; + struct exanic_capture_ctx capture_ctx[EXA_MAX_IFACES]; + int no_capture_ctxs = 0; char rx_buf[16384]; ssize_t rx_size; int status; @@ -474,7 +482,17 @@ int main(int argc, char *argv[]) switch (c) { case 'i': - interface = optarg; + if (exanic_find_port_by_interface_name( + optarg, capture_ctx[no_capture_ctxs].device, 16, &capture_ctx[no_capture_ctxs].port_number) != 0 + && + parse_device_port( + optarg, capture_ctx[no_capture_ctxs].device, &capture_ctx[no_capture_ctxs].port_number) != 0) + { + fprintf(stderr, "%s: no such interface or not an ExaNIC\n", optarg); + return 1; + } + + ++no_capture_ctxs; break; case 'w': savefile = optarg; @@ -509,16 +527,9 @@ int main(int argc, char *argv[]) } } - if (interface == NULL) + if (no_capture_ctxs == 0) goto usage_error; - if (exanic_find_port_by_interface_name(interface, device, 16, &port_number) != 0 - && parse_device_port(interface, device, &port_number) != 0) - { - fprintf(stderr, "%s: no such interface or not an ExaNIC\n", interface); - return 1; - } - if (savefile != NULL) { if (strcmp(savefile, "-") == 0) @@ -542,8 +553,10 @@ int main(int argc, char *argv[]) file_size = write_pcap_header(savefp, nsec_pcap, snaplen); } - /* Get the exanic handle */ - exanic = exanic_acquire_handle(device); + for (int i = 0; i < no_capture_ctxs; ++i) + { + /* Get the exanic handle */ + captuexanic = exanic_acquire_handle(device); if (exanic == NULL) { fprintf(stderr, "%s: %s\n", device, exanic_get_last_error()); @@ -568,17 +581,18 @@ int main(int argc, char *argv[]) set_promisc = promisc && !exanic_get_promiscuous_mode(exanic, port_number); - signal(SIGHUP, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGPIPE, signal_handler); - signal(SIGALRM, signal_handler); - signal(SIGTERM, signal_handler); - if (set_promisc) { if (set_promiscuous_mode(exanic, port_number, 1) == -1) set_promisc = 0; } + } + + signal(SIGHUP, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGPIPE, signal_handler); + signal(SIGALRM, signal_handler); + signal(SIGTERM, signal_handler); /* Start reading from the rx buffer */ while (run) From ea2bb137f66d65b953212bc7c4c1cdeb6492198a Mon Sep 17 00:00:00 2001 From: Denis Ivaykin Date: Thu, 20 Apr 2017 00:41:07 +1000 Subject: [PATCH 2/5] exanic-capture multi interface support --- util/exanic-capture.c | 127 +++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/util/exanic-capture.c b/util/exanic-capture.c index c1ae063..aa60cab 100644 --- a/util/exanic-capture.c +++ b/util/exanic-capture.c @@ -18,7 +18,7 @@ #include "pcap-structures.h" -typedef enum +typedef enum { FORMAT_PCAP = 0, FORMAT_ERF = 1, @@ -445,22 +445,32 @@ static int set_promiscuous_mode(exanic_t *exanic, int port_number, int enable) return 0; } -int main(int argc, char *argv[]) +struct exanic_rx_context { - const char *interface = NULL; - const char *savefile = NULL; - FILE *savefp = NULL; char device[16]; int port_number; exanic_t *exanic; exanic_rx_t *rx; + int set_promisc; +}; + +#define EXA_MAX_IFACES 8 + +int main(int argc, char *argv[]) +{ + const char *interface = NULL; + const char *savefile = NULL; + FILE *savefp = NULL; + struct exanic_rx_context rx_ctxs[EXA_MAX_IFACES]; + int rx_ctxs_no = 0; + int rx_ctx_idx = 0; char rx_buf[16384]; ssize_t rx_size; int status; uint32_t timestamp; struct timespec ts; int hw_tstamp = 0, nsec_pcap = 0, snaplen = sizeof(rx_buf), flush = 0; - int promisc = 1, set_promisc, filter; + int promisc = 1, filter; unsigned long rx_success = 0, rx_aborted = 0, rx_corrupt = 0, rx_hwovfl = 0, rx_swovfl = 0, rx_other = 0; file_format_type file_format = FORMAT_PCAP; @@ -469,12 +479,24 @@ int main(int argc, char *argv[]) char file_name_buf[4096]; int c; + memset(&rx_ctxs, 0, sizeof(rx_ctxs)); + while ((c = getopt(argc, argv, "i:w:s:C:F:pHNh?")) != -1) { switch (c) { case 'i': - interface = optarg; + if (exanic_find_port_by_interface_name( + optarg, rx_ctxs[rx_ctxs_no].device, 16, &rx_ctxs[rx_ctxs_no].port_number) != 0 + && + parse_device_port( + optarg, rx_ctxs[rx_ctxs_no].device, &rx_ctxs[rx_ctxs_no].port_number) != 0) + { + fprintf(stderr, "%s: no such interface or not an ExaNIC\n", optarg); + return 1; + } + + ++rx_ctxs_no; break; case 'w': savefile = optarg; @@ -509,16 +531,9 @@ int main(int argc, char *argv[]) } } - if (interface == NULL) + if (rx_ctxs_no == 0) goto usage_error; - if (exanic_find_port_by_interface_name(interface, device, 16, &port_number) != 0 - && parse_device_port(interface, device, &port_number) != 0) - { - fprintf(stderr, "%s: no such interface or not an ExaNIC\n", interface); - return 1; - } - if (savefile != NULL) { if (strcmp(savefile, "-") == 0) @@ -542,31 +557,40 @@ int main(int argc, char *argv[]) file_size = write_pcap_header(savefp, nsec_pcap, snaplen); } - /* Get the exanic handle */ - exanic = exanic_acquire_handle(device); - if (exanic == NULL) + for (int i = 0; i < rx_ctxs_no; ++i) { - fprintf(stderr, "%s: %s\n", device, exanic_get_last_error()); - goto err_acquire_handle; - } + /* Get the exanic handle */ + rx_ctxs[i].exanic = exanic_acquire_handle(rx_ctxs[i].device); + if (rx_ctxs[i].exanic == NULL) + { + fprintf(stderr, "%s: %s\n", rx_ctxs[i].device, exanic_get_last_error()); + goto err_acquire_handle; + } - filter = optind < argc; - if (filter) - rx = exanic_acquire_unused_filter_buffer(exanic, port_number); - else - rx = exanic_acquire_rx_buffer(exanic, port_number, 0); + filter = optind < argc; + if (filter) + rx_ctxs[i].rx = exanic_acquire_unused_filter_buffer(rx_ctxs[i].exanic, rx_ctxs[i].port_number); + else + rx_ctxs[i].rx = exanic_acquire_rx_buffer(rx_ctxs[i].exanic, rx_ctxs[i].port_number, 0); - if (rx == NULL) - { - fprintf(stderr, "%s:%d: %s\n", device, port_number, - exanic_get_last_error()); - goto err_acquire_rx; - } + if (rx_ctxs[i].rx == NULL) + { + fprintf(stderr, "%s:%d: %s\n", rx_ctxs[i].device, rx_ctxs[i].port_number, + exanic_get_last_error()); + goto err_acquire_rx; + } + + if (filter && !apply_filters(rx_ctxs[i].exanic, rx_ctxs[i].rx, &argv[optind], argc-optind)) + goto err_apply_filters; - if (filter && !apply_filters(exanic, rx, &argv[optind], argc-optind)) - goto err_apply_filters; + rx_ctxs[i].set_promisc = promisc && !exanic_get_promiscuous_mode(rx_ctxs[i].exanic, rx_ctxs[i].port_number); - set_promisc = promisc && !exanic_get_promiscuous_mode(exanic, port_number); + if (rx_ctxs[i].set_promisc) + { + if (set_promiscuous_mode(rx_ctxs[i].exanic, rx_ctxs[i].port_number, 1) == -1) + rx_ctxs[i].set_promisc = 0; + } + } signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); @@ -574,25 +598,22 @@ int main(int argc, char *argv[]) signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); - if (set_promisc) - { - if (set_promiscuous_mode(exanic, port_number, 1) == -1) - set_promisc = 0; - } - /* Start reading from the rx buffer */ while (run) { - rx_size = exanic_receive_frame_ex(rx, rx_buf, sizeof(rx_buf), + rx_size = exanic_receive_frame_ex(rx_ctxs[rx_ctx_idx].rx, rx_buf, sizeof(rx_buf), ×tamp, &status); if (rx_size < 0 && status == EXANIC_RX_FRAME_OK) + { + rx_ctx_idx = (++rx_ctx_idx) % rx_ctxs_no; continue; + } /* Get timestamp */ if (rx_size > 0 && hw_tstamp) { - uint64_t counter = exanic_timestamp_to_counter(exanic, timestamp); + uint64_t counter = exanic_timestamp_to_counter(rx_ctxs[rx_ctx_idx].exanic, timestamp); ts.tv_sec = counter / 1000000000; ts.tv_nsec = counter % 1000000000; } @@ -631,7 +652,7 @@ int main(int argc, char *argv[]) snaplen, savefp); else if (file_format == FORMAT_ERF) file_size += write_erf_packet(rx_buf, rx_size, &ts, - port_number, + rx_ctxs[rx_ctx_idx].port_number, snaplen, savefp); if (flush) fflush(savefp); @@ -681,23 +702,27 @@ int main(int argc, char *argv[]) rx_other++; } - if (set_promisc) - set_promiscuous_mode(exanic, port_number, 0); - fprintf(stderr, "%s: received=%lu corrupt=%lu aborted=%lu hw_lost=%lu sw_lost=%lu other=%lu\n", argv[0], rx_success, rx_corrupt, rx_aborted, rx_hwovfl, rx_swovfl, rx_other); - exanic_release_rx_buffer(rx); - exanic_release_handle(exanic); if (savefp != NULL) fclose(savefp); return 0; err_open_next_file: err_apply_filters: - exanic_release_rx_buffer(rx); err_acquire_rx: - exanic_release_handle(exanic); + for (int i = 0; i < rx_ctxs_no; ++i) + { + if (rx_ctxs[i].set_promisc && rx_ctxs[i].exanic) + set_promiscuous_mode(rx_ctxs[i].exanic, rx_ctxs[i].port_number, 0); + + if (rx_ctxs[i].rx) + exanic_release_rx_buffer(rx); + + if (rx_ctxs[i].exanic) + exanic_release_handle(exanic); + } err_acquire_handle: if (savefp != NULL) fclose(savefp); From 8488f3dd74a13205326ae4f72ddaadf12b3f43d3 Mon Sep 17 00:00:00 2001 From: Denis Ivaykin Date: Thu, 20 Apr 2017 23:12:38 +1000 Subject: [PATCH 3/5] check for max interfaces --- util/exanic-capture.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/util/exanic-capture.c b/util/exanic-capture.c index 370144b..04a1eb1 100644 --- a/util/exanic-capture.c +++ b/util/exanic-capture.c @@ -498,6 +498,12 @@ int main(int argc, char *argv[]) switch (c) { case 'i': + if (rx_ctxs_no >= EXA_MAX_IFACES) + { + fprintf(stderr, "maximum interfaces supported: %d\n", EXA_MAX_IFACES); + return 1; + } + if (exanic_find_port_by_interface_name( optarg, rx_ctxs[rx_ctxs_no].device, 16, &rx_ctxs[rx_ctxs_no].port_number) != 0 && @@ -743,7 +749,7 @@ int main(int argc, char *argv[]) return 1; usage_error: - fprintf(stderr, "Usage: %s -i interface\n", argv[0]); + fprintf(stderr, "Usage: %s -i interface...\n", argv[0]); fprintf(stderr, " [-w savefile] [-s snaplen] [-C file_size]\n"); fprintf(stderr, " [-F file_format] [-p] [-H] [-N] [filter...]\n"); fprintf(stderr, " -i: specify Linux interface (e.g. eth0) or ExaNIC port name (e.g. exanic0:0)\n"); From bef90b44c622eed44b2be2325ea3de02a2d85878 Mon Sep 17 00:00:00 2001 From: Denis Ivaykin Date: Fri, 21 Apr 2017 08:45:58 +1000 Subject: [PATCH 4/5] couple of fixes --- util/exanic-capture.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/util/exanic-capture.c b/util/exanic-capture.c index 04a1eb1..9be1a23 100644 --- a/util/exanic-capture.c +++ b/util/exanic-capture.c @@ -469,7 +469,6 @@ struct exanic_rx_context int main(int argc, char *argv[]) { - const char *interface = NULL; const char *savefile = NULL; FILE *savefp = NULL; struct exanic_rx_context rx_ctxs[EXA_MAX_IFACES]; @@ -624,7 +623,7 @@ int main(int argc, char *argv[]) if (rx_size < 0 && status == EXANIC_RX_FRAME_OK) { - rx_ctx_idx = (++rx_ctx_idx) % rx_ctxs_no; + rx_ctx_idx = (rx_ctx_idx + 1) % rx_ctxs_no; continue; } @@ -737,10 +736,10 @@ int main(int argc, char *argv[]) set_promiscuous_mode(rx_ctxs[i].exanic, rx_ctxs[i].port_number, 0); if (rx_ctxs[i].rx) - exanic_release_rx_buffer(rx); + exanic_release_rx_buffer(rx_ctxs[i].rx); if (rx_ctxs[i].exanic) - exanic_release_handle(exanic); + exanic_release_handle(rx_ctxs[i].exanic); } err_acquire_handle: if (savefp != NULL) From 16d5187458b3ee8063eee76ab152755a2d904ddb Mon Sep 17 00:00:00 2001 From: Denis Ivaykin Date: Fri, 5 May 2017 15:04:10 +1000 Subject: [PATCH 5/5] add optional UTC offset in seconds to be written to capture files --- util/exanic-capture.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/util/exanic-capture.c b/util/exanic-capture.c index 9be1a23..fd9574d 100644 --- a/util/exanic-capture.c +++ b/util/exanic-capture.c @@ -463,6 +463,7 @@ struct exanic_rx_context exanic_t *exanic; exanic_rx_t *rx; int set_promisc; + exanic_cycles_t utc_offset_cycles; }; #define EXA_MAX_IFACES 8 @@ -478,6 +479,7 @@ int main(int argc, char *argv[]) ssize_t rx_size; int status; exanic_cycles32_t timestamp; + int utc_offset_sec = 0; struct timespec ts; struct exanic_timespecps tsps; int hw_tstamp = 0, nsec_pcap = 0, snaplen = sizeof(rx_buf), flush = 0; @@ -492,7 +494,7 @@ int main(int argc, char *argv[]) memset(&rx_ctxs, 0, sizeof(rx_ctxs)); - while ((c = getopt(argc, argv, "i:w:s:C:F:pHNh?")) != -1) + while ((c = getopt(argc, argv, "i:w:s:C:F:U:pHNh?")) != -1) { switch (c) { @@ -534,6 +536,9 @@ int main(int argc, char *argv[]) else goto usage_error; break; + case 'U': + utc_offset_sec = atoi(optarg); + break; case 'p': promisc = 0; break; @@ -607,6 +612,8 @@ int main(int argc, char *argv[]) if (set_promiscuous_mode(rx_ctxs[i].exanic, rx_ctxs[i].port_number, 1) == -1) rx_ctxs[i].set_promisc = 0; } + + rx_ctxs[i].utc_offset_cycles = rx_ctxs[i].exanic->tick_hz * utc_offset_sec; } signal(SIGHUP, signal_handler); @@ -630,7 +637,8 @@ int main(int argc, char *argv[]) /* Get timestamp */ if (rx_size > 0 && hw_tstamp) { - const uint64_t timestamp64 = exanic_expand_timestamp(rx_ctxs[rx_ctx_idx].exanic, timestamp); + const uint64_t timestamp64 = exanic_expand_timestamp(rx_ctxs[rx_ctx_idx].exanic, timestamp) + + rx_ctxs[rx_ctx_idx].utc_offset_cycles; /* Add optional UTC offset in cycles */ exanic_cycles_to_timespecps(rx_ctxs[rx_ctx_idx].exanic, timestamp64, &tsps); } else @@ -756,6 +764,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " -s: maximum data length to capture\n"); fprintf(stderr, " -C: file size at which to start a new save file (in millions of bytes)\n"); fprintf(stderr, " -F: file format [pcap|erf] (default is pcap)\n"); + fprintf(stderr, " -U: UTC offset to add to hardware timestamp (in seconds)\n"); fprintf(stderr, " -p: do not attempt to put interface in promiscuous mode\n"); fprintf(stderr, " -H: use hardware timestamps (requires exanic-clock-sync or exanic-ptpd)\n"); fprintf(stderr, " -N: write nanosecond-resolution pcap format\n\n");