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

[WIP/RFC] [skip ci] Add initial implementation for pcap-openvizsla module #840

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,18 @@ if(NOT DISABLE_TC)
endif()
endif()

#
# OpenVizsla
#
pkg_check_modules(OPENVIZSLA openvizsla)
if(OPENVIZSLA_FOUND)
set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-openvizsla.c)
include_directories(AFTER ${OPENVIZSLA_INCLUDE_DIRS})
link_directories(AFTER ${OPENVIZSLA_LIBRARY_DIRS})
set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${OPENVIZSLA_LIBRARIES})
set(PCAP_SUPPORT_OPENVIZSLA TRUE)
endif(OPENVIZSLA_FOUND)

#
# Remote capture support.
#
Expand Down
3 changes: 3 additions & 0 deletions cmakeconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@
/* target host supports RDMA sniffing */
#cmakedefine PCAP_SUPPORT_RDMASNIFF 1

/* target host supports OpenVizsla */
#cmakedefine PCAP_SUPPORT_OPENVIZSLA 1

/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1

Expand Down
33 changes: 33 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3094,6 +3094,39 @@ if test "x$enable_rdma" != "xno"; then
AC_SUBST(PCAP_SUPPORT_RDMASNIFF)
fi

AC_ARG_ENABLE([openvizsla],
[AC_HELP_STRING([--enable-openvizsla],[enable OpenVizsla support @<:@default=yes, if support available@:>@])],
[],
[enable_openvizsla=ifavailable])

if test "xxx_only" = yes; then
# User requested something-else-only pcap, so they don't
# want OpenVizsla support.
enable_openvizsla=no
fi

if test "x$enable_openvizsla" != "xno"; then
if test "x$PKGCONFIG" != "xno"; then
AC_MSG_CHECKING([for libopenvizsla])
if "$PKGCONFIG" openvizsla; then
AC_MSG_RESULT([yes])
OPENVIZSLA_CFLAGS=`"$PKGCONFIG" --cflags openvizsla`
OPENVIZSLA_LIBS=`"$PKGCONFIG" --libs openvizsla`
CFLAGS="$CFLAGS $OPENVIZSLA_CFLAGS"
LIBS="$LIBS $OPENVIZSLA_LIBS"
MODULE_C_SRC="$MODULE_C_SRC pcap-openvizsla.c"

AC_DEFINE(PCAP_SUPPORT_OPENVIZSLA, 1, [support OpenVizsla])
else
AC_MSG_RESULT([no])
if test "x$enable_openvizsla" = "xyes"; then
AC_MSG_ERROR([--enable-openvizsla was given, but the openvizsla package is not installed])
fi
fi
fi
AC_SUBST(PCAP_SUPPORT_OPENVIZSLA)
fi

#
# If this is a platform where we need to have the .pc file and
# pcap-config script supply an rpath option to specify the directory
Expand Down
208 changes: 208 additions & 0 deletions pcap-openvizsla.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "pcap-int.h"
#include "pcap-openvizsla.h"

#include <openvizsla.h>

#define OPENVIZSLA_IFACE "openvizsla"

struct pcap_openvizsla {
enum ov_usb_speed usb_speed;
struct ov_device* ov;
};

struct pcap_openvizsla_read {
pcap_handler callback;
u_char *user;
};

static void openvizsla_read_cb(struct ov_packet* packet, void* data) {
struct pcap_openvizsla_read* r = (struct pcap_openvizsla_read*)data;

struct pcap_pkthdr pkth;
pkth.caplen = ov_to_host_16(packet->size) + sizeof(struct ov_packet);
pkth.len = pkth.caplen;
pkth.ts.tv_sec = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can no time stamp be supplied?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The device provides 24-bit timestamp with precision of 1/60 usec. Unfortunately, this value wraps around many times during the capture. What would be preferred way to provide best possible timestamp (combining 24-bit timestamp and the host wall clock)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the 24-bit timestamp goes back to zero about 3.58 times per second, is that correct? (If yes, then just a combination of UNIX time and the 24-bit timestamp does not tell the exact time when a packet was received, especially at less then 3.58 packets per second, it needs to be something else.)

Is there any way to keep the 24-bit timestamp in sync with the host clock, such as sending a pulse to the device every second or a fraction of a second?

Copy link
Contributor Author

@matwey matwey Sep 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. I think that the simplest way would be to use host receive UNIX timestamp and keep the counter as is.

pkth.ts.tv_usec = 0;

r->callback(r->user, &pkth, (const u_char*)packet);
}

static int openvizsla_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
{
struct pcap_openvizsla* handlep = handle->priv;
struct pcap_openvizsla_read r;

r.callback = callback;
r.user = user;

int ret = 0;

if ((ret = ov_capture_start(handlep->ov, handle->buffer, handle->bufsize, openvizsla_read_cb, &r)) < 0) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't start capture: %s", ov_get_error_string(handlep->ov));
return PCAP_ERROR;
}

