|
|
1.1 root 1: /* 1.1.1.8 ! root 2: * Cisco router simulation platform. 1.1 root 3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected]) 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> 1.1.1.4 root 14: #include <errno.h> 1.1 root 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> 1.1.1.4 root 21: #include <getopt.h> 1.1 root 22: 1.1.1.4 root 23: #include "dynamips.h" 1.1.1.8 ! root 24: #include "cpu.h" 1.1 root 25: #include "mips64_exec.h" 1.1.1.8 ! root 26: #include "mips64_jit.h" ! 27: #include "ppc32_exec.h" ! 28: #include "ppc32_jit.h" 1.1 root 29: #include "dev_c7200.h" 1.1.1.4 root 30: #include "dev_c3600.h" 1.1.1.6 root 31: #include "dev_c2691.h" 32: #include "dev_c3725.h" 33: #include "dev_c3745.h" 1.1.1.8 ! root 34: #include "dev_c2600.h" ! 35: #include "ppc32_vmtest.h" 1.1 root 36: #include "dev_vtty.h" 37: #include "ptask.h" 1.1.1.5 root 38: #include "timer.h" 1.1.1.4 root 39: #include "registry.h" 40: #include "hypervisor.h" 1.1.1.2 root 41: #include "net_io.h" 1.1 root 42: #include "net_io_bridge.h" 1.1.1.4 root 43: #include "net_io_filter.h" 44: #include "crc.h" 45: #include "atm.h" 46: #include "frame_relay.h" 47: #include "eth_switch.h" 1.1.1.2 root 48: #ifdef GEN_ETH 49: #include "gen_eth.h" 50: #endif 1.1 root 51: #ifdef PROFILE 52: #include "profiler.h" 53: #endif 54: 55: /* Default name for logfile */ 1.1.1.4 root 56: #define LOGFILE_DEFAULT_NAME "dynamips_log.txt" 1.1 root 57: 58: /* Software version */ 1.1.1.4 root 59: const char *sw_version = DYNAMIPS_VERSION"-"JIT_ARCH; 60: 61: /* Hypervisor */ 62: int hypervisor_mode = 0; 63: int hypervisor_tcp_port = 0; 1.1 root 64: 65: /* Log file */ 1.1.1.4 root 66: char *log_file_name = NULL; 1.1 root 67: FILE *log_file = NULL; 68: 69: /* VM flags */ 70: volatile int vm_save_state = 0; 71: 72: /* Generic signal handler */ 73: void signal_gen_handler(int sig) 74: { 75: switch(sig) { 76: case SIGHUP: 1.1.1.4 root 77: /* For future use */ 1.1 root 78: break; 79: 80: case SIGQUIT: 81: /* save VM context */ 82: vm_save_state = TRUE; 1.1.1.4 root 83: break; 84: 85: case SIGINT: 86: /* CTRL+C has been pressed */ 87: if (hypervisor_mode) 88: hypervisor_stopsig(); 89: else { 90: /* In theory, this shouldn't happen thanks to VTTY settings */ 91: vm_instance_t *vm; 92: 93: if ((vm = vm_acquire("default")) != NULL) { 94: /* Only forward ctrl-c if user has requested local terminal */ 95: if (vm->vtty_con_type == VTTY_TYPE_TERM) { 96: vtty_store_ctrlc(vm->vtty_con); 97: } else { 98: vm_stop(vm); 99: } 100: vm_release(vm); 101: } else { 102: fprintf(stderr,"Error: Cannot acquire instance handle.\n"); 103: } 104: } 1.1 root 105: break; 106: 107: default: 108: fprintf(stderr,"Unhandled signal %d\n",sig); 109: } 110: } 111: 112: /* Setups signals */ 113: static void setup_signals(void) 114: { 115: struct sigaction act; 116: 117: memset(&act,0,sizeof(act)); 118: act.sa_handler = signal_gen_handler; 119: act.sa_flags = SA_RESTART; 120: sigaction(SIGHUP,&act,NULL); 121: sigaction(SIGQUIT,&act,NULL); 1.1.1.4 root 122: sigaction(SIGINT,&act,NULL); 1.1 root 123: } 124: 1.1.1.4 root 125: /* Create general log file */ 126: static void create_log_file(void) 127: { 128: /* Set the default value of the log file name */ 129: if (!log_file_name) { 130: if (!(log_file_name = strdup(LOGFILE_DEFAULT_NAME))) { 131: fprintf(stderr,"Unable to set log file name.\n"); 132: exit(EXIT_FAILURE); 133: } 1.1 root 134: } 135: 1.1.1.4 root 136: if (!(log_file = fopen(log_file_name,"w"))) { 137: fprintf(stderr,"Unable to create log file (%s).\n",strerror(errno)); 138: exit(EXIT_FAILURE); 1.1 root 139: } 1.1.1.4 root 140: } 1.1 root 141: 1.1.1.4 root 142: /* Close general log file */ 143: static void close_log_file(void) 144: { 145: if (log_file) fclose(log_file); 146: free(log_file_name); 1.1 root 147: 1.1.1.4 root 148: log_file = NULL; 149: log_file_name = NULL; 150: } 1.1 root 151: 1.1.1.4 root 152: /* Display the command line use */ 153: static void show_usage(int argc,char *argv[],int platform) 154: { 155: u_int def_ram_size,def_rom_size,def_nvram_size; 156: u_int def_conf_reg,def_clock_div; 157: u_int def_disk0_size,def_disk1_size; 158: u_int def_nm_iomem_size = 0; 159: 160: switch(platform) { 161: case VM_TYPE_C7200: 162: def_ram_size = C7200_DEFAULT_RAM_SIZE; 163: def_rom_size = C7200_DEFAULT_ROM_SIZE; 164: def_nvram_size = C7200_DEFAULT_NVRAM_SIZE; 165: def_conf_reg = C7200_DEFAULT_CONF_REG; 166: def_clock_div = C7200_DEFAULT_CLOCK_DIV; 167: def_disk0_size = C7200_DEFAULT_DISK0_SIZE; 168: def_disk1_size = C7200_DEFAULT_DISK1_SIZE; 169: break; 170: case VM_TYPE_C3600: 171: def_ram_size = C3600_DEFAULT_RAM_SIZE; 172: def_rom_size = C3600_DEFAULT_ROM_SIZE; 173: def_nvram_size = C3600_DEFAULT_NVRAM_SIZE; 174: def_conf_reg = C3600_DEFAULT_CONF_REG; 175: def_clock_div = C3600_DEFAULT_CLOCK_DIV; 176: def_disk0_size = C3600_DEFAULT_DISK0_SIZE; 177: def_disk1_size = C3600_DEFAULT_DISK1_SIZE; 178: def_nm_iomem_size = C3600_DEFAULT_IOMEM_SIZE; 179: break; 1.1.1.6 root 180: case VM_TYPE_C2691: 181: def_ram_size = C2691_DEFAULT_RAM_SIZE; 182: def_rom_size = C2691_DEFAULT_ROM_SIZE; 183: def_nvram_size = C2691_DEFAULT_NVRAM_SIZE; 184: def_conf_reg = C2691_DEFAULT_CONF_REG; 185: def_clock_div = C2691_DEFAULT_CLOCK_DIV; 186: def_disk0_size = C2691_DEFAULT_DISK0_SIZE; 187: def_disk1_size = C2691_DEFAULT_DISK1_SIZE; 188: def_nm_iomem_size = C2691_DEFAULT_IOMEM_SIZE; 189: break; 190: case VM_TYPE_C3725: 191: def_ram_size = C3725_DEFAULT_RAM_SIZE; 192: def_rom_size = C3725_DEFAULT_ROM_SIZE; 193: def_nvram_size = C3725_DEFAULT_NVRAM_SIZE; 194: def_conf_reg = C3725_DEFAULT_CONF_REG; 195: def_clock_div = C3725_DEFAULT_CLOCK_DIV; 196: def_disk0_size = C3725_DEFAULT_DISK0_SIZE; 197: def_disk1_size = C3725_DEFAULT_DISK1_SIZE; 198: def_nm_iomem_size = C3725_DEFAULT_IOMEM_SIZE; 199: break; 200: case VM_TYPE_C3745: 201: def_ram_size = C3745_DEFAULT_RAM_SIZE; 202: def_rom_size = C3745_DEFAULT_ROM_SIZE; 203: def_nvram_size = C3745_DEFAULT_NVRAM_SIZE; 204: def_conf_reg = C3745_DEFAULT_CONF_REG; 205: def_clock_div = C3745_DEFAULT_CLOCK_DIV; 206: def_disk0_size = C3745_DEFAULT_DISK0_SIZE; 207: def_disk1_size = C3745_DEFAULT_DISK1_SIZE; 208: def_nm_iomem_size = C3745_DEFAULT_IOMEM_SIZE; 209: break; 1.1.1.8 ! root 210: case VM_TYPE_C2600: ! 211: def_ram_size = C2600_DEFAULT_RAM_SIZE; ! 212: def_rom_size = C2600_DEFAULT_ROM_SIZE; ! 213: def_nvram_size = C2600_DEFAULT_NVRAM_SIZE; ! 214: def_conf_reg = C2600_DEFAULT_CONF_REG; ! 215: def_clock_div = C2600_DEFAULT_CLOCK_DIV; ! 216: def_disk0_size = C2600_DEFAULT_DISK0_SIZE; ! 217: def_disk1_size = C2600_DEFAULT_DISK1_SIZE; ! 218: def_nm_iomem_size = C3745_DEFAULT_IOMEM_SIZE; ! 219: break; ! 220: case VM_TYPE_PPC32_TEST: ! 221: def_ram_size = PPC32_VMTEST_DEFAULT_RAM_SIZE; 1.1.1.4 root 222: default: 223: fprintf(stderr,"show_usage: invalid platform.\n"); 224: return; 225: } 226: 227: printf("Usage: %s [options] <ios_image>\n\n",argv[0]); 1.1 root 228: 1.1.1.4 root 229: printf("Available options:\n" 1.1.1.5 root 230: " -H <tcp_port> : Run in hypervisor mode\n\n" 1.1.1.6 root 231: " -P <platform> : Platform to emulate (7200, 3600, " 232: "2691, 3725 or 3745) " 1.1.1.4 root 233: "(default: 7200)\n\n" 234: " -l <log_file> : Set logging file (default is %s)\n" 235: " -j : Disable the JIT compiler, very slow\n" 236: " --exec-area <size> : Set the exec area size (default: %d Mb)\n" 237: " --idle-pc <pc> : Set the idle PC (default: disabled)\n" 238: " --timer-itv <val> : Timer IRQ interval check (default: %u)\n" 239: "\n" 240: " -i <instance> : Set instance ID\n" 241: " -r <ram_size> : Set the virtual RAM size (default: %u Mb)\n" 242: " -o <rom_size> : Set the virtual ROM size (default: %u Mb)\n" 243: " -n <nvram_size> : Set the NVRAM size (default: %d Kb)\n" 244: " -c <conf_reg> : Set the configuration register " 245: "(default: 0x%04x)\n" 246: " -m <mac_addr> : Set the MAC address of the chassis\n" 247: " (default: automatically generated)\n" 248: " -C <cfg_file> : Import an IOS configuration file " 249: "into NVRAM\n" 250: " -X : Do not use a file to simulate RAM (faster)\n" 1.1.1.6 root 251: " -G <ghost_file> : Use a ghost file to simulate RAM\n" 252: " -g <ghost_file> : Generate a ghost RAM file\n" 1.1.1.8 ! root 253: " --sparse-mem : Use sparse memory\n" 1.1.1.4 root 254: " -R <rom_file> : Load an alternate ROM (default: embedded)\n" 255: " -k <clock_div> : Set the clock divisor (default: %d)\n" 256: "\n" 257: " -T <port> : Console is on TCP <port>\n" 258: " -U <si_desc> : Console in on serial interface <si_desc>\n" 259: " (default is on the terminal)\n" 260: "\n" 261: " -A <port> : AUX is on TCP <port>\n" 262: " -B <si_desc> : AUX is on serial interface <si_desc>\n" 263: " (default is no AUX port)\n" 264: "\n" 265: " --disk0 <size> : Set PCMCIA ATA disk0: size " 266: "(default: %u Mb)\n" 267: " --disk1 <size> : Set PCMCIA ATA disk1: size " 268: "(default: %u Mb)\n" 269: "\n", 270: LOGFILE_DEFAULT_NAME,MIPS_EXEC_AREA_SIZE,VM_TIMER_IRQ_CHECK_ITV, 271: def_ram_size,def_rom_size,def_nvram_size,def_conf_reg, 272: def_clock_div,def_disk0_size,def_disk1_size); 273: 274: switch(platform) { 275: case VM_TYPE_C7200: 276: printf(" -t <npe_type> : Select NPE type (default: \"%s\")\n" 277: " -M <midplane> : Select Midplane (\"std\" or \"vxr\")\n" 278: " -p <pa_desc> : Define a Port Adapter\n" 279: " -s <pa_nio> : Bind a Network IO interface to a " 280: "Port Adapter\n", 281: C7200_DEFAULT_NPE_TYPE); 282: break; 1.1 root 283: 1.1.1.4 root 284: case VM_TYPE_C3600: 285: printf(" -t <chassis_type> : Select Chassis type " 286: "(default: \"%s\")\n" 287: " --iomem-size <val> : IO memory (in percents, default: %u)\n" 288: " -p <nm_desc> : Define a Network Module\n" 289: " -s <nm_nio> : Bind a Network IO interface to a " 290: "Network Module\n", 291: C3600_DEFAULT_CHASSIS,def_nm_iomem_size); 292: break; 1.1.1.6 root 293: 294: case VM_TYPE_C2691: 295: printf(" --iomem-size <val> : IO memory (in percents, default: %u)\n" 296: " -p <nm_desc> : Define a Network Module\n" 297: " -s <nm_nio> : Bind a Network IO interface to a " 298: "Network Module\n", 299: def_nm_iomem_size); 300: break; 301: 302: case VM_TYPE_C3725: 303: printf(" --iomem-size <val> : IO memory (in percents, default: %u)\n" 304: " -p <nm_desc> : Define a Network Module\n" 305: " -s <nm_nio> : Bind a Network IO interface to a " 306: "Network Module\n", 307: def_nm_iomem_size); 308: break; 309: 310: case VM_TYPE_C3745: 311: printf(" --iomem-size <val> : IO memory (in percents, default: %u)\n" 312: " -p <nm_desc> : Define a Network Module\n" 313: " -s <nm_nio> : Bind a Network IO interface to a " 314: "Network Module\n", 315: def_nm_iomem_size); 316: break; 1.1.1.8 ! root 317: ! 318: case VM_TYPE_C2600: ! 319: printf(" --iomem-size <val> : IO memory (in percents, default: %u)\n" ! 320: " -p <nm_desc> : Define a Network Module\n" ! 321: " -s <nm_nio> : Bind a Network IO interface to a " ! 322: "Network Module\n", ! 323: def_nm_iomem_size); ! 324: break; 1.1.1.4 root 325: } 1.1 root 326: 1.1.1.4 root 327: printf("\n" 328: #if DEBUG_SYM_TREE 329: " -S <sym_file> : Load a symbol file\n" 330: #endif 331: " -a <cfg_file> : Virtual ATM switch configuration file\n" 332: " -f <cfg_file> : Virtual Frame-Relay switch configuration " 333: "file\n" 334: " -E <cfg_file> : Virtual Ethernet switch configuration file\n" 335: " -b <cfg_file> : Virtual bridge configuration file\n" 336: " -e : Show network device list of the " 337: "host machine\n" 338: "\n"); 339: 340: printf("<si_desc> format:\n" 341: " \"device{:baudrate{:databits{:parity{:stopbits{:hwflow}}}}}}\"\n" 342: "\n"); 1.1 root 343: 1.1.1.4 root 344: switch(platform) { 345: case VM_TYPE_C7200: 346: printf("<pa_desc> format:\n" 347: " \"slot:pa_driver\"\n" 348: "\n"); 349: 350: printf("<pa_nio> format:\n" 351: " \"slot:port:netio_type{:netio_parameters}\"\n" 352: "\n"); 353: 354: /* Show the possible NPE drivers */ 355: c7200_npe_show_drivers(); 356: 357: /* Show the possible PA drivers */ 358: c7200_pa_show_drivers(); 359: break; 360: 361: case VM_TYPE_C3600: 362: printf("<nm_desc> format:\n" 363: " \"slot:nm_driver\"\n" 364: "\n"); 365: 366: printf("<nm_nio> format:\n" 367: " \"slot:port:netio_type{:netio_parameters}\"\n" 368: "\n"); 369: 370: /* Show the possible chassis types for C3600 platform */ 371: c3600_chassis_show_drivers(); 372: 1.1.1.6 root 373: /* Show the possible NM drivers */ 1.1.1.4 root 374: c3600_nm_show_drivers(); 1.1 root 375: break; 1.1.1.6 root 376: 377: case VM_TYPE_C2691: 378: printf("<nm_desc> format:\n" 379: " \"slot:nm_driver\"\n" 380: "\n"); 381: 382: printf("<nm_nio> format:\n" 383: " \"slot:port:netio_type{:netio_parameters}\"\n" 384: "\n"); 385: 386: /* Show the possible NM drivers */ 387: c2691_nm_show_drivers(); 388: break; 389: 390: case VM_TYPE_C3725: 391: printf("<nm_desc> format:\n" 392: " \"slot:nm_driver\"\n" 393: "\n"); 394: 395: printf("<nm_nio> format:\n" 396: " \"slot:port:netio_type{:netio_parameters}\"\n" 397: "\n"); 398: 399: /* Show the possible NM drivers */ 400: c3725_nm_show_drivers(); 401: break; 402: 403: case VM_TYPE_C3745: 404: printf("<nm_desc> format:\n" 405: " \"slot:nm_driver\"\n" 406: "\n"); 407: 408: printf("<nm_nio> format:\n" 409: " \"slot:port:netio_type{:netio_parameters}\"\n" 410: "\n"); 411: 412: /* Show the possible NM drivers */ 413: c3745_nm_show_drivers(); 414: break; 1.1.1.8 ! root 415: ! 416: case VM_TYPE_C2600: ! 417: printf("<nm_desc> format:\n" ! 418: " \"slot:nm_driver\"\n" ! 419: "\n"); ! 420: ! 421: printf("<nm_nio> format:\n" ! 422: " \"slot:port:netio_type{:netio_parameters}\"\n" ! 423: "\n"); ! 424: ! 425: /* Show the possible chassis types for C2600 platform */ ! 426: c2600_mainboard_show_drivers(); ! 427: ! 428: /* Show the possible NM drivers */ ! 429: c2600_nm_show_drivers(); ! 430: break; 1.1 root 431: } 432: 1.1.1.4 root 433: /* Show the possible NETIO types */ 434: netio_show_types(); 1.1 root 435: } 436: 1.1.1.4 root 437: /* Find an option in the command line */ 438: static char *cli_find_option(int argc,char *argv[],char *opt) 1.1 root 439: { 1.1.1.4 root 440: int i; 1.1 root 441: 1.1.1.4 root 442: for(i=1;i<argc;i++) { 443: if (!strncmp(argv[i],opt,2)) { 444: if (argv[i][2] != 0) 445: return(&argv[i][2]); 446: else { 447: if (argv[i+1] != NULL) 448: return(argv[i+1]); 449: else { 450: fprintf(stderr,"Error: option '%s': no argument specified.\n", 451: opt); 452: exit(EXIT_FAILURE); 453: } 454: } 455: } 1.1 root 456: } 457: 1.1.1.4 root 458: return NULL; 459: } 1.1 root 460: 1.1.1.4 root 461: /* Determine the platform (Cisco 3600, 7200). Default is Cisco 7200 */ 462: static int cli_get_platform_type(int argc,char *argv[]) 463: { 464: int vm_type = VM_TYPE_C7200; 465: char *str; 1.1 root 466: 1.1.1.4 root 467: if ((str = cli_find_option(argc,argv,"-P"))) { 468: if (!strcmp(str,"3600")) 469: vm_type = VM_TYPE_C3600; 470: else if (!strcmp(str,"7200")) 471: vm_type = VM_TYPE_C7200; 1.1.1.6 root 472: else if (!strcmp(str,"2691")) 473: vm_type = VM_TYPE_C2691; 474: else if (!strcmp(str,"3725")) 475: vm_type = VM_TYPE_C3725; 476: else if (!strcmp(str,"3745")) 477: vm_type = VM_TYPE_C3745; 1.1.1.8 ! root 478: else if (!strcmp(str,"2600")) ! 479: vm_type = VM_TYPE_C2600; ! 480: else if (!strcmp(str,"PPC32_TEST")) ! 481: vm_type = VM_TYPE_PPC32_TEST; 1.1.1.4 root 482: else 483: fprintf(stderr,"Invalid platform type '%s'\n",str); 1.1 root 484: } 485: 1.1.1.4 root 486: return(vm_type); 487: } 1.1 root 488: 1.1.1.4 root 489: /* Command Line long options */ 490: #define OPT_DISK0_SIZE 0x100 491: #define OPT_DISK1_SIZE 0x101 492: #define OPT_EXEC_AREA 0x102 493: #define OPT_IDLE_PC 0x103 494: #define OPT_TIMER_ITV 0x104 495: #define OPT_VM_DEBUG 0x105 496: #define OPT_IOMEM_SIZE 0x106 1.1.1.8 ! root 497: #define OPT_SPARSE_MEM 0x107 1.1.1.4 root 498: 499: static struct option cmd_line_lopts[] = { 500: { "disk0" , 1, NULL, OPT_DISK0_SIZE }, 501: { "disk1" , 1, NULL, OPT_DISK1_SIZE }, 502: { "exec-area" , 1, NULL, OPT_EXEC_AREA }, 503: { "idle-pc" , 1, NULL, OPT_IDLE_PC }, 504: { "timer-itv" , 1, NULL, OPT_TIMER_ITV }, 505: { "vm-debug" , 1, NULL, OPT_VM_DEBUG }, 506: { "iomem-size" , 1, NULL, OPT_IOMEM_SIZE }, 1.1.1.8 ! root 507: { "sparse-mem" , 0, NULL, OPT_SPARSE_MEM }, 1.1.1.4 root 508: { NULL , 0, NULL, 0 }, 509: }; 1.1 root 510: 1.1.1.4 root 511: /* Parse specific options for the Cisco 7200 platform */ 512: static int cli_parse_c7200_options(vm_instance_t *vm,int option) 513: { 514: c7200_t *router; 1.1 root 515: 1.1.1.4 root 516: router = VM_C7200(vm); 1.1 root 517: 1.1.1.4 root 518: switch(option) { 519: /* NPE type */ 520: case 't': 521: c7200_npe_set_type(router,optarg); 522: break; 1.1 root 523: 1.1.1.4 root 524: /* Midplane type */ 525: case 'M': 526: c7200_midplane_set_type(router,optarg); 527: break; 1.1 root 528: 1.1.1.4 root 529: /* Set the base MAC address */ 530: case 'm': 531: if (!c7200_midplane_set_mac_addr(router,optarg)) 532: printf("MAC address set to '%s'.\n",optarg); 533: break; 1.1 root 534: 1.1.1.4 root 535: /* PA settings */ 536: case 'p': 537: return(c7200_cmd_pa_create(router,optarg)); 538: 539: /* PA NIO settings */ 540: case 's': 541: return(c7200_cmd_add_nio(router,optarg)); 1.1 root 542: 1.1.1.4 root 543: /* Unknown option */ 544: default: 545: return(-1); 546: } 1.1 root 547: 548: return(0); 549: } 550: 1.1.1.4 root 551: /* Parse specific options for the Cisco 3600 platform */ 552: static int cli_parse_c3600_options(vm_instance_t *vm,int option) 1.1 root 553: { 1.1.1.4 root 554: c3600_t *router; 1.1 root 555: 1.1.1.4 root 556: router = VM_C3600(vm); 1.1 root 557: 1.1.1.4 root 558: switch(option) { 559: /* chassis type */ 560: case 't': 561: c3600_chassis_set_type(router,optarg); 562: break; 1.1 root 563: 1.1.1.4 root 564: /* IO memory reserved for NMs (in percents!) */ 565: case OPT_IOMEM_SIZE: 566: router->nm_iomem_size = 0x8000 | atoi(optarg); 567: break; 1.1 root 568: 1.1.1.4 root 569: /* NM settings */ 570: case 'p': 571: return(c3600_cmd_nm_create(router,optarg)); 572: 573: /* NM NIO settings */ 574: case 's': 575: return(c3600_cmd_add_nio(router,optarg)); 576: 577: /* Unknown option */ 578: default: 579: return(-1); 1.1 root 580: } 581: 582: return(0); 583: } 584: 1.1.1.6 root 585: /* Parse specific options for the Cisco 2691 platform */ 586: static int cli_parse_c2691_options(vm_instance_t *vm,int option) 587: { 588: c2691_t *router; 589: 590: router = VM_C2691(vm); 591: 592: switch(option) { 593: /* IO memory reserved for NMs (in percents!) */ 594: case OPT_IOMEM_SIZE: 595: router->nm_iomem_size = 0x8000 | atoi(optarg); 596: break; 597: 598: /* NM settings */ 599: case 'p': 600: return(c2691_cmd_nm_create(router,optarg)); 601: 602: /* NM NIO settings */ 603: case 's': 604: return(c2691_cmd_add_nio(router,optarg)); 605: 606: /* Unknown option */ 607: default: 608: return(-1); 609: } 610: 611: return(0); 612: } 613: 614: /* Parse specific options for the Cisco 3725 platform */ 615: static int cli_parse_c3725_options(vm_instance_t *vm,int option) 616: { 617: c3725_t *router; 618: 619: router = VM_C3725(vm); 620: 621: switch(option) { 622: /* IO memory reserved for NMs (in percents!) */ 623: case OPT_IOMEM_SIZE: 624: router->nm_iomem_size = 0x8000 | atoi(optarg); 625: break; 626: 627: /* NM settings */ 628: case 'p': 629: return(c3725_cmd_nm_create(router,optarg)); 630: 631: /* NM NIO settings */ 632: case 's': 633: return(c3725_cmd_add_nio(router,optarg)); 634: 635: /* Unknown option */ 636: default: 637: return(-1); 638: } 639: 640: return(0); 641: } 642: 643: /* Parse specific options for the Cisco 3745 platform */ 644: static int cli_parse_c3745_options(vm_instance_t *vm,int option) 645: { 646: c3745_t *router; 647: 648: router = VM_C3745(vm); 649: 650: switch(option) { 651: /* IO memory reserved for NMs (in percents!) */ 652: case OPT_IOMEM_SIZE: 653: router->nm_iomem_size = 0x8000 | atoi(optarg); 654: break; 655: 656: /* NM settings */ 657: case 'p': 658: return(c3745_cmd_nm_create(router,optarg)); 659: 660: /* NM NIO settings */ 661: case 's': 662: return(c3745_cmd_add_nio(router,optarg)); 663: 664: /* Unknown option */ 665: default: 666: return(-1); 667: } 668: 669: return(0); 670: } 671: 1.1.1.8 ! root 672: /* Parse specific options for the Cisco 2600 platform */ ! 673: static int cli_parse_c2600_options(vm_instance_t *vm,int option) ! 674: { ! 675: c2600_t *router; ! 676: ! 677: router = VM_C2600(vm); ! 678: ! 679: switch(option) { ! 680: /* IO memory reserved for NMs (in percents!) */ ! 681: case OPT_IOMEM_SIZE: ! 682: router->nm_iomem_size = 0x8000 | atoi(optarg); ! 683: break; ! 684: ! 685: /* Mainboard type */ ! 686: case 't': ! 687: c2600_mainboard_set_type(router,optarg); ! 688: break; ! 689: ! 690: /* NM settings */ ! 691: case 'p': ! 692: return(c2600_cmd_nm_create(router,optarg)); ! 693: ! 694: /* NM NIO settings */ ! 695: case 's': ! 696: return(c2600_cmd_add_nio(router,optarg)); ! 697: ! 698: /* Unknown option */ ! 699: default: ! 700: return(-1); ! 701: } ! 702: ! 703: return(0); ! 704: } ! 705: 1.1.1.4 root 706: /* Create a router instance */ 707: static vm_instance_t *cli_create_instance(char *name,int platform_type, 708: int instance_id) 1.1 root 709: { 1.1.1.8 ! root 710: vm_instance_t *vm; 1.1.1.4 root 711: c7200_t *c7200; 712: c3600_t *c3600; 1.1.1.6 root 713: c2691_t *c2691; 714: c3725_t *c3725; 715: c3745_t *c3745; 1.1.1.8 ! root 716: c2600_t *c2600; 1.1.1.3 root 717: 1.1.1.4 root 718: switch(platform_type) { 719: case VM_TYPE_C7200: 720: if (!(c7200 = c7200_create_instance(name,instance_id))) { 721: fprintf(stderr,"C7200: unable to create instance!\n"); 722: return NULL; 723: } 724: return(c7200->vm); 1.1 root 725: 1.1.1.4 root 726: case VM_TYPE_C3600: 727: if (!(c3600 = c3600_create_instance(name,instance_id))) { 728: fprintf(stderr,"C3600: unable to create instance!\n"); 729: return NULL; 730: } 731: return(c3600->vm); 1.1 root 732: 1.1.1.6 root 733: case VM_TYPE_C2691: 734: if (!(c2691 = c2691_create_instance(name,instance_id))) { 735: fprintf(stderr,"C2691: unable to create instance!\n"); 736: return NULL; 737: } 738: return(c2691->vm); 739: 740: case VM_TYPE_C3725: 741: if (!(c3725 = c3725_create_instance(name,instance_id))) { 742: fprintf(stderr,"C3725: unable to create instance!\n"); 743: return NULL; 744: } 745: return(c3725->vm); 746: 747: case VM_TYPE_C3745: 748: if (!(c3745 = c3745_create_instance(name,instance_id))) { 749: fprintf(stderr,"C3745: unable to create instance!\n"); 750: return NULL; 751: } 752: return(c3745->vm); 753: 1.1.1.8 ! root 754: case VM_TYPE_C2600: ! 755: if (!(c2600 = c2600_create_instance(name,instance_id))) { ! 756: fprintf(stderr,"C2600: unable to create instance!\n"); ! 757: return NULL; ! 758: } ! 759: return(c2600->vm); ! 760: ! 761: case VM_TYPE_PPC32_TEST: ! 762: if (!(vm = ppc32_vmtest_create_instance(name,instance_id))) { ! 763: fprintf(stderr,"PPC32_TEST: unable to create instance!\n"); ! 764: return NULL; ! 765: } ! 766: return(vm); ! 767: 1.1.1.4 root 768: default: 769: fprintf(stderr,"Unknown platform type '%d'!\n",platform_type); 770: return NULL; 771: } 1.1 root 772: } 773: 1.1.1.4 root 774: /* Parse the command line */ 775: static int parse_std_cmd_line(int argc,char *argv[],int *platform) 1.1 root 776: { 1.1.1.4 root 777: char *options_list = 1.1.1.6 root 778: "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:"; 1.1.1.4 root 779: vm_instance_t *vm; 780: int instance_id; 781: int res,option; 782: char *str; 1.1 root 783: 1.1.1.4 root 784: /* Get the instance ID */ 785: instance_id = 0; 1.1 root 786: 1.1.1.4 root 787: /* Use the old VM file naming type */ 788: vm_file_naming_type = 1; 1.1 root 789: 1.1.1.4 root 790: if ((str = cli_find_option(argc,argv,"-i"))) { 791: instance_id = atoi(str); 792: printf("Instance ID set to %d.\n",instance_id); 793: } 1.1 root 794: 1.1.1.4 root 795: if ((str = cli_find_option(argc,argv,"-N"))) 796: vm_file_naming_type = atoi(str); 1.1.1.2 root 797: 1.1.1.4 root 798: /* Get the platform type */ 799: *platform = cli_get_platform_type(argc,argv); 800: 801: /* Create the default instance */ 802: if (!(vm = cli_create_instance("default",*platform,instance_id))) 803: exit(EXIT_FAILURE); 1.1 root 804: 805: opterr = 0; 806: 1.1.1.4 root 807: while((option = getopt_long(argc,argv,options_list, 808: cmd_line_lopts,NULL)) != -1) 809: { 1.1 root 810: switch(option) 811: { 1.1.1.4 root 812: /* Instance ID (already managed) */ 813: case 'i': 814: break; 815: 816: /* Platform (already managed) */ 817: case 'P': 818: break; 819: 1.1 root 820: /* RAM size */ 821: case 'r': 1.1.1.4 root 822: vm->ram_size = strtol(optarg, NULL, 10); 823: printf("Virtual RAM size set to %d MB.\n",vm->ram_size); 1.1 root 824: break; 825: 826: /* ROM size */ 827: case 'o': 1.1.1.4 root 828: vm->rom_size = strtol(optarg, NULL, 10); 829: printf("Virtual ROM size set to %d MB.\n",vm->rom_size); 1.1 root 830: break; 831: 832: /* NVRAM size */ 833: case 'n': 1.1.1.4 root 834: vm->nvram_size = strtol(optarg, NULL, 10); 835: printf("NVRAM size set to %d KB.\n",vm->nvram_size); 1.1 root 836: break; 837: 1.1.1.4 root 838: /* Execution area size */ 839: case OPT_EXEC_AREA: 840: vm->exec_area_size = atoi(optarg); 1.1 root 841: break; 842: 1.1.1.4 root 843: /* PCMCIA disk0 size */ 844: case OPT_DISK0_SIZE: 845: vm->pcmcia_disk_size[0] = atoi(optarg); 846: printf("PCMCIA ATA disk0 size set to %u MB.\n", 847: vm->pcmcia_disk_size[0]); 1.1 root 848: break; 849: 1.1.1.4 root 850: /* PCMCIA disk1 size */ 851: case OPT_DISK1_SIZE: 852: vm->pcmcia_disk_size[1] = atoi(optarg); 853: printf("PCMCIA ATA disk1 size set to %u MB.\n", 854: vm->pcmcia_disk_size[1]); 855: break; 856: 857: /* Config Register */ 858: case 'c': 859: vm->conf_reg_setup = strtol(optarg, NULL, 0); 860: printf("Config. Register set to 0x%x.\n",vm->conf_reg_setup); 1.1 root 861: break; 862: 863: /* IOS configuration file */ 864: case 'C': 1.1.1.4 root 865: vm_ios_set_config(vm,optarg); 1.1 root 866: break; 867: 1.1.1.3 root 868: /* Use physical memory to emulate RAM (no-mapped file) */ 869: case 'X': 1.1.1.4 root 870: vm->ram_mmap = 0; 1.1.1.3 root 871: break; 872: 1.1.1.6 root 873: /* Use a ghost file to simulate RAM */ 874: case 'G': 875: vm->ghost_ram_filename = strdup(optarg); 876: vm->ghost_status = VM_GHOST_RAM_USE; 877: break; 878: 879: /* Generate a ghost RAM image */ 880: case 'g': 881: vm->ghost_ram_filename = strdup(optarg); 882: vm->ghost_status = VM_GHOST_RAM_GENERATE; 883: break; 884: 1.1.1.8 ! root 885: /* Use sparse memory */ ! 886: case OPT_SPARSE_MEM: ! 887: vm->sparse_mem = TRUE; ! 888: break; ! 889: 1.1 root 890: /* Alternate ROM */ 891: case 'R': 1.1.1.4 root 892: vm->rom_filename = optarg; 1.1 root 893: break; 894: 1.1.1.4 root 895: /* Idle PC */ 896: case OPT_IDLE_PC: 897: vm->idle_pc = strtoull(optarg,NULL,0); 898: printf("Idle PC set to 0x%llx.\n",vm->idle_pc); 1.1 root 899: break; 900: 1.1.1.4 root 901: /* Timer IRQ check interval */ 902: case OPT_TIMER_ITV: 903: vm->timer_irq_check_itv = atoi(optarg); 1.1 root 904: break; 905: 1.1.1.4 root 906: /* Clock divisor */ 907: case 'k': 908: vm->clock_divisor = atoi(optarg); 909: 910: if (!vm->clock_divisor) { 911: fprintf(stderr,"Invalid Clock Divisor specified!\n"); 912: exit(EXIT_FAILURE); 913: } 914: 915: printf("Using a clock divisor of %d.\n",vm->clock_divisor); 1.1.1.3 root 916: break; 917: 1.1.1.4 root 918: /* Disable JIT */ 919: case 'j': 920: vm->jit_use = FALSE; 1.1 root 921: break; 922: 1.1.1.4 root 923: /* VM debug level */ 924: case OPT_VM_DEBUG: 925: vm->debug_level = atoi(optarg); 926: break; 1.1 root 927: 1.1.1.4 root 928: /* Log file */ 929: case 'l': 930: if (!(log_file_name = strdup(optarg))) { 931: fprintf(stderr,"Unable to set log file name.\n"); 1.1 root 932: exit(EXIT_FAILURE); 933: } 1.1.1.4 root 934: printf("Log file: writing to %s\n",log_file_name); 935: break; 1.1 root 936: 1.1.1.4 root 937: #if DEBUG_SYM_TREE 938: /* Symbol file */ 939: case 'S': 940: vm->sym_filename = strdup(optarg); 1.1 root 941: break; 1.1.1.4 root 942: #endif 1.1 root 943: 944: /* TCP server for Console Port */ 945: case 'T': 1.1.1.4 root 946: vm->vtty_con_type = VTTY_TYPE_TCP; 947: vm->vtty_con_tcp_port = atoi(optarg); 948: break; 949: 950: /* Serial interface for Console port */ 951: case 'U': 952: vm->vtty_con_type = VTTY_TYPE_SERIAL; 953: if (vtty_parse_serial_option(&vm->vtty_con_serial_option,optarg)) { 954: fprintf(stderr, 955: "Invalid Console serial interface descriptor!\n"); 956: exit(EXIT_FAILURE); 957: } 1.1 root 958: break; 959: 960: /* TCP server for AUX Port */ 961: case 'A': 1.1.1.4 root 962: vm->vtty_aux_type = VTTY_TYPE_TCP; 963: vm->vtty_aux_tcp_port = atoi(optarg); 964: break; 965: 966: /* Serial interface for AUX port */ 967: case 'B': 968: vm->vtty_aux_type = VTTY_TYPE_SERIAL; 969: if (vtty_parse_serial_option(&vm->vtty_aux_serial_option,optarg)) { 970: fprintf(stderr,"Invalid AUX serial interface descriptor!\n"); 971: exit(EXIT_FAILURE); 972: } 1.1 root 973: break; 974: 975: /* Virtual ATM switch */ 976: case 'a': 977: if (atmsw_start(optarg) == -1) 978: exit(EXIT_FAILURE); 979: break; 980: 1.1.1.3 root 981: /* Virtual Frame-Relay switch */ 982: case 'f': 983: if (frsw_start(optarg) == -1) 984: exit(EXIT_FAILURE); 985: break; 986: 1.1.1.4 root 987: /* Virtual Ethernet switch */ 988: case 'E': 989: if (ethsw_start(optarg) == -1) 990: exit(EXIT_FAILURE); 991: break; 992: 1.1 root 993: /* Virtual bridge */ 994: case 'b': 995: if (netio_bridge_start(optarg) == -1) 996: exit(EXIT_FAILURE); 997: break; 998: 1.1.1.2 root 999: #ifdef GEN_ETH 1000: /* Ethernet device list */ 1001: case 'e': 1002: gen_eth_show_dev_list(); 1003: exit(EXIT_SUCCESS); 1004: #endif 1005: 1.1 root 1006: /* Oops ! */ 1007: case '?': 1.1.1.4 root 1008: show_usage(argc,argv,*platform); 1.1 root 1009: exit(EXIT_FAILURE); 1.1.1.4 root 1010: 1011: /* Parse options specific to the platform */ 1012: default: 1013: res = 0; 1014: 1015: switch(vm->type) { 1016: case VM_TYPE_C7200: 1017: res = cli_parse_c7200_options(vm,option); 1018: break; 1019: case VM_TYPE_C3600: 1020: res = cli_parse_c3600_options(vm,option); 1.1.1.6 root 1021: break; 1022: case VM_TYPE_C2691: 1023: res = cli_parse_c2691_options(vm,option); 1024: break; 1025: case VM_TYPE_C3725: 1026: res = cli_parse_c3725_options(vm,option); 1027: break; 1028: case VM_TYPE_C3745: 1029: res = cli_parse_c3745_options(vm,option); 1.1.1.4 root 1030: break; 1.1.1.8 ! root 1031: case VM_TYPE_C2600: ! 1032: res = cli_parse_c2600_options(vm,option); ! 1033: break; 1.1.1.4 root 1034: } 1035: 1036: if (res == -1) 1037: exit(EXIT_FAILURE); 1.1 root 1038: } 1039: } 1040: 1041: /* Last argument, this is the IOS filename */ 1042: if (optind == (argc - 1)) { 1043: /* setting IOS image file */ 1.1.1.4 root 1044: vm_ios_set_image(vm,argv[optind]); 1045: printf("IOS image file: %s\n\n",vm->ios_image); 1.1 root 1046: } else { 1047: /* IOS missing */ 1048: fprintf(stderr,"Please specify an IOS image filename\n"); 1.1.1.4 root 1049: show_usage(argc,argv,*platform); 1.1 root 1050: exit(EXIT_FAILURE); 1051: } 1052: 1.1.1.4 root 1053: vm_release(vm); 1054: return(0); 1055: } 1056: 1057: /* 1058: * Run in hypervisor mode with a config file if the "-H" option 1059: * is present in command line. 1060: */ 1061: static int run_hypervisor(int argc,char *argv[]) 1062: { 1063: char *options_list = "H:l:hN:"; 1064: int i,option; 1065: 1066: for(i=1;i<argc;i++) 1067: if (!strcmp(argv[i],"-H")) { 1068: hypervisor_mode = 1; 1069: break; 1.1 root 1070: } 1071: 1.1.1.4 root 1072: /* standard mode with one instance */ 1073: if (!hypervisor_mode) 1074: return(FALSE); 1075: 1076: opterr = 0; 1077: while((option = getopt(argc,argv,options_list)) != -1) { 1078: switch(option) 1079: { 1080: /* Hypervisor TCP port */ 1081: case 'H': 1082: hypervisor_tcp_port = atoi(optarg); 1083: break; 1084: 1085: /* Log file */ 1086: case 'l': 1087: if (!(log_file_name = malloc(strlen(optarg)+1))) { 1088: fprintf(stderr,"Unable to set log file name.\n"); 1089: exit(EXIT_FAILURE); 1090: } 1091: strcpy(log_file_name, optarg); 1092: printf("Log file: writing to %s\n",log_file_name); 1093: break; 1094: 1095: /* VM file naming type */ 1096: case 'N': 1097: vm_file_naming_type = atoi(optarg); 1098: break; 1099: 1100: /* Oops ! */ 1101: case '?': 1102: show_usage(argc,argv,VM_TYPE_C7200); 1103: exit(EXIT_FAILURE); 1104: } 1.1 root 1105: } 1106: 1.1.1.4 root 1107: return(TRUE); 1108: } 1.1 root 1109: 1.1.1.4 root 1110: /* Delete all objects */ 1111: void dynamips_reset(void) 1112: { 1113: printf("Shutdown in progress...\n"); 1.1 root 1114: 1.1.1.6 root 1115: /* Delete all virtual router instances */ 1.1.1.4 root 1116: c7200_delete_all_instances(); 1117: c3600_delete_all_instances(); 1.1.1.6 root 1118: c2691_delete_all_instances(); 1119: c3725_delete_all_instances(); 1120: c3745_delete_all_instances(); 1.1.1.8 ! root 1121: c2600_delete_all_instances(); ! 1122: ppc32_vmtest_delete_all_instances(); 1.1.1.4 root 1123: 1124: /* Delete ATM and Frame-Relay switches + bridges */ 1125: netio_bridge_delete_all(); 1126: atmsw_delete_all(); 1127: frsw_delete_all(); 1128: ethsw_delete_all(); 1.1 root 1129: 1.1.1.4 root 1130: /* Delete all NIO descriptors */ 1131: netio_delete_all(); 1.1 root 1132: 1.1.1.4 root 1133: printf("Shutdown completed.\n"); 1134: } 1.1 root 1135: 1.1.1.4 root 1136: int main(int argc,char *argv[]) 1137: { 1138: vm_instance_t *vm; 1139: int platform,res; 1.1 root 1140: 1.1.1.4 root 1141: /* Default emulation: Cisco 7200 */ 1142: platform = VM_TYPE_C7200; 1.1 root 1143: 1.1.1.4 root 1144: #ifdef PROFILE 1145: atexit(profiler_savestat); 1146: #endif 1147: 1.1.1.8 ! root 1148: printf("Cisco Router Simulation Platform (version %s)\n",sw_version); ! 1149: printf("Copyright (c) 2005-2007 Christophe Fillot.\n"); 1.1.1.6 root 1150: printf("Build date: %s %s\n\n",__DATE__,__TIME__); 1.1.1.4 root 1151: 1.1.1.5 root 1152: /* Initialize timers */ 1153: timer_init(); 1154: 1.1.1.4 root 1155: /* Initialize object registry */ 1156: registry_init(); 1157: 1158: /* Initialize ATM module (for HEC checksums) */ 1159: atm_init(); 1160: 1161: /* Initialize CRC functions */ 1162: crc_init(); 1163: 1164: /* Initialize NetIO code */ 1165: netio_rxl_init(); 1166: 1167: /* Initialize NetIO packet filters */ 1168: netio_filter_load_all(); 1169: 1170: /* Initialize VTTY code */ 1171: vtty_init(); 1172: 1173: /* Parse standard command line */ 1174: if (!run_hypervisor(argc,argv)) 1175: parse_std_cmd_line(argc,argv,&platform); 1176: 1177: /* Create general log file */ 1178: create_log_file(); 1179: 1180: /* Periodic tasks initialization */ 1181: if (ptask_init(0) == -1) 1.1 root 1182: exit(EXIT_FAILURE); 1183: 1.1.1.4 root 1184: /* Create instruction lookup tables */ 1185: mips64_jit_create_ilt(); 1186: mips64_exec_create_ilt(); 1.1.1.8 ! root 1187: ppc32_jit_create_ilt(); ! 1188: ppc32_exec_create_ilt(); 1.1 root 1189: 1190: setup_signals(); 1191: 1.1.1.4 root 1192: if (!hypervisor_mode) { 1193: /* Initialize the default instance */ 1194: vm = vm_acquire("default"); 1195: assert(vm != NULL); 1196: 1197: switch(platform) { 1198: case VM_TYPE_C7200: 1199: res = c7200_init_instance(VM_C7200(vm)); 1200: break; 1201: case VM_TYPE_C3600: 1202: res = c3600_init_instance(VM_C3600(vm)); 1.1.1.6 root 1203: break; 1204: case VM_TYPE_C2691: 1205: res = c2691_init_instance(VM_C2691(vm)); 1206: break; 1207: case VM_TYPE_C3725: 1208: res = c3725_init_instance(VM_C3725(vm)); 1209: break; 1210: case VM_TYPE_C3745: 1211: res = c3745_init_instance(VM_C3745(vm)); 1.1.1.4 root 1212: break; 1.1.1.8 ! root 1213: case VM_TYPE_C2600: ! 1214: res = c2600_init_instance(VM_C2600(vm)); ! 1215: break; ! 1216: case VM_TYPE_PPC32_TEST: ! 1217: res = ppc32_vmtest_init_instance(vm); ! 1218: break; 1.1.1.4 root 1219: default: 1220: res = -1; 1221: } 1222: 1223: if (res == -1) { 1224: fprintf(stderr,"Unable to initialize router instance.\n"); 1225: exit(EXIT_FAILURE); 1226: } 1.1 root 1227: 1.1.1.7 root 1228: #if (DEBUG_INSN_PERF_CNT > 0) || (DEBUG_BLOCK_PERF_CNT > 0) 1.1.1.4 root 1229: { 1.1.1.8 ! root 1230: m_uint64_t counter,prev = 0,delta; 1.1.1.4 root 1231: while(vm->status == VM_STATUS_RUNNING) { 1.1.1.8 ! root 1232: counter = cpu_get_perf_counter(vm->boot_cpu); ! 1233: delta = counter - prev; ! 1234: prev = counter; 1.1.1.4 root 1235: printf("delta = %llu\n",delta); 1236: sleep(1); 1237: } 1238: } 1239: #else 1240: /* Start instance monitoring */ 1241: vm_monitor(vm); 1242: #endif 1.1 root 1243: 1.1.1.4 root 1244: /* Free resources used by instance */ 1245: vm_release(vm); 1246: } else { 1247: hypervisor_tcp_server(hypervisor_tcp_port); 1248: } 1.1 root 1249: 1.1.1.4 root 1250: dynamips_reset(); 1251: close_log_file(); 1.1 root 1252: return(0); 1253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.