added dynamic interface manipulation for guests
management of tap devices on the host
This commit is contained in:
+2
-2
@@ -1,3 +1,3 @@
|
||||
|
||||
dumm: dumm.c dumm.h guest.c guest.h main.c
|
||||
gcc -o dumm dumm.c guest.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -Wall
|
||||
dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h mconsole.c mconsole.h main.c
|
||||
gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -Wall
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef DUMM_H
|
||||
#define DUMM_H
|
||||
|
||||
@@ -45,6 +60,14 @@ struct dumm_t {
|
||||
void (*destroy) (dumm_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new group of UML hosts and networks.
|
||||
*
|
||||
* Dumm uses its working dir to create folders and files it works with.
|
||||
*
|
||||
* @return created UML group, or NULL if failed.
|
||||
*/
|
||||
dumm_t *dumm_create();
|
||||
|
||||
#endif /* DUMM_H */
|
||||
|
||||
|
||||
+108
-15
@@ -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;
|
||||
}
|
||||
|
||||
+63
-2
@@ -1,23 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef GUEST_H
|
||||
#define GUEST_H
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/iterator.h>
|
||||
|
||||
#include "iface.h"
|
||||
|
||||
typedef struct guest_t guest_t;
|
||||
|
||||
/**
|
||||
* @brief A guest is a UML instance running on the host.
|
||||
**/
|
||||
struct guest_t {
|
||||
|
||||
/**
|
||||
* @brief Get the name of this guest.
|
||||
*
|
||||
* @return name of the guest
|
||||
*/
|
||||
char* (*get_name) (guest_t *this);
|
||||
|
||||
/**
|
||||
* @brief Start the guest.
|
||||
*
|
||||
* @return TRUE if guest successfully started
|
||||
*/
|
||||
bool (*start) (guest_t *this);
|
||||
|
||||
/**
|
||||
* @brief Kill the guest.
|
||||
*
|
||||
* @return TRUE if guest was running and killed
|
||||
*/
|
||||
bool (*stop) (guest_t *this);
|
||||
|
||||
/**
|
||||
* @brief Create a new interface for that host.
|
||||
*
|
||||
* @param name name of the interface in the guest
|
||||
* @return created interface, or NULL if failed
|
||||
*/
|
||||
iface_t* (*create_iface)(guest_t *this, char *name);
|
||||
|
||||
/**
|
||||
* @brief Create an iterator over all guest interfaces.
|
||||
*
|
||||
* @return iterator over iface_t's
|
||||
*/
|
||||
iterator_t* (*create_iface_iterator)(guest_t *this);
|
||||
|
||||
/**
|
||||
* @brief Close and destroy a guest with all interfaces
|
||||
*/
|
||||
void (*destroy) (guest_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new, unstarted guest.
|
||||
*
|
||||
* @param name name of the guest
|
||||
* @param kernel kernel to boot for this guest
|
||||
* @param master read-only master filesystem for guest
|
||||
* @param mem amount of memory to give the guest
|
||||
*/
|
||||
guest_t *guest_create(char *name, char *kernel, char *master, int mem);
|
||||
|
||||
|
||||
#endif /* GUEST_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2002 Jeff Dike
|
||||
*
|
||||
* Based on the "tunctl" utlity from Jeff Dike.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include "iface.h"
|
||||
|
||||
typedef struct private_iface_t private_iface_t;
|
||||
|
||||
struct private_iface_t {
|
||||
/** public interface */
|
||||
iface_t public;
|
||||
/** device name in guest (eth0) */
|
||||
char *guest;
|
||||
/** device name at host (tap0) */
|
||||
char *host;
|
||||
/** tap device handle to manage taps */
|
||||
int tap;
|
||||
/** mconsole for guest */
|
||||
mconsole_t *mconsole;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of iface_t.get_guest.
|
||||
*/
|
||||
static char* get_guest(private_iface_t *this)
|
||||
{
|
||||
return this->guest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of iface_t.get_host.
|
||||
*/
|
||||
static char* get_host(private_iface_t *this)
|
||||
{
|
||||
return this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy the tap device
|
||||
*/
|
||||
static bool destroy_tap(private_iface_t *this)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, this->host, sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
if (ioctl(this->tap, TUNSETIFF, &ifr) < 0 ||
|
||||
ioctl(this->tap, TUNSETPERSIST, 0) < 0)
|
||||
{
|
||||
DBG1("removing %s failed: %m", this->host);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* create the tap device
|
||||
*/
|
||||
static char* create_tap(private_iface_t *this)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
|
||||
if (ioctl(this->tap, TUNSETIFF, &ifr) < 0 ||
|
||||
ioctl(this->tap, TUNSETPERSIST, 1) < 0)
|
||||
{
|
||||
DBG1("creating new tap device failed: %m");
|
||||
return NULL;
|
||||
}
|
||||
return strdup(ifr.ifr_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of iface_t.destroy.
|
||||
*/
|
||||
static void destroy(private_iface_t *this)
|
||||
{
|
||||
this->mconsole->del_iface(this->mconsole, this->guest);
|
||||
destroy_tap(this);
|
||||
close(this->tap);
|
||||
free(this->guest);
|
||||
free(this->host);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* create the iface instance
|
||||
*/
|
||||
iface_t *iface_create(char *guest, mconsole_t *mconsole)
|
||||
{
|
||||
private_iface_t *this = malloc_thing(private_iface_t);
|
||||
|
||||
this->public.get_host = (char*(*)(iface_t*))get_host;
|
||||
this->public.get_guest = (char*(*)(iface_t*))get_guest;
|
||||
this->public.destroy = (void*)destroy;
|
||||
|
||||
this->mconsole = mconsole;
|
||||
this->tap = open(TAP_DEVICE, O_RDWR);
|
||||
if (this->tap < 0)
|
||||
{
|
||||
DBG1("unable to open tap device %s: %m", TAP_DEVICE);
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
this->guest = strdup(guest);
|
||||
this->host = create_tap(this);
|
||||
if (this->host == NULL)
|
||||
{
|
||||
destroy_tap(this);
|
||||
close(this->tap);
|
||||
free(this->guest);
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
if (!this->mconsole->add_iface(this->mconsole, this->guest, this->host))
|
||||
{
|
||||
DBG1("creating interface '%s' in guest failed", this->guest);
|
||||
destroy_tap(this);
|
||||
close(this->tap);
|
||||
free(this->guest);
|
||||
free(this->host);
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IFACE_H
|
||||
#define IFACE_H
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/iterator.h>
|
||||
|
||||
#include "mconsole.h"
|
||||
|
||||
#define TAP_DEVICE "/dev/net/tun"
|
||||
|
||||
typedef struct iface_t iface_t;
|
||||
|
||||
/**
|
||||
* @brief Interface in a guest, connected to a tap device on the host.
|
||||
*/
|
||||
struct iface_t {
|
||||
|
||||
/**
|
||||
* @brief Get the interface name in the guest (e.g. eth0).
|
||||
*
|
||||
* @return guest interface name
|
||||
*/
|
||||
char* (*get_guest)(iface_t *this);
|
||||
|
||||
/**
|
||||
* @brief Get the interface name at the host (e.g. tap0).
|
||||
*
|
||||
* @return host interface (tap device) name
|
||||
*/
|
||||
char* (*get_host)(iface_t *this);
|
||||
|
||||
/*
|
||||
bool (*up) (iface_t *this);
|
||||
bool (*down) (iface_t *this);
|
||||
bool (*add_addr) (iface_t *this, host_t *addr);
|
||||
bool (*del_addr) (iface_t *this, host_t *addr);
|
||||
iterator_t* (*create_addr_iterator) (iface_t *this);
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Destroy an interface
|
||||
*/
|
||||
void (*destroy) (iface_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new interface for a guest
|
||||
*
|
||||
* @param guest name of the interface in the guest
|
||||
* @param mconsole mconsole of guest
|
||||
* @return interface descriptor, or NULL if failed
|
||||
*/
|
||||
iface_t *iface_create(char *guest, mconsole_t *mconsole);
|
||||
|
||||
#endif /* IFACE_H */
|
||||
+221
-19
@@ -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 <stdio.h>
|
||||
@@ -20,7 +35,7 @@ static void usage()
|
||||
}
|
||||
|
||||
/**
|
||||
* show usage information (commandline arguments)
|
||||
* help for dumm root shell
|
||||
*/
|
||||
static void help()
|
||||
{
|
||||
@@ -29,15 +44,29 @@ static void help()
|
||||
printf(" kernel=<uml-kernel>\n");
|
||||
printf(" master=<read-only root files>\n");
|
||||
printf(" memory=<guest memory in MB>\n");
|
||||
printf("guests list running guests\n");
|
||||
printf("list list running guests\n");
|
||||
printf("guest <name> open guest menu for <name>\n");
|
||||
printf("help show this help\n");
|
||||
printf("quit kill quests and exit\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* help for guest shell
|
||||
*/
|
||||
static void help_guest()
|
||||
{
|
||||
printf("addif <name> add an interface to the guest\n");
|
||||
printf("delif <name> remove the interface\n");
|
||||
printf("listif list guests interfaces\n");
|
||||
printf("help show this help\n");
|
||||
printf("quit quit the guest menu\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* start an UML guest
|
||||
*/
|
||||
static void start(umli_t *umli, char *line)
|
||||
static void start(dumm_t *dumm, char *line)
|
||||
{
|
||||
enum {
|
||||
NAME = 0,
|
||||
@@ -101,7 +130,7 @@ static void start(umli_t *umli, char *line)
|
||||
mem = 128;
|
||||
}
|
||||
|
||||
if (umli->start_guest(umli, name, kernel, master, mem))
|
||||
if (dumm->start_guest(dumm, name, kernel, master, mem))
|
||||
{
|
||||
printf("starting guest '%s'\n", name);
|
||||
}
|
||||
@@ -112,19 +141,187 @@ static void start(umli_t *umli, char *line)
|
||||
}
|
||||
|
||||
/**
|
||||
* list running UML guests
|
||||
* add an iface to a guest
|
||||
*/
|
||||
static void guests(umli_t *umli)
|
||||
static void add_if(guest_t *guest, char *name)
|
||||
{
|
||||
iterator_t *iterator;
|
||||
guest_t *guest;
|
||||
iface_t *iface;
|
||||
|
||||
iterator = umli->create_guest_iterator(umli);
|
||||
while (iterator->iterate(iterator, (void**)&guest))
|
||||
iface = guest->create_iface(guest, name);
|
||||
if (iface)
|
||||
{
|
||||
printf("%s\n", guest->get_name(guest));
|
||||
printf("created guest interface '%s' connected to '%s'\n",
|
||||
iface->get_guest(iface), iface->get_host(iface));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("failed to create guest interface\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete an iface from a guest
|
||||
*/
|
||||
static void del_if(guest_t *guest, char *name)
|
||||
{
|
||||
iface_t *iface;
|
||||
iterator_t *iterator;
|
||||
bool found = FALSE;
|
||||
|
||||
iterator = guest->create_iface_iterator(guest);
|
||||
while (iterator->iterate(iterator, (void**)&iface))
|
||||
{
|
||||
if (streq(name, iface->get_guest(iface)))
|
||||
{
|
||||
iterator->remove(iterator);
|
||||
printf("removing interface '%s' ('%s') from %s\n",
|
||||
iface->get_guest(iface), iface->get_host(iface),
|
||||
guest->get_name(guest));
|
||||
iface->destroy(iface);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
if (!found)
|
||||
{
|
||||
printf("guest '%s' has no interface named '%s'\n",
|
||||
guest->get_name(guest), name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list interfaces on a guest
|
||||
*/
|
||||
static void list_if(guest_t *guest)
|
||||
{
|
||||
iface_t *iface;
|
||||
iterator_t *iterator;
|
||||
|
||||
iterator = guest->create_iface_iterator(guest);
|
||||
while (iterator->iterate(iterator, (void**)&iface))
|
||||
{
|
||||
printf("'%s' => '%s'\n", iface->get_guest(iface), iface->get_host(iface));
|
||||
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* subshell for guests
|
||||
*/
|
||||
static void guest(dumm_t *dumm, char *name)
|
||||
{
|
||||
char *line = NULL;
|
||||
char prompt[32];
|
||||
int len;
|
||||
iterator_t *iterator;
|
||||
guest_t *guest;
|
||||
bool found = FALSE;
|
||||
|
||||
iterator = dumm->create_guest_iterator(dumm);
|
||||
while (iterator->iterate(iterator, (void**)&guest))
|
||||
{
|
||||
if (streq(name, guest->get_name(guest)))
|
||||
{
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
if (!found)
|
||||
{
|
||||
printf("guest '%s' not found\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
len = snprintf(prompt, sizeof(prompt), "dumm@%s# ", name);
|
||||
if (len < 0 || len >= sizeof(prompt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
enum {
|
||||
QUIT = 0,
|
||||
HELP,
|
||||
ADDIF,
|
||||
DELIF,
|
||||
LISTIF,
|
||||
};
|
||||
char *const opts[] = {
|
||||
[QUIT] = "quit",
|
||||
[HELP] = "help",
|
||||
[ADDIF] = "addif",
|
||||
[DELIF] = "delif",
|
||||
[LISTIF] = "listif",
|
||||
NULL
|
||||
};
|
||||
char *pos, *value;
|
||||
|
||||
free(line);
|
||||
line = readline(prompt);
|
||||
if (line == NULL || *line == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
add_history(line);
|
||||
pos = line;
|
||||
while (*pos != '\0')
|
||||
{
|
||||
if (*pos == ' ')
|
||||
{
|
||||
*pos = ',';
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
pos = line;
|
||||
switch (getsubopt(&pos, opts, &value))
|
||||
{
|
||||
case QUIT:
|
||||
free(line);
|
||||
break;
|
||||
case HELP:
|
||||
help_guest();
|
||||
continue;
|
||||
case ADDIF:
|
||||
add_if(guest, pos);
|
||||
continue;
|
||||
case DELIF:
|
||||
del_if(guest, pos);
|
||||
continue;
|
||||
case LISTIF:
|
||||
list_if(guest);
|
||||
continue;
|
||||
default:
|
||||
printf("command unknown: '%s'\n", line);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list running UML guests
|
||||
*/
|
||||
static void list(dumm_t *dumm)
|
||||
{
|
||||
iterator_t *guests, *ifaces;
|
||||
guest_t *guest;
|
||||
iface_t *iface;
|
||||
|
||||
guests = dumm->create_guest_iterator(dumm);
|
||||
while (guests->iterate(guests, (void**)&guest))
|
||||
{
|
||||
printf("%s\n", guest->get_name(guest));
|
||||
ifaces = guest->create_iface_iterator(guest);
|
||||
while (ifaces->iterate(ifaces, (void**)&iface))
|
||||
{
|
||||
printf(" '%s' => '%s'\n", iface->get_guest(iface), iface->get_host(iface));
|
||||
}
|
||||
ifaces->destroy(ifaces);
|
||||
}
|
||||
guests->destroy(guests);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +329,7 @@ static void guests(umli_t *umli)
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
umli_t *umli;
|
||||
dumm_t *dumm;
|
||||
char *line = NULL;
|
||||
|
||||
while (TRUE)
|
||||
@@ -164,7 +361,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
umli = umli_create();
|
||||
dumm = dumm_create();
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
@@ -172,13 +369,15 @@ int main(int argc, char *argv[])
|
||||
QUIT = 0,
|
||||
HELP,
|
||||
START,
|
||||
GUESTS,
|
||||
LIST,
|
||||
GUEST,
|
||||
};
|
||||
char *const opts[] = {
|
||||
[QUIT] = "quit",
|
||||
[HELP] = "help",
|
||||
[START] = "start",
|
||||
[GUESTS] = "guests",
|
||||
[LIST] = "list",
|
||||
[GUEST] = "guest",
|
||||
NULL
|
||||
};
|
||||
char *pos, *value;
|
||||
@@ -210,10 +409,13 @@ int main(int argc, char *argv[])
|
||||
help();
|
||||
continue;
|
||||
case START:
|
||||
start(umli, pos);
|
||||
start(dumm, pos);
|
||||
continue;
|
||||
case GUESTS:
|
||||
guests(umli);
|
||||
case LIST:
|
||||
list(dumm);
|
||||
continue;
|
||||
case GUEST:
|
||||
guest(dumm, pos);
|
||||
continue;
|
||||
default:
|
||||
printf("command unknown: '%s'\n", line);
|
||||
@@ -221,7 +423,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
}
|
||||
umli->destroy(umli);
|
||||
dumm->destroy(dumm);
|
||||
clear_history();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2001-2004 Jeff Dike
|
||||
*
|
||||
* Based on the "uml_mconsole" utilty from Jeff Dike.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include "mconsole.h"
|
||||
|
||||
#define MCONSOLE_MAGIC 0xcafebabe
|
||||
#define MCONSOLE_VERSION 2
|
||||
#define MCONSOLE_MAX_DATA 512
|
||||
|
||||
typedef struct private_mconsole_t private_mconsole_t;
|
||||
|
||||
struct private_mconsole_t {
|
||||
/** public interface */
|
||||
mconsole_t public;
|
||||
/** mconsole socket */
|
||||
int socket;
|
||||
/** address of uml socket */
|
||||
struct sockaddr_un uml;
|
||||
};
|
||||
|
||||
/**
|
||||
* send a request to UML using mconsole
|
||||
*/
|
||||
static bool request(private_mconsole_t *this, char *command)
|
||||
{
|
||||
struct {
|
||||
u_int32_t magic;
|
||||
u_int32_t version;
|
||||
u_int32_t len;
|
||||
char data[MCONSOLE_MAX_DATA];
|
||||
} request;
|
||||
struct {
|
||||
u_int32_t err;
|
||||
u_int32_t more;
|
||||
u_int32_t len;
|
||||
char data[MCONSOLE_MAX_DATA];
|
||||
} reply;
|
||||
bool first = TRUE, good = TRUE;
|
||||
int len;
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.magic = MCONSOLE_MAGIC;
|
||||
request.version = MCONSOLE_VERSION;
|
||||
request.len = min(strlen(command), sizeof(reply.data) - 1);
|
||||
strncpy(request.data, command, request.len);
|
||||
|
||||
if (sendto(this->socket, &request, sizeof(request), 0,
|
||||
(struct sockaddr*)&this->uml, sizeof(this->uml)) < 0)
|
||||
{
|
||||
DBG1("sending mconsole command to UML failed: %m");
|
||||
return FALSE;
|
||||
}
|
||||
do
|
||||
{
|
||||
len = recvfrom(this->socket, &reply, sizeof(reply), 0, NULL, 0);
|
||||
if (len < 0)
|
||||
{
|
||||
DBG1("receiving from mconsole failed: %m");
|
||||
return FALSE;
|
||||
}
|
||||
if (first && reply.err)
|
||||
{
|
||||
good = FALSE;
|
||||
DBG1("received error from UML mconsole: %s", reply.data);
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
while (reply.more);
|
||||
return good;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of mconsole_t.add_iface.
|
||||
*/
|
||||
static bool add_iface(private_mconsole_t *this, char *guest, char *host)
|
||||
{
|
||||
char buf[128];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "config %s=tuntap,%s", guest, host);
|
||||
if (len < 0 || len >= sizeof(buf))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return request(this, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of mconsole_t.del_iface.
|
||||
*/
|
||||
static bool del_iface(private_mconsole_t *this, char *guest)
|
||||
{
|
||||
char buf[128];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "remove %s", guest);
|
||||
if (len < 0 || len >= sizeof(buf))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return request(this, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of mconsole_t.destroy.
|
||||
*/
|
||||
static void destroy(private_mconsole_t *this)
|
||||
{
|
||||
close(this->socket);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* create the mconsole instance
|
||||
*/
|
||||
mconsole_t *mconsole_create(char *sock)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
private_mconsole_t *this = malloc_thing(private_mconsole_t);
|
||||
|
||||
this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface;
|
||||
this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
|
||||
this->public.destroy = (void*)destroy;
|
||||
|
||||
this->socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (this->socket < 0)
|
||||
{
|
||||
DBG1("opening mconsole socket failed: %m");
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
sprintf(&addr.sun_path[1], "%5d", getpid());
|
||||
if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
DBG1("binding mconsole socket failed: %m");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
memset(&this->uml, 0, sizeof(this->uml));
|
||||
this->uml.sun_family = AF_UNIX;
|
||||
strncpy(this->uml.sun_path, sock, sizeof(this->uml.sun_path));
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MCONSOLE_H
|
||||
#define MCONSOLE_H
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct mconsole_t mconsole_t;
|
||||
|
||||
/**
|
||||
* @brief UML mconsole, change running UML configuration using mconsole.
|
||||
*/
|
||||
struct mconsole_t {
|
||||
|
||||
/**
|
||||
* @brief Create a guest interface and connect it to tap host interface.
|
||||
*
|
||||
* @param guest name of the interface to create in the guest
|
||||
* @param host name of the tap device to connect guest to
|
||||
* @return TRUE if interface created
|
||||
*/
|
||||
bool (*add_iface)(mconsole_t *this, char *guest, char *host);
|
||||
|
||||
/**
|
||||
* @brief Delete a guest interface.
|
||||
*
|
||||
* @param guest name of the interface to delete on the guest
|
||||
* @return TRUE if interface deleted
|
||||
*/
|
||||
bool (*del_iface)(mconsole_t *this, char *guest);
|
||||
|
||||
/**
|
||||
* @brief Destroy the mconsole instance
|
||||
*/
|
||||
void (*destroy) (mconsole_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new mconsole connection to a guest.
|
||||
*
|
||||
* @param socket guests mconsole socket
|
||||
* @return mconsole instance, or NULL if failed
|
||||
*/
|
||||
mconsole_t *mconsole_create(char *socket);
|
||||
|
||||
#endif /* MCONSOLE_H */
|
||||
|
||||
Reference in New Issue
Block a user