Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exanic-capture support for up-to 8 interfaces simultaniously, support for static UTC offset #2

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
147 changes: 93 additions & 54 deletions util/exanic-capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#include "pcap-structures.h"

typedef enum
typedef enum
{
FORMAT_PCAP = 0,
FORMAT_ERF = 1,
Expand Down Expand Up @@ -456,23 +456,34 @@ 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;
exanic_cycles_t utc_offset_cycles;
};

#define EXA_MAX_IFACES 8

int main(int argc, char *argv[])
{
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;
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;
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;
Expand All @@ -481,12 +492,30 @@ int main(int argc, char *argv[])
char file_name_buf[4096];
int c;

while ((c = getopt(argc, argv, "i:w:s:C:F:pHNh?")) != -1)
memset(&rx_ctxs, 0, sizeof(rx_ctxs));

while ((c = getopt(argc, argv, "i:w:s:C:F:U:pHNh?")) != -1)
{
switch (c)
{
case 'i':
interface = optarg;
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
&&
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;
Expand All @@ -507,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;
Expand All @@ -521,16 +553,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)
Expand All @@ -554,58 +579,67 @@ 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;
}

rx_ctxs[i].utc_offset_cycles = rx_ctxs[i].exanic->tick_hz * utc_offset_sec;
}

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;
}

/* 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),
&timestamp, &status);

if (rx_size < 0 && status == EXANIC_RX_FRAME_OK)
{
rx_ctx_idx = (rx_ctx_idx + 1) % rx_ctxs_no;
continue;
}

/* Get timestamp */
if (rx_size > 0 && hw_tstamp)
{
const uint64_t timestamp64 = exanic_expand_timestamp(exanic, timestamp);
exanic_cycles_to_timespecps(exanic, timestamp64, &tsps);
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
{
Expand Down Expand Up @@ -644,7 +678,7 @@ int main(int argc, char *argv[])
snaplen, savefp);
else if (file_format == FORMAT_ERF)
file_size += write_erf_packet(rx_buf, rx_size, &tsps,
port_number,
rx_ctxs[rx_ctx_idx].port_number,
snaplen, savefp);
if (flush)
fflush(savefp);
Expand Down Expand Up @@ -694,38 +728,43 @@ 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_ctxs[i].rx);

if (rx_ctxs[i].exanic)
exanic_release_handle(rx_ctxs[i].exanic);
}
err_acquire_handle:
if (savefp != NULL)
fclose(savefp);
err_open_savefile:
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");
fprintf(stderr, " -w: dump frames to given file in specified format (- for stdout)\n");
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");
Expand Down