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

add -w output.pcap command line option to direct the output to a pcap #853

Merged
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
161 changes: 100 additions & 61 deletions src/common/sendpacket.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* injection method, then by all means add it here (and send me a patch).
*
* Anyways, long story short, for now the order of preference is:
* 0. pcap_dump
* 1. TX_RING
* 2. PF_PACKET
* 3. BPF
Expand Down Expand Up @@ -223,6 +224,7 @@
#undef INJECT_METHOD
#define INJECT_METHOD "pcap_sendpacket()"
#endif
static sendpacket_t *sendpacket_open_pcap_dump(const char *, char *) _U_;
#ifdef HAVE_LIBXDP
#include <sys/mman.h>
static sendpacket_t *sendpacket_open_xsk(const char *, char *) _U_;
Expand Down Expand Up @@ -457,7 +459,12 @@

break;

case SP_TYPE_LIBPCAP_DUMP:
pcap_dump((u_char *)sp->handle.dump.dump, pkthdr, data);
retcode = len;
break;

case SP_TYPE_NETMAP:

Check warning on line 467 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:467:5 [bugprone-branch-clone]

switch has 2 consecutive identical branches
#ifdef HAVE_NETMAP
retcode = sendpacket_send_netmap(sp, data, len);

Expand Down Expand Up @@ -536,62 +543,60 @@

errbuf[0] = '\0';

#ifdef HAVE_TUNTAP
snprintf(sys_dev_dir, sizeof(sys_dev_dir), "/sys/class/net/%s/", device);
device_exists = access(sys_dev_dir, R_OK) == 0;
#endif

/* khial is universal */
if (stat(device, &sdata) == 0) {
if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
sp = sendpacket_open_khial(device, errbuf);

} else {
switch (sdata.st_mode & S_IFMT) {
case S_IFBLK:
errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
case S_IFDIR:
errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
case S_IFIFO:
errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
case S_IFLNK:
errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
case S_IFREG:
errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
default:
errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
if (sendpacket_type == SP_TYPE_LIBPCAP_DUMP){
sp =

(device, errbuf);
}else{
#ifdef HAVE_TUNTAP
snprintf(sys_dev_dir, sizeof(sys_dev_dir), "/sys/class/net/%s/", device);
device_exists = access(sys_dev_dir, R_OK) == 0;
#endif

/* khial is universal */
if (stat(device, &sdata) == 0) {
if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
sp = sendpacket_open_khial(device, errbuf);

Check warning on line 559 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:559:22 [performance-no-int-to-ptr]

integer to pointer cast pessimizes optimization opportunities

} else {
switch (sdata.st_mode & S_IFMT) {
case S_IFBLK:
errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
case S_IFDIR:
errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
case S_IFIFO:
errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
case S_IFLNK:
errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
case S_IFREG:
errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
default:
errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
}
}
}
#ifdef HAVE_TUNTAP
} else if (strncmp(device, "tap", 3) == 0 && !device_exists) {
sp = sendpacket_open_tuntap(device, errbuf);
#endif
} else {
#ifdef HAVE_NETMAP
if (sendpacket_type == SP_TYPE_NETMAP)
sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
else
#endif
#ifdef HAVE_LIBXDP
if (sendpacket_type == SP_TYPE_LIBXDP)
sp = sendpacket_open_xsk(device, errbuf);
else
#endif
#if defined HAVE_PF_PACKET
sp = sendpacket_open_pf(device, errbuf);
#elif defined HAVE_BPF
#ifdef HAVE_TUNTAP
} else if (strncmp(device, "tap", 3) == 0 && !device_exists) {
sp = sendpacket_open_tuntap(device, errbuf);
#endif
} else {
#ifdef HAVE_NETMAP
if (sendpacket_type == SP_TYPE_NETMAP)
sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
else
#endif
#if defined HAVE_PF_PACKET
sp = sendpacket_open_pf(device, errbuf);
#elif defined HAVE_BPF
sp = sendpacket_open_bpf(device, errbuf);
#elif defined HAVE_LIBDNET
#elif defined HAVE_LIBDNET
sp = sendpacket_open_libdnet(device, errbuf);
#elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
#elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
sp = sendpacket_open_pcap(device, errbuf);
#elif defined HAVE_LIBXDP
sp = sendpacket_open_xsk(device, errbuf);
#else
#error "No defined packet injection method for sendpacket_open()"
#endif
#else
#error "No defined packet injection method for sendpacket_open()"
#endif
}
}

