diff --git a/src/send_packets.c b/src/send_packets.c index fd057634..e7969fe4 100644 --- a/src/send_packets.c +++ b/src/send_packets.c @@ -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 @@ -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 diff --git a/src/tcpreplay_api.c b/src/tcpreplay_api.c index c4a412a4..7e379aef 100644 --- a/src/tcpreplay_api.c +++ b/src/tcpreplay_api.c @@ -487,6 +487,9 @@ tcpreplay_close(tcpreplay_t *ctx) intlist = intlistnext; } } + + /* free --include / --exclude list */ + free_list(options->list); } /** diff --git a/src/tcpreplay_api.h b/src/tcpreplay_api.h index c7154ed0..70540588 100644 --- a/src/tcpreplay_api.h +++ b/src/tcpreplay_api.h @@ -23,6 +23,7 @@ #include "defines.h" #include "config.h" #include +#include #include #include #include @@ -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; diff --git a/src/tcpreplay_opts.def b/src/tcpreplay_opts.def index c3ddfa9d..bf424258 100644 --- a/src/tcpreplay_opts.def +++ b/src/tcpreplay_opts.def @@ -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 \n" "#include \n" - "#include \n"; + "#include \n" + "extern tcpreplay_t *ctx;"; homerc = "$$/"; @@ -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; @@ -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; @@ -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;