On 2017-01-31 at 23:31:35 +0100, Vadim Kochan <vadi...@gmail.com> wrote: > Add ability to send packets from pcap file if it has > ".pcap" extension via "-i,--in" option. > > By default packet sending is delayed considering original > packets timestamps if no rate or delay is specified via -b/-t options. > > Signed-off-by: Vadim Kochan <vadi...@gmail.com> > --- > trafgen.c | 155 > +++++++++++++++++++++++++++++++++++++++++++++---------- > trafgen/Makefile | 4 ++ > trafgen_conf.h | 3 ++ > trafgen_parser.y | 2 +- > 4 files changed, 137 insertions(+), 27 deletions(-) > > diff --git a/trafgen.c b/trafgen.c > index 524b260..c0d77a3 100644 > --- a/trafgen.c > +++ b/trafgen.c > @@ -5,6 +5,8 @@ > * Subject to the GPL, version 2. > */ > > +#define _GNU_SOURCE > + > #include <stdio.h> > #include <string.h> > #include <getopt.h> > @@ -16,7 +18,6 @@ > #include <sys/fsuid.h> > #include <sys/prctl.h> > #include <sys/stat.h> > -#include <sys/time.h> > #include <sys/wait.h> > #include <sys/mman.h> > #include <net/ethernet.h> > @@ -55,6 +56,7 @@ > #include "ring_tx.h" > #include "csum.h" > #include "trafgen_proto.h" > +#include "pcap_io.h" > > #ifndef timeval_to_timespec > #define timeval_to_timespec(tv, ts) { \ > @@ -65,14 +67,17 @@ > > enum shaper_type { > SHAPER_NONE, > + SHAPER_DELAY, > SHAPER_PKTS, > SHAPER_BYTES, > + SHAPER_TSTAMP, > }; > > struct shaper { > enum shaper_type type; > unsigned long long sent; > unsigned long long rate; > + struct timeval tstamp; > struct timeval start; > struct timeval end; > struct timespec delay; > @@ -88,6 +93,7 @@ struct ctx { > struct sockaddr_in dest; > struct shaper sh; > char *packet_str; > + char *pcap_in; > }; > > struct cpu_stats { > @@ -556,15 +562,12 @@ static int xmit_smoke_probe(int icmp_sock, struct ctx > *ctx) > > static bool shaper_is_set(struct shaper *sh) > { > - if ((sh->delay.tv_sec | sh->delay.tv_nsec) > 0) > - return true; > - > - return sh->type != SHAPER_NONE; > + return sh->type != SHAPER_NONE; > } > > static void shaper_init(struct shaper *sh) > { > - if (sh->type == SHAPER_NONE) > + if (sh->type == SHAPER_NONE || sh->type == SHAPER_DELAY) > return; > > memset(&sh->delay, 0, sizeof(struct timespec)); > @@ -574,6 +577,12 @@ static void shaper_init(struct shaper *sh) > > static void shaper_set_delay(struct shaper *sh, time_t sec, long int ns) > { > + if (!(sec | ns)) { > + sh->type = SHAPER_NONE; > + return; > + } > + > + sh->type = SHAPER_DELAY; > sh->delay.tv_sec = sec; > sh->delay.tv_nsec = ns; > } > @@ -586,23 +595,48 @@ static void shaper_set_rate(struct shaper *sh, unsigned > long long rate, > sh->type = type; > } > > -static void shaper_delay(struct shaper *sh, unsigned long pkt_len) > +static void shaper_set_tstamp(struct shaper *sh, struct timeval *tv) > { > - if (sh->type != SHAPER_NONE) > + sh->tstamp.tv_sec = tv->tv_sec; > + sh->tstamp.tv_usec = tv->tv_usec; > +} > + > +static void shaper_delay(struct shaper *sh, struct packet *pkt) > +{ > + if (sh->type == SHAPER_BYTES || sh->type == SHAPER_PKTS) { > + unsigned long pkt_len = pkt->len; > + > sh->sent += sh->type == SHAPER_BYTES ? pkt_len : 1; > > - if (sh->sent >= sh->rate && sh->rate > 0) { > - struct timeval delay_us; > - struct timeval time_sent; > - struct timeval time_1s = { .tv_sec = 1 }; > + if (sh->sent >= sh->rate && sh->rate > 0) { > + struct timeval delay_us; > + struct timeval time_sent; > + struct timeval time_1s = { .tv_sec = 1 }; > + > + bug_on(gettimeofday(&sh->end, NULL)); > + timersub(&sh->end, &sh->start, &time_sent); > + > + if (timercmp(&time_1s, &time_sent, > )) { > + timersub(&time_1s, &time_sent, &delay_us); > + timeval_to_timespec(&delay_us, &sh->delay); > + } > + } > + } else if (sh->type == SHAPER_TSTAMP) { > + struct timeval pkt_diff; > + struct timeval diff; > > bug_on(gettimeofday(&sh->end, NULL)); > - timersub(&sh->end, &sh->start, &time_sent); > + timersub(&sh->end, &sh->start, &diff); > + timersub(&pkt->tstamp, &sh->tstamp, &pkt_diff); > + > + if (timercmp(&diff, &pkt_diff, <)) { > + struct timeval delay; > > - if (timercmp(&time_1s, &time_sent, > )) { > - timersub(&time_1s, &time_sent, &delay_us); > - timeval_to_timespec(&delay_us, &sh->delay); > + timersub(&pkt_diff, &diff, &delay); > + timeval_to_timespec(&delay, &sh->delay); > } > + > + memcpy(&sh->tstamp, &pkt->tstamp, sizeof(sh->tstamp)); > } > > if ((sh->delay.tv_sec | sh->delay.tv_nsec) > 0) { > @@ -698,7 +732,7 @@ retry: > num--; > > if (shaper_is_set(&ctx->sh)) > - shaper_delay(&ctx->sh, packets[i].len); > + shaper_delay(&ctx->sh, &packets[i]); > } > > bug_on(gettimeofday(&end, NULL)); > @@ -910,16 +944,79 @@ static void xmit_packet_precheck(struct ctx *ctx, > unsigned int cpu) > } > } > > +static void pcap_load_packets(const char *path) > +{ > + const struct pcap_file_ops *pcap_io = pcap_ops[PCAP_OPS_SG]; > + uint32_t link_type, magic; > + pcap_pkthdr_t phdr; > + size_t buf_len; > + uint8_t *buf; > + int ret; > + int fd; > + > + fd = open(path, O_RDONLY | O_LARGEFILE | O_NOATIME); > + if (fd < 0 && errno == EPERM) > + fd = open_or_die(path, O_RDONLY | O_LARGEFILE); > + if (fd < 0) > + panic("Cannot open file %s! %s.\n", path, strerror(errno)); > + > + if (pcap_io->init_once_pcap) > + pcap_io->init_once_pcap(false); > + > + ret = pcap_io->pull_fhdr_pcap(fd, &magic, &link_type); > + if (ret) > + panic("Error reading pcap header!\n"); > + > + if (pcap_io->prepare_access_pcap) { > + ret = pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, false); > + if (ret) > + panic("Error prepare reading pcap!\n"); > + } > + > + buf_len = round_up(1024 * 1024, RUNTIME_PAGE_SIZE); > + buf = xmalloc_aligned(buf_len, CO_CACHE_LINE_SIZE); > + > + while (pcap_io->read_pcap(fd, &phdr, magic, buf, buf_len) > 0) { > + struct packet *pkt; > + size_t pkt_len; > + > + pkt_len = pcap_get_length(&phdr, magic); > + if (!pkt_len) > + continue; > + > + realloc_packet(); > + > + pkt = current_packet(); > + > + pkt->len = pkt_len; > + pkt->payload = xzmalloc(pkt_len); > + memcpy(pkt->payload, buf, pkt_len); > + pcap_get_tstamp(&phdr, magic, &pkt->tstamp); > + } > + > + if (pcap_io->prepare_close_pcap) > + pcap_io->prepare_close_pcap(fd, PCAP_MODE_RD); > + > + free(buf); > + close(fd); > +} > + > static void main_loop(struct ctx *ctx, char *confname, bool slow, > unsigned int cpu, bool invoke_cpp, char **cpp_argv, > unsigned long orig_num) > { > - if (ctx->packet_str) > - compile_packets_str(ctx->packet_str, ctx->verbose, cpu); > - else > - compile_packets(confname, ctx->verbose, cpu, invoke_cpp, > cpp_argv); > - > - preprocess_packets(); > + if (confname && strstr(confname, ".pcap")) {
Please use a bool in struct ctx to hold this condition instead of repeatedly using this construct. > + pcap_load_packets(confname); > + shaper_set_tstamp(&ctx->sh, &packets[0].tstamp); > + ctx->num = plen; > + } else { > + if (ctx->packet_str) > + compile_packets_str(ctx->packet_str, ctx->verbose, cpu); > + else > + compile_packets(confname, ctx->verbose, cpu, > invoke_cpp, cpp_argv); > + > + preprocess_packets(); > + } > > xmit_packet_precheck(ctx, cpu); > > @@ -1061,9 +1158,13 @@ int main(int argc, char **argv) > case 'J': > ctx.jumbo_support = true; > break; > - case 'c': > case 'i': > confname = xstrdup(optarg); > + if (strstr(confname, ".pcap")) { > + ctx.sh.type = SHAPER_TSTAMP; > + break; > + } > + case 'c': > if (!strncmp("-", confname, strlen("-"))) > ctx.cpus = 1; > break; > @@ -1115,7 +1216,7 @@ int main(int argc, char **argv) > break; > case 'b': > rate = strtoul(optarg, &ptr, 0); > - if (!rate || optarg == ptr) > + if (!rate && optarg == ptr) > panic("Invalid rate param\n"); > > if (strncmp(ptr, "pps", strlen("pps")) == 0) { > @@ -1149,6 +1250,8 @@ int main(int argc, char **argv) > } else if (strncmp(ptr, "GiB", strlen("GiB")) == 0) { > shape_type = SHAPER_BYTES; > rate *= 1 << 30; > + } else if (strcmp("0", optarg) == 0) { strncmp, please. Or even better, just check rate == 0. > + shape_type = SHAPER_NONE; > } else { > panic("Invalid unit type for rate\n"); > } > @@ -1236,7 +1339,7 @@ int main(int argc, char **argv) > sleep(0); > } > > - if (shaper_is_set(&ctx.sh)) { > + if (shaper_is_set(&ctx.sh) || (confname && strstr(confname, ".pcap"))) { > prctl(PR_SET_TIMERSLACK, 1UL); > /* Fall back to single core to not mess up correct timing. > * We are slow anyway! > diff --git a/trafgen/Makefile b/trafgen/Makefile > index 876ed93..a7c0ddd 100644 > --- a/trafgen/Makefile > +++ b/trafgen/Makefile > @@ -21,6 +21,10 @@ trafgen-objs = xmalloc.o \ > timer.o \ > sysctl.o \ > cpp.o \ > + pcap_sg.o \ > + pcap_rw.o \ > + pcap_mm.o \ > + iosched.o \ > trafgen_proto.o \ > trafgen_l2.o \ > trafgen_l3.o \ > diff --git a/trafgen_conf.h b/trafgen_conf.h > index 61da012..8c77268 100644 > --- a/trafgen_conf.h > +++ b/trafgen_conf.h > @@ -3,6 +3,7 @@ > > #include <stdint.h> > #include <stdio.h> > +#include <sys/time.h> > #include <sys/types.h> > > #include "trafgen_proto.h" > @@ -40,6 +41,7 @@ struct packet { > size_t len; > struct proto_hdr *headers[PROTO_MAX_LAYERS]; > size_t headers_count; > + struct timeval tstamp; > }; > > struct packet_dyn { > @@ -78,5 +80,6 @@ extern void set_fill(uint8_t val, size_t len); > extern struct packet *current_packet(void); > extern uint32_t current_packet_id(void); > extern struct packet *packet_get(uint32_t id); > +extern void realloc_packet(void); > > #endif /* TRAFGEN_CONF */ > diff --git a/trafgen_parser.y b/trafgen_parser.y > index b5fcbc0..c189a51 100644 > --- a/trafgen_parser.y > +++ b/trafgen_parser.y > @@ -165,7 +165,7 @@ static inline void __setup_new_csum16(struct csum16 *s, > off_t from, off_t to, > s->which = which; > } > > -static void realloc_packet(void) > +void realloc_packet(void) > { > if (test_ignore()) > return; > -- > 2.11.0 > -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.