From 95fc8bcd04ca820de86fb35ca4cd38737fbcc98e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 9 Jan 2013 17:59:17 +0100 Subject: [PATCH] trafgen: allow to schedule packets on specific CPUs Signed-off-by: Daniel Borkmann --- src/trafgen.c | 106 +++++++++++++++++++++++++++++++++-------------- src/trafgen/Makefile | 3 +- src/trafgen_conf.h | 1 + src/trafgen_lexer.l | 4 +- src/trafgen_parser.y | 113 +++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 164 insertions(+), 63 deletions(-) diff --git a/src/trafgen.c b/src/trafgen.c index 25b6a73e..0fcd2437 100644 --- a/src/trafgen.c +++ b/src/trafgen.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "xmalloc.h" #include "die.h" @@ -57,7 +58,7 @@ struct ctx { bool rand, rfraw, jumbo_support, verbose, smoke_test; - unsigned long kpull, num, gap, reserve_size; + unsigned long kpull, num, gap, reserve_size, cpus; struct sockaddr_in dest; char *device, *device_trans, *rhost; }; @@ -65,8 +66,12 @@ struct ctx { struct cpu_stats { unsigned long long tx_packets, tx_bytes; unsigned long tv_sec, tv_usec; + unsigned int state; }; +#define CPU_STATS_STATE_CFG 1 +#define CPU_STATS_STATE_RES 2 + sig_atomic_t sigint = 0; struct packet *packets = NULL; @@ -187,6 +192,10 @@ static void help(void) " trafgen --dev wlan0 --rfraw --conf beacon-test.txf -V --cpus 2\n" " trafgen --dev eth0 --conf trafgen.txf --rand --gap 1000\n" " trafgen --dev eth0 --conf trafgen.txf --rand --num 1400000 -k1000\n\n" + "Packet config examples:\n" + " Run packet on all CPUs: { fill(0xff, 64) }\n" + " Run packet only on CPU1: cpu(1): { fill(0xff, 64) }\n" + " Run packet only on CPU1-2: cpu(1:2): { fill(0xff, 64) }\n" "Note:\n" " Smoke test example: machine A, 10.0.0.2 (trafgen) is directly\n" " connected to machine B (test kernel), 10.0.0.1. If ICMP reply fails\n" @@ -286,6 +295,8 @@ static struct cpu_stats *setup_shared_var(unsigned long cpus) close(fd); unlink(".tmp_mmap"); + memset(buff, 0, sizeof(zbuff)); + return buff; } @@ -491,6 +502,7 @@ retry: stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; + stats[cpu].state = CPU_STATS_STATE_RES; } static void xmit_fastpath_or_die(struct ctx *ctx, int cpu) @@ -581,18 +593,35 @@ static void xmit_fastpath_or_die(struct ctx *ctx, int cpu) stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; + stats[cpu].state = CPU_STATS_STATE_RES; } -static int xmit_packet_precheck(const struct ctx *ctx) +static int xmit_packet_precheck(struct ctx *ctx, int cpu) { int i; - size_t mtu; - - if (plen == 0) - return -1; + unsigned long plen_total; + size_t mtu, total_len = 0; bug_on(plen != dlen); + for (i = 0; i < plen; ++i) + total_len += packets[i].len; + + stats[cpu].tx_packets = plen; + stats[cpu].tx_bytes = total_len; + stats[cpu].state = CPU_STATS_STATE_CFG; + + for (i = 0, plen_total = plen; i < ctx->cpus; i++) { + if (i == cpu) + continue; + while (stats[i].state != CPU_STATS_STATE_CFG) + sleep(0); + plen_total += stats[i].tx_packets; + } + + if (ctx->num > 0) + ctx->num = (unsigned long) round((1.0 * plen / plen_total) * ctx->num); + for (mtu = device_mtu(ctx->device), i = 0; i < plen; ++i) { if (packets[i].len > mtu + 14) panic("Device MTU < than packet%d's size!\n", i); @@ -600,16 +629,32 @@ static int xmit_packet_precheck(const struct ctx *ctx) panic("Packet%d's size too short!\n", i); } + if (plen == 0) { + memset(&stats[cpu], 0, sizeof(stats[cpu])); + stats[cpu].state = CPU_STATS_STATE_RES; + return -1; + } + return 0; } static void main_loop(struct ctx *ctx, char *confname, bool slow, int cpu) { compile_packets(confname, ctx->verbose, cpu); - if (xmit_packet_precheck(ctx) < 0) + if (xmit_packet_precheck(ctx, cpu) < 0) return; if (cpu == 0) { + int i; + size_t total_len = 0, total_pkts = 0; + + for (i = 0; i < ctx->cpus; ++i) { + total_len += stats[i].tx_bytes; + total_pkts += stats[i].tx_packets; + } + + printf("%6zu packets to schedule\n", total_pkts); + printf("%6zu bytes in total\n", total_len); printf("Running! Hang up with ^C!\n\n"); fflush(stdout); } @@ -631,12 +676,13 @@ int main(int argc, char **argv) bool slow = false; int c, opt_index, i, j, vals[4] = {0}, irq; char *confname = NULL, *ptr; - unsigned long cpus = get_number_cpus_online(), cpus_tmp, num = 0; + unsigned long cpus_tmp, num_orig = 0; unsigned long long tx_packets, tx_bytes; struct ctx ctx; srand(time(NULL)); fmemset(&ctx, 0, sizeof(ctx)); + ctx.cpus = get_number_cpus_online(); while ((c = getopt_long(argc, argv, short_options, long_options, &opt_index)) != EOF) { @@ -652,8 +698,8 @@ int main(int argc, char **argv) break; case 'P': cpus_tmp = strtoul(optarg, NULL, 0); - if (cpus_tmp > 0 && cpus_tmp < cpus) - cpus = cpus_tmp; + if (cpus_tmp > 0 && cpus_tmp < ctx.cpus) + ctx.cpus = cpus_tmp; break; case 'd': case 'o': @@ -664,7 +710,7 @@ int main(int argc, char **argv) break; case 's': slow = true; - cpus = 1; + ctx.cpus = 1; ctx.smoke_test = true; ctx.rhost = xstrdup(optarg); break; @@ -682,14 +728,14 @@ int main(int argc, char **argv) ctx.kpull = strtoul(optarg, NULL, 0); break; case 'n': - num = strtoul(optarg, NULL, 0); + num_orig = ctx.num = strtoul(optarg, NULL, 0); break; case 't': slow = true; ctx.gap = strtoul(optarg, NULL, 0); if (ctx.gap > 0) /* Fall back to single core to have correct timing */ - cpus = 1; + ctx.cpus = 1; break; case 'S': ptr = optarg; @@ -755,8 +801,6 @@ int main(int argc, char **argv) header(); - stats = setup_shared_var(cpus); - set_system_socket_memory(vals); if (ctx.rfraw) { @@ -770,20 +814,16 @@ int main(int argc, char **argv) irq = device_irq_number(ctx.device); device_reset_irq_affinity(irq); - if (num > 0 && num <= cpus) - cpus = 1; + if (ctx.num > 0 && ctx.num <= ctx.cpus) + ctx.cpus = 1; + + stats = setup_shared_var(ctx.cpus); - for (i = 0; i < cpus; i++) { + for (i = 0; i < ctx.cpus; i++) { pid_t pid = fork(); switch (pid) { case 0: - if (num > 0) { - ctx.num = num / cpus; - if (i == cpus - 1) - ctx.num += num % cpus; - } - cpu_affinity(i); main_loop(&ctx, confname, slow, i); @@ -793,7 +833,7 @@ int main(int argc, char **argv) } } - for (i = 0; i < cpus; i++) { + for (i = 0; i < ctx.cpus; i++) { int status; wait(&status); @@ -804,21 +844,27 @@ int main(int argc, char **argv) reset_system_socket_memory(vals); - for (i = 0, tx_packets = tx_bytes = 0; i < cpus; i++) { + for (i = 0, tx_packets = tx_bytes = 0; i < ctx.cpus; i++) { + while (stats[i].state != CPU_STATS_STATE_RES) + sleep(0); tx_packets += stats[i].tx_packets; tx_bytes += stats[i].tx_bytes; } + if (num_orig > 0 && sigint == 0) + bug_on(num_orig != tx_packets); + fflush(stdout); printf("\n"); printf("\r%12llu packets outgoing\n", tx_packets); printf("\r%12llu bytes outgoing\n", tx_bytes); - for (i = 0; i < cpus; i++) - printf("\r%12lu sec, %lu usec on CPU%d\n", - stats[i].tv_sec, stats[i].tv_usec, i); + for (i = 0; i < ctx.cpus; i++) + printf("\r%12lu sec, %lu usec on CPU%d (%llu packets)\n", + stats[i].tv_sec, stats[i].tv_usec, i, + stats[i].tx_packets); thread_out: - destroy_shared_var(stats, cpus); + destroy_shared_var(stats, ctx.cpus); free(ctx.device); free(ctx.device_trans); diff --git a/src/trafgen/Makefile b/src/trafgen/Makefile index 330248ca..289aa28f 100644 --- a/src/trafgen/Makefile +++ b/src/trafgen/Makefile @@ -1,5 +1,6 @@ trafgen-libs = -lnl-genl-3 \ - -lnl-3 + -lnl-3 \ + -lm trafgen-objs = xmalloc.o \ xio.o \ diff --git a/src/trafgen_conf.h b/src/trafgen_conf.h index 9acbf516..d4bd9be8 100644 --- a/src/trafgen_conf.h +++ b/src/trafgen_conf.h @@ -29,6 +29,7 @@ struct randomizer { struct packet { uint8_t *payload; size_t len; + int cpu_specific; }; struct packet_dyn { diff --git a/src/trafgen_lexer.l b/src/trafgen_lexer.l index a0cc5617..b5a45299 100644 --- a/src/trafgen_lexer.l +++ b/src/trafgen_lexer.l @@ -39,6 +39,7 @@ number_ascii ([a-zA-Z]) %% +"cpu" { return K_CPU; } "fill" { return K_FILL; } "rnd" { return K_RND; } "drnd" { return K_DRND; } @@ -54,8 +55,9 @@ number_ascii ([a-zA-Z]) "[" { return '['; } "]" { return ']'; } "," { return ','; } +":" { return ':'; } "\n" { yylineno++; } -([ \t\r\n]+) { return K_WHITE; } +([ \t\r\n]+)? { return K_WHITE; } "/*"([^\*]|\*[^/])*"*/" { return K_COMMENT; } diff --git a/src/trafgen_parser.y b/src/trafgen_parser.y index 4e7c83d7..a51c410c 100644 --- a/src/trafgen_parser.y +++ b/src/trafgen_parser.y @@ -45,7 +45,17 @@ extern size_t dlen; #define packetdc_last (packet_dyn[packetd_last].clen - 1) #define packetdr_last (packet_dyn[packetd_last].rlen - 1) -static int dfunc_note_flag = 0; +static int dfunc_note_flag = 0, our_cpu, min_cpu = -1, max_cpu = -1; + +static inline int test_ignore(void) +{ + if (min_cpu < 0 && max_cpu < 0) + return 0; + else if (max_cpu >= our_cpu && min_cpu <= our_cpu) + return 0; + else + return 1; +} static void give_note_dynamic(void) { @@ -56,40 +66,52 @@ static void give_note_dynamic(void) } } -static inline void init_new_packet_slot(struct packet *slot) +static inline void __init_new_packet_slot(struct packet *slot, int cpu_specific) { slot->payload = NULL; slot->len = 0; + if (cpu_specific) + slot->cpu_specific = our_cpu; + else + slot->cpu_specific = -1; } -static inline void init_new_counter_slot(struct packet_dyn *slot) +static inline void __init_new_counter_slot(struct packet_dyn *slot) { slot->cnt = NULL; slot->clen = 0; } -static inline void init_new_randomizer_slot(struct packet_dyn *slot) +static inline void __init_new_randomizer_slot(struct packet_dyn *slot) { slot->rnd = NULL; slot->rlen = 0; } -static void realloc_packet(void) +static void realloc_packet(int cpu_specific) { + if (test_ignore()) + return; + plen++; packets = xrealloc(packets, 1, plen * sizeof(*packets)); - init_new_packet_slot(&packets[packet_last]); + + __init_new_packet_slot(&packets[packet_last], cpu_specific); dlen++; packet_dyn = xrealloc(packet_dyn, 1, dlen * sizeof(*packet_dyn)); - init_new_counter_slot(&packet_dyn[packetd_last]); - init_new_randomizer_slot(&packet_dyn[packetd_last]); + + __init_new_counter_slot(&packet_dyn[packetd_last]); + __init_new_randomizer_slot(&packet_dyn[packetd_last]); } static void set_byte(uint8_t val) { struct packet *pkt = &packets[packet_last]; + if (test_ignore()) + return; + pkt->len++; pkt->payload = xrealloc(pkt->payload, 1, pkt->len); pkt->payload[payload_last] = val; @@ -100,6 +122,9 @@ static void set_fill(uint8_t val, size_t len) int i; struct packet *pkt = &packets[packet_last]; + if (test_ignore()) + return; + pkt->len += len; pkt->payload = xrealloc(pkt->payload, 1, pkt->len); for (i = 0; i < len; ++i) @@ -111,6 +136,9 @@ static void set_rnd(size_t len) int i; struct packet *pkt = &packets[packet_last]; + if (test_ignore()) + return; + pkt->len += len; pkt->payload = xrealloc(pkt->payload, 1, pkt->len); for (i = 0; i < len; ++i) @@ -122,6 +150,9 @@ static void set_seqinc(uint8_t start, size_t len, uint8_t stepping) int i; struct packet *pkt = &packets[packet_last]; + if (test_ignore()) + return; + pkt->len += len; pkt->payload = xrealloc(pkt->payload, 1, pkt->len); for (i = 0; i < len; ++i) { @@ -137,6 +168,9 @@ static void set_seqdec(uint8_t start, size_t len, uint8_t stepping) int i; struct packet *pkt = &packets[packet_last]; + if (test_ignore()) + return; + pkt->len += len; pkt->payload = xrealloc(pkt->payload, 1, pkt->len); for (i = 0; i < len; ++i) { @@ -147,8 +181,9 @@ static void set_seqdec(uint8_t start, size_t len, uint8_t stepping) } } -static inline void setup_new_counter(struct counter *c, uint8_t start, uint8_t stop, - uint8_t stepping, int type) +static inline void __setup_new_counter(struct counter *c, uint8_t start, + uint8_t stop, uint8_t stepping, + int type) { c->min = start; c->max = stop; @@ -158,7 +193,7 @@ static inline void setup_new_counter(struct counter *c, uint8_t start, uint8_t s c->type = type; } -static inline void setup_new_randomizer(struct randomizer *r) +static inline void __setup_new_randomizer(struct randomizer *r) { r->val = (uint8_t) rand(); r->off = payload_last; @@ -169,6 +204,9 @@ static void set_drnd(void) struct packet *pkt = &packets[packet_last]; struct packet_dyn *pktd = &packet_dyn[packetd_last]; + if (test_ignore()) + return; + give_note_dynamic(); pkt->len++; @@ -177,7 +215,7 @@ static void set_drnd(void) pktd->rlen++; pktd->rnd = xrealloc(pktd->rnd, 1, pktd->rlen * sizeof(struct randomizer)); - setup_new_randomizer(&pktd->rnd[packetdr_last]); + __setup_new_randomizer(&pktd->rnd[packetdr_last]); } static void set_dincdec(uint8_t start, uint8_t stop, uint8_t stepping, int type) @@ -185,6 +223,9 @@ static void set_dincdec(uint8_t start, uint8_t stop, uint8_t stepping, int type) struct packet *pkt = &packets[packet_last]; struct packet_dyn *pktd = &packet_dyn[packetd_last]; + if (test_ignore()) + return; + give_note_dynamic(); pkt->len++; @@ -193,7 +234,7 @@ static void set_dincdec(uint8_t start, uint8_t stop, uint8_t stepping, int type) pktd->clen++; pktd->cnt =xrealloc(pktd->cnt, 1, pktd->clen * sizeof(struct counter)); - setup_new_counter(&pktd->cnt[packetdc_last], start, stop, stepping, type); + __setup_new_counter(&pktd->cnt[packetdc_last], start, stop, stepping, type); } %} @@ -202,9 +243,9 @@ static void set_dincdec(uint8_t start, uint8_t stop, uint8_t stepping, int type) long int number; } -%token K_COMMENT K_FILL K_RND K_SEQINC K_SEQDEC K_DRND K_DINC K_DDEC K_WHITE +%token K_COMMENT K_FILL K_RND K_SEQINC K_SEQDEC K_DRND K_DINC K_DDEC K_WHITE K_CPU -%token ',' '{' '}' '(' ')' '[' ']' +%token ',' '{' '}' '(' ')' '[' ']' ':' %token number @@ -224,7 +265,26 @@ inline_comment ; packet - : '{' delimiter payload delimiter '}' { realloc_packet(); } + : '{' delimiter payload delimiter '}' { + min_cpu = max_cpu = -1; + realloc_packet(0); + } + | K_CPU '(' number ':' number ')' ':' K_WHITE '{' delimiter payload delimiter '}' { + min_cpu = $3; + max_cpu = $5; + + if (min_cpu > max_cpu) { + int tmp = min_cpu; + min_cpu = max_cpu; + max_cpu = tmp; + } + + realloc_packet(1); + } + | K_CPU '(' number ')' ':' K_WHITE '{' delimiter payload delimiter '}' { + min_cpu = max_cpu = $3; + realloc_packet(1); + } ; payload @@ -364,27 +424,18 @@ void cleanup_packets(void) int compile_packets(char *file, int verbose, int cpu) { + our_cpu = cpu; + yyin = fopen(file, "r"); if (!yyin) panic("Cannot open file!\n"); - realloc_packet(); + realloc_packet(0); yyparse(); finalize_packet(); - if (cpu == 0) { - if (verbose) { - dump_conf(); - } else { - int i; - size_t total_len = 0; - - printf("%6zu packets to schedule\n", plen); - for (i = 0; i < plen; ++i) - total_len += packets[i].len; - printf("%6zu bytes in total\n", total_len); - } - } + if (our_cpu == 0 && verbose) + dump_conf(); fclose(yyin); return 0; @@ -392,5 +443,5 @@ int compile_packets(char *file, int verbose, int cpu) void yyerror(const char *err) { - panic("Syntax error at line %d: '%s'! %s!\n", yylineno, yytext, err); + panic("Syntax error at line%d, at char '%s'! %s!\n", yylineno, yytext, err); } -- 2.11.4.GIT