1 |
/* |
2 |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
5 |
* Many thanks to Nicolas Szalay for his patch |
6 |
* for the command line parsing and virtual machine |
7 |
* settings (RAM, ROM, NVRAM, ...) |
8 |
*/ |
9 |
|
10 |
#include <stdio.h> |
11 |
#include <stdlib.h> |
12 |
#include <unistd.h> |
13 |
#include <string.h> |
14 |
#include <errno.h> |
15 |
#include <sys/types.h> |
16 |
#include <sys/stat.h> |
17 |
#include <sys/mman.h> |
18 |
#include <signal.h> |
19 |
#include <fcntl.h> |
20 |
#include <assert.h> |
21 |
#include <getopt.h> |
22 |
|
23 |
#include "dynamips.h" |
24 |
#include "cpu.h" |
25 |
#include "mips64_exec.h" |
26 |
#include "mips64_jit.h" |
27 |
#include "ppc32_exec.h" |
28 |
#include "ppc32_jit.h" |
29 |
#include "dev_c7200.h" |
30 |
#include "dev_c3600.h" |
31 |
#include "dev_c2691.h" |
32 |
#include "dev_c3725.h" |
33 |
#include "dev_c3745.h" |
34 |
#include "dev_c2600.h" |
35 |
#include "dev_c1700.h" |
36 |
#include "dev_c6msfc1.h" |
37 |
#include "dev_c6sup1.h" |
38 |
#include "ppc32_vmtest.h" |
39 |
#include "dev_vtty.h" |
40 |
#include "ptask.h" |
41 |
#include "timer.h" |
42 |
#include "plugin.h" |
43 |
#include "registry.h" |
44 |
#include "hypervisor.h" |
45 |
#include "net_io.h" |
46 |
#include "net_io_bridge.h" |
47 |
#include "net_io_filter.h" |
48 |
#include "crc.h" |
49 |
#include "atm.h" |
50 |
#include "frame_relay.h" |
51 |
#include "eth_switch.h" |
52 |
#ifdef GEN_ETH |
53 |
#include "gen_eth.h" |
54 |
#endif |
55 |
#ifdef PROFILE |
56 |
#include "profiler.h" |
57 |
#endif |
58 |
|
59 |
/* Default name for logfile */ |
60 |
#define LOGFILE_DEFAULT_NAME "dynamips_log.txt" |
61 |
|
62 |
/* Software version */ |
63 |
const char *sw_version = DYNAMIPS_VERSION"-"JIT_ARCH; |
64 |
|
65 |
/* Software version tag */ |
66 |
const char *sw_version_tag = "2007050300"; |
67 |
|
68 |
/* Hypervisor */ |
69 |
int hypervisor_mode = 0; |
70 |
int hypervisor_tcp_port = 0; |
71 |
char *hypervisor_ip_address = NULL; |
72 |
|
73 |
/* Log file */ |
74 |
char *log_file_name = NULL; |
75 |
FILE *log_file = NULL; |
76 |
|
77 |
/* VM flags */ |
78 |
volatile int vm_save_state = 0; |
79 |
|
80 |
/* Default platform */ |
81 |
static char *default_platform = "7200"; |
82 |
|
83 |
/* Generic signal handler */ |
84 |
void signal_gen_handler(int sig) |
85 |
{ |
86 |
switch(sig) { |
87 |
case SIGHUP: |
88 |
/* For future use */ |
89 |
break; |
90 |
|
91 |
case SIGQUIT: |
92 |
/* save VM context */ |
93 |
vm_save_state = TRUE; |
94 |
break; |
95 |
|
96 |
case SIGINT: |
97 |
/* CTRL+C has been pressed */ |
98 |
if (hypervisor_mode) |
99 |
hypervisor_stopsig(); |
100 |
else { |
101 |
/* In theory, this shouldn't happen thanks to VTTY settings */ |
102 |
vm_instance_t *vm; |
103 |
|
104 |
if ((vm = vm_acquire("default")) != NULL) { |
105 |
/* Only forward ctrl-c if user has requested local terminal */ |
106 |
if (vm->vtty_con_type == VTTY_TYPE_TERM) { |
107 |
vtty_store_ctrlc(vm->vtty_con); |
108 |
} else { |
109 |
vm_stop(vm); |
110 |
} |
111 |
vm_release(vm); |
112 |
} else { |
113 |
fprintf(stderr,"Error: Cannot acquire instance handle.\n"); |
114 |
} |
115 |
} |
116 |
break; |
117 |
|
118 |
default: |
119 |
fprintf(stderr,"Unhandled signal %d\n",sig); |
120 |
} |
121 |
} |
122 |
|
123 |
/* Setups signals */ |
124 |
static void setup_signals(void) |
125 |
{ |
126 |
struct sigaction act; |
127 |
|
128 |
memset(&act,0,sizeof(act)); |
129 |
act.sa_handler = signal_gen_handler; |
130 |
act.sa_flags = SA_RESTART; |
131 |
sigaction(SIGHUP,&act,NULL); |
132 |
sigaction(SIGQUIT,&act,NULL); |
133 |
sigaction(SIGINT,&act,NULL); |
134 |
} |
135 |
|
136 |
/* Create general log file */ |
137 |
static void create_log_file(void) |
138 |
{ |
139 |
/* Set the default value of the log file name */ |
140 |
if (!log_file_name) { |
141 |
if (!(log_file_name = strdup(LOGFILE_DEFAULT_NAME))) { |
142 |
fprintf(stderr,"Unable to set log file name.\n"); |
143 |
exit(EXIT_FAILURE); |
144 |
} |
145 |
} |
146 |
|
147 |
if (!(log_file = fopen(log_file_name,"w"))) { |
148 |
fprintf(stderr,"Unable to create log file (%s).\n",strerror(errno)); |
149 |
exit(EXIT_FAILURE); |
150 |
} |
151 |
} |
152 |
|
153 |
/* Close general log file */ |
154 |
static void close_log_file(void) |
155 |
{ |
156 |
if (log_file) fclose(log_file); |
157 |
free(log_file_name); |
158 |
|
159 |
log_file = NULL; |
160 |
log_file_name = NULL; |
161 |
} |
162 |
|
163 |
/* Display the command line use */ |
164 |
static void show_usage(vm_instance_t *vm,int argc,char *argv[]) |
165 |
{ |
166 |
printf("Usage: %s [options] <ios_image>\n\n",argv[0]); |
167 |
|
168 |
printf("Available options:\n" |
169 |
" -H [<ip_address>:]<tcp_port> : Run in hypervisor mode\n\n" |
170 |
" -P <platform> : Platform to emulate (7200, 3600, " |
171 |
"2691, 3725, 3745, 2600 or 1700) " |
172 |
"(default: 7200)\n\n" |
173 |
" -l <log_file> : Set logging file (default is %s)\n" |
174 |
" -j : Disable the JIT compiler, very slow\n" |
175 |
" --exec-area <size> : Set the exec area size (default: %d Mb)\n" |
176 |
" --idle-pc <pc> : Set the idle PC (default: disabled)\n" |
177 |
" --timer-itv <val> : Timer IRQ interval check (default: %u)\n" |
178 |
"\n" |
179 |
" -i <instance> : Set instance ID\n" |
180 |
" -r <ram_size> : Set the virtual RAM size (default: %u Mb)\n" |
181 |
" -o <rom_size> : Set the virtual ROM size (default: %u Mb)\n" |
182 |
" -n <nvram_size> : Set the NVRAM size (default: %d Kb)\n" |
183 |
" -c <conf_reg> : Set the configuration register " |
184 |
"(default: 0x%04x)\n" |
185 |
" -m <mac_addr> : Set the MAC address of the chassis\n" |
186 |
" (default: automatically generated)\n" |
187 |
" -C <cfg_file> : Import an IOS configuration file " |
188 |
"into NVRAM\n" |
189 |
" -X : Do not use a file to simulate RAM (faster)\n" |
190 |
" -G <ghost_file> : Use a ghost file to simulate RAM\n" |
191 |
" -g <ghost_file> : Generate a ghost RAM file\n" |
192 |
" --sparse-mem : Use sparse memory\n" |
193 |
" -R <rom_file> : Load an alternate ROM (default: embedded)\n" |
194 |
" -k <clock_div> : Set the clock divisor (default: %d)\n" |
195 |
"\n" |
196 |
" -T <port> : Console is on TCP <port>\n" |
197 |
" -U <si_desc> : Console in on serial interface <si_desc>\n" |
198 |
" (default is on the terminal)\n" |
199 |
"\n" |
200 |
" -A <port> : AUX is on TCP <port>\n" |
201 |
" -B <si_desc> : AUX is on serial interface <si_desc>\n" |
202 |
" (default is no AUX port)\n" |
203 |
"\n" |
204 |
" --disk0 <size> : Set PCMCIA ATA disk0: size " |
205 |
"(default: %u Mb)\n" |
206 |
" --disk1 <size> : Set PCMCIA ATA disk1: size " |
207 |
"(default: %u Mb)\n" |
208 |
"\n", |
209 |
LOGFILE_DEFAULT_NAME,MIPS_EXEC_AREA_SIZE,VM_TIMER_IRQ_CHECK_ITV, |
210 |
vm->ram_size,vm->rom_size,vm->nvram_size,vm->conf_reg_setup, |
211 |
vm->clock_divisor,vm->pcmcia_disk_size[0],vm->pcmcia_disk_size[1]); |
212 |
|
213 |
if (vm->platform->cli_show_options != NULL) |
214 |
vm->platform->cli_show_options(vm); |
215 |
|
216 |
printf("\n" |
217 |
#if DEBUG_SYM_TREE |
218 |
" -S <sym_file> : Load a symbol file\n" |
219 |
#endif |
220 |
" -a <cfg_file> : Virtual ATM switch configuration file\n" |
221 |
" -f <cfg_file> : Virtual Frame-Relay switch configuration " |
222 |
"file\n" |
223 |
" -E <cfg_file> : Virtual Ethernet switch configuration file\n" |
224 |
" -b <cfg_file> : Virtual bridge configuration file\n" |
225 |
" -e : Show network device list of the " |
226 |
"host machine\n" |
227 |
"\n"); |
228 |
|
229 |
printf("<si_desc> format:\n" |
230 |
" \"device{:baudrate{:databits{:parity{:stopbits{:hwflow}}}}}}\"\n" |
231 |
"\n"); |
232 |
|
233 |
switch(vm->slots_type) { |
234 |
case CISCO_CARD_TYPE_PA: |
235 |
printf("<pa_desc> format:\n" |
236 |
" \"slot:sub_slot:pa_driver\"\n" |
237 |
"\n"); |
238 |
|
239 |
printf("<pa_nio> format:\n" |
240 |
" \"slot:port:netio_type{:netio_parameters}\"\n" |
241 |
"\n"); |
242 |
break; |
243 |
|
244 |
case CISCO_CARD_TYPE_NM: |
245 |
printf("<nm_desc> format:\n" |
246 |
" \"slot:sub_slot:nm_driver\"\n" |
247 |
"\n"); |
248 |
|
249 |
printf("<nm_nio> format:\n" |
250 |
" \"slot:port:netio_type{:netio_parameters}\"\n" |
251 |
"\n"); |
252 |
break; |
253 |
|
254 |
case CISCO_CARD_TYPE_WIC: |
255 |
printf("<wic_desc> format:\n" |
256 |
" \"slot:wic_driver\"\n" |
257 |
"\n"); |
258 |
|
259 |
printf("<wic_nio> format:\n" |
260 |
" \"slot:port:netio_type{:netio_parameters}\"\n" |
261 |
"\n"); |
262 |
break; |
263 |
} |
264 |
|
265 |
if (vm->platform->show_spec_drivers != NULL) |
266 |
vm->platform->show_spec_drivers(); |
267 |
|
268 |
/* Show possible slot drivers */ |
269 |
vm_slot_show_drivers(vm); |
270 |
|
271 |
/* Show the possible NETIO types */ |
272 |
netio_show_types(); |
273 |
} |
274 |
|
275 |
/* Find an option in the command line */ |
276 |
static char *cli_find_option(int argc,char *argv[],char *opt) |
277 |
{ |
278 |
int i; |
279 |
|
280 |
for(i=1;i<argc;i++) { |
281 |
if (!strncmp(argv[i],opt,2)) { |
282 |
if (argv[i][2] != 0) |
283 |
return(&argv[i][2]); |
284 |
else { |
285 |
if (argv[i+1] != NULL) |
286 |
return(argv[i+1]); |
287 |
else { |
288 |
fprintf(stderr,"Error: option '%s': no argument specified.\n", |
289 |
opt); |
290 |
exit(EXIT_FAILURE); |
291 |
} |
292 |
} |
293 |
} |
294 |
} |
295 |
|
296 |
return NULL; |
297 |
} |
298 |
|
299 |
/* Load plugins */ |
300 |
static void cli_load_plugins(int argc,char *argv[]) |
301 |
{ |
302 |
char *str; |
303 |
int i; |
304 |
|
305 |
for(i=1;i<argc;i++) { |
306 |
if (!strncmp(argv[i],"-L",2)) { |
307 |
if (argv[i][2] != 0) |
308 |
str = &argv[i][2]; |
309 |
else { |
310 |
if (argv[i+1] != NULL) |
311 |
str = argv[i+1]; |
312 |
else { |
313 |
fprintf(stderr,"Plugin error: no argument specified.\n"); |
314 |
exit(EXIT_FAILURE); |
315 |
} |
316 |
} |
317 |
|
318 |
if (!plugin_load(str)) |
319 |
fprintf(stderr,"Unable to load plugin '%s'!\n",str); |
320 |
} |
321 |
} |
322 |
} |
323 |
|
324 |
/* Determine the platform (Cisco 3600, 7200). Default is Cisco 7200 */ |
325 |
static vm_platform_t *cli_get_platform_type(int argc,char *argv[]) |
326 |
{ |
327 |
vm_platform_t *platform; |
328 |
char *str; |
329 |
|
330 |
if (!(str = cli_find_option(argc,argv,"-P"))) |
331 |
str = default_platform; |
332 |
|
333 |
if (!(platform = vm_platform_find_cli_name(str))) |
334 |
fprintf(stderr,"Invalid platform type '%s'\n",str); |
335 |
|
336 |
return platform; |
337 |
} |
338 |
|
339 |
static struct option cmd_line_lopts[] = { |
340 |
{ "disk0" , 1, NULL, OPT_DISK0_SIZE }, |
341 |
{ "disk1" , 1, NULL, OPT_DISK1_SIZE }, |
342 |
{ "exec-area" , 1, NULL, OPT_EXEC_AREA }, |
343 |
{ "idle-pc" , 1, NULL, OPT_IDLE_PC }, |
344 |
{ "timer-itv" , 1, NULL, OPT_TIMER_ITV }, |
345 |
{ "vm-debug" , 1, NULL, OPT_VM_DEBUG }, |
346 |
{ "iomem-size" , 1, NULL, OPT_IOMEM_SIZE }, |
347 |
{ "sparse-mem" , 0, NULL, OPT_SPARSE_MEM }, |
348 |
{ NULL , 0, NULL, 0 }, |
349 |
}; |
350 |
|
351 |
/* Create a router instance */ |
352 |
static vm_instance_t *cli_create_instance(char *name,char *platform_name, |
353 |
int instance_id) |
354 |
{ |
355 |
vm_instance_t *vm; |
356 |
|
357 |
vm = vm_create_instance(name,instance_id,platform_name); |
358 |
|
359 |
if (vm == NULL) { |
360 |
fprintf(stderr,"C7200: unable to create instance!\n"); |
361 |
return NULL; |
362 |
} |
363 |
|
364 |
return vm; |
365 |
} |
366 |
|
367 |
/* Parse the command line */ |
368 |
static int parse_std_cmd_line(int argc,char *argv[]) |
369 |
{ |
370 |
char *options_list = |
371 |
"r:o:n:c:m:l:C:i:jt:p:s:k:T:U:A:B:a:f:E:b:S:R:M:eXP:N:G:g:L:"; |
372 |
vm_platform_t *platform; |
373 |
vm_instance_t *vm; |
374 |
int instance_id; |
375 |
int option; |
376 |
char *str; |
377 |
|
378 |
/* Get the instance ID */ |
379 |
instance_id = 0; |
380 |
|
381 |
/* Use the old VM file naming type */ |
382 |
vm_file_naming_type = 1; |
383 |
|
384 |
cli_load_plugins(argc,argv); |
385 |
|
386 |
if ((str = cli_find_option(argc,argv,"-i"))) { |
387 |
instance_id = atoi(str); |
388 |
printf("Instance ID set to %d.\n",instance_id); |
389 |
} |
390 |
|
391 |
if ((str = cli_find_option(argc,argv,"-N"))) |
392 |
vm_file_naming_type = atoi(str); |
393 |
|
394 |
/* Get the platform type */ |
395 |
if (!(platform = cli_get_platform_type(argc,argv))) |
396 |
exit(EXIT_FAILURE); |
397 |
|
398 |
/* Create the default instance */ |
399 |
if (!(vm = cli_create_instance("default",platform->name,instance_id))) |
400 |
exit(EXIT_FAILURE); |
401 |
|
402 |
opterr = 0; |
403 |
|
404 |
while((option = getopt_long(argc,argv,options_list, |
405 |
cmd_line_lopts,NULL)) != -1) |
406 |
{ |
407 |
switch(option) |
408 |
{ |
409 |
/* Instance ID (already managed) */ |
410 |
case 'i': |
411 |
break; |
412 |
|
413 |
/* Platform (already managed) */ |
414 |
case 'P': |
415 |
break; |
416 |
|
417 |
/* RAM size */ |
418 |
case 'r': |
419 |
vm->ram_size = strtol(optarg, NULL, 10); |
420 |
printf("Virtual RAM size set to %d MB.\n",vm->ram_size); |
421 |
break; |
422 |
|
423 |
/* ROM size */ |
424 |
case 'o': |
425 |
vm->rom_size = strtol(optarg, NULL, 10); |
426 |
printf("Virtual ROM size set to %d MB.\n",vm->rom_size); |
427 |
break; |
428 |
|
429 |
/* NVRAM size */ |
430 |
case 'n': |
431 |
vm->nvram_size = strtol(optarg, NULL, 10); |
432 |
printf("NVRAM size set to %d KB.\n",vm->nvram_size); |
433 |
break; |
434 |
|
435 |
/* Execution area size */ |
436 |
case OPT_EXEC_AREA: |
437 |
vm->exec_area_size = atoi(optarg); |
438 |
break; |
439 |
|
440 |
/* PCMCIA disk0 size */ |
441 |
case OPT_DISK0_SIZE: |
442 |
vm->pcmcia_disk_size[0] = atoi(optarg); |
443 |
printf("PCMCIA ATA disk0 size set to %u MB.\n", |
444 |
vm->pcmcia_disk_size[0]); |
445 |
break; |
446 |
|
447 |
/* PCMCIA disk1 size */ |
448 |
case OPT_DISK1_SIZE: |
449 |
vm->pcmcia_disk_size[1] = atoi(optarg); |
450 |
printf("PCMCIA ATA disk1 size set to %u MB.\n", |
451 |
vm->pcmcia_disk_size[1]); |
452 |
break; |
453 |
|
454 |
/* Config Register */ |
455 |
case 'c': |
456 |
vm->conf_reg_setup = strtol(optarg, NULL, 0); |
457 |
printf("Config. Register set to 0x%x.\n",vm->conf_reg_setup); |
458 |
break; |
459 |
|
460 |
/* IOS configuration file */ |
461 |
case 'C': |
462 |
vm_ios_set_config(vm,optarg); |
463 |
break; |
464 |
|
465 |
/* Use physical memory to emulate RAM (no-mapped file) */ |
466 |
case 'X': |
467 |
vm->ram_mmap = 0; |
468 |
break; |
469 |
|
470 |
/* Use a ghost file to simulate RAM */ |
471 |
case 'G': |
472 |
vm->ghost_ram_filename = strdup(optarg); |
473 |
vm->ghost_status = VM_GHOST_RAM_USE; |
474 |
break; |
475 |
|
476 |
/* Generate a ghost RAM image */ |
477 |
case 'g': |
478 |
vm->ghost_ram_filename = strdup(optarg); |
479 |
vm->ghost_status = VM_GHOST_RAM_GENERATE; |
480 |
break; |
481 |
|
482 |
/* Use sparse memory */ |
483 |
case OPT_SPARSE_MEM: |
484 |
vm->sparse_mem = TRUE; |
485 |
break; |
486 |
|
487 |
/* Alternate ROM */ |
488 |
case 'R': |
489 |
vm->rom_filename = optarg; |
490 |
break; |
491 |
|
492 |
/* Idle PC */ |
493 |
case OPT_IDLE_PC: |
494 |
vm->idle_pc = strtoull(optarg,NULL,0); |
495 |
printf("Idle PC set to 0x%llx.\n",vm->idle_pc); |
496 |
break; |
497 |
|
498 |
/* Timer IRQ check interval */ |
499 |
case OPT_TIMER_ITV: |
500 |
vm->timer_irq_check_itv = atoi(optarg); |
501 |
break; |
502 |
|
503 |
/* Clock divisor */ |
504 |
case 'k': |
505 |
vm->clock_divisor = atoi(optarg); |
506 |
|
507 |
if (!vm->clock_divisor) { |
508 |
fprintf(stderr,"Invalid Clock Divisor specified!\n"); |
509 |
exit(EXIT_FAILURE); |
510 |
} |
511 |
|
512 |
printf("Using a clock divisor of %d.\n",vm->clock_divisor); |
513 |
break; |
514 |
|
515 |
/* Disable JIT */ |
516 |
case 'j': |
517 |
vm->jit_use = FALSE; |
518 |
break; |
519 |
|
520 |
/* VM debug level */ |
521 |
case OPT_VM_DEBUG: |
522 |
vm->debug_level = atoi(optarg); |
523 |
break; |
524 |
|
525 |
/* Log file */ |
526 |
case 'l': |
527 |
if (!(log_file_name = strdup(optarg))) { |
528 |
fprintf(stderr,"Unable to set log file name.\n"); |
529 |
exit(EXIT_FAILURE); |
530 |
} |
531 |
printf("Log file: writing to %s\n",log_file_name); |
532 |
break; |
533 |
|
534 |
#if DEBUG_SYM_TREE |
535 |
/* Symbol file */ |
536 |
case 'S': |
537 |
vm->sym_filename = strdup(optarg); |
538 |
break; |
539 |
#endif |
540 |
|
541 |
/* TCP server for Console Port */ |
542 |
case 'T': |
543 |
vm->vtty_con_type = VTTY_TYPE_TCP; |
544 |
vm->vtty_con_tcp_port = atoi(optarg); |
545 |
break; |
546 |
|
547 |
/* Serial interface for Console port */ |
548 |
case 'U': |
549 |
vm->vtty_con_type = VTTY_TYPE_SERIAL; |
550 |
if (vtty_parse_serial_option(&vm->vtty_con_serial_option,optarg)) { |
551 |
fprintf(stderr, |
552 |
"Invalid Console serial interface descriptor!\n"); |
553 |
exit(EXIT_FAILURE); |
554 |
} |
555 |
break; |
556 |
|
557 |
/* TCP server for AUX Port */ |
558 |
case 'A': |
559 |
vm->vtty_aux_type = VTTY_TYPE_TCP; |
560 |
vm->vtty_aux_tcp_port = atoi(optarg); |
561 |
break; |
562 |
|
563 |
/* Serial interface for AUX port */ |
564 |
case 'B': |
565 |
vm->vtty_aux_type = VTTY_TYPE_SERIAL; |
566 |
if (vtty_parse_serial_option(&vm->vtty_aux_serial_option,optarg)) { |
567 |
fprintf(stderr,"Invalid AUX serial interface descriptor!\n"); |
568 |
exit(EXIT_FAILURE); |
569 |
} |
570 |
break; |
571 |
|
572 |
/* Port settings */ |
573 |
case 'p': |
574 |
vm_slot_cmd_create(vm,optarg); |
575 |
break; |
576 |
|
577 |
/* NIO settings */ |
578 |
case 's': |
579 |
vm_slot_cmd_add_nio(vm,optarg); |
580 |
break; |
581 |
|
582 |
/* Virtual ATM switch */ |
583 |
case 'a': |
584 |
if (atmsw_start(optarg) == -1) |
585 |
exit(EXIT_FAILURE); |
586 |
break; |
587 |
|
588 |
/* Virtual Frame-Relay switch */ |
589 |
case 'f': |
590 |
if (frsw_start(optarg) == -1) |
591 |
exit(EXIT_FAILURE); |
592 |
break; |
593 |
|
594 |
/* Virtual Ethernet switch */ |
595 |
case 'E': |
596 |
if (ethsw_start(optarg) == -1) |
597 |
exit(EXIT_FAILURE); |
598 |
break; |
599 |
|
600 |
/* Virtual bridge */ |
601 |
case 'b': |
602 |
if (netio_bridge_start(optarg) == -1) |
603 |
exit(EXIT_FAILURE); |
604 |
break; |
605 |
|
606 |
#ifdef GEN_ETH |
607 |
/* Ethernet device list */ |
608 |
case 'e': |
609 |
gen_eth_show_dev_list(); |
610 |
exit(EXIT_SUCCESS); |
611 |
#endif |
612 |
|
613 |
/* Load plugin (already handled) */ |
614 |
case 'L': |
615 |
break; |
616 |
|
617 |
/* Oops ! */ |
618 |
case '?': |
619 |
show_usage(vm,argc,argv); |
620 |
exit(EXIT_FAILURE); |
621 |
|
622 |
/* Parse options specific to the platform */ |
623 |
default: |
624 |
if (vm->platform->cli_parse_options != NULL) |
625 |
if (vm->platform->cli_parse_options(vm,option) == -1) |
626 |
exit(EXIT_FAILURE); |
627 |
} |
628 |
} |
629 |
|
630 |
/* Last argument, this is the IOS filename */ |
631 |
if (optind == (argc - 1)) { |
632 |
/* setting IOS image file */ |
633 |
vm_ios_set_image(vm,argv[optind]); |
634 |
printf("IOS image file: %s\n\n",vm->ios_image); |
635 |
} else { |
636 |
/* IOS missing */ |
637 |
fprintf(stderr,"Please specify an IOS image filename\n"); |
638 |
show_usage(vm,argc,argv); |
639 |
exit(EXIT_FAILURE); |
640 |
} |
641 |
|
642 |
vm_release(vm); |
643 |
return(0); |
644 |
} |
645 |
|
646 |
/* |
647 |
* Run in hypervisor mode with a config file if the "-H" option |
648 |
* is present in command line. |
649 |
*/ |
650 |
static int run_hypervisor(int argc,char *argv[]) |
651 |
{ |
652 |
char *options_list = "H:l:hN:L:"; |
653 |
int i,option; |
654 |
char *index; |
655 |
size_t len; |
656 |
|
657 |
for(i=1;i<argc;i++) |
658 |
if (!strcmp(argv[i],"-H")) { |
659 |
hypervisor_mode = 1; |
660 |
break; |
661 |
} |
662 |
|
663 |
/* standard mode with one instance */ |
664 |
if (!hypervisor_mode) |
665 |
return(FALSE); |
666 |
|
667 |
cli_load_plugins(argc,argv); |
668 |
|
669 |
opterr = 0; |
670 |
while((option = getopt(argc,argv,options_list)) != -1) { |
671 |
switch(option) |
672 |
{ |
673 |
/* Hypervisor TCP port */ |
674 |
case 'H': |
675 |
index = strrchr(optarg,':'); |
676 |
|
677 |
if (!index) { |
678 |
hypervisor_tcp_port = atoi(optarg); |
679 |
} else { |
680 |
len = index - optarg; |
681 |
hypervisor_ip_address = malloc(len + 1); |
682 |
|
683 |
if (!hypervisor_ip_address) { |
684 |
fprintf(stderr,"Unable to set hypervisor IP address!\n"); |
685 |
exit(EXIT_FAILURE); |
686 |
} |
687 |
|
688 |
memcpy(hypervisor_ip_address,optarg,len); |
689 |
hypervisor_ip_address[len] = '\0'; |
690 |
} |
691 |
break; |
692 |
|
693 |
/* Log file */ |
694 |
case 'l': |
695 |
if (!(log_file_name = malloc(strlen(optarg)+1))) { |
696 |
fprintf(stderr,"Unable to set log file name!\n"); |
697 |
exit(EXIT_FAILURE); |
698 |
} |
699 |
strcpy(log_file_name, optarg); |
700 |
printf("Log file: writing to %s\n",log_file_name); |
701 |
break; |
702 |
|
703 |
/* VM file naming type */ |
704 |
case 'N': |
705 |
vm_file_naming_type = atoi(optarg); |
706 |
break; |
707 |
|
708 |
/* Load plugin (already handled) */ |
709 |
case 'L': |
710 |
break; |
711 |
|
712 |
/* Oops ! */ |
713 |
case '?': |
714 |
//show_usage(argc,argv,VM_TYPE_C7200); |
715 |
exit(EXIT_FAILURE); |
716 |
} |
717 |
} |
718 |
|
719 |
return(TRUE); |
720 |
} |
721 |
|
722 |
/* Delete all objects */ |
723 |
void dynamips_reset(void) |
724 |
{ |
725 |
printf("Shutdown in progress...\n"); |
726 |
|
727 |
/* Delete all virtual router instances */ |
728 |
vm_delete_all_instances(); |
729 |
|
730 |
/* Delete ATM and Frame-Relay switches + bridges */ |
731 |
netio_bridge_delete_all(); |
732 |
atmsw_delete_all(); |
733 |
frsw_delete_all(); |
734 |
ethsw_delete_all(); |
735 |
|
736 |
/* Delete all NIO descriptors */ |
737 |
netio_delete_all(); |
738 |
|
739 |
printf("Shutdown completed.\n"); |
740 |
} |
741 |
|
742 |
/* Default platforms */ |
743 |
static int (*platform_register[])(void) = { |
744 |
c7200_platform_register, |
745 |
c3600_platform_register, |
746 |
c3725_platform_register, |
747 |
c3745_platform_register, |
748 |
c2691_platform_register, |
749 |
c2600_platform_register, |
750 |
c1700_platform_register, |
751 |
c6sup1_platform_register, |
752 |
c6msfc1_platform_register, |
753 |
NULL, |
754 |
}; |
755 |
|
756 |
/* Register default platforms */ |
757 |
static void register_default_platforms(void) |
758 |
{ |
759 |
int i; |
760 |
|
761 |
for(i=0;platform_register[i];i++) |
762 |
platform_register[i](); |
763 |
} |
764 |
|
765 |
int main(int argc,char *argv[]) |
766 |
{ |
767 |
vm_instance_t *vm; |
768 |
|
769 |
#ifdef PROFILE |
770 |
atexit(profiler_savestat); |
771 |
#endif |
772 |
|
773 |
printf("Cisco Router Simulation Platform (version %s)\n",sw_version); |
774 |
printf("Copyright (c) 2005-2007 Christophe Fillot.\n"); |
775 |
printf("Build date: %s %s\n\n",__DATE__,__TIME__); |
776 |
|
777 |
/* Register platforms */ |
778 |
register_default_platforms(); |
779 |
|
780 |
/* Initialize timers */ |
781 |
timer_init(); |
782 |
|
783 |
/* Initialize object registry */ |
784 |
registry_init(); |
785 |
|
786 |
/* Initialize ATM module (for HEC checksums) */ |
787 |
atm_init(); |
788 |
|
789 |
/* Initialize CRC functions */ |
790 |
crc_init(); |
791 |
|
792 |
/* Initialize NetIO code */ |
793 |
netio_rxl_init(); |
794 |
|
795 |
/* Initialize NetIO packet filters */ |
796 |
netio_filter_load_all(); |
797 |
|
798 |
/* Initialize VTTY code */ |
799 |
vtty_init(); |
800 |
|
801 |
/* Parse standard command line */ |
802 |
if (!run_hypervisor(argc,argv)) |
803 |
parse_std_cmd_line(argc,argv); |
804 |
|
805 |
/* Create general log file */ |
806 |
create_log_file(); |
807 |
|
808 |
/* Periodic tasks initialization */ |
809 |
if (ptask_init(0) == -1) |
810 |
exit(EXIT_FAILURE); |
811 |
|
812 |
/* Create instruction lookup tables */ |
813 |
mips64_jit_create_ilt(); |
814 |
mips64_exec_create_ilt(); |
815 |
ppc32_jit_create_ilt(); |
816 |
ppc32_exec_create_ilt(); |
817 |
|
818 |
setup_signals(); |
819 |
|
820 |
if (!hypervisor_mode) { |
821 |
/* Initialize the default instance */ |
822 |
vm = vm_acquire("default"); |
823 |
assert(vm != NULL); |
824 |
|
825 |
if (vm->platform->init_instance(vm) == -1) { |
826 |
fprintf(stderr,"Unable to initialize router instance.\n"); |
827 |
exit(EXIT_FAILURE); |
828 |
} |
829 |
|
830 |
#if (DEBUG_INSN_PERF_CNT > 0) || (DEBUG_BLOCK_PERF_CNT > 0) |
831 |
{ |
832 |
m_uint32_t counter,prev = 0,delta; |
833 |
while(vm->status == VM_STATUS_RUNNING) { |
834 |
counter = cpu_get_perf_counter(vm->boot_cpu); |
835 |
delta = counter - prev; |
836 |
prev = counter; |
837 |
printf("delta = %u\n",delta); |
838 |
sleep(1); |
839 |
} |
840 |
} |
841 |
#else |
842 |
/* Start instance monitoring */ |
843 |
vm_monitor(vm); |
844 |
#endif |
845 |
|
846 |
/* Free resources used by instance */ |
847 |
vm_release(vm); |
848 |
} else { |
849 |
hypervisor_tcp_server(hypervisor_ip_address,hypervisor_tcp_port); |
850 |
} |
851 |
|
852 |
dynamips_reset(); |
853 |
close_log_file(); |
854 |
return(0); |
855 |
} |