On Fri, Dec 25, 2015 at 03:19:59AM +0200, Vadim Kochan wrote:
> 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,

Sorry, may be I confused you, but I think this patch seems OK, you can
ignore my message that it does not work for mtu > 1500 as I was
performing wrong tests where rate was much less than packet len. So you
can review 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to