Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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