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.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 trafgen.8 |   4 ++
 trafgen.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/trafgen.8 b/trafgen.8
index 6f5d318..c78a373 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..969b8b7 100644
--- a/trafgen.c
+++ b/trafgen.c
@@ -55,6 +55,26 @@
 #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_PKTS,
+       SHAPER_BYTES,
+};
+
+struct shaper {
+       enum shaper_type type;
+       unsigned long rate;
+       unsigned long long sent;
+       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 +85,7 @@ struct ctx {
        struct timespec gap;
        struct sockaddr_in dest;
        char *packet_str;
+       struct shaper sh;
 };
 
 struct cpu_stats {
@@ -83,7 +104,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 +112,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 +194,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 +558,51 @@ static int xmit_smoke_probe(int icmp_sock, struct ctx *ctx)
        return -1;
 }
 
+static bool shaper_is_set(struct shaper *sh)
+{
+       return sh->rate != 0;
+}
+
+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 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 long pkt_len)
+{
+       if ((sh->start.tv_sec | sh->start.tv_usec) > 0) {
+               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 +628,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 +676,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 +975,8 @@ int main(int argc, char **argv)
        int min_opts = 5;
        char **cpp_argv = NULL;
        size_t cpp_argc = 0;
+       unsigned long rate;
+       enum shaper_type shape_type;
 
        fmemset(&ctx, 0, sizeof(ctx));
        ctx.cpus = get_number_cpus_online();
@@ -999,9 +1075,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 +1099,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 +1229,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

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