added dynamic interface manipulation for guests
[strongswan.git] / src / dumm / guest.c
index 2028823..cdb97c7 100644 (file)
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
 #define _GNU_SOURCE
 
 #include <sys/types.h>
 #define _GNU_SOURCE
 
 #include <sys/types.h>
 #include <signal.h>
 
 #include <debug.h>
 #include <signal.h>
 
 #include <debug.h>
+#include <utils/linked_list.h>
 
 #include "dumm.h"
 #include "guest.h"
 
 #include "dumm.h"
 #include "guest.h"
+#include "mconsole.h"
 
 typedef struct private_guest_t private_guest_t;
 
 struct private_guest_t {
 
 typedef struct private_guest_t private_guest_t;
 
 struct private_guest_t {
+       /** implemented public interface */
        guest_t public;
        guest_t public;
+       /** name of the guest */
        char *name;
        char *name;
+       /** kernel to boot for guest */
        char *kernel;
        char *kernel;
+       /** read only master filesystem guest uses */
        char *master;
        char *master;
+       /** amount of memory for guest, in MB */
        int mem;
        int mem;
+       /** pid of guest child process */
        int pid;
        int pid;
+       /** log file for console 0 */
        int bootlog;
        int bootlog;
+       /** mconsole to control running UML */
+       mconsole_t *mconsole;
+       /** list of interfaces attached to the guest */
+       linked_list_t *ifaces;
 };
 
 };
 
+/**
+ * Implementation of guest_t.get_name.
+ */
 static char* get_name(private_guest_t *this)
 {
        return this->name;
 }
 
 static char* get_name(private_guest_t *this)
 {
        return this->name;
 }
 
+/**
+ * Implementation of guest_t.create_iface.
+ */
+static iface_t* create_iface(private_guest_t *this, char *name)
+{
+       iterator_t *iterator;
+       iface_t *iface;
+       
+       if (this->pid == 0)
+       {
+               DBG1("guest '%s' not running, unable to add interface", this->name);
+               return NULL;
+       }
+       
+       iterator = this->ifaces->create_iterator(this->ifaces, TRUE);
+       while (iterator->iterate(iterator, (void**)&iface))
+       {
+               if (streq(name, iface->get_guest(iface)))
+               {
+                       DBG1("guest '%s' already has an interface '%s'", this->name, name);
+                       iterator->destroy(iterator);
+                       return NULL;
+               }
+       }
+       iterator->destroy(iterator);
+
+       iface = iface_create(name, this->mconsole);
+       if (iface)
+       {
+               this->ifaces->insert_last(this->ifaces, iface);
+       }
+       return iface;
+}
+
+/**
+ * Implementation of guest_t.create_iface_iterator.
+ */
+static iterator_t* create_iface_iterator(private_guest_t *this)
+{
+       return this->ifaces->create_iterator(this->ifaces, TRUE);
+}
+
+/**
+ * write format string to a buffer, and advance buffer position
+ */
 static char* write_arg(char **pos, size_t *left, char *format, ...)
 {
        size_t len;
 static char* write_arg(char **pos, size_t *left, char *format, ...)
 {
        size_t len;
@@ -50,6 +126,9 @@ static char* write_arg(char **pos, size_t *left, char *format, ...)
        return res;
 }
 
        return res;
 }
 
+/**
+ * Implementation of guest_t.start.
+ */
 static bool start(private_guest_t *this)
 {
        char buf[1024];
 static bool start(private_guest_t *this)
 {
        char buf[1024];
@@ -67,7 +146,7 @@ static bool start(private_guest_t *this)
        args[i++] = write_arg(&pos, &left, "uml_dir=%s/%s", RUN_DIR, this->name);
        args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
        args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
        args[i++] = write_arg(&pos, &left, "uml_dir=%s/%s", RUN_DIR, this->name);
        args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
        args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
-       //args[i++] = write_arg(&pos, &left, "con=pts");
+       /*args[i++] = write_arg(&pos, &left, "con=pts");*/
        args[i++] = write_arg(&pos, &left, "con0=null,fd:%d", this->bootlog);
        args[i++] = write_arg(&pos, &left, "con1=fd:0,fd:1");
        args[i++] = write_arg(&pos, &left, "con3=null,null");
        args[i++] = write_arg(&pos, &left, "con0=null,fd:%d", this->bootlog);
        args[i++] = write_arg(&pos, &left, "con1=fd:0,fd:1");
        args[i++] = write_arg(&pos, &left, "con3=null,null");
@@ -84,15 +163,30 @@ static bool start(private_guest_t *this)
                        dup2(open("/dev/null", 0), 1);
                        dup2(open("/dev/null", 0), 2);
                        execvp(args[0], args);
                        dup2(open("/dev/null", 0), 1);
                        dup2(open("/dev/null", 0), 2);
                        execvp(args[0], args);
+                       DBG1("starting UML kernel '%s' failed", args[0]);
                        exit(1);
                case -1:
                        this->pid = 0;
                        return FALSE;
                default:
                        exit(1);
                case -1:
                        this->pid = 0;
                        return FALSE;
                default:
-                       return TRUE;
+                       break;
+       }
+       /* open mconsole */
+       snprintf(buf, sizeof(buf), "%s/%s/%s/mconsole", RUN_DIR, this->name, this->name);
+       this->mconsole = mconsole_create(buf);
+       if (this->mconsole == NULL)
+       {
+               DBG1("opening mconsole at '%s' failed, stopping guest", buf);
+               kill(this->pid, SIGINT);
+               this->pid = 0;
+               return FALSE;
        }
        }
