On Wed, Dec 23, 2015 at 10:58:32PM +0200, Vadim Kochan wrote:
> 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 <[email protected]>
> > ---
> > 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.

Currently I did not come up with idea how to make shaping work correctly
if packet len is much bigger than rate because then trafgen will be
delayed for example for 3-5 seconds which is not what expected I think,
and in any case trafgen have to send a whole packet at a one time, so I
think the user should set a correct packet length. What do you think ?
If you are at the same point so I think the changes at least might be
reviewed ?

Thanks,

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to