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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 dpavlin 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 dpavlin 4 #include "dev_c2691.h"
40     #include "dev_c3725.h"
41     #include "dev_c3745.h"
42 dpavlin 1 #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 dpavlin 2 /* 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 dpavlin 1 /* 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 dpavlin 4 c2691_save_config_all(fd);
140     c3725_save_config_all(fd);
141     c3745_save_config_all(fd);
142 dpavlin 1
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 dpavlin 2 { "parser_test", 0, 10, cmd_parser_test, NULL },
175 dpavlin 1 { "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 dpavlin 2 char buffer[512],**tokens;
350     parser_context_t ctx;
351     int res;
352 dpavlin 1
353 dpavlin 2 tokens = NULL;
354     parser_context_init(&ctx);
355    
356 dpavlin 1 while(conn->active) {
357 dpavlin 2 if (!fgets(buffer,sizeof(buffer),conn->in))
358 dpavlin 1 break;
359    
360     if (!*buffer)
361     continue;
362    
363     /* Tokenize command line */
364 dpavlin 2 res = parser_scan_buffer(&ctx,buffer,strlen(buffer));
365 dpavlin 1
366 dpavlin 2 if (res != 0) {
367     tokens = NULL;
368 dpavlin 1
369 dpavlin 2 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 dpavlin 1
375 dpavlin 2 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 dpavlin 1
385 dpavlin 2 if (!tokens) {
386     hypervisor_send_reply(conn,HSC_ERR_PARSING,1,"No memory");
387     goto free_tokens;
388     }
389 dpavlin 1
390 dpavlin 2 /* 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 dpavlin 1
395 dpavlin 2 free_tokens:
396     free(tokens);
397     tokens = NULL;
398     parser_context_free(&ctx);
399     }
400 dpavlin 1 }
401    
402 dpavlin 2 free(tokens);
403     parser_context_free(&ctx);
404 dpavlin 1 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 dpavlin 2 hypervisor_vm_debug_init();
553 dpavlin 1 hypervisor_c7200_init();
554     hypervisor_c3600_init();
555 dpavlin 4 hypervisor_c2691_init();
556     hypervisor_c3725_init();
557     hypervisor_c3745_init();
558 dpavlin 1
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 dpavlin 4 printf("Hypervisor TCP control server started (port %d).\n",tcp_port);
573 dpavlin 1 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