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

Contents of /upstream/dynamips-0.2.5/hypervisor.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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