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.
