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

Feature #884 include exclude options #885

Merged
merged 3 commits into from
Jun 24, 2024
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
3 changes: 2 additions & 1 deletion docs/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
06/08/2024 Version 4.5.0-beta2
06/23/2024 Version 4.5.0-beta3
- tcpreplay --include / --exclude to control which packets are replayed (#884)
- add -w (--suppress-warnings) option to suppress warning messages (#878)
- AF_XDP compile issue due to merge issue (#876)
- memory leak in tcpprep when using include/exclude (#869)
Expand Down
47 changes: 24 additions & 23 deletions src/common/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* if an integer exists in the list.
*/

#include "defines.h"

Check failure on line 27 in src/common/list.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/list.c:27:10 [clang-diagnostic-error]

'defines.h' file not found
#include "config.h"
#include "common.h"
#include <regex.h>
Expand All @@ -44,6 +44,21 @@
return (newlist);
}

static void
add_to_list(tcpr_list_t *list_ptr, const char *first, const char *second)
{
list_ptr->min = strtoull(first, NULL, 0);
if (second != NULL) {
if (second[0] == '\0') {

Check warning on line 52 in src/common/list.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/list.c:52:9 [bugprone-branch-clone]

if with identical then and else branches
list_ptr->max = 0;
} else {
list_ptr->max = strtoull(second, NULL, 0);
}
} else {
list_ptr->max = list_ptr->min;
}
}

/**
* Processes a string (ourstr) containing the list in human readable
* format and places the data in **list and finally returns 1 for
Expand All @@ -57,7 +72,7 @@
char *first, *second;
int rcode;
regex_t preg;
char regex[] = "^[0-9]+(-[0-9]+)?$";
char regex[] = "^[0-9]+(-([0-9]+|\\s*))?$";
char *token = NULL;
u_int i;

Expand Down Expand Up @@ -91,12 +106,7 @@
}
}

list_ptr->min = strtoull(first, NULL, 0);
if (second != NULL) {
list_ptr->max = strtoull(second, NULL, 0);
} else {
list_ptr->max = list_ptr->min;
}
add_to_list(list_ptr, first, second);

while (1) {
this = strtok_r(NULL, ",", &token);
Expand All @@ -123,12 +133,7 @@
}
}

listcur->min = strtoull(first, NULL, 0);
if (second != NULL) {
listcur->max = strtoull(second, NULL, 0);
} else {
listcur->max = listcur->min;
}
add_to_list(listcur, first, second);
}

regfree(&preg);
Expand All @@ -144,10 +149,8 @@
check_list(tcpr_list_t *list, COUNTER value)
{
tcpr_list_t *current;
current = list;

do {
if ((current->min != 0) && (current->max != 0)) {
for (current = list; current; current = current->next) {
if (current->min != 0 && current->max != 0) {
if ((value >= current->min) && (value <= current->max))
return 1;
} else if (current->min == 0) {
Expand All @@ -157,12 +160,7 @@
if (value >= current->min)
return 1;
}

if (current->next != NULL)
current = current->next;
else
current = NULL;
} while (current != NULL);
}

return 0;
}
Expand All @@ -173,6 +171,9 @@
void
free_list(tcpr_list_t *list)
{
if (list == NULL)

Check warning on line 174 in src/common/list.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/list.c:174:22 [readability-braces-around-statements]

statement should be inside braces
return;

/* recursively go down the list */
if (list->next != NULL)
free_list(list->next);
Expand Down
21 changes: 21 additions & 0 deletions src/send_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,17 @@
now_is_now = false;
packetnum++;
#if defined TCPREPLAY || defined TCPREPLAY_EDIT
/* look for include or exclude LIST match */
if (options->list != NULL) {
bool rule_set = check_list(options->list, packetnum);
if ((rule_set && options->is_exclude) || (!rule_set && !options->is_exclude)) {
dbgx(2, "packet " COUNTER_SPEC " not sent due to %s rule",
packetnum,
options->is_exclude ? "exclude" : "include");
continue;
}
}

/* do we use the snaplen (caplen) or the "actual" packet len? */
pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr.len : (COUNTER)pkthdr.caplen;
#elif TCPBRIDGE
Expand Down Expand Up @@ -610,7 +621,7 @@
* what to do with each packet when processing two files a the same time
*/
void
send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *pcap2, int cache_file_idx2)

Check warning on line 624 in src/send_packets.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/send_packets.c:624:1 [readability-function-cognitive-complexity]

function 'send_dual_packets' has cognitive complexity of 163 (threshold 25)
{
struct timespec now, print_delta, last_pkt_ts;
tcpreplay_opt_t *options = ctx->options;
Expand Down Expand Up @@ -667,6 +678,16 @@
while (!ctx->abort && !(pktdata1 == NULL && pktdata2 == NULL)) {
now_is_now = false;
packetnum++;
/* look for include or exclude LIST match */
if (options->list != NULL) {
bool rule_set = check_list(options->list, packetnum);
if ((rule_set && options->is_exclude) || (!rule_set && !options->is_exclude)) {
dbgx(2, "packet " COUNTER_SPEC " not sent due to %s rule",
packetnum,
options->is_exclude ? "exclude" : "include");
continue;
}
}

/* figure out which pcap file we need to process next
* when get_next_packet() returns null for pktdata, the pkthdr
Expand Down
3 changes: 3 additions & 0 deletions src/tcpreplay_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ tcpreplay_close(tcpreplay_t *ctx)
intlist = intlistnext;
}
}

/* free --include / --exclude list */
free_list(options->list);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/tcpreplay_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "defines.h"
#include "config.h"
#include <common/interface.h>
#include <common/list.h>
#include <common/sendpacket.h>
#include <common/tcpdump.h>
#include <common/utils.h>
Expand Down Expand Up @@ -134,6 +135,10 @@ typedef struct tcpreplay_opt_s {
int source_cnt;
tcpreplay_source_t sources[MAX_FILES];

/* --include / --exclude flag and rules list */
bool is_exclude;
tcpr_list_t *list;

#ifdef ENABLE_VERBOSE
/* tcpdump verbose printing */
bool verbose;
Expand Down
92 changes: 78 additions & 14 deletions src/tcpreplay_opts.def
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ config-header = "config.h";

include = "#include \"defines.h\"\n"
"#include \"tcpreplay.h\"\n"
"#include \"tcpreplay_api.h\"\n"
"#include \"common.h\"\n"
"#include \"config.h\"\n"
"#include <stdlib.h>\n"
"#include <sys/types.h>\n"
"#include <unistd.h>\n";
"#include <unistd.h>\n"
"extern tcpreplay_t *ctx;";

homerc = "$$/";

Expand Down Expand Up @@ -286,6 +288,66 @@ option with --cachefile.
EOText;
};

flag = {
name = include;
arg-type = string;
max = 1;
descrip = "Send only selected packet numbers";
flags-cant = exclude;
flag-code = <<- EOInclude

char *include;
include = safe_strdup(OPT_ARG(INCLUDE));

ctx->options->is_exclude = false;
if (!parse_list(&ctx->options->list, include))
errx(-1, "Unable to parse include/exclude rule: %s", OPT_ARG(INCLUDE));

free(include);

EOInclude;
doc = <<- EOText
Override default of processing all packets stored in the capture file and only
send packets that are part of a supplied list of packet numbers.

@example
-x P:1-5,9,15,72-
@end example
would skip packets 1 through 5, the 9th and 15th packet, and packets 72 until the
end of the file
EOText;
};

flag = {
name = exclude;
arg-type = string;
max = 1;
descrip = "Send all but selected packet numbers";
flags-cant = include;
flag-code = <<- EOExclude

char *exclude;
exclude = safe_strdup(OPT_ARG(EXCLUDE));

ctx->options->is_exclude = true;
if (!parse_list(&ctx->options->list, exclude))
errx(-1, "Unable to parse include/exclude rule: %s", OPT_ARG(EXCLUDE));

free(exclude);

EOExclude;
doc = <<- EOText
Override default of processing all packets stored in the capture file and only
send packets that are NOT part of a supplied list of packet numbers.

@example
-x P:1-5,9,15,72-
@end example
would skip packets 1 through 5, the 9th and 15th packet, and packets 72 until the
end of the file
EOText;
};


flag = {
ifdef = ENABLE_PCAP_FINDALLDEVS;
Expand Down Expand Up @@ -543,19 +605,6 @@ are fully up before netmap transmit. Requires netmap option. Default is 10 secon
EOText;
};

flag = {
ifdef = HAVE_LIBXDP;
name = xdp;
descrip = "Write packets directly to AF_XDP enabled network adapter";
doc = <<- EOText
This feature will detect AF_XDP capable network drivers on Linux systems
that have 'libxdp-dev' and 'libbpf-dev' installed. If detected, the network
stack is bypassed and packets are sent directly to an eBPF enabled driver directly.
This will allow you to achieve full line rates on commodity network adapters, similar to rates
achieved by commercial network traffic generators.
EOText;
};


flag = {
name = no-flow-stats;
Expand Down Expand Up @@ -626,6 +675,21 @@ sending packets may cause equally long delays between printing statistics.
EOText;
};


flag = {
ifdef = HAVE_LIBXDP;
name = xdp;
descrip = "Write packets directly to AF_XDP enabled network adapter";
doc = <<- EOText
This feature will detect AF_XDP capable network drivers on Linux systems
that have 'libxdp-dev' and 'libbpf-dev' installed. If detected, the network
stack is bypassed and packets are sent directly to an eBPF enabled driver directly.
This will allow you to achieve full line rates on commodity network adapters, similar to rates
achieved by commercial network traffic generators.
EOText;
};


flag = {
ifdef = HAVE_LIBXDP;
name = xdp-batch-size;
Expand Down
16 changes: 14 additions & 2 deletions test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ EXTRA_DIST = test.pcap test.auto_bridge test.auto_client test.auto_router \
test2.rewrite_1ttl test2.rewrite_2ttl test2.rewrite_3ttl \
test2.rewrite_1ttl-hdrfix test2.rewrite_2ttl-hdrfix test2.rewrite_3ttl-hdrfix \
test2.rewrite_mtutrunc test2.rewrite_enet_subsmac \
test.rewrite_tos test2.rewrite_tos \
test.rewrite_tos test2.rewrite_tos \
test2.rewrite_enet_subsmac test2.rewrite_mac_seed \
test2.rewrite_range_portmap test2.rewrite_mac_seed_keep \
test2.rewrite_l7fuzzing test2.rewrite_sequence test2.rewrite_fixcsum \
Expand Down Expand Up @@ -209,7 +209,7 @@ tcprewrite: rewrite_portmap rewrite_range_portmap rewrite_endpoint \

tcpreplay: replay_basic replay_nano_timer replay_cache replay_pps replay_rate replay_top \
replay_config replay_multi replay_pps_multi replay_precache \
replay_stats replay_dualfile replay_maxsleep
replay_stats replay_dualfile replay_maxsleep replay_include replay_exclude

prep_config:
$(PRINTF) "%s" "[tcpprep] Config mode test: "
Expand Down Expand Up @@ -819,6 +819,18 @@ replay_maxsleep:
$(TCPREPLAY) $(ENABLE_DEBUG) -i $(nic1) --maxsleep=20 $(TEST_PCAP) $(TEST_PCAP) >> test.log 2>&1
if [ $? ] ; then $(PRINTF) "\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t%s\n" "OK"; fi

replay_include:
$(PRINTF) "%s" "[tcpreplay] Include rule test: "
$(PRINTF) "%s\n" "*** [tcpreplay] Include rule test: " >> test.log
$(TCPREPLAY) $(ENABLE_DEBUG) -i $(nic1) --include=1-5,9,15,72- $(TEST_PCAP) $(TEST_PCAP) >> test.log 2>&1
if [ $? ] ; then $(PRINTF) "\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t\t%s\n" "OK"; fi

replay_exclude:
$(PRINTF) "%s" "[tcpreplay] Exclude rule test: "
$(PRINTF) "%s\n" "*** [tcpreplay] Exclude rule test: " >> test.log
$(TCPREPLAY) $(ENABLE_DEBUG) -i $(nic1) --include=7-11,3,20,22- $(TEST_PCAP) $(TEST_PCAP) >> test.log 2>&1
if [ $? ] ; then $(PRINTF) "\t\t%s\n" "FAILED"; else $(PRINTF) "\t\t\t%s\n" "OK"; fi

clean:
rm -f *1 test.log core* *~ primary.data secondary.data

Expand Down
Loading