/[dynamips]/upstream/dynamips-0.2.6-RC3/hypervisor.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.6-RC3/hypervisor.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Sat Oct 6 16:06:49 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 15971 byte(s)
dynamips-0.2.6-RC3

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Hypervisor routines.
6 */
7
8 /* By default, Cygwin supports only 64 FDs with select()! */
9 #ifdef __CYGWIN__
10 #define FD_SETSIZE 1024
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/mman.h>
20 #include <signal.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <pthread.h>
30
31 #include "utils.h"
32 #include "parser.h"
33 #include "net.h"
34 #include "registry.h"
35 #include "mips64.h"
36 #include "dynamips.h"
37 #include "dev_c7200.h"
38 #include "dev_c3600.h"
39 #include "dev_c2691.h"
40 #include "dev_c3725.h"
41 #include "dev_c3745.h"
42 #include "hypervisor.h"
43 #include "net_io.h"
44 #include "net_io_bridge.h"
45 #include "frame_relay.h"
46 #include "atm.h"
47
48 #define DEBUG_TOKEN 0
49
50 /* Hypervisor modules */
51 static hypervisor_module_t *module_list = NULL;
52 static volatile int hypervisor_running = 0;
53
54 /* Hypervisor connection list */
55 static hypervisor_conn_t *hypervisor_conn_list = NULL;
56
57 /* Show hypervisor version */
58 static int cmd_version(hypervisor_conn_t *conn,int argc,char *argv[])
59 {
60 hypervisor_send_reply(conn,HSC_INFO_OK,1,"%s",sw_version);
61 return(0);
62 }
63
64 /* Parser test */
65 static int cmd_parser_test(hypervisor_conn_t *conn,int argc,char *argv[])
66 {
67 int i;
68
69 for(i=0;i<argc;i++)
70 hypervisor_send_reply(conn,HSC_INFO_MSG,0,
71 "arg %d (len %u): \"%s\"",
72 i,strlen(argv[i]),argv[i]);
73
74 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
75 return(0);
76 }
77
78 /* Show hypervisor module list */
79 static int cmd_mod_list(hypervisor_conn_t *conn,int argc,char *argv[])
80 {
81 hypervisor_module_t *m;
82
83 for(m=module_list;m;m=m->next)
84 hypervisor_send_reply(conn,HSC_INFO_MSG,0,"%s",m->name);
85
86 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
87 return(0);
88 }
89
90 /* Show module command list */
91 static int cmd_modcmd_list(hypervisor_conn_t *conn,int argc,char *argv[])
92 {
93 hypervisor_module_t *m;
94 hypervisor_cmd_t *cmd;
95
96 if (!(m = hypervisor_find_module(argv[0]))) {
97 hypervisor_send_reply(conn,HSC_ERR_UNK_MODULE,1,"unknown module '%s'",
98 argv[0]);
99 return(-1);
100 }
101
102 for(cmd=m->cmd_list;cmd;cmd=cmd->next)
103 hypervisor_send_reply(conn,HSC_INFO_MSG,0,"%s (min/max args: %d/%d)",
104 cmd->name,cmd->min_param,cmd->max_param);
105
106 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
107 return(0);
108 }
109
110 /* Set working directory */
111 static int cmd_set_working_dir(hypervisor_conn_t *conn,int argc,char *argv[])
112 {
113 if (chdir(argv[0]) == -1) {
114 hypervisor_send_reply(conn,HSC_ERR_INV_PARAM,1,
115 "chdir: %s",strerror(errno));
116 } else {
117 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
118 }
119 return(0);
120 }
121
122 /* Save the hypervisor configuration in the specified file */
123 static int cmd_save_config(hypervisor_conn_t *conn,int argc,char *argv[])
124 {
125 FILE *fd;
126
127 if (!(fd = fopen(argv[0],"w"))) {
128 hypervisor_send_reply(conn,HSC_ERR_FILE,1,"fopen: %s",strerror(errno));
129 return(-1);
130 }
131
132 /* Save configuration for all objects */
133 netio_save_config_all(fd);
134 frsw_save_config_all(fd);
135 atmsw_save_config_all(fd);
136 netio_bridge_save_config_all(fd);
137 c7200_save_config_all(fd);
138 c3600_save_config_all(fd);
139 c2691_save_config_all(fd);
140 c3725_save_config_all(fd);
141 c3745_save_config_all(fd);
142
143 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
144 return(0);
145 }
146
147 /* Reset hypervisor (delete all objects) */
148 static int cmd_reset(hypervisor_conn_t *conn,int argc,char *argv[])
149 {
150 dynamips_reset();
151 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
152 return(0);
153 }
154
155 /* Close connection */
156 static int cmd_close(hypervisor_conn_t *conn,int argc,char *argv[])
157 {
158 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
159 conn->active = FALSE;
160 return(0);
161 }
162
163 /* Stop hypervisor */
164 static int cmd_stop(hypervisor_conn_t *conn,int argc,char *argv[])
165 {
166 hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
167 hypervisor_running = FALSE;
168 return(0);
169 }
170
171 /* Hypervisor commands */
172 static hypervisor_cmd_t hypervisor_cmd_array[] = {
173 { "version", 0, 0, cmd_version, NULL },
174 { "parser_test", 0, 10, cmd_parser_test, NULL },
175 { "module_list", 0, 0, cmd_mod_list, NULL },
176 { "cmd_list", 1, 1, cmd_modcmd_list, NULL },
177 { "working_dir", 1, 1, cmd_set_working_dir, NULL },
178 { "save_config", 1, 1, cmd_save_config, NULL },
179 { "reset", 0, 0, cmd_reset, NULL },
180 { "close", 0, 0, cmd_close, NULL },
181 { "stop", 0, 0, cmd_stop, NULL },
182 { NULL, -1, -1, NULL, NULL },
183 };
184
185 /* Send a reply */
186 int hypervisor_send_reply(hypervisor_conn_t *conn,int code,int done,
187 char *format,...)
188 {
189 va_list ap;
190 size_t n = 0;
191
192 if (conn != NULL) {
193 va_start(ap,format);
194 n += fprintf(conn->out,"%3d%s",code,(done)?"-":" ");
195 n += vfprintf(conn->out,format,ap);
196 n += fprintf(conn->out,"\r\n");
197 fflush(conn->out);
198 va_end(ap);
199 }
200
201 return(n);
202 }
203
204 /* Find a module */
205 hypervisor_module_t *hypervisor_find_module(char *name)
206 {
207 hypervisor_module_t *m;
208
209 for(m=module_list;m;m=m->next)
210 if (!strcmp(m->name,name))
211 return m;
212
213 return NULL;
214 }
215
216 /* Find a command in a module */
217 hypervisor_cmd_t *hypervisor_find_cmd(hypervisor_module_t *module,char *name)
218 {
219 hypervisor_cmd_t *cmd;
220
221 for(cmd=module->cmd_list;cmd;cmd=cmd->next)
222 if (!strcmp(cmd->name,name))
223 return cmd;
224
225 return NULL;
226 }
227
228 /* Find an object in the registry */
229 void *hypervisor_find_object(hypervisor_conn_t *conn,char *name,int obj_type)
230 {
231 void *p;
232
233 if (!(p = registry_find(name,obj_type))) {
234 hypervisor_send_reply(conn,HSC_ERR_UNK_OBJ,1,
235 "unable to find object '%s'",name);
236 return NULL;
237 }
238
239 return p;
240 }
241
242 /* Find a VM in the registry */
243 void *hypervisor_find_vm(hypervisor_conn_t *conn,char *name,int vm_type)
244 {
245 vm_instance_t *vm;
246
247 if (!(vm = vm_acquire(name))) {
248 hypervisor_send_reply(conn,HSC_ERR_UNK_OBJ,1,
249 "unable to find VM '%s'",name);
250 return NULL;
251 }
252
253 if (vm->type != vm_type) {
254 vm_release(vm);
255 hypervisor_send_reply(conn,HSC_ERR_BAD_OBJ,1,
256 "VM '%s' is not a VM type %d",
257 name,vm_type);
258 return NULL;
259 }
260
261 return vm;
262 }
263
264 /* Register a module */
265 hypervisor_module_t *hypervisor_register_module(char *name)
266 {
267 hypervisor_module_t *m;
268
269 if (hypervisor_find_module(name) != NULL) {
270 fprintf(stderr,"Hypervisor: module '%s' already exists.\n",name);
271 return NULL;
272 }
273
274 if (!(m = malloc(sizeof(*m)))) {
275 fprintf(stderr,"Hypervisor: unable to register new module.\n");
276 return NULL;
277 }
278
279 m->name = name;
280 m->cmd_list = NULL;
281
282 m->next = module_list;
283 module_list = m;
284 return m;
285 }
286
287 /* Register a list of commands */
288 int hypervisor_register_cmd_list(hypervisor_module_t *module,
289 hypervisor_cmd_t *cmd_list)
290 {
291 hypervisor_cmd_t *cmd = cmd_list;
292
293 while(cmd->next != NULL)
294 cmd = cmd->next;
295
296 cmd->next = module->cmd_list;
297 module->cmd_list = cmd_list;
298 return(0);
299 }
300
301 /* Register an array of commands */
302 int hypervisor_register_cmd_array(hypervisor_module_t *module,
303 hypervisor_cmd_t *cmd_array)
304 {
305 hypervisor_cmd_t *cmd;
306
307 for(cmd=cmd_array;cmd->name!=NULL;cmd++) {
308 cmd->next = module->cmd_list;
309 module->cmd_list = cmd;
310 }
311
312 return(0);
313 }
314
315 /* Locate the module and execute command */
316 static int hypervisor_exec_cmd(hypervisor_conn_t *conn,
317 char *mod_name,char *cmd_name,
318 int argc,char *argv[])
319 {
320 hypervisor_module_t *module;
321 hypervisor_cmd_t *cmd;
322
323 if (!(module = hypervisor_find_module(mod_name))) {
324 hypervisor_send_reply(conn,HSC_ERR_UNK_MODULE,1,"Unknown module '%s'",
325 mod_name);
326 return(-1);
327 }
328
329 if (!(cmd = hypervisor_find_cmd(module,cmd_name))) {
330 hypervisor_send_reply(conn,HSC_ERR_UNK_CMD,1,"Unknown command '%s'",
331 cmd_name);
332 return(-1);
333 }
334
335 if ((argc < cmd->min_param) || (argc > cmd->max_param)) {
336 hypervisor_send_reply(conn,HSC_ERR_BAD_PARAM,1,
337 "Bad number of parameters (%d with min/max=%d/%d)",
338 argc,cmd->min_param,cmd->max_param);
339 return(-1);
340 }
341
342 return(cmd->handler(conn,argc,argv));
343 }
344
345 /* Thread for servicing connections */
346 static void *hypervisor_thread(void *arg)
347 {
348 hypervisor_conn_t *conn = arg;
349 char buffer[512],**tokens;
350 parser_context_t ctx;
351 int res;
352
353 tokens = NULL;
354 parser_context_init(&ctx);
355
356 while(conn->active) {
357 if (!fgets(buffer,sizeof(buffer),conn->in))
358 break;
359
360 if (!*buffer)
361 continue;
362
363 /* Tokenize command line */
364 res = parser_scan_buffer(&ctx,buffer,strlen(buffer));
365
366 if (res != 0) {
367 tokens = NULL;
368
369 if (ctx.error != 0) {
370 hypervisor_send_reply(conn,HSC_ERR_PARSING,1,"Parse error: %s",
371 parser_strerror(&ctx));
372 goto free_tokens;
373 }
374
375 if (ctx.tok_count < 2) {
376 hypervisor_send_reply(conn,HSC_ERR_PARSING,1,
377 "At least a module and a command "
378 "must be specified");
379 goto free_tokens;
380 }
381
382 /* Map token list to an array */
383 tokens = parser_map_array(&ctx);
384
385 if (!tokens) {
386 hypervisor_send_reply(conn,HSC_ERR_PARSING,1,"No memory");
387 goto free_tokens;
388 }
389
390 /* Execute command */
391 //m_log("hypervisor_exec","%s\n",buffer);
392 hypervisor_exec_cmd(conn,tokens[0],tokens[1],ctx.
393 tok_count-2,&tokens[2]);
394
395 free_tokens:
396 free(tokens);
397 tokens = NULL;
398 parser_context_free(&ctx);
399 }
400 }
401
402 free(tokens);
403 parser_context_free(&ctx);
404 return NULL;
405 }
406
407 static void sigpipe_handler(int sig)
408 {
409 printf("SIGPIPE received.\n");
410 }
411
412 /* Initialize hypervisor */
413 int hypervisor_init(void)
414 {
415 hypervisor_module_t *module;
416
417 module = hypervisor_register_module("hypervisor");
418 assert(module != NULL);
419
420 hypervisor_register_cmd_array(module,hypervisor_cmd_array);
421 return(0);
422 }
423
424 /* Remove a connection from the list */
425 static void hypervisor_remove_conn(hypervisor_conn_t *conn)
426 {
427 if (conn->pprev != NULL) {
428 if (conn->next)
429 conn->next->pprev = conn->pprev;
430
431 *(conn->pprev) = conn->next;
432 }
433 }
434
435 /* Close a connection */
436 static void hypervisor_close_conn(hypervisor_conn_t *conn)
437 {
438 if (conn != NULL) {
439 conn->active = FALSE;
440 shutdown(conn->client_fd,2);
441 pthread_join(conn->tid,NULL);
442
443 fclose(conn->in);
444 fclose(conn->out);
445
446 shutdown(conn->client_fd,2);
447 close(conn->client_fd);
448
449 hypervisor_remove_conn(conn);
450 free(conn);
451 }
452 }
453
454 /* Close connections (dead or all) */
455 static void hypervisor_close_conn_list(int dead_status)
456 {
457 hypervisor_conn_t *conn,*next;
458
459 for(conn=hypervisor_conn_list;conn;conn=next) {
460 next = conn->next;
461
462 if (dead_status && conn->active)
463 continue;
464
465 hypervisor_close_conn(conn);
466 }
467 }
468
469 /* Add a new connection to the list */
470 static void hypervisor_add_conn(hypervisor_conn_t *conn)
471 {
472 conn->next = hypervisor_conn_list;
473 conn->pprev = &hypervisor_conn_list;
474
475 if (hypervisor_conn_list != NULL)
476 hypervisor_conn_list->pprev = &conn->next;
477
478 hypervisor_conn_list = conn;
479 }
480
481 /* Create a new connection */
482 static hypervisor_conn_t *hypervisor_create_conn(int client_fd)
483 {
484 hypervisor_conn_t *conn;
485
486 if (!(conn = malloc(sizeof(*conn))))
487 goto err_malloc;
488
489 memset(conn,0,sizeof(*conn));
490 conn->active = TRUE;
491 conn->client_fd = client_fd;
492
493 /* Open input buffered stream */
494 if (!(conn->in = fdopen(client_fd,"r"))) {
495 perror("hypervisor_create_conn: fdopen/in");
496 goto err_fd_in;
497 }
498
499 /* Open output buffered stream */
500 if (!(conn->out = fdopen(client_fd,"w"))) {
501 perror("hypervisor_create_conn: fdopen/out");
502 goto err_fd_out;
503 }
504
505 /* Set line buffering */
506 setlinebuf(conn->in);
507 setlinebuf(conn->out);
508
509 /* Create the managing thread */
510 if (pthread_create(&conn->tid,NULL,hypervisor_thread,conn) != 0)
511 goto err_thread;
512
513 /* Add it to the connection list */
514 hypervisor_add_conn(conn);
515 return conn;
516
517 err_thread:
518 fclose(conn->out);
519 err_fd_out:
520 fclose(conn->in);
521 err_fd_in:
522 free(conn);
523 err_malloc:
524 return NULL;
525 }
526
527 /* Stop hypervisor from sighandler */
528 int hypervisor_stopsig(void)
529 {
530 hypervisor_running = FALSE;
531 return(0);
532 }
533
534 /* Hypervisor TCP server */
535 int hypervisor_tcp_server(int tcp_port)
536 {
537 int fd_array[HYPERVISOR_MAX_FD];
538 struct sockaddr_storage remote_addr;
539 socklen_t remote_len;
540 int i,res,clnt,fd_count,fd_max;
541 struct timeval tv;
542 fd_set fds;
543
544 /* Initialize all hypervisor modules */
545 hypervisor_init();
546 hypervisor_nio_init();
547 hypervisor_nio_bridge_init();
548 hypervisor_frsw_init();
549 hypervisor_atmsw_init();
550 hypervisor_ethsw_init();
551 hypervisor_vm_init();
552 hypervisor_vm_debug_init();
553 hypervisor_c7200_init();
554 hypervisor_c3600_init();
555 hypervisor_c2691_init();
556 hypervisor_c3725_init();
557 hypervisor_c3745_init();
558
559 signal(SIGPIPE,sigpipe_handler);
560
561 if (!tcp_port)
562 tcp_port = HYPERVISOR_TCP_PORT;
563
564 fd_count = ip_listen(tcp_port,SOCK_STREAM,HYPERVISOR_MAX_FD,fd_array);
565
566 if (fd_count <= 0) {
567 fprintf(stderr,"Hypervisor: unable to create TCP sockets.\n");
568 return(-1);
569 }
570
571 /* Start accepting connections */
572 printf("Hypervisor TCP control server started (port %d).\n",tcp_port);
573 hypervisor_running = TRUE;
574
575 while(hypervisor_running) {
576 FD_ZERO(&fds);
577 fd_max = -1;
578
579 for(i=0;i<fd_count;i++)
580 if (fd_array[i] != -1) {
581 FD_SET(fd_array[i],&fds);
582 if (fd_array[i] > fd_max)
583 fd_max = fd_array[i];
584 }
585
586 /* Wait for incoming connections */
587 tv.tv_sec = 0;
588 tv.tv_usec = 500 * 1000; /* 500 ms */
589 res = select(fd_max+1,&fds,NULL,NULL,&tv);
590
591 if (res == -1) {
592 if (errno == EINTR)
593 continue;
594 else
595 perror("hypervisor_tcp_server: select");
596 }
597
598 /* Accept connections on signaled sockets */
599 for(i=0;i<fd_count;i++) {
600 if (fd_array[i] == -1)
601 continue;
602
603 if (!FD_ISSET(fd_array[i],&fds))
604 continue;
605
606 remote_len = sizeof(remote_addr);
607 clnt = accept(fd_array[i],(struct sockaddr *)&remote_addr,
608 &remote_len);
609
610 if (clnt < 0) {
611 perror("hypervisor_tcp_server: accept");
612 continue;
613 }
614
615 /* create a new connection and start a thread to handle it */
616 if (!hypervisor_create_conn(clnt)) {
617 fprintf(stderr,"hypervisor_tcp_server: unable to create new "
618 "connection for FD %d\n",clnt);
619 close(clnt);
620 }
621 }
622
623 /* Walk through the connection list to eliminate dead connections */
624 hypervisor_close_conn_list(TRUE);
625 }
626
627 /* Close all control sockets */
628 printf("Hypervisor: closing control sockets.\n");
629 for(i=0;i<fd_count;i++) {
630 if (fd_array[i] != -1) {
631 shutdown(fd_array[i],2);
632 close(fd_array[i]);
633 }
634 }
635
636 /* Close all remote client connections */
637 printf("Hypervisor: closing remote client connections.\n");
638 hypervisor_close_conn_list(FALSE);
639 return(0);
640 }

  ViewVC Help
Powered by ViewVC 1.1.26