Make variable unsigned to allow proper build.
[netsniff-ng.git] / src / trafgen / trafgen.c
blobc93ffebf7827e410c3c4752220e4f0247be97daf
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL.
8 * A high-performance network traffic generator that uses the zero-copy
9 * kernelspace TX_RING for network I/O. On comodity Gigabit hardware up
10 * to > 1.1 Mio 64 Byte pps have been achieved with trafgen from the
11 * userspace on a Intel Core 2 Quad Q6600 with 2.40GHz, 4GB RAM, Intel
12 * 82566DC-2 NIC, for instance.
14 * Who can now hold the fords when the King of the Nine Riders comes? And
15 * other armies will come. I am too late. All is lost. I tarried on the
16 * way. All is lost. Even if my errand is performed, no one will ever
17 * know. There will be no one I can tell. It will be in vain.
19 * -- The Lord of the Rings, Frodo thinking,
20 * Chapter 'The Stairs of Cirith Ungol'.
23 #include <stdio.h>
24 #include <string.h>
25 #include <getopt.h>
26 #include <ctype.h>
27 #include <stdbool.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <signal.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <net/ethernet.h>
40 #include "xmalloc.h"
41 #include "opt_memcpy.h"
42 #include "strlcpy.h"
43 #include "parser.h"
44 #include "die.h"
45 #include "netdev.h"
46 #include "psched.h"
47 #include "misc.h"
48 #include "tty.h"
49 #include "timespec.h"
50 #include "version.h"
51 #include "mtrand.h"
52 #include "signals.h"
53 #include "tx_ring.h"
55 struct counter {
56 uint16_t id;
57 uint8_t min;
58 uint8_t max;
59 uint8_t inc;
60 uint8_t val;
61 off_t off;
64 struct randomizer {
65 uint8_t val;
66 off_t off;
69 struct packet {
70 uint8_t *payload;
71 size_t plen;
72 struct counter *cnt;
73 size_t clen;
74 struct randomizer *rnd;
75 size_t rlen;
78 struct pktconf {
79 unsigned long num;
80 unsigned long gap;
81 struct packet *pkts;
82 size_t len;
85 struct stats {
86 unsigned long tx_bytes;
87 unsigned long tx_packets;
90 struct mode {
91 struct stats stats;
92 char *device;
93 int cpu;
94 int rand;
95 unsigned long kpull;
96 /* 0 for automatic, > 0 for manual */
97 unsigned int reserve_size;
98 int jumbo_support;
101 #define CPU_UNKNOWN -1
102 #define CPU_NOTOUCH -2
104 sig_atomic_t sigint = 0;
106 static const char *short_options = "d:c:n:t:vJhS:HQb:B:rk:";
108 static struct option long_options[] = {
109 {"dev", required_argument, 0, 'd'},
110 {"conf", required_argument, 0, 'c'},
111 {"num", required_argument, 0, 'n'},
112 {"gap", required_argument, 0, 't'},
113 {"ring-size", required_argument, 0, 'S'},
114 {"bind-cpu", required_argument, 0, 'b'},
115 {"unbind-cpu", required_argument, 0, 'B'},
116 {"kernel-pull", required_argument, 0, 'k'},
117 {"jumbo-support", no_argument, 0, 'J'},
118 {"rand", no_argument, 0, 'r'},
119 {"prio-high", no_argument, 0, 'H'},
120 {"notouch-irq", no_argument, 0, 'Q'},
121 {"version", no_argument, 0, 'v'},
122 {"help", no_argument, 0, 'h'},
123 {0, 0, 0, 0}
126 static struct itimerval itimer;
127 static int sock;
128 static unsigned long interval = TX_KERNEL_PULL_INT;
130 static inline uint8_t lcrand(uint8_t val)
132 return 0xFF & (3 * val + 3);
135 static void signal_handler(int number)
137 switch (number) {
138 case SIGINT:
139 sigint = 1;
140 break;
141 case SIGHUP:
142 break;
143 default:
144 break;
148 static void timer_elapsed(int number)
150 itimer.it_interval.tv_sec = 0;
151 itimer.it_interval.tv_usec = interval;
152 itimer.it_value.tv_sec = 0;
153 itimer.it_value.tv_usec = interval;
155 pull_and_flush_tx_ring(sock);
156 setitimer(ITIMER_REAL, &itimer, NULL);
159 static void header(void)
161 printf("%s%s%s\n", colorize_start(bold), "trafgen "
162 VERSION_STRING, colorize_end());
165 static void help(void)
167 printf("\ntrafgen %s, network packet generator\n",
168 VERSION_STRING);
169 printf("http://www.netsniff-ng.org\n\n");
170 printf("Usage: trafgen [options]\n");
171 printf("Options:\n");
172 printf(" -d|--dev <netdev> Networking Device i.e., eth0\n");
173 printf(" -c|--conf <file> Packet configuration file\n");
174 printf(" -J|--jumbo-support Support for 64KB Super Jumbo Frames\n");
175 printf(" Default TX slot: 2048Byte\n");
176 printf(" -n|--num <uint> Number of packets until exit\n");
177 printf(" `-- 0 Loop until interrupt (default)\n");
178 printf(" `- n Send n packets and done\n");
179 printf(" -r|--rand Randomize packet selection process\n");
180 printf(" Instead of a round robin selection\n");
181 printf(" -t|--gap <int> Interpacket gap in us (approx)\n");
182 printf(" -S|--ring-size <size> Manually set ring size to <size>:\n");
183 printf(" mmap space in KB/MB/GB, e.g. \'10MB\'\n");
184 printf(" -k|--kernel-pull <int> Kernel pull from user interval in us\n");
185 printf(" Default is 10us where the TX_RING\n");
186 printf(" is populated with payload from uspace\n");
187 printf(" -b|--bind-cpu <cpu> Bind to specific CPU (or CPU-range)\n");
188 printf(" -B|--unbind-cpu <cpu> Forbid to use specific CPU (or CPU-range)\n");
189 printf(" -H|--prio-high Make this high priority process\n");
190 printf(" -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n");
191 printf(" -v|--version Show version\n");
192 printf(" -h|--help Guess what?!\n");
193 printf("\n");
194 printf("Examples:\n");
195 printf(" See trafgen.txf for configuration file examples.\n");
196 printf(" trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0\n");
197 printf(" trafgen --dev eth0 --conf trafgen.txf --rand --gap 1000\n");
198 printf(" trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0 --num 10 --rand\n");
199 printf("\n");
200 printf("Note:\n");
201 printf(" This tool is targeted for network developers! You should\n");
202 printf(" be aware of what you are doing and what these options above\n");
203 printf(" mean! Only use this tool in an isolated LAN that you own!\n");
204 printf("\n");
205 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
206 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
207 printf("Swiss federal institute of technology (ETH Zurich)\n");
208 printf("License: GNU GPL version 2\n");
209 printf("This is free software: you are free to change and redistribute it.\n");
210 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
212 die();
215 static void version(void)
217 printf("\ntrafgen %s, network packet generator\n",
218 VERSION_STRING);
219 printf("http://www.netsniff-ng.org\n\n");
220 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
221 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
222 printf("Swiss federal institute of technology (ETH Zurich)\n");
223 printf("License: GNU GPL version 2\n");
224 printf("This is free software: you are free to change and redistribute it.\n");
225 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
227 die();
231 * TX_RING doen't allow us to specify inter-packet gaps, see
232 * http://lingrok.org/source/xref/linux-2.6-linus/net/packet/af_packet.c,
233 * function tpacket_fill_skb(), so instead, we use sendto(2). Since
234 * this is also not high-perf, copying between address spaces is okay.
236 static void tx_tgap_or_die(struct mode *mode, struct pktconf *cfg)
238 int ifindex, mtu, ret;
239 size_t l, c, r;
240 struct sockaddr_ll s_addr;
241 unsigned long num = 1;
242 char *pkt;
243 struct counter *cnt;
244 struct randomizer *rnd;
246 if (!mode || !cfg)
247 panic("Panic over invalid args for TX trigger!\n");
248 if (cfg->len == 0)
249 panic("Panic over invalid args for TX trigger!\n");
250 if (!device_up_and_running(mode->device))
251 panic("Device not up and running!\n");
253 mtu = device_mtu(mode->device);
254 for (l = 0; l < cfg->len; ++l) {
255 /* eth src + eth dst + type == 14, fcs added by driver */
256 if (cfg->pkts[l].plen > mtu + 14)
257 panic("Device MTU < than your packet size!\n");
258 if (cfg->pkts[l].plen <= 14)
259 panic("Device packet size too short!\n");
262 set_memcpy();
263 sock = pf_socket();
264 pkt = xmalloc_aligned(mtu, 64);
265 memset(pkt, 0, mtu);
266 ifindex = device_ifindex(mode->device);
268 if (cfg->num > 0)
269 num = cfg->num;
271 printf("MD: TX %s %luus\n\n", mode->rand ? "RND" : "RR", cfg->gap);
272 printf("Running! Hang up with ^C!\n\n");
274 memset(&s_addr, 0, sizeof(s_addr));
275 s_addr.sll_family = PF_PACKET;
276 s_addr.sll_halen = ETH_ALEN;
277 s_addr.sll_ifindex = ifindex;
279 l = 0;
280 while (likely(sigint == 0) && likely(num > 0)) {
281 for (c = 0; c < cfg->pkts[l].clen; ++c) {
282 cnt = &(cfg->pkts[l].cnt[c]);
283 cnt->val -= cnt->min;
284 cnt->val = (cnt->val + cnt->inc) %
285 (cnt->max - cnt->min + 1);
286 cnt->val += cnt->min;
287 cfg->pkts[l].payload[cnt->off] = cnt->val;
290 for (r = 0; r < cfg->pkts[l].rlen; ++r) {
291 rnd = &(cfg->pkts[l].rnd[r]);
292 rnd->val = lcrand(rnd->val);
293 cfg->pkts[l].payload[rnd->off] = rnd->val;
296 __memcpy(pkt, cfg->pkts[l].payload, cfg->pkts[l].plen);
297 mode->stats.tx_bytes += cfg->pkts[l].plen;
298 mode->stats.tx_packets++;
300 ret = sendto(sock, pkt, cfg->pkts[l].plen, 0,
301 (struct sockaddr *) &s_addr, sizeof(s_addr));
302 if (ret < 0)
303 whine("sendto error!\n");
304 if (mode->rand)
305 l = mt_rand_int32() % cfg->len;
306 else {
307 l++;
308 if (l >= cfg->len)
309 l = 0;
311 if (cfg->num > 0)
312 num--;
314 xusleep2(cfg->gap);
317 close(sock);
318 xfree(pkt);
320 fflush(stdout);
321 printf("\n");
322 printf("\r%lu frames outgoing\n", mode->stats.tx_packets);
323 printf("\r%lu bytes outgoing\n", mode->stats.tx_bytes);
326 static void tx_fire_or_die(struct mode *mode, struct pktconf *cfg)
328 int irq, ifindex, mtu;
329 unsigned int size, it = 0;
330 unsigned long num = 1;
331 uint8_t *out = NULL;
332 size_t l , c, r;
333 struct ring tx_ring;
334 struct frame_map *hdr;
335 struct counter *cnt;
336 struct randomizer *rnd;
338 if (!mode || !cfg)
339 panic("Panic over invalid args for TX trigger!\n");
340 if (cfg->len == 0)
341 panic("Panic over invalid args for TX trigger!\n");
342 if (!device_up_and_running(mode->device))
343 panic("Device not up and running!\n");
345 mtu = device_mtu(mode->device);
346 for (l = 0; l < cfg->len; ++l) {
347 /* eth src + eth dst + type == 14, fcs added by driver */
348 if (cfg->pkts[l].plen > mtu + 14)
349 panic("Device MTU < than your packet size!\n");
350 if (cfg->pkts[l].plen <= 14)
351 panic("Device packet size too short!\n");
354 set_memcpy();
355 sock = pf_socket();
357 memset(&tx_ring, 0, sizeof(tx_ring));
359 ifindex = device_ifindex(mode->device);
360 size = ring_size(mode->device, mode->reserve_size);
362 set_packet_loss_discard(sock);
363 setup_tx_ring_layout(sock, &tx_ring, size, mode->jumbo_support);
364 create_tx_ring(sock, &tx_ring);
365 mmap_tx_ring(sock, &tx_ring);
366 alloc_tx_ring_frames(&tx_ring);
367 bind_tx_ring(sock, &tx_ring, ifindex);
368 mt_init_by_seed_time();
370 if (mode->cpu >= 0 && ifindex > 0) {
371 irq = device_irq_number(mode->device);
372 device_bind_irq_to_cpu(mode->cpu, irq);
373 printf("IRQ: %s:%d > CPU%d\n", mode->device, irq,
374 mode->cpu);
377 if (mode->kpull)
378 interval = mode->kpull;
379 if (cfg->num > 0)
380 num = cfg->num;
382 printf("MD: FIRE %s %luus\n\n", mode->rand ? "RND" : "RR", interval);
383 printf("Running! Hang up with ^C!\n\n");
385 itimer.it_interval.tv_sec = 0;
386 itimer.it_interval.tv_usec = interval;
387 itimer.it_value.tv_sec = 0;
388 itimer.it_value.tv_usec = interval;
389 setitimer(ITIMER_REAL, &itimer, NULL);
391 l = 0;
392 while (likely(sigint == 0) && likely(num > 0)) {
393 while (user_may_pull_from_tx(tx_ring.frames[it].iov_base) &&
394 likely(num > 0)) {
395 hdr = tx_ring.frames[it].iov_base;
396 /* Kernel assumes: data = ph.raw + po->tp_hdrlen -
397 * sizeof(struct sockaddr_ll); */
398 out = ((uint8_t *) hdr) + TPACKET_HDRLEN -
399 sizeof(struct sockaddr_ll);
401 hdr->tp_h.tp_snaplen = cfg->pkts[l].plen;
402 hdr->tp_h.tp_len = cfg->pkts[l].plen;
404 for (c = 0; c < cfg->pkts[l].clen; ++c) {
405 cnt = &(cfg->pkts[l].cnt[c]);
406 cnt->val -= cnt->min;
407 cnt->val = (cnt->val + cnt->inc) %
408 (cnt->max - cnt->min + 1);
409 cnt->val += cnt->min;
410 cfg->pkts[l].payload[cnt->off] = cnt->val;
413 for (r = 0; r < cfg->pkts[l].rlen; ++r) {
414 rnd = &(cfg->pkts[l].rnd[r]);
415 rnd->val = lcrand(rnd->val);
416 cfg->pkts[l].payload[rnd->off] = rnd->val;
419 __memcpy(out, cfg->pkts[l].payload, cfg->pkts[l].plen);
420 mode->stats.tx_bytes += cfg->pkts[l].plen;
421 mode->stats.tx_packets++;
423 if (mode->rand)
424 l = mt_rand_int32() % cfg->len;
425 else {
426 l++;
427 if (l >= cfg->len)
428 l = 0;
431 kernel_may_pull_from_tx(&hdr->tp_h);
432 next_slot(&it, &tx_ring);
434 if (cfg->num > 0)
435 num--;
436 if (unlikely(sigint == 1))
437 break;
441 destroy_tx_ring(sock, &tx_ring);
442 close(sock);
444 fflush(stdout);
445 printf("\n");
446 printf("\r%lu frames outgoing\n", mode->stats.tx_packets);
447 printf("\r%lu bytes outgoing\n", mode->stats.tx_bytes);
450 #define TYPE_NUM 0
451 #define TYPE_CNT 1
452 #define TYPE_RND 2
453 #define TYPE_EOL 3
455 static inline char *getuint_or_obj(char *in, uint32_t *out, int *type)
457 if (*in == '\n') {
458 *type = TYPE_EOL;
459 } else if (*in == '$') {
460 in++;
461 if (!strncmp("II", in, strlen("II"))) {
462 in += 2;
463 in = getuint(in, out);
464 *type = TYPE_CNT;
465 } else if (!strncmp("PRB", in, strlen("PRB"))) {
466 *type = TYPE_RND;
467 in += 3;
468 } else
469 panic("Syntax error!\n");
470 } else {
471 in = getuint(in, out);
472 *type = TYPE_NUM;
475 return in;
478 static void dump_conf(struct pktconf *cfg)
480 size_t i, j;
482 info("n %lu, gap %lu us, pkts %zu\n", cfg->num, cfg->gap, cfg->len);
483 if (cfg->len == 0)
484 return;
486 for (i = 0; i < cfg->len; ++i) {
487 info("[%zu] pkt\n", i);
488 info(" len %zu cnts %zu rnds %zu\n", cfg->pkts[i].plen,
489 cfg->pkts[i].clen, cfg->pkts[i].rlen);
490 info(" payload ");
491 for (j = 0; j < cfg->pkts[i].plen; ++j)
492 info("%02x ", cfg->pkts[i].payload[j]);
493 info("\n");
494 for (j = 0; j < cfg->pkts[i].clen; ++j)
495 info(" cnt%zu [%u,%u], inc %u, off %zu\n",
496 j, cfg->pkts[i].cnt[j].min,
497 cfg->pkts[i].cnt[j].max,
498 cfg->pkts[i].cnt[j].inc,
499 cfg->pkts[i].cnt[j].off);
500 for (j = 0; j < cfg->pkts[i].rlen; ++j)
501 info(" rnd%zu off %zu\n",
502 j, cfg->pkts[i].rnd[j].off);
506 /* Seems to need a rewrite later ;-) */
507 static void parse_conf_or_die(char *file, struct pktconf *cfg)
509 unsigned int withinpkt = 0;
510 unsigned long line = 0;
511 char *pb, buff[1024];
512 FILE *fp;
513 struct counter *cnts = NULL;
514 size_t l = 0;
515 off_t offset = 0;
517 if (!file || !cfg)
518 panic("Panic over invalid args for the parser!\n");
520 fp = fopen(file, "r");
521 if (!fp)
522 panic("Cannot open config file!\n");
523 memset(buff, 0, sizeof(buff));
525 info("CFG:\n");
526 srand(time(NULL));
528 while (fgets(buff, sizeof(buff), fp) != NULL) {
529 line++;
530 buff[sizeof(buff) - 1] = 0;
531 pb = skips(buff);
533 /* A comment or junk. Skip this line */
534 if (*pb == '#' || *pb == '\n') {
535 memset(buff, 0, sizeof(buff));
536 continue;
539 if (!withinpkt && *pb == '$') {
540 pb++;
541 if (!strncmp("II", pb, strlen("II"))) {
542 uint32_t id, min = 0, max = 0xFF, inc = 1;
543 pb += 2;
544 pb = getuint(pb, &id);
545 pb = skipchar(pb, ':');
546 pb = skips(pb);
547 pb = getuint(pb, &min);
548 pb = skipchar(pb, ',');
549 pb = getuint(pb, &max);
550 pb = skipchar(pb, ',');
551 pb = getuint(pb, &inc);
552 l++;
553 cnts = xrealloc(cnts, 1, l * sizeof(*cnts));
554 cnts[l - 1].id = 0xFF & id;
555 cnts[l - 1].min = 0xFF & min;
556 cnts[l - 1].max = 0xFF & max;
557 cnts[l - 1].inc = 0xFF & inc;
558 if (cnts[l - 1].min >= cnts[l - 1].max)
559 panic("Counter min >= max!\n");
560 if (cnts[l - 1].inc >= cnts[l - 1].max)
561 panic("Counter inc >= max!\n");
562 } else if (!strncmp("P", pb, strlen("P"))) {
563 uint32_t id;
564 pb++;
565 pb = getuint(pb, &id);
566 pb = skips(pb);
567 pb = skipchar(pb, '{');
568 withinpkt = 1;
569 cfg->len++;
570 cfg->pkts = xrealloc(cfg->pkts, 1,
571 cfg->len * sizeof(*cfg->pkts));
572 memset(&cfg->pkts[cfg->len - 1], 0,
573 sizeof(cfg->pkts[cfg->len - 1]));
574 offset = 0;
575 } else
576 panic("Unknown instruction! Syntax error "
577 "on line %lu!\n", line);
578 } else if (withinpkt && *pb == '}') {
579 withinpkt = 0;
580 } else if (withinpkt) {
581 int type, i, found;
582 uint32_t val = 0;
583 while (1) {
584 found = 0;
585 pb = getuint_or_obj(pb, &val, &type);
586 if (type == TYPE_EOL)
587 break;
588 if (type == TYPE_CNT) {
589 size_t z;
590 struct counter *new;
591 for (i = 0; i < l; ++i) {
592 if (val == cnts[i].id) {
593 found = 1;
594 break;
597 if (!found)
598 panic("Counter %u not found!\n");
600 val = cnts[i].min;
601 z = ++(cfg->pkts[cfg->len - 1].clen);
602 cfg->pkts[cfg->len - 1].cnt =
603 xrealloc(cfg->pkts[cfg->len - 1].cnt,
604 1, z * sizeof(struct counter));
605 new = &cfg->pkts[cfg->len - 1].cnt[z - 1];
606 new->min = cnts[i].min;
607 new->max = cnts[i].max;
608 new->inc = cnts[i].inc;
609 new->off = offset;
610 new->val = val;
611 } else if (type == TYPE_RND) {
612 size_t z;
613 struct randomizer *new;
615 val = 0xFF & rand();
616 z = ++(cfg->pkts[cfg->len - 1].rlen);
617 cfg->pkts[cfg->len - 1].rnd =
618 xrealloc(cfg->pkts[cfg->len - 1].rnd,
619 1, z * sizeof(struct randomizer));
620 new = &cfg->pkts[cfg->len - 1].rnd[z - 1];
621 new->val = val;
622 new->off = offset;
625 cfg->pkts[cfg->len - 1].plen++;
626 cfg->pkts[cfg->len - 1].payload =
627 xrealloc(cfg->pkts[cfg->len - 1].payload,
628 1, cfg->pkts[cfg->len - 1].plen);
629 cfg->pkts[cfg->len - 1].payload[cfg->pkts[cfg->len - 1].plen - 1] =
630 0xFF & val;
631 offset++;
632 pb = skipchar_s(pb, ',');
634 } else
635 panic("Syntax error!\n");
636 memset(buff, 0, sizeof(buff));
639 fclose(fp);
640 if (cnts)
641 xfree(cnts);
642 dump_conf(cfg);
645 static void cleanup_cfg(struct pktconf *cfg)
647 size_t l;
649 for (l = 0; l < cfg->len; ++l) {
650 if (cfg->pkts[l].plen > 0)
651 xfree(cfg->pkts[l].payload);
652 if (cfg->pkts[l].clen > 0)
653 xfree(cfg->pkts[l].cnt);
654 if (cfg->pkts[l].rlen > 0)
655 xfree(cfg->pkts[l].rnd);
658 if (cfg->len > 0)
659 xfree(cfg->pkts);
662 static int main_loop(struct mode *mode, char *confname, unsigned long pkts,
663 unsigned long gap)
665 struct pktconf cfg = {
666 .num = pkts,
667 .gap = gap,
668 .len = 0,
671 parse_conf_or_die(confname, &cfg);
672 if (gap > 0)
673 tx_tgap_or_die(mode, &cfg);
674 else
675 tx_fire_or_die(mode, &cfg);
676 cleanup_cfg(&cfg);
678 return 0;
681 int main(int argc, char **argv)
683 int c, opt_index, ret, i, j;
684 char *confname = NULL, *ptr;
685 unsigned long pkts = 0, gap = 0;
686 bool prio_high = false;
687 struct mode mode;
689 check_for_root_maybe_die();
691 memset(&mode, 0, sizeof(mode));
692 mode.cpu = CPU_UNKNOWN;
694 while ((c = getopt_long(argc, argv, short_options, long_options,
695 &opt_index)) != EOF) {
696 switch (c) {
697 case 'h':
698 help();
699 break;
700 case 'v':
701 version();
702 break;
703 case 'd':
704 mode.device = xstrndup(optarg, IFNAMSIZ);
705 break;
706 case 'r':
707 mode.rand = 1;
708 break;
709 case 'J':
710 mode.jumbo_support = 1;
711 break;
712 case 'c':
713 confname = xstrdup(optarg);
714 break;
715 case 'k':
716 mode.kpull = atol(optarg);
717 break;
718 case 'n':
719 pkts = atol(optarg);
720 break;
721 case 't':
722 gap = atol(optarg);
723 break;
724 case 'S':
725 ptr = optarg;
726 mode.reserve_size = 0;
728 for (j = i = strlen(optarg); i > 0; --i) {
729 if (!isdigit(optarg[j - i]))
730 break;
731 ptr++;
734 if (!strncmp(ptr, "KB", strlen("KB")))
735 mode.reserve_size = 1 << 10;
736 else if (!strncmp(ptr, "MB", strlen("MB")))
737 mode.reserve_size = 1 << 20;
738 else if (!strncmp(ptr, "GB", strlen("GB")))
739 mode.reserve_size = 1 << 30;
740 else
741 panic("Syntax error in ring size param!\n");
743 *ptr = 0;
744 mode.reserve_size *= atoi(optarg);
745 break;
746 case 'b':
747 set_cpu_affinity(optarg, 0);
748 /* Take the first CPU for rebinding the IRQ */
749 if (mode.cpu != CPU_NOTOUCH)
750 mode.cpu = atoi(optarg);
751 break;
752 case 'B':
753 set_cpu_affinity(optarg, 1);
754 break;
755 case 'H':
756 prio_high = true;
757 break;
758 case 'Q':
759 mode.cpu = CPU_NOTOUCH;
760 break;
761 case '?':
762 switch (optopt) {
763 case 'd':
764 case 'c':
765 case 'n':
766 case 'S':
767 case 'b':
768 case 'k':
769 case 'B':
770 case 't':
771 panic("Option -%c requires an argument!\n",
772 optopt);
773 default:
774 if (isprint(optopt))
775 whine("Unknown option character "
776 "`0x%X\'!\n", optopt);
777 die();
779 default:
780 break;
784 if (argc < 5)
785 help();
786 if (mode.device == NULL)
787 error_and_die(EXIT_FAILURE, "No networking device given!\n");
788 if (confname == NULL)
789 error_and_die(EXIT_FAILURE, "No configuration file given!\n");
790 if (device_mtu(mode.device) == 0)
791 error_and_die(EXIT_FAILURE, "This is no networking device!\n");
792 if (device_up_and_running(mode.device) == 0)
793 error_and_die(EXIT_FAILURE, "Networking device not running!\n");
795 register_signal(SIGINT, signal_handler);
796 register_signal(SIGHUP, signal_handler);
797 register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO);
799 header();
801 if (prio_high == true) {
802 set_proc_prio(get_default_proc_prio());
803 set_sched_status(get_default_sched_policy(),
804 get_default_sched_prio());
807 ret = main_loop(&mode, confname, pkts, gap);
809 xfree(mode.device);
810 xfree(confname);
811 return ret;