/[dynamips]/upstream/dynamips-0.2.6-RC1/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-RC1/hypervisor.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Sat Oct 6 16:03:58 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 15709 byte(s)
import dynamips-0.2.6-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26