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
+2 -2
View File
@@ -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
+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.
*/
#include <sys/stat.h>
#include <debug.h>
+23
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.
*/
#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
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;
}
+63 -2
View File
@@ -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 */
+154
View File
@@ -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;
}
+70
View File
@@ -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
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 <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;
}
+170
View File
@@ -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;
}
+60
View File
@@ -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 */