/[dynamips]/trunk/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 /trunk/hypervisor.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 15921 byte(s)
make working copy

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

  ViewVC Help
Powered by ViewVC 1.1.26