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, version 2.
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,488,095 pps 64 Byte pps have been achieved with 2 trafgen instances
11 * bound to different CPUs from the userspace and turned off pause frames,
12 * ask Ronald from NST (Network Security Toolkit) for more details. ;-)
13 * So, this line-rate result is the very same as pktgen from kernelspace!
15 * Who can now hold the fords when the King of the Nine Riders comes? And
16 * other armies will come. I am too late. All is lost. I tarried on the
17 * way. All is lost. Even if my errand is performed, no one will ever
18 * know. There will be no one I can tell. It will be in vain.
20 * -- The Lord of the Rings, Frodo thinking,
21 * Chapter 'The Stairs of Cirith Ungol'.
28 trafgen - a high-performance zero-copy network packet generator
32 trafgen -d|--dev <netdev> -c|--conf <file> [-J|--jumbo-support][-n|--num <uint>]
33 [-r|--rand][-t|--gap <usec>][-S|--ring-size <size>]
34 [-k|--kernel-pull <usec>][-b|--bind-cpu <cpu>][-B|--unbind-cpu <cpu>]
35 [-H|--prio-high][-Q|--notouch-irq][-v|--version][-h|--help]
39 A high-performance network traffic generator that uses the zero-copy TX_RING
40 for network I/O. For instance, on comodity Gigabit hardware up to 1,488,095 pps
41 64 Byte pps have been achieved with trafgen.
47 =item trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0
49 Use packet configuration trafgen.txf, eth0 as transmission device and CPU0
50 for binding the process.
60 Print help text and lists all options.
66 =item -d|--dev <netdev>
68 Device for transmission i.e., eth0.
70 =item -c|--conf <conf>
72 Path to packet configuration file.
74 =item -J|--jumbo-support
76 Support for 64KB Super Jumbo Frames
80 Number of packets to generate before exiting.
81 0 means forever until SIGINT.
85 Randomize packet selection process instead of round-robin.
89 Interpacket gap in microseconds.
91 =item -S|--ring-size <size>
93 Manually set ring size to <size>: mmap space in KB/MB/GB.
95 =item -k|--kernel-pull <uint>
97 Kernel pull from user interval in microseconds.
98 Default value is 10 microseconds.
100 =item -b|--bind-cpu <cpu>
102 Bind to specific CPU (or CPU-range).
104 =item -B|--unbind-cpu <cpu>
106 Forbid to use specific CPU (or CPU-range).
110 Make this high priority process.
112 =item -Q|--notouch-irq
114 Do not touch IRQ CPU affinity of NIC.
122 =item Generate traffic defined in trafgen.txf on eth0 using CPU 0
124 trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0
126 =item Generate traffic on eth0 using CPU 0, wait 100 us between packets
128 trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0 --gap 100
130 =item Generate 100,000 packet on eth0 using CPU 0
132 trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0 --num 100000
138 Written by Daniel Borkmann <daniel@netsniff-ng.org>
142 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
146 Please report bugs to <bugs@netsniff-ng.org>
157 #include <sys/socket.h>
158 #include <sys/types.h>
159 #include <sys/stat.h>
160 #include <sys/time.h>
167 #include <net/ethernet.h>
170 #include "opt_memcpy.h"
178 #include "timespec.h"
202 struct randomizer
*rnd
;
214 unsigned long tx_bytes
;
215 unsigned long tx_packets
;
224 /* 0 for automatic, > 0 for manual */
225 unsigned int reserve_size
;
229 #define CPU_UNKNOWN -1
230 #define CPU_NOTOUCH -2
232 sig_atomic_t sigint
= 0;
234 static const char *short_options
= "d:c:n:t:vJhS:HQb:B:rk:";
236 static struct option long_options
[] = {
237 {"dev", required_argument
, 0, 'd'},
238 {"conf", required_argument
, 0, 'c'},
239 {"num", required_argument
, 0, 'n'},
240 {"gap", required_argument
, 0, 't'},
241 {"ring-size", required_argument
, 0, 'S'},
242 {"bind-cpu", required_argument
, 0, 'b'},
243 {"unbind-cpu", required_argument
, 0, 'B'},
244 {"kernel-pull", required_argument
, 0, 'k'},
245 {"jumbo-support", no_argument
, 0, 'J'},
246 {"rand", no_argument
, 0, 'r'},
247 {"prio-high", no_argument
, 0, 'H'},
248 {"notouch-irq", no_argument
, 0, 'Q'},
249 {"version", no_argument
, 0, 'v'},
250 {"help", no_argument
, 0, 'h'},
254 static struct itimerval itimer
;
256 static unsigned long interval
= TX_KERNEL_PULL_INT
;
258 static inline uint8_t lcrand(uint8_t val
)
260 return 0xFF & (3 * val
+ 3);
263 static void signal_handler(int number
)
276 static void timer_elapsed(int number
)
278 itimer
.it_interval
.tv_sec
= 0;
279 itimer
.it_interval
.tv_usec
= interval
;
280 itimer
.it_value
.tv_sec
= 0;
281 itimer
.it_value
.tv_usec
= interval
;
283 pull_and_flush_tx_ring(sock
);
284 setitimer(ITIMER_REAL
, &itimer
, NULL
);
287 static void header(void)
289 printf("%s%s%s\n", colorize_start(bold
), "trafgen "
290 VERSION_STRING
, colorize_end());
293 static void help(void)
295 printf("\ntrafgen %s, high-perf zero-copy network packet generator\n",
297 printf("http://www.netsniff-ng.org\n\n");
298 printf("Usage: trafgen [options]\n");
299 printf("Options:\n");
300 printf(" -d|--dev <netdev> Networking Device i.e., eth0\n");
301 printf(" -c|--conf <file> Packet configuration file\n");
302 printf(" -J|--jumbo-support Support for 64KB Super Jumbo Frames\n");
303 printf(" Default TX slot: 2048Byte\n");
304 printf(" -n|--num <uint> Number of packets until exit\n");
305 printf(" `-- 0 Loop until interrupt (default)\n");
306 printf(" `- n Send n packets and done\n");
307 printf(" -r|--rand Randomize packet selection process\n");
308 printf(" Instead of a round robin selection\n");
309 printf(" -t|--gap <uint> Interpacket gap in us (approx)\n");
310 printf(" -S|--ring-size <size> Manually set ring size to <size>:\n");
311 printf(" mmap space in KB/MB/GB, e.g. \'10MB\'\n");
312 printf(" -k|--kernel-pull <uint>Kernel pull from user interval in us\n");
313 printf(" Default is 10us where the TX_RING\n");
314 printf(" is populated with payload from uspace\n");
315 printf(" -b|--bind-cpu <cpu> Bind to specific CPU (or CPU-range)\n");
316 printf(" -B|--unbind-cpu <cpu> Forbid to use specific CPU (or CPU-range)\n");
317 printf(" -H|--prio-high Make this high priority process\n");
318 printf(" -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n");
319 printf(" -v|--version Show version\n");
320 printf(" -h|--help Guess what?!\n");
322 printf("Examples:\n");
323 printf(" See trafgen.txf for configuration file examples.\n");
324 printf(" trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0\n");
325 printf(" trafgen --dev eth0 --conf trafgen.txf --rand --gap 1000\n");
326 printf(" trafgen --dev eth0 --conf trafgen.txf --bind-cpu 0 --num 10 --rand\n");
329 printf(" This tool is targeted for network developers! You should\n");
330 printf(" be aware of what you are doing and what these options above\n");
331 printf(" mean! Only use this tool in an isolated LAN that you own!\n");
333 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
334 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
335 printf("Swiss federal institute of technology (ETH Zurich)\n");
336 printf("License: GNU GPL version 2\n");
337 printf("This is free software: you are free to change and redistribute it.\n");
338 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
343 static void version(void)
345 printf("\ntrafgen %s, high-perf zero-copy network packet generator\n",
347 printf("http://www.netsniff-ng.org\n\n");
348 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
349 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
350 printf("Swiss federal institute of technology (ETH Zurich)\n");
351 printf("License: GNU GPL version 2\n");
352 printf("This is free software: you are free to change and redistribute it.\n");
353 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
359 * TX_RING doen't allow us to specify inter-packet gaps, see
360 * http://lingrok.org/source/xref/linux-2.6-linus/net/packet/af_packet.c,
361 * function tpacket_fill_skb(), so instead, we use sendto(2). Since
362 * this is also not high-perf, copying between address spaces is okay.
364 static void tx_tgap_or_die(struct mode
*mode
, struct pktconf
*cfg
)
366 int ifindex
, mtu
, ret
;
368 struct sockaddr_ll s_addr
;
369 unsigned long num
= 1;
372 struct randomizer
*rnd
;
375 panic("Panic over invalid args for TX trigger!\n");
377 panic("Panic over invalid args for TX trigger!\n");
378 if (!device_up_and_running(mode
->device
))
379 panic("Device not up and running!\n");
381 mtu
= device_mtu(mode
->device
);
382 for (l
= 0; l
< cfg
->len
; ++l
) {
383 /* eth src + eth dst + type == 14, fcs added by driver */
384 if (cfg
->pkts
[l
].plen
> mtu
+ 14)
385 panic("Device MTU < than your packet size!\n");
386 if (cfg
->pkts
[l
].plen
<= 14)
387 panic("Device packet size too short!\n");
392 pkt
= xmalloc_aligned(mtu
, 64);
394 ifindex
= device_ifindex(mode
->device
);
399 printf("MD: TX %s %luus\n\n", mode
->rand
? "RND" : "RR", cfg
->gap
);
400 printf("Running! Hang up with ^C!\n\n");
402 memset(&s_addr
, 0, sizeof(s_addr
));
403 s_addr
.sll_family
= PF_PACKET
;
404 s_addr
.sll_halen
= ETH_ALEN
;
405 s_addr
.sll_ifindex
= ifindex
;
408 while (likely(sigint
== 0) && likely(num
> 0)) {
409 for (c
= 0; c
< cfg
->pkts
[l
].clen
; ++c
) {
410 cnt
= &(cfg
->pkts
[l
].cnt
[c
]);
411 cnt
->val
-= cnt
->min
;
412 cnt
->val
= (cnt
->val
+ cnt
->inc
) %
413 (cnt
->max
- cnt
->min
+ 1);
414 cnt
->val
+= cnt
->min
;
415 cfg
->pkts
[l
].payload
[cnt
->off
] = cnt
->val
;
418 for (r
= 0; r
< cfg
->pkts
[l
].rlen
; ++r
) {
419 rnd
= &(cfg
->pkts
[l
].rnd
[r
]);
420 rnd
->val
= lcrand(rnd
->val
);
421 cfg
->pkts
[l
].payload
[rnd
->off
] = rnd
->val
;
424 __memcpy(pkt
, cfg
->pkts
[l
].payload
, cfg
->pkts
[l
].plen
);
425 mode
->stats
.tx_bytes
+= cfg
->pkts
[l
].plen
;
426 mode
->stats
.tx_packets
++;
428 ret
= sendto(sock
, pkt
, cfg
->pkts
[l
].plen
, 0,
429 (struct sockaddr
*) &s_addr
, sizeof(s_addr
));
431 whine("sendto error!\n");
433 l
= mt_rand_int32() % cfg
->len
;
450 printf("\r%12lu frames outgoing\n", mode
->stats
.tx_packets
);
451 printf("\r%12lu bytes outgoing\n", mode
->stats
.tx_bytes
);
454 static void tx_fire_or_die(struct mode
*mode
, struct pktconf
*cfg
)
456 int irq
, ifindex
, mtu
;
457 unsigned int size
, it
= 0;
458 unsigned long num
= 1;
462 struct frame_map
*hdr
;
464 struct randomizer
*rnd
;
467 panic("Panic over invalid args for TX trigger!\n");
469 panic("Panic over invalid args for TX trigger!\n");
470 if (!device_up_and_running(mode
->device
))
471 panic("Device not up and running!\n");
473 mtu
= device_mtu(mode
->device
);
474 for (l
= 0; l
< cfg
->len
; ++l
) {
475 /* eth src + eth dst + type == 14, fcs added by driver */
476 if (cfg
->pkts
[l
].plen
> mtu
+ 14)
477 panic("Device MTU < than your packet size!\n");
478 if (cfg
->pkts
[l
].plen
<= 14)
479 panic("Device packet size too short!\n");
485 memset(&tx_ring
, 0, sizeof(tx_ring
));
487 ifindex
= device_ifindex(mode
->device
);
488 size
= ring_size(mode
->device
, mode
->reserve_size
);
490 set_packet_loss_discard(sock
);
491 setup_tx_ring_layout(sock
, &tx_ring
, size
, mode
->jumbo_support
);
492 create_tx_ring(sock
, &tx_ring
);
493 mmap_tx_ring(sock
, &tx_ring
);
494 alloc_tx_ring_frames(&tx_ring
);
495 bind_tx_ring(sock
, &tx_ring
, ifindex
);
496 mt_init_by_seed_time();
498 if (mode
->cpu
>= 0 && ifindex
> 0) {
499 irq
= device_irq_number(mode
->device
);
500 device_bind_irq_to_cpu(mode
->cpu
, irq
);
501 printf("IRQ: %s:%d > CPU%d\n", mode
->device
, irq
,
506 interval
= mode
->kpull
;
510 printf("MD: FIRE %s %luus\n\n", mode
->rand
? "RND" : "RR", interval
);
511 printf("Running! Hang up with ^C!\n\n");
513 itimer
.it_interval
.tv_sec
= 0;
514 itimer
.it_interval
.tv_usec
= interval
;
515 itimer
.it_value
.tv_sec
= 0;
516 itimer
.it_value
.tv_usec
= interval
;
517 setitimer(ITIMER_REAL
, &itimer
, NULL
);
520 while (likely(sigint
== 0) && likely(num
> 0)) {
521 while (user_may_pull_from_tx(tx_ring
.frames
[it
].iov_base
) &&
523 hdr
= tx_ring
.frames
[it
].iov_base
;
524 /* Kernel assumes: data = ph.raw + po->tp_hdrlen -
525 * sizeof(struct sockaddr_ll); */
526 out
= ((uint8_t *) hdr
) + TPACKET_HDRLEN
-
527 sizeof(struct sockaddr_ll
);
529 hdr
->tp_h
.tp_snaplen
= cfg
->pkts
[l
].plen
;
530 hdr
->tp_h
.tp_len
= cfg
->pkts
[l
].plen
;
532 for (c
= 0; c
< cfg
->pkts
[l
].clen
; ++c
) {
533 cnt
= &(cfg
->pkts
[l
].cnt
[c
]);
534 cnt
->val
-= cnt
->min
;
535 cnt
->val
= (cnt
->val
+ cnt
->inc
) %
536 (cnt
->max
- cnt
->min
+ 1);
537 cnt
->val
+= cnt
->min
;
538 cfg
->pkts
[l
].payload
[cnt
->off
] = cnt
->val
;
541 for (r
= 0; r
< cfg
->pkts
[l
].rlen
; ++r
) {
542 rnd
= &(cfg
->pkts
[l
].rnd
[r
]);
543 rnd
->val
= lcrand(rnd
->val
);
544 cfg
->pkts
[l
].payload
[rnd
->off
] = rnd
->val
;
547 __memcpy(out
, cfg
->pkts
[l
].payload
, cfg
->pkts
[l
].plen
);
548 mode
->stats
.tx_bytes
+= cfg
->pkts
[l
].plen
;
549 mode
->stats
.tx_packets
++;
552 l
= mt_rand_int32() % cfg
->len
;
559 kernel_may_pull_from_tx(&hdr
->tp_h
);
560 next_slot(&it
, &tx_ring
);
564 if (unlikely(sigint
== 1))
569 destroy_tx_ring(sock
, &tx_ring
);
574 printf("\r%12lu frames outgoing\n", mode
->stats
.tx_packets
);
575 printf("\r%12lu bytes outgoing\n", mode
->stats
.tx_bytes
);
583 static inline char *getuint_or_obj(char *in
, uint32_t *out
, int *type
)
587 } else if (*in
== '$') {
589 if (!strncmp("II", in
, strlen("II"))) {
591 in
= getuint(in
, out
);
593 } else if (!strncmp("PRB", in
, strlen("PRB"))) {
597 panic("Syntax error!\n");
599 in
= getuint(in
, out
);
606 static void dump_conf(struct pktconf
*cfg
)
610 info("n %lu, gap %lu us, pkts %zu\n", cfg
->num
, cfg
->gap
, cfg
->len
);
614 for (i
= 0; i
< cfg
->len
; ++i
) {
615 info("[%zu] pkt\n", i
);
616 info(" len %zu cnts %zu rnds %zu\n", cfg
->pkts
[i
].plen
,
617 cfg
->pkts
[i
].clen
, cfg
->pkts
[i
].rlen
);
619 for (j
= 0; j
< cfg
->pkts
[i
].plen
; ++j
)
620 info("%02x ", cfg
->pkts
[i
].payload
[j
]);
622 for (j
= 0; j
< cfg
->pkts
[i
].clen
; ++j
)
623 info(" cnt%zu [%u,%u], inc %u, off %zu\n",
624 j
, cfg
->pkts
[i
].cnt
[j
].min
,
625 cfg
->pkts
[i
].cnt
[j
].max
,
626 cfg
->pkts
[i
].cnt
[j
].inc
,
627 cfg
->pkts
[i
].cnt
[j
].off
);
628 for (j
= 0; j
< cfg
->pkts
[i
].rlen
; ++j
)
629 info(" rnd%zu off %zu\n",
630 j
, cfg
->pkts
[i
].rnd
[j
].off
);
634 /* Seems to need a rewrite later ;-) */
635 static void parse_conf_or_die(char *file
, struct pktconf
*cfg
)
637 unsigned int withinpkt
= 0;
638 unsigned long line
= 0;
639 char *pb
, buff
[1024];
641 struct counter
*cnts
= NULL
;
646 panic("Panic over invalid args for the parser!\n");
648 fp
= fopen(file
, "r");
650 panic("Cannot open config file!\n");
651 memset(buff
, 0, sizeof(buff
));
656 while (fgets(buff
, sizeof(buff
), fp
) != NULL
) {
658 buff
[sizeof(buff
) - 1] = 0;
661 /* A comment or junk. Skip this line */
662 if (*pb
== '#' || *pb
== '\n') {
663 memset(buff
, 0, sizeof(buff
));
667 if (!withinpkt
&& *pb
== '$') {
669 if (!strncmp("II", pb
, strlen("II"))) {
670 uint32_t id
, min
= 0, max
= 0xFF, inc
= 1;
672 pb
= getuint(pb
, &id
);
673 pb
= skipchar(pb
, ':');
675 pb
= getuint(pb
, &min
);
676 pb
= skipchar(pb
, ',');
677 pb
= getuint(pb
, &max
);
678 pb
= skipchar(pb
, ',');
679 pb
= getuint(pb
, &inc
);
681 cnts
= xrealloc(cnts
, 1, l
* sizeof(*cnts
));
682 cnts
[l
- 1].id
= 0xFF & id
;
683 cnts
[l
- 1].min
= 0xFF & min
;
684 cnts
[l
- 1].max
= 0xFF & max
;
685 cnts
[l
- 1].inc
= 0xFF & inc
;
686 if (cnts
[l
- 1].min
>= cnts
[l
- 1].max
)
687 panic("Counter min >= max!\n");
688 if (cnts
[l
- 1].inc
>= cnts
[l
- 1].max
)
689 panic("Counter inc >= max!\n");
690 } else if (!strncmp("P", pb
, strlen("P"))) {
693 pb
= getuint(pb
, &id
);
695 pb
= skipchar(pb
, '{');
698 cfg
->pkts
= xrealloc(cfg
->pkts
, 1,
699 cfg
->len
* sizeof(*cfg
->pkts
));
700 memset(&cfg
->pkts
[cfg
->len
- 1], 0,
701 sizeof(cfg
->pkts
[cfg
->len
- 1]));
704 panic("Unknown instruction! Syntax error "
705 "on line %lu!\n", line
);
706 } else if (withinpkt
&& *pb
== '}') {
708 } else if (withinpkt
) {
713 pb
= getuint_or_obj(pb
, &val
, &type
);
714 if (type
== TYPE_EOL
)
716 if (type
== TYPE_CNT
) {
719 for (i
= 0; i
< l
; ++i
) {
720 if (val
== cnts
[i
].id
) {
726 panic("Counter %u not found!\n");
729 z
= ++(cfg
->pkts
[cfg
->len
- 1].clen
);
730 cfg
->pkts
[cfg
->len
- 1].cnt
=
731 xrealloc(cfg
->pkts
[cfg
->len
- 1].cnt
,
732 1, z
* sizeof(struct counter
));
733 new = &cfg
->pkts
[cfg
->len
- 1].cnt
[z
- 1];
734 new->min
= cnts
[i
].min
;
735 new->max
= cnts
[i
].max
;
736 new->inc
= cnts
[i
].inc
;
739 } else if (type
== TYPE_RND
) {
741 struct randomizer
*new;
744 z
= ++(cfg
->pkts
[cfg
->len
- 1].rlen
);
745 cfg
->pkts
[cfg
->len
- 1].rnd
=
746 xrealloc(cfg
->pkts
[cfg
->len
- 1].rnd
,
747 1, z
* sizeof(struct randomizer
));
748 new = &cfg
->pkts
[cfg
->len
- 1].rnd
[z
- 1];
753 cfg
->pkts
[cfg
->len
- 1].plen
++;
754 cfg
->pkts
[cfg
->len
- 1].payload
=
755 xrealloc(cfg
->pkts
[cfg
->len
- 1].payload
,
756 1, cfg
->pkts
[cfg
->len
- 1].plen
);
757 cfg
->pkts
[cfg
->len
- 1].payload
[cfg
->pkts
[cfg
->len
- 1].plen
- 1] =
760 pb
= skipchar_s(pb
, ',');
763 panic("Syntax error!\n");
764 memset(buff
, 0, sizeof(buff
));
773 static void cleanup_cfg(struct pktconf
*cfg
)
777 for (l
= 0; l
< cfg
->len
; ++l
) {
778 if (cfg
->pkts
[l
].plen
> 0)
779 xfree(cfg
->pkts
[l
].payload
);
780 if (cfg
->pkts
[l
].clen
> 0)
781 xfree(cfg
->pkts
[l
].cnt
);
782 if (cfg
->pkts
[l
].rlen
> 0)
783 xfree(cfg
->pkts
[l
].rnd
);
790 static int main_loop(struct mode
*mode
, char *confname
, unsigned long pkts
,
793 struct pktconf cfg
= {
799 parse_conf_or_die(confname
, &cfg
);
801 tx_tgap_or_die(mode
, &cfg
);
803 tx_fire_or_die(mode
, &cfg
);
809 int main(int argc
, char **argv
)
811 int c
, opt_index
, ret
, i
, j
;
812 char *confname
= NULL
, *ptr
;
813 unsigned long pkts
= 0, gap
= 0;
814 bool prio_high
= false;
817 check_for_root_maybe_die();
819 memset(&mode
, 0, sizeof(mode
));
820 mode
.cpu
= CPU_UNKNOWN
;
822 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
823 &opt_index
)) != EOF
) {
832 mode
.device
= xstrndup(optarg
, IFNAMSIZ
);
838 mode
.jumbo_support
= 1;
841 confname
= xstrdup(optarg
);
844 mode
.kpull
= atol(optarg
);
854 mode
.reserve_size
= 0;
856 for (j
= i
= strlen(optarg
); i
> 0; --i
) {
857 if (!isdigit(optarg
[j
- i
]))
862 if (!strncmp(ptr
, "KB", strlen("KB")))
863 mode
.reserve_size
= 1 << 10;
864 else if (!strncmp(ptr
, "MB", strlen("MB")))
865 mode
.reserve_size
= 1 << 20;
866 else if (!strncmp(ptr
, "GB", strlen("GB")))
867 mode
.reserve_size
= 1 << 30;
869 panic("Syntax error in ring size param!\n");
872 mode
.reserve_size
*= atoi(optarg
);
875 set_cpu_affinity(optarg
, 0);
876 /* Take the first CPU for rebinding the IRQ */
877 if (mode
.cpu
!= CPU_NOTOUCH
)
878 mode
.cpu
= atoi(optarg
);
881 set_cpu_affinity(optarg
, 1);
887 mode
.cpu
= CPU_NOTOUCH
;
899 panic("Option -%c requires an argument!\n",
903 whine("Unknown option character "
904 "`0x%X\'!\n", optopt
);
914 if (mode
.device
== NULL
)
915 panic("No networking device given!\n");
916 if (confname
== NULL
)
917 panic("No configuration file given!\n");
918 if (device_mtu(mode
.device
) == 0)
919 panic("This is no networking device!\n");
920 if (device_up_and_running(mode
.device
) == 0)
921 panic("Networking device not running!\n");
923 register_signal(SIGINT
, signal_handler
);
924 register_signal(SIGHUP
, signal_handler
);
925 register_signal_f(SIGALRM
, timer_elapsed
, SA_SIGINFO
);
929 if (prio_high
== true) {
930 set_proc_prio(get_default_proc_prio());
931 set_sched_status(get_default_sched_policy(),
932 get_default_sched_prio());
935 ret
= main_loop(&mode
, confname
, pkts
, gap
);