if (sp) {
sp->open = 1;
sp->cache_dir = direction;
Expand Down Expand Up @@ -679,6 +684,11 @@
#endif
break;

case SP_TYPE_LIBPCAP_DUMP:
pcap_dump_close(sp->handle.dump.dump);
pcap_close(sp->handle.dump.pcap);
break;

case SP_TYPE_LIBDNET:
#ifdef HAVE_LIBDNET
eth_close(sp->handle.ldnet);
Expand Down Expand Up @@ -726,6 +736,9 @@

if (sp->handle_type == SP_TYPE_KHIAL) {
addr = sendpacket_get_hwaddr_khial(sp);
} else if( sp->handle_type == SP_TYPE_LIBPCAP_DUMP) {
sendpacket_seterr(sp, "Error: sendpacket_get_hwaddr() not yet supported for pcap dump");
Copy link
Member

Choose a reason for hiding this comment

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

This will need to get implemented.

Copy link
Author

@jasonlue jasonlue Jun 4, 2024

Choose a reason for hiding this comment

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

I think sendpacket_get_hwaddr() only makes sense for real interfaces. Pcap file as an output doesn't support sendpacket_get_hwaddr. The err msg is misleading.

Copy link
Member

@fklassen fklassen Jun 4, 2024

Choose a reason for hiding this comment

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

OK, I still have this in staging and will investigate. I'll probably just change the error message. I may get 4.5.0-beta1 out before this merges so that the testers can have some time to shake out the bugs.

return NULL;
} else {
#if defined HAVE_PF_PACKET
addr = sendpacket_get_hwaddr_pf(sp);
Expand Down Expand Up @@ -824,6 +837,37 @@
}
#endif /* HAVE_PCAP_INJECT || HAVE_PCAP_SENDPACKET */

/**
* Inner sendpacket_open() method for using libpcap
*/
static sendpacket_t *
sendpacket_open_pcap_dump(const char *device, char *errbuf)
{
pcap_t *pcap;
pcap_dumper_t* dump;
sendpacket_t *sp;

Check warning on line 848 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:848:19 [cppcoreguidelines-init-variables]

variable 'sp' is not initialized

Check warning on line 848 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:848:19 [readability-identifier-length]

variable name 'sp' is too short, expected at least 3 characters

assert(device);
assert(errbuf);

dbg(1, "sendpacket: using Libpcap");

pcap = pcap_open_dead(DLT_EN10MB, 65535);
if ((dump = pcap_dump_open(pcap, device)) == NULL){
char* err_msg = pcap_geterr(pcap);

Check warning on line 857 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:857:15 [cppcoreguidelines-init-variables]

variable 'err_msg' is not initialized
strlcpy(errbuf, err_msg, PCAP_ERRBUF_SIZE);
pcap_close(pcap);
return NULL;
}

sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));

Check warning on line 863 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:863:10 [performance-no-int-to-ptr]

integer to pointer cast pessimizes optimization opportunities
strlcpy(sp->device, device, sizeof(sp->device));
sp->handle.dump.pcap = pcap;
sp->handle.dump.dump = dump;
sp->handle_type = SP_TYPE_LIBPCAP_DUMP;
return sp;
}

