added dynamic interface manipulation for guests

management of tap devices on the host
This commit is contained in:
Martin Willi
2007-07-25 13:23:45 +00:00
parent 5c7da9d402
commit f85fdda835
10 changed files with 886 additions and 38 deletions
+108 -15
View 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>
@@ -10,27 +25,88 @@
#include <signal.h>
#include <debug.h>
#include <utils/linked_list.h>
#include "dumm.h"
#include "guest.h"
#include "mconsole.h"
typedef struct private_guest_t private_guest_t;
struct private_guest_t {
/** implemented public interface */
guest_t public;
/** name of the guest */
char *name;
/** kernel to boot for guest */
char *kernel;
/** read only master filesystem guest uses */
char *master;
/** amount of memory for guest, in MB */
int mem;
/** pid of guest child process */
int pid;
/** log file for console 0 */
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;
}
/**
* 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;
@@ -50,6 +126,9 @@ static char* write_arg(char **pos, size_t *left, char *format, ...)
return res;
}
/**
* Implementation of guest_t.start.
*/
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, "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");
@@ -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);
DBG1("starting UML kernel '%s' failed", args[0]);
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)
@@ -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)
{
@@ -138,6 +232,7 @@ static bool umount_unionfs(char *name)
}
if (system(cmd) != 0)
{
DBG1("unmounting guest unionfs for %s failed", name);
return FALSE;
}
return TRUE;
@@ -151,7 +246,6 @@ static bool mount_unionfs(char *name, char *master)
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))
@@ -160,7 +254,7 @@ static bool mount_unionfs(char *name, char *master)
}
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;
@@ -183,18 +277,21 @@ static int open_bootlog(char *name)
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;
}
/**
* stop guest, unmount mounts
* Implementation of guest_t.destroy.
*/
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);
@@ -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;
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) ||
!makedir(RUN_DIR, name))
!makedir(RUN_DIR, name) || !mount_unionfs(name, master))
{
DBG1("creating guest directories for %s failed failed.", name);
free(this);
return NULL;
}
if (!mount_unionfs(name, master))
{
DBG1("mounting guest unionfs for %s failed.", name);
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->mconsole = NULL;
this->ifaces = linked_list_create();
return &this->public;
}