diff options
author | Martin Willi <martin@strongswan.org> | 2007-07-25 13:23:45 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-07-25 13:23:45 +0000 |
commit | f85fdda83598cdfde287ee0acb5581d9cb2f261b (patch) | |
tree | b83ef7735a7eb81b9ae447b8045b0e011eb92bba | |
parent | 5c7da9d402a71992a5dc47c5ab25fd6f1479f5a7 (diff) | |
download | strongswan-f85fdda83598cdfde287ee0acb5581d9cb2f261b.tar.bz2 strongswan-f85fdda83598cdfde287ee0acb5581d9cb2f261b.tar.xz |
added dynamic interface manipulation for guests
management of tap devices on the host
-rw-r--r-- | src/dumm/Makefile | 4 | ||||
-rw-r--r-- | src/dumm/dumm.c | 15 | ||||
-rw-r--r-- | src/dumm/dumm.h | 23 | ||||
-rw-r--r-- | src/dumm/guest.c | 123 | ||||
-rw-r--r-- | src/dumm/guest.h | 65 | ||||
-rw-r--r-- | src/dumm/iface.c | 154 | ||||
-rw-r--r-- | src/dumm/iface.h | 70 | ||||
-rw-r--r-- | src/dumm/main.c | 234 | ||||
-rw-r--r-- | src/dumm/mconsole.c | 170 | ||||
-rw-r--r-- | src/dumm/mconsole.h | 60 |
10 files changed, 883 insertions, 35 deletions
diff --git a/src/dumm/Makefile b/src/dumm/Makefile index 39bdb0b4a..c60e57dbc 100644 --- a/src/dumm/Makefile +++ b/src/dumm/Makefile @@ -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 diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index 7536bce57..f5ca7d300 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -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> diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h index f18817abc..fd2ba46e8 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.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 */ + diff --git a/src/dumm/guest.c b/src/dumm/guest.c index 202882367..cdb97c7bd 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -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)) - { - 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; } @@ -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; } diff --git a/src/dumm/guest.h b/src/dumm/guest.h index 39a72c081..f4e9f50c6 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -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 */ + diff --git a/src/dumm/iface.c b/src/dumm/iface.c new file mode 100644 index 000000000..9e690d488 --- /dev/null +++ b/src/dumm/iface.c @@ -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; +} + diff --git a/src/dumm/iface.h b/src/dumm/iface.h new file mode 100644 index 000000000..de69fcbba --- /dev/null +++ b/src/dumm/iface.h @@ -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 */ diff --git a/src/dumm/main.c b/src/dumm/main.c index 26896c2df..7e22ddfd6 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -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 add_if(guest_t *guest, char *name) +{ + iface_t *iface; + + iface = guest->create_iface(guest, name); + if (iface) + { + 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 guests(umli_t *umli) +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 = umli->create_guest_iterator(umli); + iterator = dumm->create_guest_iterator(dumm); while (iterator->iterate(iterator, (void**)&guest)) { - printf("%s\n", guest->get_name(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 LIST: + list(dumm); continue; - case GUESTS: - guests(umli); + 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; } diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c new file mode 100644 index 000000000..b782ebe81 --- /dev/null +++ b/src/dumm/mconsole.c @@ -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; +} + diff --git a/src/dumm/mconsole.h b/src/dumm/mconsole.h new file mode 100644 index 000000000..8d71053a5 --- /dev/null +++ b/src/dumm/mconsole.h @@ -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 */ + |