/[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 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/hypervisor.c
File MIME type: text/plain
File size: 16056 byte(s)
dynamips-0.2.7

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 1 #include "hypervisor.h"
45     #include "net_io.h"
46     #include "net_io_bridge.h"
47     #include "frame_relay.h"
48     #include "atm.h"
49    
50     #define DEBUG_TOKEN 0
51    
52     /* Hypervisor modules */
53     static hypervisor_module_t *module_list = NULL;
54     static volatile int hypervisor_running = 0;
55    
56     /* Hypervisor connection list */
57     static hypervisor_conn_t *hypervisor_conn_list = NULL;
58    
59     /* Show hypervisor version */
60     static int cmd_version(hypervisor_conn_t *conn,int argc,char *argv[])
61     {
62     hypervisor_send_reply(conn,HSC_INFO_OK,1,"%s",sw_version);
63     return(0);
64     }
65    
66 dpavlin 2 /* Parser test */
67     static int cmd_parser_test(hypervisor_conn_t *conn,int argc,char *argv[])
68     {
69     int i;
70    
71     for(i=0;i<argc;i++)
72     hypervisor_send_reply(conn,HSC_INFO_MSG,0,
73     "arg %d (len %u): \"%s\"",
74     i,strlen(argv[i]),argv[i]);
75    
76     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
77     return(0);
78     }
79    
80 dpavlin 1 /* Show hypervisor module list */
81     static int cmd_mod_list(hypervisor_conn_t *conn,int argc,char *argv[])
82     {
83     hypervisor_module_t *m;
84    
85     for(m=module_list;m;m=m->next)
86     hypervisor_send_reply(conn,HSC_INFO_MSG,0,"%s",m->name);
87    
88     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
89     return(0);
90     }
91    
92     /* Show module command list */
93     static int cmd_modcmd_list(hypervisor_conn_t *conn,int argc,char *argv[])
94     {
95     hypervisor_module_t *m;
96     hypervisor_cmd_t *cmd;
97    
98     if (!(m = hypervisor_find_module(argv[0]))) {
99     hypervisor_send_reply(conn,HSC_ERR_UNK_MODULE,1,"unknown module '%s'",
100     argv[0]);
101     return(-1);
102     }
103    
104     for(cmd=m->cmd_list;cmd;cmd=cmd->next)
105     hypervisor_send_reply(conn,HSC_INFO_MSG,0,"%s (min/max args: %d/%d)",
106     cmd->name,cmd->min_param,cmd->max_param);
107    
108     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
109     return(0);
110     }
111    
112     /* Set working directory */
113     static int cmd_set_working_dir(hypervisor_conn_t *conn,int argc,char *argv[])
114     {
115     if (chdir(argv[0]) == -1) {
116     hypervisor_send_reply(conn,HSC_ERR_INV_PARAM,1,
117     "chdir: %s",strerror(errno));
118     } else {
119     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
120     }
121     return(0);
122     }
123    
124     /* Save the hypervisor configuration in the specified file */
125     static int cmd_save_config(hypervisor_conn_t *conn,int argc,char *argv[])
126     {
127     FILE *fd;
128    
129     if (!(fd = fopen(argv[0],"w"))) {
130     hypervisor_send_reply(conn,HSC_ERR_FILE,1,"fopen: %s",strerror(errno));
131     return(-1);
132     }
133    
134     /* Save configuration for all objects */
135     netio_save_config_all(fd);
136     frsw_save_config_all(fd);
137     atmsw_save_config_all(fd);
138     netio_bridge_save_config_all(fd);
139     c7200_save_config_all(fd);
140     c3600_save_config_all(fd);
141 dpavlin 4 c2691_save_config_all(fd);
142     c3725_save_config_all(fd);
143     c3745_save_config_all(fd);
144 dpavlin 7 c2600_save_config_all(fd);
145 dpavlin 1
146     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
147     return(0);
148     }
149    
150     /* Reset hypervisor (delete all objects) */
151     static int cmd_reset(hypervisor_conn_t *conn,int argc,char *argv[])
152     {
153     dynamips_reset();
154     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
155     return(0);
156     }
157    
158     /* Close connection */
159     static int cmd_close(hypervisor_conn_t *conn,int argc,char *argv[])
160     {
161     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
162     conn->active = FALSE;
163     return(0);
164     }
165    
166     /* Stop hypervisor */
167     static int cmd_stop(hypervisor_conn_t *conn,int argc,char *argv[])
168     {
169     hypervisor_send_reply(conn,HSC_INFO_OK,1,"OK");
170     hypervisor_running = FALSE;
171     return(0);
172     }
173    
174     /* Hypervisor commands */
175     static hypervisor_cmd_t hypervisor_cmd_array[] = {
176     { "version", 0, 0, cmd_version, NULL },
177 dpavlin 2 { "parser_test", 0, 10, cmd_parser_test, NULL },
178 dpavlin 1 { "module_list", 0, 0, cmd_mod_list, NULL },
179     { "cmd_list", 1, 1, cmd_modcmd_list, NULL },
180     { "working_dir", 1, 1, cmd_set_working_dir, NULL },
181     { "save_config", 1, 1, cmd_save_config, NULL },
182     { "reset", 0, 0, cmd_reset, NULL },
183     { "close", 0, 0, cmd_close, NULL },
184     { "stop", 0, 0, cmd_stop, NULL },
185     { NULL, -1, -1, NULL, NULL },
186     };
187    
188     /* Send a reply */
189     int hypervisor_send_reply(hypervisor_conn_t *conn,int code,int done,
190     char *format,...)
191     {
192     va_list ap;
193     size_t n = 0;
194    
195     if (conn != NULL) {
196     va_start(ap,format);
197     n += fprintf(conn->out,"%3d%s",code,(done)?"-":" ");
198     n += vfprintf(conn->out,format,ap);
199     n += fprintf(conn->out,"\r\n");
200     fflush(conn->out);
201     va_end(ap);
202     }
203    
204     return(n);
205     }
206    
207     /* Find a module */
208     hypervisor_module_t *hypervisor_find_module(char *name)
209     {
210     hypervisor_module_t *m;
211    
212     for(m=module_list;m;m=m->next)
213     if (!strcmp(m->name,name))
214     return m;
215    
216     return NULL;
217     }
218    
219     /* Find a command in a module */
220     hypervisor_cmd_t *hypervisor_find_cmd(hypervisor_module_t *module,char *name)
221     {
222     hypervisor_cmd_t *cmd;
223    
224     for(cmd=module->cmd_list;cmd;cmd=cmd->next)
225     if (!strcmp(cmd->name,name))
226     return cmd;
227    
228     return NULL;
229     }
230    
231     /* Find an object in the registry */
232     void *hypervisor_find_object(hypervisor_conn_t *conn,char *name,int obj_type)
233     {
234     void *p;
235    
236     if (!(p = registry_find(name,obj_type))) {
237     hypervisor_send_reply(conn,HSC_ERR_UNK_OBJ,1,
238     "unable to find object '%s'",name);
239     return NULL;
240     }
241    
242     return p;
243     }
244    
245     /* Find a VM in the registry */
246     void *hypervisor_find_vm(hypervisor_conn_t *conn,char *name,int vm_type)
247     {
248     vm_instance_t *vm;
249    
250     if (!(vm = vm_acquire(name))) {
251     hypervisor_send_reply(conn,HSC_ERR_UNK_OBJ,1,
252     "unable to find VM '%s'",name);
253     return NULL;
254     }
255    
256     if (vm->type != vm_type) {
257     vm_release(vm);
258     hypervisor_send_reply(conn,HSC_ERR_BAD_OBJ,1,
259     "VM '%s' is not a VM type %d",
260     name,vm_type);
261     return NULL;
262     }
263    
264     return vm;
265     }
266    
267     /* Register a module */
268     hypervisor_module_t *hypervisor_register_module(char *name)
269     {
270     hypervisor_module_t *m;
271    
272     if (hypervisor_find_module(name) != NULL) {
273     fprintf(stderr,"Hypervisor: module '%s' already exists.\n",name);
274     return NULL;
275     }
276    
277     if (!(m = malloc(sizeof(*m)))) {
278     fprintf(stderr,"Hypervisor: unable to register new module.\n");
279     return NULL;
280     }
281    
282     m->name = name;
283     m->cmd_list = NULL;
284    
285     m->next = module_list;
286     module_list = m;
287     return m;
288     }
289    
290     /* Register a list of commands */
291     int hypervisor_register_cmd_list(hypervisor_module_t *module,
292     hypervisor_cmd_t *cmd_list)
293     {
294     hypervisor_cmd_t *cmd = cmd_list;
295    
296     while(cmd->next != NULL)
297     cmd = cmd->next;
298    
299     cmd->next = module->cmd_list;
300     module->cmd_list = cmd_list;
301     return(0);
302     }
303    
304     /* Register an array of commands */
305     int hypervisor_register_cmd_array(hypervisor_module_t *module,
306     hypervisor_cmd_t *cmd_array)
307     {
308     hypervisor_cmd_t *cmd;
309    
310     for(cmd=cmd_array;cmd->name!=NULL;cmd++) {
311     cmd->next = module->cmd_list;
312     module->cmd_list = cmd;
313     }
314    
315     return(0);
316     }
317    
318     /* Locate the module and execute command */
319     static int hypervisor_exec_cmd(hypervisor_conn_t *conn,
320     char *mod_name,char *cmd_name,
321     int argc,char *argv[])
322     {
323     hypervisor_module_t *module;
324     hypervisor_cmd_t *cmd;
325    
326     if (!(module = hypervisor_find_module(mod_name))) {
327     hypervisor_send_reply(conn,HSC_ERR_UNK_MODULE,1,"Unknown module '%s'",
328     mod_name);
329     return(-1);
330     }
331    
332     if (!(cmd = hypervisor_find_cmd(module,cmd_name))) {
333     hypervisor_send_reply(conn,HSC_ERR_UNK_CMD,1,"Unknown command '%s'",
334     cmd_name);
335     return(-1);
336     }
337    
338     if ((argc < cmd->min_param) || (argc > cmd->max_param)) {
339     hypervisor_send_reply(conn,HSC_ERR_BAD_PARAM,1,
340     "Bad number of parameters (%d with min/max=%d/%d)",
341     argc,cmd->min_param,cmd->max_param);
342     return(-1);
343     }
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 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     module = hypervisor_register_module("hypervisor");
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(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 dpavlin 2 hypervisor_vm_debug_init();
556 dpavlin 1 hypervisor_c7200_init();
557     hypervisor_c3600_init();
558 dpavlin 4 hypervisor_c2691_init();
559     hypervisor_c3725_init();
560     hypervisor_c3745_init();
561 dpavlin 7 hypervisor_c2600_init();
562 dpavlin 1
563     signal(SIGPIPE,sigpipe_handler);
564    
565     if (!tcp_port)
566     tcp_port = HYPERVISOR_TCP_PORT;
567    
568     fd_count = ip_listen(tcp_port,SOCK_STREAM,HYPERVISOR_MAX_FD,fd_array);
569    
570     if (fd_count <= 0) {
571     fprintf(stderr,"Hypervisor: unable to create TCP sockets.\n");
572     return(-1);
573     }
574    
575     /* Start accepting connections */
576 dpavlin 4 printf("Hypervisor TCP control server started (port %d).\n",tcp_port);
577 dpavlin 1 hypervisor_running = TRUE;
578    
579     while(hypervisor_running) {
580     FD_ZERO(&fds);
581     fd_max = -1;
582    
583     for(i=0;i<fd_count;i++)
584     if (fd_array[i] != -1) {
585     FD_SET(fd_array[i],&fds);
586     if (fd_array[i] > fd_max)
587     fd_max = fd_array[i];
588     }
589    
590     /* Wait for incoming connections */
591     tv.tv_sec = 0;
592     tv.tv_usec = 500 * 1000; /* 500 ms */
593     res = select(fd_max+1,&fds,NULL,NULL,&tv);
594    
595     if (res == -1) {
596     if (errno == EINTR)
597     continue;
598     else
599     perror("hypervisor_tcp_server: select");
600     }
601    
602     /* Accept connections on signaled sockets */
603     for(i=0;i<fd_count;i++) {
604     if (fd_array[i] == -1)
605     continue;
606    
607     if (!FD_ISSET(fd_array[i],&fds))
608     continue;
609    
610     remote_len = sizeof(remote_addr);
611     clnt = accept(fd_array[i],(struct sockaddr *)&remote_addr,
612     &remote_len);
613    
614     if (clnt < 0) {
615     perror("hypervisor_tcp_server: accept");
616     continue;
617     }
618    
619     /* create a new connection and start a thread to handle it */
620     if (!hypervisor_create_conn(clnt)) {
621     fprintf(stderr,"hypervisor_tcp_server: unable to create new "
622     "connection for FD %d\n",clnt);
623     close(clnt);
624     }
625     }
626    
627     /* Walk through the connection list to eliminate dead connections */
628     hypervisor_close_conn_list(TRUE);
629     }
630    
631     /* Close all control sockets */
632     printf("Hypervisor: closing control sockets.\n");
633     for(i=0;i<fd_count;i++) {
634     if (fd_array[i] != -1) {
635     shutdown(fd_array[i],2);
636     close(fd_array[i]);
637     }
638     }
639    
640     /* Close all remote client connections */
641     printf("Hypervisor: closing remote client connections.\n");
642     hypervisor_close_conn_list(FALSE);
643     return(0);
644     }

  ViewVC Help
Powered by ViewVC 1.1.26