#if defined HAVE_LIBDNET && !defined HAVE_PF_PACKET && !defined HAVE_BPF
/**
* Inner sendpacket_open() method for using libdnet
Expand Down Expand Up @@ -1260,16 +1304,11 @@
{
int dlt = DLT_EN10MB;

switch (sp->handle_type) {
case SP_TYPE_KHIAL:
case SP_TYPE_NETMAP:
case SP_TYPE_TUNTAP:
case SP_TYPE_LIBXDP:
/* always EN10MB */
return dlt;
default:
;
}
if (sp->handle_type == SP_TYPE_KHIAL || sp->handle_type == SP_TYPE_NETMAP || sp->handle_type == SP_TYPE_TUNTAP || sp->handle_type == SP_TYPE_LIBPCAP_DUMP) {

Check warning on line 1307 in src/common/sendpacket.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.c:1307:5 [bugprone-branch-clone]

if with identical then and else branches
/* always EN10MB */
} else {
#if defined HAVE_BPF
int rcode;

#if defined HAVE_BPF
if ((ioctl(sp->handle.fd, BIOCGDLT, &dlt)) < 0) {
Expand Down
7 changes: 7 additions & 0 deletions src/common/sendpacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#pragma once

#include "defines.h"

Check failure on line 23 in src/common/sendpacket.h

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/sendpacket.h:23:10 [clang-diagnostic-error]

'defines.h' file not found
#include "config.h"
#include <sys/socket.h>

Expand Down Expand Up @@ -68,6 +68,7 @@
SP_TYPE_KHIAL,
SP_TYPE_NETMAP,
SP_TYPE_TUNTAP,
SP_TYPE_LIBPCAP_DUMP
SP_TYPE_LIBXDP
} sendpacket_type_t;

Expand All @@ -81,8 +82,14 @@
KHIAL_DIRECTION_TX,
} khial_direction_t;

typedef struct pcap_dump_s{
pcap_t *pcap;
pcap_dumper_t* dump;
} pcap_dump_t;

union sendpacket_handle {
pcap_t *pcap;
pcap_dump_t dump;
int fd;
#ifdef HAVE_LIBDNET
eth_t *ldnet;
Expand Down
135 changes: 77 additions & 58 deletions src/tcpreplay_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
* returns 0 on success, and -1 on error & -2 on warning.
*/
int
tcpreplay_post_args(tcpreplay_t *ctx, int argc)

Check warning on line 144 in src/tcpreplay_api.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/tcpreplay_api.c:144:1 [readability-function-cognitive-complexity]

function 'tcpreplay_post_args' has cognitive complexity of 88 (threshold 25)
{
char *temp, *intname;
char *ebuf;
Expand Down Expand Up @@ -338,76 +338,95 @@
tcpreplay_setwarn(ctx, "%s", "--pktlen may cause problems. Use with caution.");
}

if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF1))) == NULL) {
if (!strncmp(OPT_ARG(INTF1), "netmap:", 7) || !strncmp(OPT_ARG(INTF1), "vale", 4))
tcpreplay_seterr(ctx, "Unable to connect to netmap interface %s. Ensure netmap module is installed (see INSTALL).",
OPT_ARG(INTF1));
else
tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1));
switch (WHICH_IDX_INTF1){
case INDEX_OPT_WRITE:
options->intf1_name = safe_strdup(OPT_ARG(INTF1));
ctx->sp_type = SP_TYPE_LIBPCAP_DUMP;
/* open interfaces for writing */
if ((ctx->intf1 = sendpacket_open(options->intf1_name, ebuf, TCPR_DIR_C2S, ctx->sp_type, ctx)) == NULL) {
tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf1_name, ebuf);
ret = -1;
goto out;
}
break;

case INDEX_OPT_INTF1:
if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF1))) == NULL) {
if (!strncmp(OPT_ARG(INTF1), "netmap:", 7) || !strncmp(OPT_ARG(INTF1), "vale", 4))
tcpreplay_seterr(ctx, "Unable to connect to netmap interface %s. Ensure netmap module is installed (see INSTALL).",
OPT_ARG(INTF1));
else
tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1));

ret = -1;
goto out;
}

ret = -1;
goto out;
}
if (!strncmp(intname, "netmap:", 7) || !strncmp(intname, "vale:", 5)) {
#ifdef HAVE_NETMAP
options->netmap = 1;
ctx->sp_type = SP_TYPE_NETMAP;
#else
tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with netmap support");
ret = -1;
goto out;
#endif
}

