On Wed, Dec 23, 2015 at 10:31:23PM +0200, Vadim Kochan wrote:
> Added -b,--rate option in units of:
> 
>     pps/B/kB/MB/kBit/Mbit/Gbit/KiB/MiB/GiB
> 
> to specify rate at which packets will be sent.
> Similary to -t,--gap option the packets will be sent
> in slow mode with 1 CPU.
> 
> Tested with ifpps.
> 
> Signed-off-by: Vadim Kochan <vadi...@gmail.com>
> ---
> v2:
>     1) Fixed KB -> kB
>     2) Added SHAPER_NONE type
> 
>  trafgen.8 |   4 ++
>  trafgen.c | 140 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 135 insertions(+), 9 deletions(-)
> 
> diff --git a/trafgen.8 b/trafgen.8
> index 6f5d318..677fc7d 100644
> --- a/trafgen.8
> +++ b/trafgen.8
> @@ -136,6 +136,10 @@ probing for a given interval, iii) ping-like debugging 
> with specific payload
>  patterns. Furthermore, the TX_RING interface does not cope with interpacket
>  gaps.
>  .PP
> +.SS -b <rate>, --rate <rate>
> +Specify the rate of packet sending in 
> <num>pps/B/kB/MB/GB/kBit/Mbit/Gbit/KiB/MiB/GiB units.
> +Similary to -t,--gap option - packets are sent in slow mode.
> +.PP
>  .SS -S <size>, --ring-size <size>
>  Manually define the TX_RING resp. TX_RING size in ''<num>KiB/MiB/GiB''. On
>  default the size is being determined based on the network connectivity rate.
> diff --git a/trafgen.c b/trafgen.c
> index df2ecf4..f208336 100644
> --- a/trafgen.c
> +++ b/trafgen.c
> @@ -55,6 +55,27 @@
>  #include "ring_tx.h"
>  #include "csum.h"
>  
> +#ifndef timeval_to_timespec
> +#define timeval_to_timespec(tv, ts) {         \
> +     (ts)->tv_sec = (tv)->tv_sec;          \
> +     (ts)->tv_nsec = (tv)->tv_usec * 1000; \
> +}
> +#endif
> +
> +enum shaper_type {
> +     SHAPER_NONE,
> +     SHAPER_PKTS,
> +     SHAPER_BYTES,
> +};
> +
> +struct shaper {
> +     enum shaper_type type;
> +     unsigned long long sent;
> +     unsigned long long rate;
> +     struct timeval start;
> +     struct timeval end;
> +};
> +
>  struct ctx {
>       bool rand, rfraw, jumbo_support, verbose, smoke_test, enforce, 
> qdisc_path;
>       size_t reserve_size;
> @@ -65,6 +86,7 @@ struct ctx {
>       struct timespec gap;
>       struct sockaddr_in dest;
>       char *packet_str;
> +     struct shaper sh;
>  };
>  
>  struct cpu_stats {
> @@ -83,7 +105,7 @@ size_t plen = 0;
>  struct packet_dyn *packet_dyn = NULL;
>  size_t dlen = 0;
>  
> -static const char *short_options = 
> "d:c:n:t:vJhS:rk:i:o:VRs:P:eE:pu:g:CHQqD:";
> +static const char *short_options = 
> "d:c:n:t:vJhS:rk:i:o:VRs:P:eE:pu:g:CHQqD:b:";
>  static const struct option long_options[] = {
>       {"dev",                 required_argument,      NULL, 'd'},
>       {"out",                 required_argument,      NULL, 'o'},
> @@ -91,6 +113,7 @@ static const struct option long_options[] = {
>       {"conf",                required_argument,      NULL, 'c'},
>       {"num",                 required_argument,      NULL, 'n'},
>       {"gap",                 required_argument,      NULL, 't'},
> +     {"rate",                required_argument,      NULL, 'b'},
>       {"cpus",                required_argument,      NULL, 'P'},
>       {"ring-size",           required_argument,      NULL, 'S'},
>       {"kernel-pull",         required_argument,      NULL, 'k'},
> @@ -172,6 +195,7 @@ static void __noreturn help(void)
>            "  -r|--rand                      Randomize packet selection (def: 
> round robin)\n"
>            "  -P|--cpus <uint>               Specify number of forks(<= CPUs) 
> (def: #CPUs)\n"
>            "  -t|--gap <time>                Set approx. interpacket gap 
> (s/ms/us/ns, def: us)\n"
> +          "  -b|--rate <rate>               Send traffic at specified rate 
> (pps/B/kB/MB/GB/kBit/Mbit/Gbit/KiB/MiB/GiB)\n"
>            "  -S|--ring-size <size>          Manually set mmap size 
> (KiB/MiB/GiB)\n"
>            "  -E|--seed <uint>               Manually set srand(3) seed\n"
>            "  -u|--user <userid>             Drop privileges and change to 
> userid\n"
> @@ -535,6 +559,52 @@ static int xmit_smoke_probe(int icmp_sock, struct ctx 
> *ctx)
>       return -1;
>  }
>  
> +static bool shaper_is_set(struct shaper *sh)
> +{
> +     return sh->type != SHAPER_NONE;
> +}
> +
> +static void shaper_start(struct shaper *sh)
> +{
> +     bug_on(gettimeofday(&sh->start, NULL));
> +     sh->sent = 0;
> +}
> +
> +static void shaper_init(struct shaper *sh, unsigned long long rate, enum 
> shaper_type type)
> +{
> +     memset(sh, 0, sizeof(struct shaper));
> +     sh->rate = rate;
> +     sh->type = type;
> +}
> +
> +static void shaper_delay(struct shaper *sh, unsigned long pkt_len)
> +{
> +     if ((sh->start.tv_sec | sh->start.tv_usec) <= 0)
> +             return;
> +
> +     sh->sent += sh->type == SHAPER_BYTES ? pkt_len : 1;
> +
> +     if (sh->sent >= sh->rate) {
> +             struct timeval delay_us;
> +             struct timespec delay_ns;
> +             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, &delay_ns);
> +
> +                     if ((delay_ns.tv_sec | delay_ns.tv_nsec) > 0)
> +                             nanosleep(&delay_ns, NULL);
> +             }
> +
> +             shaper_start(sh);
> +     }
> +}
> +
>  static void xmit_slowpath_or_die(struct ctx *ctx, unsigned int cpu, unsigned 
> long orig_num)
>  {
>       int ret, icmp_sock = -1;
> @@ -560,6 +630,9 @@ static void xmit_slowpath_or_die(struct ctx *ctx, 
> unsigned int cpu, unsigned lon
>  
>       bug_on(gettimeofday(&start, NULL));
>  
> +     if (shaper_is_set(&ctx->sh))
> +             shaper_start(&ctx->sh);
> +
>       while (likely(sigint == 0 && num > 0 && plen > 0)) {
>               pktd = &packet_dyn[i];
>               if (packet_dyn_has_elems(pktd)) {
> @@ -605,6 +678,9 @@ retry:
>               if (ctx->num > 0)
>                       num--;
>  
> +             if (shaper_is_set(&ctx->sh))
> +                     shaper_delay(&ctx->sh, packets[i].len);
> +
>               if ((ctx->gap.tv_sec | ctx->gap.tv_nsec) > 0)
>                       nanosleep(&ctx->gap, NULL);
>       }
> @@ -901,6 +977,8 @@ int main(int argc, char **argv)
>       int min_opts = 5;
>       char **cpp_argv = NULL;
>       size_t cpp_argc = 0;
> +     unsigned long long rate;
> +     enum shaper_type shape_type;
>  
>       fmemset(&ctx, 0, sizeof(ctx));
>       ctx.cpus = get_number_cpus_online();
> @@ -999,9 +1077,7 @@ int main(int argc, char **argv)
>                       ctx.num = orig_num;
>                       break;
>               case 't':
> -                     slow = true;
>                       ptr = optarg;
> -                     prctl(PR_SET_TIMERSLACK, 1UL);
>                       gap = strtoul(optarg, NULL, 0);
>  
>                       for (j = i = strlen(optarg); i > 0; --i) {
> @@ -1025,14 +1101,51 @@ int main(int argc, char **argv)
>                       } else if (!strncmp(ptr, "s", strlen("s"))) {
>                               ctx.gap.tv_sec = gap;
>                               ctx.gap.tv_nsec = 0;
> -                     } else
> +                     } else {
>                               panic("Syntax error in time param!\n");
> +                     }
> +                     break;
> +             case 'b':
> +                     rate = strtoul(optarg, &ptr, 0);
> +                     if (!rate || optarg == ptr)
> +                             panic("Invalid rate param\n");
> +
> +                     if (strncmp(ptr, "pps", strlen("pps")) == 0) {
> +                             shape_type = SHAPER_PKTS;
> +                     } else if (strncmp(ptr, "B", strlen("B")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                     } else if (strncmp(ptr, "kB", strlen("kB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000;
> +                     } else if (strncmp(ptr, "MB", strlen("MB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000 * 1000;
> +                     } else if (strncmp(ptr, "GB", strlen("GB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000 * 1000 * 1000;
> +                     } else if (strncmp(ptr, "kbit", strlen("kbit")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000 / 8;
> +                     } else if (strncmp(ptr, "Mbit", strlen("Mbit")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000 * 1000 / 8;
> +                     } else if (strncmp(ptr, "Gbit", strlen("Gbit")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1000 * 1000 * 1000 / 8;
> +                     } else if (strncmp(ptr, "KiB", strlen("KiB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1 << 10;
> +                     } else if (strncmp(ptr, "MiB", strlen("MiB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1 << 20;
> +                     } else if (strncmp(ptr, "GiB", strlen("GiB")) == 0) {
> +                             shape_type = SHAPER_BYTES;
> +                             rate *= 1 << 30;
> +                     } else {
> +                             panic("Invalid unit type for rate\n");
> +                     }
>  
> -                     if (gap > 0)
> -                             /* Fall back to single core to not mess up
> -                              * correct timing. We are slow anyway!
> -                              */
> -                             ctx.cpus = 1;
> +                     shaper_init(&ctx.sh, rate, shape_type);
>                       break;
>               case 'S':
>                       ptr = optarg;
> @@ -1118,6 +1231,15 @@ int main(int argc, char **argv)
>               sleep(0);
>       }
>  
> +     if (shaper_is_set(&ctx.sh) || (ctx.gap.tv_sec | ctx.gap.tv_nsec) > 0) {
> +             prctl(PR_SET_TIMERSLACK, 1UL);
> +             /* Fall back to single core to not mess up correct timing.
> +              * We are slow anyway!
> +              */
> +             ctx.cpus = 1;
> +             slow = true;
> +     }
> +
>       /*
>        * If number of packets is smaller than number of CPUs use only as
>        * many CPUs as there are packets. Otherwise we end up sending more
> -- 
> 2.6.3
> 

Sorry, seems it does not work for mtu > 1500, I will try to fix it.

-- 
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