/[dynamips]/trunk/vm.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 /trunk/vm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 25703 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Virtual machine abstraction.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <sys/types.h>
15 #include <assert.h>
16
17 #include "registry.h"
18 #include "device.h"
19 #include "pci_dev.h"
20 #include "pci_io.h"
21 #include "cpu.h"
22 #include "mips64_jit.h"
23 #include "vm.h"
24 #include "dev_vtty.h"
25
26 #include MIPS64_ARCH_INC_FILE
27
28 #define DEBUG_VM 1
29
30 #define VM_GLOCK() pthread_mutex_lock(&vm_global_lock)
31 #define VM_GUNLOCK() pthread_mutex_unlock(&vm_global_lock)
32
33 /* Type of VM file naming (0=use VM name, 1=use instance ID) */
34 int vm_file_naming_type = 0;
35
36 /* Platform list */
37 static struct vm_platform_list *vm_platforms = NULL;
38
39 /* Pool of ghost images */
40 static vm_ghost_image_t *vm_ghost_pool = NULL;
41
42 /* Global lock for VM manipulation */
43 static pthread_mutex_t vm_global_lock = PTHREAD_MUTEX_INITIALIZER;
44
45 /* Free all chunks used by a VM */
46 static void vm_chunk_free_all(vm_instance_t *vm);
47
48 /* Initialize a VM object */
49 void vm_object_init(vm_obj_t *obj)
50 {
51 memset(obj,0,sizeof(*obj));
52 }
53
54 /* Add a VM object to an instance */
55 void vm_object_add(vm_instance_t *vm,vm_obj_t *obj)
56 {
57 obj->next = vm->vm_object_list;
58 obj->pprev = &vm->vm_object_list;
59
60 if (vm->vm_object_list)
61 vm->vm_object_list->pprev = &obj->next;
62
63 vm->vm_object_list = obj;
64 }
65
66 /* Remove a VM object from an instance */
67 void vm_object_remove(vm_instance_t *vm,vm_obj_t *obj)
68 {
69 if (obj->next)
70 obj->next->pprev = obj->pprev;
71 *(obj->pprev) = obj->next;
72
73 obj->shutdown(vm,obj->data);
74 }
75
76 /* Find an object given its name */
77 vm_obj_t *vm_object_find(vm_instance_t *vm,char *name)
78 {
79 vm_obj_t *obj;
80
81 for(obj=vm->vm_object_list;obj;obj=obj->next)
82 if (!strcmp(obj->name,name))
83 return obj;
84
85 return NULL;
86 }
87
88 /* Check that a mandatory object is present */
89 int vm_object_check(vm_instance_t *vm,char *name)
90 {
91 return(vm_object_find(vm,name) ? 0 : -1);
92 }
93
94 /* Shut down all objects of an instance */
95 void vm_object_free_list(vm_instance_t *vm)
96 {
97 vm_obj_t *obj,*next;
98
99 for(obj=vm->vm_object_list;obj;obj=next) {
100 next = obj->next;
101
102 if (obj->shutdown != NULL) {
103 #if DEBUG_VM
104 vm_log(vm,"VM_OBJECT","Shutdown of object \"%s\"\n",obj->name);
105 #endif
106 obj->shutdown(vm,obj->data);
107 }
108 }
109
110 vm->vm_object_list = NULL;
111 }
112
113 /* Rebuild the object list pointers */
114 static void vm_object_rebuild_list(vm_instance_t *vm)
115 {
116 vm_obj_t **obj;
117
118 for(obj=&vm->vm_object_list;*obj;obj=&(*obj)->next)
119 (*obj)->pprev = obj;
120 }
121
122 /* Dump the object list of an instance */
123 void vm_object_dump(vm_instance_t *vm)
124 {
125 vm_obj_t *obj;
126
127 printf("VM \"%s\" (%u) object list:\n",vm->name,vm->instance_id);
128
129 for(obj=vm->vm_object_list;obj;obj=obj->next) {
130 printf(" - %-15s [data=%p]\n",obj->name,obj->data);
131 }
132
133 printf("\n");
134 }
135
136 /* Get VM type */
137 char *vm_get_type(vm_instance_t *vm)
138 {
139 return vm->platform->name;
140 }
141
142 /* Get log name */
143 static char *vm_get_log_name(vm_instance_t *vm)
144 {
145 if (vm->platform->log_name != NULL)
146 return vm->platform->log_name;
147
148 /* default value */
149 return "VM";
150 }
151
152 /* Get MAC address MSB */
153 u_int vm_get_mac_addr_msb(vm_instance_t *vm)
154 {
155 if (vm->platform->get_mac_addr_msb != NULL)
156 return(vm->platform->get_mac_addr_msb());
157
158 /* default value */
159 return(0xC6);
160 }
161
162 /* Generate a filename for use by the instance */
163 char *vm_build_filename(vm_instance_t *vm,char *name)
164 {
165 char *filename,*machine;
166
167 machine = vm_get_type(vm);
168
169 switch(vm_file_naming_type) {
170 case 1:
171 filename = dyn_sprintf("%s_i%u_%s",machine,vm->instance_id,name);
172 break;
173 case 0:
174 default:
175 filename = dyn_sprintf("%s_%s_%s",machine,vm->name,name);
176 break;
177 }
178
179 assert(filename != NULL);
180 return filename;
181 }
182
183 /* Erase lock file */
184 void vm_release_lock(vm_instance_t *vm,int erase)
185 {
186 if (vm->lock_fd != NULL) {
187 fclose(vm->lock_fd);
188 vm->lock_fd = NULL;
189 }
190
191 if (vm->lock_file != NULL) {
192 if (erase)
193 unlink(vm->lock_file);
194 free(vm->lock_file);
195 vm->lock_file = NULL;
196 }
197 }
198
199 /* Check that an instance lock file doesn't already exist */
200 int vm_get_lock(vm_instance_t *vm)
201 {
202 char pid_str[32];
203 struct flock lock;
204
205 vm->lock_file = vm_build_filename(vm,"lock");
206
207 if (!(vm->lock_fd = fopen(vm->lock_file,"w"))) {
208 fprintf(stderr,"Unable to create lock file \"%s\".\n",vm->lock_file);
209 return(-1);
210 }
211
212 memset(&lock,0,sizeof(lock));
213 lock.l_type = F_WRLCK;
214 lock.l_whence = SEEK_SET;
215 lock.l_start = 0;
216 lock.l_len = 0;
217
218 if (fcntl(fileno(vm->lock_fd),F_SETLK,&lock) == -1) {
219 if (fcntl(fileno(vm->lock_fd),F_GETLK,&lock) == 0) {
220 snprintf(pid_str,sizeof(pid_str),"%ld",(long)lock.l_pid);
221 } else {
222 strcpy(pid_str,"unknown");
223 }
224
225 fprintf(stderr,
226 "\nAn emulator instance (PID %s) is already running with "
227 "identifier %u.\n"
228 "If this is not the case, please erase file \"%s\".\n\n",
229 pid_str,vm->instance_id,vm->lock_file);
230 vm_release_lock(vm,FALSE);
231 return(-1);
232 }
233
234 /* write the emulator PID */
235 fprintf(vm->lock_fd,"%ld\n",(u_long)getpid());
236 return(0);
237 }
238
239 /* Log a message */
240 void vm_flog(vm_instance_t *vm,char *module,char *format,va_list ap)
241 {
242 if (vm->log_fd)
243 m_flog(vm->log_fd,module,format,ap);
244 }
245
246 /* Log a message */
247 void vm_log(vm_instance_t *vm,char *module,char *format,...)
248 {
249 va_list ap;
250
251 if (vm->log_fd) {
252 va_start(ap,format);
253 vm_flog(vm,module,format,ap);
254 va_end(ap);
255 }
256 }
257
258 /* Close the log file */
259 int vm_close_log(vm_instance_t *vm)
260 {
261 if (vm->log_fd)
262 fclose(vm->log_fd);
263
264 free(vm->log_file);
265
266 vm->log_file = NULL;
267 vm->log_fd = NULL;
268 return(0);
269 }
270
271 /* Create the log file */
272 int vm_create_log(vm_instance_t *vm)
273 {
274 if (vm->log_file_enabled) {
275 vm_close_log(vm);
276
277 if (!(vm->log_file = vm_build_filename(vm,"log.txt")))
278 return(-1);
279
280 if (!(vm->log_fd = fopen(vm->log_file,"w"))) {
281 fprintf(stderr,"VM %s: unable to create log file '%s'\n",
282 vm->name,vm->log_file);
283 free(vm->log_file);
284 vm->log_file = NULL;
285 return(-1);
286 }
287 }
288
289 return(0);
290 }
291
292 /* Error message */
293 void vm_error(vm_instance_t *vm,char *format,...)
294 {
295 char buffer[2048];
296 va_list ap;
297
298 va_start(ap,format);
299 vsnprintf(buffer,sizeof(buffer),format,ap);
300 va_end(ap);
301
302 fprintf(stderr,"%s '%s': %s",vm_get_log_name(vm),vm->name,buffer);
303 }
304
305 /* Create a new VM instance */
306 static vm_instance_t *vm_create(char *name,int instance_id,
307 vm_platform_t *platform)
308 {
309 vm_instance_t *vm;
310
311 if (!(vm = malloc(sizeof(*vm)))) {
312 fprintf(stderr,"VM %s: unable to create new instance!\n",name);
313 return NULL;
314 }
315
316 memset(vm,0,sizeof(*vm));
317
318 if (!(vm->name = strdup(name))) {
319 fprintf(stderr,"VM %s: unable to store instance name!\n",name);
320 goto err_name;
321 }
322
323 vm->instance_id = instance_id;
324 vm->platform = platform;
325 vm->status = VM_STATUS_HALTED;
326 vm->jit_use = JIT_SUPPORT;
327 vm->exec_blk_direct_jump = TRUE;
328 vm->vtty_con_type = VTTY_TYPE_TERM;
329 vm->vtty_aux_type = VTTY_TYPE_NONE;
330 vm->timer_irq_check_itv = VM_TIMER_IRQ_CHECK_ITV;
331 vm->log_file_enabled = TRUE;
332 vm->rommon_vars.filename = vm_build_filename(vm,"rommon_vars");
333
334 if (!vm->rommon_vars.filename)
335 goto err_rommon;
336
337 /* XXX */
338 rommon_load_file(&vm->rommon_vars);
339
340 /* create lock file */
341 if (vm_get_lock(vm) == -1)
342 goto err_lock;
343
344 /* create log file */
345 if (vm_create_log(vm) == -1)
346 goto err_log;
347
348 if (registry_add(vm->name,OBJ_TYPE_VM,vm) == -1) {
349 fprintf(stderr,"VM: Unable to store instance '%s' in registry!\n",
350 vm->name);
351 goto err_reg_add;
352 }
353
354 return vm;
355
356 err_reg_add:
357 vm_close_log(vm);
358 err_log:
359 free(vm->lock_file);
360 err_lock:
361 free(vm->rommon_vars.filename);
362 err_rommon:
363 free(vm->name);
364 err_name:
365 free(vm);
366 return NULL;
367 }
368
369 /*
370 * Shutdown hardware resources used by a VM.
371 * The CPU must have been stopped.
372 */
373 int vm_hardware_shutdown(vm_instance_t *vm)
374 {
375 int i;
376
377 if ((vm->status == VM_STATUS_HALTED) || !vm->cpu_group) {
378 vm_log(vm,"VM","trying to shutdown an inactive VM.\n");
379 return(-1);
380 }
381
382 vm_log(vm,"VM","shutdown procedure engaged.\n");
383
384 /* Mark the VM as halted */
385 vm->status = VM_STATUS_HALTED;
386
387 /* Free the object list */
388 vm_object_free_list(vm);
389
390 /* Free resources used by PCI busses */
391 vm_log(vm,"VM","removing PCI busses.\n");
392 pci_io_data_remove(vm,vm->pci_io_space);
393 pci_bus_remove(vm->pci_bus[0]);
394 pci_bus_remove(vm->pci_bus[1]);
395 vm->pci_bus[0] = vm->pci_bus[1] = NULL;
396
397 /* Free the PCI bus pool */
398 for(i=0;i<VM_PCI_POOL_SIZE;i++) {
399 if (vm->pci_bus_pool[i] != NULL) {
400 pci_bus_remove(vm->pci_bus_pool[i]);
401 vm->pci_bus_pool[i] = NULL;
402 }
403 }
404
405 /* Remove the IRQ routing vectors */
406 vm->set_irq = NULL;
407 vm->clear_irq = NULL;
408
409 /* Delete the VTTY for Console and AUX ports */
410 vm_log(vm,"VM","deleting VTTY.\n");
411 vm_delete_vtty(vm);
412
413 /* Delete system CPU group */
414 vm_log(vm,"VM","deleting system CPUs.\n");
415 cpu_group_delete(vm->cpu_group);
416 vm->cpu_group = NULL;
417 vm->boot_cpu = NULL;
418
419 vm_log(vm,"VM","shutdown procedure completed.\n");
420 return(0);
421 }
422
423 /* Free resources used by a VM */
424 void vm_free(vm_instance_t *vm)
425 {
426 if (vm != NULL) {
427 /* Free hardware resources */
428 vm_hardware_shutdown(vm);
429
430 /* Close log file */
431 vm_close_log(vm);
432
433 /* Remove the lock file */
434 vm_release_lock(vm,TRUE);
435
436 /* Free all chunks */
437 vm_chunk_free_all(vm);
438
439 /* Free various elements */
440 free(vm->rommon_vars.filename);
441 free(vm->ghost_ram_filename);
442 free(vm->sym_filename);
443 free(vm->ios_image);
444 free(vm->ios_config);
445 free(vm->rom_filename);
446 free(vm->name);
447 free(vm);
448 }
449 }
450
451 /* Get an instance given a name */
452 vm_instance_t *vm_acquire(char *name)
453 {
454 return(registry_find(name,OBJ_TYPE_VM));
455 }
456
457 /* Release a VM (decrement reference count) */
458 int vm_release(vm_instance_t *vm)
459 {
460 return(registry_unref(vm->name,OBJ_TYPE_VM));
461 }
462
463 /* Initialize RAM */
464 int vm_ram_init(vm_instance_t *vm,m_uint64_t paddr)
465 {
466 m_uint32_t len;
467
468 len = vm->ram_size * 1048576;
469
470 if (vm->ghost_status == VM_GHOST_RAM_USE) {
471 return(dev_ram_ghost_init(vm,"ram",vm->sparse_mem,vm->ghost_ram_filename,
472 paddr,len));
473 }
474
475 return(dev_ram_init(vm,"ram",vm->ram_mmap,
476 (vm->ghost_status != VM_GHOST_RAM_GENERATE),
477 vm->ghost_ram_filename,vm->sparse_mem,paddr,len));
478 }
479
480 /* Initialize VTTY */
481 int vm_init_vtty(vm_instance_t *vm)
482 {
483 /* Create Console and AUX ports */
484 vm->vtty_con = vtty_create(vm,"Console port",
485 vm->vtty_con_type,vm->vtty_con_tcp_port,
486 &vm->vtty_con_serial_option);
487
488 vm->vtty_aux = vtty_create(vm,"AUX port",
489 vm->vtty_aux_type,vm->vtty_aux_tcp_port,
490 &vm->vtty_aux_serial_option);
491 return(0);
492 }
493
494 /* Delete VTTY */
495 void vm_delete_vtty(vm_instance_t *vm)
496 {
497 vtty_delete(vm->vtty_con);
498 vtty_delete(vm->vtty_aux);
499 vm->vtty_con = vm->vtty_aux = NULL;
500 }
501
502 /* Bind a device to a virtual machine */
503 int vm_bind_device(vm_instance_t *vm,struct vdevice *dev)
504 {
505 struct vdevice **cur;
506 u_int i;
507
508 /*
509 * Add this device to the device array. The index in the device array
510 * is used by the MTS subsystem.
511 */
512 for(i=0;i<VM_DEVICE_MAX;i++)
513 if (!vm->dev_array[i])
514 break;
515
516 if (i == VM_DEVICE_MAX) {
517 fprintf(stderr,"VM%u: vm_bind_device: device table full.\n",
518 vm->instance_id);
519 return(-1);
520 }
521
522 vm->dev_array[i] = dev;
523 dev->id = i;
524
525 /*
526 * Add it to the linked-list (devices are ordered by physical addresses).
527 */
528 for(cur=&vm->dev_list;*cur;cur=&(*cur)->next)
529 if ((*cur)->phys_addr > dev->phys_addr)
530 break;
531
532 dev->next = *cur;
533 if (*cur) (*cur)->pprev = &dev->next;
534 dev->pprev = cur;
535 *cur = dev;
536 return(0);
537 }
538
539 /* Unbind a device from a virtual machine */
540 int vm_unbind_device(vm_instance_t *vm,struct vdevice *dev)
541 {
542 u_int i;
543
544 if (!dev || !dev->pprev)
545 return(-1);
546
547 /* Remove the device from the linked list */
548 if (dev->next)
549 dev->next->pprev = dev->pprev;
550
551 *(dev->pprev) = dev->next;
552
553 /* Remove the device from the device array */
554 for(i=0;i<VM_DEVICE_MAX;i++)
555 if (vm->dev_array[i] == dev) {
556 vm->dev_array[i] = NULL;
557 break;
558 }
559
560 /* Clear device list info */
561 dev->next = NULL;
562 dev->pprev = NULL;
563 return(0);
564 }
565
566 /* Map a device at the specified physical address */
567 int vm_map_device(vm_instance_t *vm,struct vdevice *dev,m_uint64_t base_addr)
568 {
569 #if 0
570 /* Suspend VM activity */
571 vm_suspend(vm);
572
573 if (cpu_group_sync_state(vm->cpu_group) == -1) {
574 fprintf(stderr,"VM%u: unable to sync with system CPUs.\n",
575 vm->instance_id);
576 return(-1);
577 }
578 #endif
579
580 /* Unbind the device if it was already active */
581 vm_unbind_device(vm,dev);
582
583 /* Map the device at the new base address and rebuild MTS */
584 dev->phys_addr = base_addr;
585 vm_bind_device(vm,dev);
586 cpu_group_rebuild_mts(vm->cpu_group);
587
588 #if 0
589 vm_resume(vm);
590 #endif
591 return(0);
592 }
593
594 /* Suspend a VM instance */
595 int vm_suspend(vm_instance_t *vm)
596 {
597 if (vm->status == VM_STATUS_RUNNING) {
598 cpu_group_save_state(vm->cpu_group);
599 cpu_group_set_state(vm->cpu_group,CPU_STATE_SUSPENDED);
600 vm->status = VM_STATUS_SUSPENDED;
601 }
602 return(0);
603 }
604
605 /* Resume a VM instance */
606 int vm_resume(vm_instance_t *vm)
607 {
608 if (vm->status == VM_STATUS_SUSPENDED) {
609 cpu_group_restore_state(vm->cpu_group);
610 vm->status = VM_STATUS_RUNNING;
611 }
612 return(0);
613 }
614
615 /* Stop an instance */
616 int vm_stop(vm_instance_t *vm)
617 {
618 cpu_group_stop_all_cpu(vm->cpu_group);
619 vm->status = VM_STATUS_SHUTDOWN;
620 return(0);
621 }
622
623 /* Monitor an instance periodically */
624 void vm_monitor(vm_instance_t *vm)
625 {
626 while(vm->status != VM_STATUS_SHUTDOWN)
627 usleep(200000);
628 }
629
630 /* Create a new chunk */
631 static vm_chunk_t *vm_chunk_create(vm_instance_t *vm)
632 {
633 vm_chunk_t *chunk;
634 size_t area_len;
635
636 if (!(chunk = malloc(sizeof(*chunk))))
637 return NULL;
638
639 area_len = VM_CHUNK_AREA_SIZE * VM_PAGE_SIZE;
640
641 if (!(chunk->area = m_memalign(VM_PAGE_SIZE,area_len))) {
642 free(chunk);
643 return NULL;
644 }
645
646 chunk->page_alloc = 0;
647 chunk->page_total = VM_CHUNK_AREA_SIZE;
648
649 chunk->next = vm->chunks;
650 vm->chunks = chunk;
651 return chunk;
652 }
653
654 /* Free a chunk */
655 static void vm_chunk_free(vm_chunk_t *chunk)
656 {
657 free(chunk->area);
658 free(chunk);
659 }
660
661 /* Free all chunks used by a VM */
662 static void vm_chunk_free_all(vm_instance_t *vm)
663 {
664 vm_chunk_t *chunk,*next;
665
666 for(chunk=vm->chunks;chunk;chunk=next) {
667 next = chunk->next;
668 vm_chunk_free(chunk);
669 }
670
671 vm->chunks = NULL;
672 }
673
674 /* Allocate an host page */
675 void *vm_alloc_host_page(vm_instance_t *vm)
676 {
677 vm_chunk_t *chunk = vm->chunks;
678 void *ptr;
679
680 if (!chunk || (chunk->page_alloc == chunk->page_total)) {
681 chunk = vm_chunk_create(vm);
682 if (!chunk) return NULL;
683 }
684
685 ptr = chunk->area + (chunk->page_alloc * VM_PAGE_SIZE);
686 chunk->page_alloc++;
687 return(ptr);
688 }
689
690 /* Free resources used by a ghost image */
691 static void vm_ghost_image_free(vm_ghost_image_t *img)
692 {
693 if (img) {
694 if (img->fd != -1) {
695 close(img->fd);
696
697 if (img->area_ptr != NULL)
698 munmap(img->area_ptr,img->file_size);
699 }
700
701 free(img->filename);
702 free(img);
703 }
704 }
705
706 /* Find a specified ghost image in the pool */
707 static vm_ghost_image_t *vm_ghost_image_find(char *filename)
708 {
709 vm_ghost_image_t *img;
710
711 for(img=vm_ghost_pool;img;img=img->next)
712 if (!strcmp(img->filename,filename))
713 return img;
714
715 return NULL;
716 }
717
718 /* Load a new ghost image */
719 static vm_ghost_image_t *vm_ghost_image_load(char *filename)
720 {
721 vm_ghost_image_t *img;
722
723 if (!(img = calloc(1,sizeof(*img))))
724 return NULL;
725
726 img->fd = -1;
727
728 if (!(img->filename = strdup(filename))) {
729 vm_ghost_image_free(img);
730 return NULL;
731 }
732
733 img->fd = memzone_open_file(img->filename,&img->area_ptr,&img->file_size);
734
735 if (img->fd == -1) {
736 vm_ghost_image_free(img);
737 return NULL;
738 }
739
740 m_log("GHOST","loaded ghost image %s (fd=%d) at addr=%p (size=0x%llx)\n",
741 img->filename,img->fd,img->area_ptr,(long long)img->file_size);
742
743 return img;
744 }
745
746 /* Get a ghost image */
747 int vm_ghost_image_get(char *filename,u_char **ptr,int *fd)
748 {
749 vm_ghost_image_t *img;
750
751 VM_GLOCK();
752
753 /* Do we already have this image in the pool ? */
754 if ((img = vm_ghost_image_find(filename)) != NULL) {
755 img->ref_count++;
756 *ptr = img->area_ptr;
757 *fd = img->fd;
758 VM_GUNLOCK();
759 return(0);
760 }
761
762 /* Load the ghost file and add it into the pool */
763 if (!(img = vm_ghost_image_load(filename))) {
764 VM_GUNLOCK();
765 fprintf(stderr,"Unable to load ghost image %s\n",filename);
766 return(-1);
767 }
768
769 img->ref_count = 1;
770 *ptr = img->area_ptr;
771 *fd = img->fd;
772
773 img->next = vm_ghost_pool;
774 vm_ghost_pool = img;
775 VM_GUNLOCK();
776 return(0);
777 }
778
779 /* Release a ghost image */
780 int vm_ghost_image_release(int fd)
781 {
782 vm_ghost_image_t **img,*next;
783
784 VM_GLOCK();
785
786 for(img=&vm_ghost_pool;*img;img=&(*img)->next) {
787 if ((*img)->fd == fd) {
788 assert((*img)->ref_count > 0);
789
790 (*img)->ref_count--;
791
792 if ((*img)->ref_count == 0) {
793 m_log("GHOST","unloaded ghost image %s (fd=%d) at "
794 "addr=%p (size=0x%llx)\n",
795 (*img)->filename,(*img)->fd,(*img)->area_ptr,
796 (long long)(*img)->file_size);
797
798 next = (*img)->next;
799 vm_ghost_image_free(*img);
800 *img = next;
801 }
802
803 VM_GUNLOCK();
804 return(0);
805 }
806 }
807
808 VM_GUNLOCK();
809 return(-1);
810 }
811
812 /* Open a VM file and map it in memory */
813 int vm_mmap_open_file(vm_instance_t *vm,char *name,
814 u_char **ptr,off_t *fsize)
815 {
816 char *filename;
817 int fd;
818
819 if (!(filename = vm_build_filename(vm,name))) {
820 fprintf(stderr,"vm_mmap_open_file: unable to create filename (%s)\n",
821 name);
822 return(-1);
823 }
824
825 if ((fd = memzone_open_file(filename,ptr,fsize)) == -1)
826 fprintf(stderr,"vm_mmap_open_file: unable to open file '%s' (%s)\n",
827 filename,strerror(errno));
828
829 free(filename);
830 return(fd);
831 }
832
833 /* Open/Create a VM file and map it in memory */
834 int vm_mmap_create_file(vm_instance_t *vm,char *name,size_t len,u_char **ptr)
835 {
836 char *filename;
837 int fd;
838
839 if (!(filename = vm_build_filename(vm,name))) {
840 fprintf(stderr,"vm_mmap_create_file: unable to create filename (%s)\n",
841 name);
842 return(-1);
843 }
844
845 if ((fd = memzone_create_file(filename,len,ptr)) == -1)
846 fprintf(stderr,"vm_mmap_create_file: unable to open file '%s' (%s)\n",
847 filename,strerror(errno));
848
849 free(filename);
850 return(fd);
851 }
852
853 /* Close a memory mapped file */
854 int vm_mmap_close_file(int fd,u_char *ptr,size_t len)
855 {
856 if (ptr != NULL)
857 munmap(ptr,len);
858
859 if (fd != -1)
860 close(fd);
861
862 return(0);
863 }
864
865 /* Save the Cisco IOS configuration from NVRAM */
866 int vm_ios_save_config(vm_instance_t *vm)
867 {
868 char *output;
869 int res;
870
871 if (!(output = vm_build_filename(vm,"ios_cfg.txt")))
872 return(-1);
873
874 res = vm_nvram_extract_config(vm,output);
875 free(output);
876 return(res);
877 }
878
879 /* Set Cisco IOS image to use */
880 int vm_ios_set_image(vm_instance_t *vm,char *ios_image)
881 {
882 char *str;
883
884 if (!(str = strdup(ios_image)))
885 return(-1);
886
887 if (vm->ios_image != NULL) {
888 free(vm->ios_image);
889 vm->ios_image = NULL;
890 }
891
892 vm->ios_image = str;
893 return(0);
894 }
895
896 /* Unset a Cisco IOS configuration file */
897 void vm_ios_unset_config(vm_instance_t *vm)
898 {
899 if (vm->ios_config != NULL) {
900 free(vm->ios_config);
901 vm->ios_config = NULL;
902 }
903 }
904
905 /* Set Cisco IOS configuration file to use */
906 int vm_ios_set_config(vm_instance_t *vm,char *ios_config)
907 {
908 char *str;
909
910 if (!(str = strdup(ios_config)))
911 return(-1);
912
913 vm_ios_unset_config(vm);
914 vm->ios_config = str;
915 return(0);
916 }
917
918 /* Extract IOS configuration from NVRAM and write it to a file */
919 int vm_nvram_extract_config(vm_instance_t *vm,char *filename)
920 {
921 u_char *cfg_buffer;
922 ssize_t cfg_len;
923 FILE *fd;
924
925 if (!vm->platform->nvram_extract_config)
926 return(-1);
927
928 /* Extract the IOS configuration */
929 if (((cfg_len = vm->platform->nvram_extract_config(vm,&cfg_buffer)) < 0) ||
930 (cfg_buffer == NULL))
931 return(-1);
932
933 /* Write configuration to the specified filename */
934 if (!(fd = fopen(filename,"w"))) {
935 vm_error(vm,"unable to create file '%s'\n",filename);
936 free(cfg_buffer);
937 return(-1);
938 }
939
940 fwrite(cfg_buffer,cfg_len,1,fd);
941
942 fclose(fd);
943 free(cfg_buffer);
944 return(0);
945 }
946
947 /* Read an IOS configuraton from a file and push it to NVRAM */
948 int vm_nvram_push_config(vm_instance_t *vm,char *filename)
949 {
950 u_char *cfg_buffer;
951 ssize_t len;
952 int res;
953
954 if (!vm->platform->nvram_push_config)
955 return(-1);
956
957 /* Read configuration */
958 if (((len = m_read_file(filename,&cfg_buffer)) <= 0) || !cfg_buffer)
959 return(-1);
960
961 /* Push it! */
962 res = vm->platform->nvram_push_config(vm,cfg_buffer,len);
963 free(cfg_buffer);
964 return(res);
965 }
966
967 /* Save general VM configuration into the specified file */
968 void vm_save_config(vm_instance_t *vm,FILE *fd)
969 {
970 fprintf(fd,"vm create %s %u %s\n",
971 vm->name,vm->instance_id,vm->platform->name);
972
973 if (vm->ios_image)
974 fprintf(fd,"vm set_ios %s %s\n",vm->name,vm->ios_image);
975
976 fprintf(fd,"vm set_ram %s %u\n",vm->name,vm->ram_size);
977 fprintf(fd,"vm set_nvram %s %u\n",vm->name,vm->nvram_size);
978 fprintf(fd,"vm set_ram_mmap %s %u\n",vm->name,vm->ram_mmap);
979 fprintf(fd,"vm set_clock_divisor %s %u\n",vm->name,vm->clock_divisor);
980 fprintf(fd,"vm set_conf_reg %s 0x%4.4x\n",vm->name,vm->conf_reg_setup);
981
982 if (vm->vtty_con_type == VTTY_TYPE_TCP)
983 fprintf(fd,"vm set_con_tcp_port %s %d\n",vm->name,vm->vtty_con_tcp_port);
984
985 if (vm->vtty_aux_type == VTTY_TYPE_TCP)
986 fprintf(fd,"vm set_aux_tcp_port %s %d\n",vm->name,vm->vtty_aux_tcp_port);
987
988 /* Save slot config */
989 vm_slot_save_all_config(vm,fd);
990 }
991
992 /* Find a platform */
993 vm_platform_t *vm_platform_find(char *name)
994 {
995 struct vm_platform_list *p;
996
997 for(p=vm_platforms;p;p=p->next)
998 if (!strcmp(p->platform->name,name))
999 return(p->platform);
1000
1001 return NULL;
1002 }
1003
1004 /* Find a platform given its CLI name */
1005 vm_platform_t *vm_platform_find_cli_name(char *name)
1006 {
1007 struct vm_platform_list *p;
1008
1009 for(p=vm_platforms;p;p=p->next)
1010 if (!strcmp(p->platform->cli_name,name))
1011 return(p->platform);
1012
1013 return NULL;
1014 }
1015
1016 /* Register a platform */
1017 int vm_platform_register(vm_platform_t *platform)
1018 {
1019 struct vm_platform_list *p;
1020
1021 if (vm_platform_find(platform->name) != NULL) {
1022 fprintf(stderr,"vm_platform_register: platform '%s' already exists.\n",
1023 platform->name);
1024 return(-1);
1025 }
1026
1027 if (!(p = malloc(sizeof(*p)))) {
1028 fprintf(stderr,"vm_platform_register: unable to record platform.\n");
1029 return(-1);
1030 }
1031
1032 p->platform = platform;
1033 p->next = vm_platforms;
1034 vm_platforms = p;
1035 return(0);
1036 }
1037
1038 /* Create an instance of the specified type */
1039 vm_instance_t *vm_create_instance(char *name,int instance_id,char *type)
1040 {
1041 vm_platform_t *platform;
1042 vm_instance_t *vm = NULL;
1043
1044 if (!(platform = vm_platform_find(type))) {
1045 fprintf(stderr,"VM %s: unknown platform '%s'\n",name,type);
1046 goto error;
1047 }
1048
1049 /* Create a generic VM instance */
1050 if (!(vm = vm_create(name,instance_id,platform)))
1051 goto error;
1052
1053 /* Initialize specific parts */
1054 if (vm->platform->create_instance(vm) == -1)
1055 goto error;
1056
1057 return vm;
1058
1059 error:
1060 fprintf(stderr,"VM %s: unable to create instance!\n",name);
1061 vm_free(vm);
1062 return NULL;
1063 }
1064
1065 /* Free resources used by a VM instance */
1066 static int vm_reg_delete_instance(void *data,void *arg)
1067 {
1068 vm_instance_t *vm = data;
1069 return(vm->platform->delete_instance(vm));
1070 }
1071
1072 /* Delete a VM instance */
1073 int vm_delete_instance(char *name)
1074 {
1075 return(registry_delete_if_unused(name,OBJ_TYPE_VM,
1076 vm_reg_delete_instance,NULL));
1077 }
1078
1079 /* Initialize a VM instance */
1080 int vm_init_instance(vm_instance_t *vm)
1081 {
1082 return(vm->platform->init_instance(vm));
1083 }
1084
1085 /* Stop a VM instance */
1086 int vm_stop_instance(vm_instance_t *vm)
1087 {
1088 return(vm->platform->stop_instance(vm));
1089 }
1090
1091 /* Delete all VM instances */
1092 int vm_delete_all_instances(void)
1093 {
1094 return(registry_delete_type(OBJ_TYPE_VM,vm_reg_delete_instance,NULL));
1095 }
1096
1097 /* Save configurations of all VM instances */
1098 static void vm_reg_save_config(registry_entry_t *entry,void *opt,int *err)
1099 {
1100 vm_instance_t *vm = entry->data;
1101 FILE *fd = opt;
1102
1103 vm_save_config(vm,fd);
1104
1105 /* Save specific platform options */
1106 if (vm->platform->save_config != NULL)
1107 vm->platform->save_config(vm,fd);
1108 }
1109
1110 /* Save all VM configs */
1111 int vm_save_config_all(FILE *fd)
1112 {
1113 registry_foreach_type(OBJ_TYPE_VM,vm_reg_save_config,fd,NULL);
1114 return(0);
1115 }

  ViewVC Help
Powered by ViewVC 1.1.26