if (!strncmp(intname, "netmap:", 7) || !strncmp(intname, "vale:", 5)) {
#ifdef HAVE_NETMAP
options->netmap = 1;
ctx->sp_type = SP_TYPE_NETMAP;
#else
tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with netmap support");
ret = -1;
goto out;
#endif
}
options->intf1_name = safe_strdup(intname);

options->intf1_name = safe_strdup(intname);
/* open interfaces for writing */
if ((ctx->intf1 = sendpacket_open(options->intf1_name, ebuf, TCPR_DIR_C2S, ctx->sp_type, ctx)) == NULL) {
tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf1_name, ebuf);
ret = -1;
goto out;
}

/* open interfaces for writing */
if ((ctx->intf1 = sendpacket_open(options->intf1_name, ebuf, TCPR_DIR_C2S, ctx->sp_type, ctx)) == NULL) {
tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf1_name, ebuf);
ret = -1;
goto out;
}
#ifdef HAVE_LIBXDP
ctx->intf1->batch_size = OPT_VALUE_XDP_BATCH_SIZE;
#endif
#if defined HAVE_NETMAP
ctx->intf1->netmap_delay = ctx->options->netmap_delay;
ctx->intf1->batch_size = OPT_VALUE_XDP_BATCH_SIZE;
#endif
#if defined HAVE_NETMAP
ctx->intf1->netmap_delay = ctx->options->netmap_delay;
#endif

ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);
ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);

if (HAVE_OPT(INTF2)) {
if (!HAVE_OPT(CACHEFILE) && !HAVE_OPT(DUALFILE)) {
tcpreplay_seterr(ctx, "--intf2=%s requires either --cachefile or --dualfile", OPT_ARG(INTF2));
ret = -1;
goto out;
}
if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF2))) == NULL) {
tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2));
ret = -1;
goto out;
}
if (HAVE_OPT(INTF2)) {
if (!HAVE_OPT(CACHEFILE) && !HAVE_OPT(DUALFILE)) {
tcpreplay_seterr(ctx, "--intf2=%s requires either --cachefile or --dualfile", OPT_ARG(INTF2));
ret = -1;
goto out;
}
if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF2))) == NULL) {
tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2));
ret = -1;
goto out;
}

options->intf2_name = safe_strdup(intname);
options->intf2_name = safe_strdup(intname);

/* open interface for writing */
if ((ctx->intf2 = sendpacket_open(options->intf2_name, ebuf, TCPR_DIR_S2C, ctx->sp_type, ctx)) == NULL) {
tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf2_name, ebuf);
}
/* open interface for writing */
if ((ctx->intf2 = sendpacket_open(options->intf2_name, ebuf, TCPR_DIR_S2C, ctx->sp_type, ctx)) == NULL) {
tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf2_name, ebuf);
}

#if defined HAVE_NETMAP
ctx->intf2->netmap_delay = ctx->options->netmap_delay;
#endif
#if defined HAVE_NETMAP
ctx->intf2->netmap_delay = ctx->options->netmap_delay;
#endif

ctx->intf2dlt = sendpacket_get_dlt(ctx->intf2);
if (ctx->intf2dlt != ctx->intf1dlt) {
tcpreplay_seterr(ctx, "DLT type mismatch for %s (%s) and %s (%s)",
options->intf1_name, pcap_datalink_val_to_name(ctx->intf1dlt),
options->intf2_name, pcap_datalink_val_to_name(ctx->intf2dlt));
ret = -1;
goto out;
}
}
break;

ctx->intf2dlt = sendpacket_get_dlt(ctx->intf2);
if (ctx->intf2dlt != ctx->intf1dlt) {
tcpreplay_seterr(ctx, "DLT type mismatch for %s (%s) and %s (%s)",
options->intf1_name, pcap_datalink_val_to_name(ctx->intf1dlt),
options->intf2_name, pcap_datalink_val_to_name(ctx->intf2dlt));
ret = -1;
goto out;
}
default:
assert(false); //shouldn't happen!
}

if (HAVE_OPT(CACHEFILE)) {
Expand Down
Loading
Loading