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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Sat Oct 6 16:01:44 2007 UTC (12 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 15020 byte(s)
import 0.2.5 from upstream

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

  ViewVC Help
Powered by ViewVC 1.1.26