Skip to content

Commit

Permalink
Merge pull request #885 from appneta/Feature_#884_include_exclude_opt…
Browse files Browse the repository at this point in the history
…ions

Feature #884 include exclude options
  • Loading branch information
fklassen authored Jun 24, 2024
2 parents 724bdaf + 23b035b commit 3ece9a8
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 40 deletions.
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 @@ -44,6 +44,21 @@ new_list()
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') {
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 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
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 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
}
}

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 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
}
}

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 @@ tcpr_dir_t
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 @@ check_list(tcpr_list_t *list, COUNTER value)
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 @@ check_list(tcpr_list_t *list, COUNTER value)
void
free_list(tcpr_list_t *list)
{
if (list == NULL)
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 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
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 @@ -667,6 +678,16 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
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

0 comments on commit 3ece9a8

Please sign in to comment.