+       return TRUE;
 }
 
 }
 
+/**
+ * Implementation of guest_t.stop.
+ */
 static void stop(private_guest_t *this)
 {
        if (this->pid)
 static void stop(private_guest_t *this)
 {
        if (this->pid)
@@ -103,7 +197,7 @@ static void stop(private_guest_t *this)
 }
 
 /**
 }
 
 /**
- * create a directory
+ * Check if directory exists, create otherwise
  */
 static bool makedir(char *dir, char *name)
 {
  */
 static bool makedir(char *dir, char *name)
 {
@@ -138,6 +232,7 @@ static bool umount_unionfs(char *name)
        }
        if (system(cmd) != 0)
        {
        }
        if (system(cmd) != 0)
        {
+               DBG1("unmounting guest unionfs for %s failed", name);
                return FALSE;
        }
        return TRUE;
                return FALSE;
        }
        return TRUE;
@@ -151,7 +246,6 @@ static bool mount_unionfs(char *name, char *master)
        char cmd[256];
        size_t len;
        
        char cmd[256];
        size_t len;
        
-       /* mount unionfs */
        len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s %s/%s",
                                   HOST_DIR, name, master, MOUNT_DIR, name);
        if (len < 0 || len >= sizeof(cmd))
        len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s %s/%s",
                                   HOST_DIR, name, master, MOUNT_DIR, name);
        if (len < 0 || len >= sizeof(cmd))
@@ -160,7 +254,7 @@ static bool mount_unionfs(char *name, char *master)
        }
        if (system(cmd) != 0)
        {
        }
        if (system(cmd) != 0)
        {
-               DBG1("mounting unionfs using '%s' failed.", cmd);
+               DBG1("mounting guest unionfs for %s using '%s' failed", name, cmd);
                return FALSE;
        }
        return TRUE;
                return FALSE;
        }
        return TRUE;
@@ -183,18 +277,21 @@ static int open_bootlog(char *name)
        fd = open(blg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
        if (fd == -1)
        {
        fd = open(blg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
        if (fd == -1)
        {
+               DBG1("opening bootlog '%s' for %s failed, using stdout", blg, name);
                return 1;
        }
        return fd;
 }
 
 /**
                return 1;
        }
        return fd;
 }
 
 /**
- * stop guest, unmount mounts
+ * Implementation of guest_t.destroy.
  */
 static void destroy(private_guest_t *this)
 {
        stop(this);
        umount_unionfs(this->name);
  */
 static void destroy(private_guest_t *this)
 {
        stop(this);
        umount_unionfs(this->name);
+       this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
+       DESTROY_IF(this->mconsole);
        free(this->name);
        free(this->kernel);
        free(this->master);
        free(this->name);
        free(this->kernel);
        free(this->master);
@@ -209,21 +306,15 @@ guest_t *guest_create(char *name, char *kernel, char *master, int mem)
        private_guest_t *this = malloc_thing(private_guest_t);
        
        this->public.get_name = (void*)get_name;
        private_guest_t *this = malloc_thing(private_guest_t);
        
        this->public.get_name = (void*)get_name;
+       this->public.create_iface = (iface_t*(*)(guest_t*,char*))create_iface;
+       this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
        this->public.destroy = (void*)destroy;
        
        if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) ||
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
        this->public.destroy = (void*)destroy;
        
        if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) ||
-               !makedir(RUN_DIR, name))
-       {
-               DBG1("creating guest directories for %s failed failed.", name);
-               free(this);
-               return NULL;
-       }
-       
-       if (!mount_unionfs(name, master))
+               !makedir(RUN_DIR, name) || !mount_unionfs(name, master))
        {
        {
-               DBG1("mounting guest unionfs for %s failed.", name);
                free(this);
                return NULL;
        }
                free(this);
                return NULL;
        }
@@ -234,6 +325,8 @@ guest_t *guest_create(char *name, char *kernel, char *master, int mem)
        this->mem = mem;
        this->pid = 0;
        this->bootlog = open_bootlog(name);
        this->mem = mem;
        this->pid = 0;
        this->bootlog = open_bootlog(name);
+       this->mconsole = NULL;
+       this->ifaces = linked_list_create();
 
        return &this->public;
 }
 
        return &this->public;
 }