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.

Reply via email to