/[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

Annotation of /trunk/hypervisor.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Sat Oct 6 16:33:40 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.8-RC1/hypervisor.c
File MIME type: text/plain
File size: 15921 byte(s)
dynamips-0.2.8-RC1

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * 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 dpavlin 7 #include "cpu.h"
36     #include "vm.h"
37 dpavlin 1 #include "dynamips.h"
38     #include "dev_c7200.h"
39     #include "dev_c3600.h"
40 dpavlin 4 #include "dev_c2691.h"
41     #include "dev_c3725.h"
42     #include "dev_c3745.h"
43 dpavlin 7 #include "dev_c2600.h"
44 dpavlin 11 #include "dev_c1700.h"
45 dpavlin 1 #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 dpavlin 2 /* 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 dpavlin 1 /* 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 dpavlin 11 vm_save_config_all(fd);
141 dpavlin 1
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 dpavlin 2 { "parser_test", 0, 10, cmd_parser_test, NULL },
174 dpavlin 1 { "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 dpavlin 11 void *hypervisor_find_vm(hypervisor_conn_t *conn,char *name)
243 dpavlin 1 {
244 dpavlin 11 vm_platform_t *platform = conn->cur_module->opt;
245 dpavlin 1 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 dpavlin 11 if (vm->platform != platform) {
254 dpavlin 1 vm_release(vm);
255     hypervisor_send_reply(conn,HSC_ERR_BAD_OBJ,1,
256 dpavlin 11 "VM '%s' is not a VM type %s",
257     name,platform->name);
258 dpavlin 1 return NULL;
259     }
260    
261     return vm;
262     }
263    
264     /* Register a module */
265 dpavlin 11 hypervisor_module_t *hypervisor_register_module(char *name,void *opt)
266 dpavlin 1 {
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 dpavlin 11 m->opt = opt;
281 dpavlin 1 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 dpavlin 11 conn->cur_module = module;
344    
345 dpavlin 1 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 dpavlin 2 char buffer[512],**tokens;
353     parser_context_t ctx;
354     int res;
355 dpavlin 1
356 dpavlin 2 tokens = NULL;
357     parser_context_init(&ctx);
358    
359 dpavlin 1 while(conn->active) {
360 dpavlin 2 if (!fgets(buffer,sizeof(buffer),conn->in))
361 dpavlin 1 break;
362    
363     if (!*buffer)
364     continue;
365    
366     /* Tokenize command line */
367 dpavlin 2 res = parser_scan_buffer(&ctx,buffer,strlen(buffer));
368 dpavlin 1
369 dpavlin 2 if (res != 0) {
370     tokens = NULL;
371 dpavlin 1
372 dpavlin 2 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 dpavlin 1
378 dpavlin 2 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 dpavlin 1
388 dpavlin 2 if (!tokens) {
389     hypervisor_send_reply(conn,HSC_ERR_PARSING,1,"No memory");
390     goto free_tokens;
391     }
392 dpavlin 1
393 dpavlin 2 /* 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 dpavlin 1
398 dpavlin 2 free_tokens:
399     free(tokens);
400     tokens = NULL;
401     parser_context_free(&ctx);
402     }
403 dpavlin 1 }
404    
405 dpavlin 2 free(tokens);
406     parser_context_free(&ctx);
407 dpavlin 1 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 dpavlin 11 module = hypervisor_register_module("hypervisor",NULL);
421 dpavlin 1 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 dpavlin 11 int hypervisor_tcp_server(char *ip_addr,int tcp_port)
539 dpavlin 1 {
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 dpavlin 2 hypervisor_vm_debug_init();
556 dpavlin 1
557     signal(SIGPIPE,sigpipe_handler);
558    
559     if (!tcp_port)
560     tcp_port = HYPERVISOR_TCP_PORT;
561    
562 dpavlin 11 fd_count = ip_listen(ip_addr,tcp_port,SOCK_STREAM,
563     HYPERVISOR_MAX_FD,fd_array);
564 dpavlin 1
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 dpavlin 4 printf("Hypervisor TCP control server started (port %d).\n",tcp_port);
572 dpavlin 1 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