if ((ret = ov_capture_dispatch(handlep->ov, max_packets)) < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way in which the callback routine can break out of the loop? If, for example, a callback routine calls pcap_breakloop(), that should cause pcap_loop() or pcap_breakloop() not to process any more packets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

breakloop_op implementation has been added.

if (handle->break_loop) {
handle->break_loop = 0;

ov_capture_stop(handlep->ov);

return PCAP_ERROR_BREAK;
}

snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"An error occured during capturing: %s", ov_get_error_string(handlep->ov));
return PCAP_ERROR;
}

ov_capture_stop(handlep->ov);

return ret;
}

static void openvizsla_cleanup(pcap_t* handle)
{
struct pcap_openvizsla* handlep = handle->priv;

ov_free(handlep->ov);
pcap_cleanup_live_common(handle);
}

static void openvizsla_breakloop(pcap_t* handle)
{
struct pcap_openvizsla* handlep = handle->priv;

ov_capture_breakloop(handlep->ov);
pcap_breakloop_common(handle);
}

static int openvizsla_activate(pcap_t* handle)
{
struct pcap_openvizsla* handlep = handle->priv;
int ret = 0;

if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
handle->snapshot = MAXIMUM_SNAPLEN;

handle->bufsize = handle->snapshot;
handle->offset = 0;
handle->linktype = DLT_OPENVIZSLA;
handle->buffer = malloc(handle->bufsize);
if (!handle->buffer) {
pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, "malloc");
goto fail_buffer_malloc;
}

handle->cleanup_op = openvizsla_cleanup;
handle->read_op = openvizsla_read;
handle->setfilter_op = install_bpf_program; /* no kernel filtering */
handle->breakloop_op = openvizsla_breakloop;

handlep->ov = ov_new(NULL);
if (!handlep->ov) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't create OpenVizsla device handler");
goto fail_ov_init;
}

ret = ov_open(handlep->ov);
if (ret < 0) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't open device: %s", ov_get_error_string(handlep->ov));
goto fail_ov_open;
}

ret = ov_set_usb_speed(handlep->ov, handlep->usb_speed);
if (ret < 0) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't set USB speed: %s", ov_get_error_string(handlep->ov));
goto fail_ov_set_usb_speed;
}

return 0;

fail_ov_set_usb_speed:
fail_ov_open:
ov_free(handlep->ov);
fail_ov_init:
free(handle->buffer);
handle->buffer = NULL;
fail_buffer_malloc:
return PCAP_ERROR;
}

int openvizsla_findalldevs(pcap_if_list_t *devlistp, char *err_str)
{
/* Always find one device */
return 0;
}

pcap_t *openvizsla_create(const char *device, char *ebuf, int *is_ours)
{
const char *cp;
char *cpend;
long devnum;
pcap_t *p;
struct pcap_openvizsla* handlep;
enum ov_usb_speed usb_speed;

cp = strrchr(device, '/');
if (cp == NULL)
cp = device;

if (strncmp(cp, OPENVIZSLA_IFACE, sizeof (OPENVIZSLA_IFACE - 1)) != 0) {
*is_ours = 0;
return NULL;
}

cp += sizeof OPENVIZSLA_IFACE - 1;
devnum = strtol(cp, &cpend, 10);
if (cpend == cp) {
*is_ours = 0;
return NULL;
}
if (devnum < 0) {
*is_ours = 0;
return NULL;
}

switch (*cpend) {
case '\0': /* Fallback to 'l' */
case 'l': {
usb_speed = OV_LOW_SPEED;
} break;
case 'f': {
usb_speed = OV_FULL_SPEED;
} break;
case 'h': {
usb_speed = OV_HIGH_SPEED;
} break;
default: {
*is_ours = 0;
return NULL;
}
}

*is_ours = 1;

p = PCAP_CREATE_COMMON(ebuf, struct pcap_openvizsla);
if (p == NULL)
return NULL;

p->activate_op = openvizsla_activate;

handlep = p->priv;
handlep->usb_speed = usb_speed;

return p;
}
5 changes: 5 additions & 0 deletions pcap-openvizsla.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
* Prototypes for OpenVizsla-related functions
*/
int openvizsla_findalldevs(pcap_if_list_t *devlistp, char *err_str);
pcap_t *openvizsla_create(const char *device, char *ebuf, int *is_ours);
7 changes: 7 additions & 0 deletions pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ struct rtentry; /* declarations in <net/if.h> */
#include "pcap-airpcap.h"
#endif

#ifdef PCAP_SUPPORT_OPENVIZSLA
#include "pcap-openvizsla.h"
#endif

#ifdef _WIN32
/*
* To quote the WSAStartup() documentation:
Expand Down Expand Up @@ -697,6 +701,9 @@ static struct capture_source_type {
#endif
#ifdef HAVE_AIRPCAP_API
{ airpcap_findalldevs, airpcap_create },
#endif
#ifdef PCAP_SUPPORT_OPENVIZSLA
{ openvizsla_findalldevs, openvizsla_create },
#endif
{ NULL, NULL }
};
Expand Down