guest interface/address management using hackish mconsole exec patch, ruby bindings

This commit is contained in:
Martin Willi
2008-07-07 14:56:04 +00:00
parent 36beca7cef
commit 02a6083633
8 changed files with 291 additions and 2 deletions
+25
View File
@@ -25,6 +25,7 @@
#include <signal.h> #include <signal.h>
#include <dirent.h> #include <dirent.h>
#include <termios.h> #include <termios.h>
#include <stdarg.h>
#include <debug.h> #include <debug.h>
#include <utils/linked_list.h> #include <utils/linked_list.h>
@@ -324,6 +325,29 @@ static bool load_template(private_guest_t *this, char *path)
return TRUE; return TRUE;
} }
/**
* Implementation of gues_t.exec
*/
static int exec(private_guest_t *this, char *cmd, ...)
{
char buf[512];
size_t len;
va_list args;
if (this->mconsole)
{
va_start(args, cmd);
len = vsnprintf(buf, sizeof(buf), cmd, args);
va_end(args);
if (len > 0 && len < sizeof(buf))
{
return this->mconsole->exec(this->mconsole, buf);
}
}
return FALSE;
}
/** /**
* Implementation of guest_t.sigchild. * Implementation of guest_t.sigchild.
*/ */
@@ -448,6 +472,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.start = (void*)start; this->public.start = (void*)start;
this->public.stop = (void*)stop; this->public.stop = (void*)stop;
this->public.load_template = (bool(*)(guest_t*, char *path))load_template; this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
this->public.exec = (bool(*)(guest_t*, char *cmd, ...))exec;
this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy; this->public.destroy = (void*)destroy;
+10 -1
View File
@@ -140,7 +140,16 @@ struct guest_t {
* @return FALSE if failed * @return FALSE if failed
*/ */
bool (*load_template)(guest_t *this, char *parent); bool (*load_template)(guest_t *this, char *parent);
/**
* Execute a command in the guest.
*
* @param cmd command to execute
* @param ... printf style argument list for cmd
* @return TRUE if command executed
*/
bool (*exec)(guest_t *this, char *cmd, ...);
/** /**
* @brief Called whenever a SIGCHILD for the guests PID is received. * @brief Called whenever a SIGCHILD for the guests PID is received.
*/ */
+69 -1
View File
@@ -25,6 +25,7 @@
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <debug.h> #include <debug.h>
#include <utils/linked_list.h>
#include "iface.h" #include "iface.h"
@@ -43,10 +44,12 @@ struct private_iface_t {
guest_t *guest; guest_t *guest;
/** mconsole for guest */ /** mconsole for guest */
mconsole_t *mconsole; mconsole_t *mconsole;
/** list of interface addresses */
linked_list_t *addresses;
}; };
/** /**
* bring an interface up or down * bring an interface up or down (host side)
*/ */
bool iface_control(char *name, bool up) bool iface_control(char *name, bool up)
{ {
@@ -97,11 +100,69 @@ static char* get_hostif(private_iface_t *this)
return this->hostif; return this->hostif;
} }
/**
* Implementation of iface_t.add_address
*/
static bool add_address(private_iface_t *this, host_t *addr)
{
if (this->guest->exec(this->guest, "ip addr add %H dev %s",
addr, this->guestif))
{
this->addresses->insert_last(this->addresses, addr);
return TRUE;
}
addr->destroy(addr);
return FALSE;
}
/**
* Implementation of iface_t.create_address_enumerator
*/
static enumerator_t* create_address_enumerator(private_iface_t *this)
{
return this->addresses->create_enumerator(this->addresses);
}
/**
* Implementation of iface_t.delete_address
*/
static bool delete_address(private_iface_t *this, host_t *addr)
{
enumerator_t *enumerator;
bool success = FALSE;
host_t *current;
enumerator = create_address_enumerator(this);
while (enumerator->enumerate(enumerator, &current))
{
if (current->ip_equals(current, addr))
{
if (this->guest->exec(this->guest, "ip addr del %H dev %s",
current, this->guestif))
{
this->addresses->remove_at(this->addresses, enumerator);
success = TRUE;
}
break;
}
}
enumerator->destroy(enumerator);
return success;
}
/** /**
* Implementation of iface_t.set_bridge. * Implementation of iface_t.set_bridge.
*/ */
static void set_bridge(private_iface_t *this, bridge_t *bridge) static void set_bridge(private_iface_t *this, bridge_t *bridge)
{ {
if (this->bridge == NULL && bridge)
{
this->guest->exec(this->guest, "ip link set %s up", this->guestif);
}
else if (this->bridge && bridge == NULL)
{
this->guest->exec(this->guest, "ip link set %s down", this->guestif);
}
this->bridge = bridge; this->bridge = bridge;
} }
@@ -194,10 +255,13 @@ static void destroy(private_iface_t *this)
{ {
this->bridge->disconnect_iface(this->bridge, &this->public); this->bridge->disconnect_iface(this->bridge, &this->public);
} }
/* TODO: iface mgmt is not blocking yet, so wait some ticks */
usleep(50000);
this->mconsole->del_iface(this->mconsole, this->guestif); this->mconsole->del_iface(this->mconsole, this->guestif);
destroy_tap(this); destroy_tap(this);
free(this->guestif); free(this->guestif);
free(this->hostif); free(this->hostif);
this->addresses->destroy(this->addresses);
free(this); free(this);
} }
@@ -210,6 +274,9 @@ iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
this->public.get_hostif = (char*(*)(iface_t*))get_hostif; this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
this->public.get_guestif = (char*(*)(iface_t*))get_guestif; this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
this->public.add_address = (bool(*)(iface_t*, host_t *addr))add_address;
this->public.create_address_enumerator = (enumerator_t*(*)(iface_t*))create_address_enumerator;
this->public.delete_address = (bool(*)(iface_t*, host_t *addr))delete_address;
this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge; this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge; this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge;
this->public.get_guest = (guest_t*(*)(iface_t*))get_guest; this->public.get_guest = (guest_t*(*)(iface_t*))get_guest;
@@ -240,6 +307,7 @@ iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
{ {
DBG1("bringing iface '%s' up failed: %m", this->hostif); DBG1("bringing iface '%s' up failed: %m", this->hostif);
} }
this->addresses = linked_list_create();
return &this->public; return &this->public;
} }
+24
View File
@@ -18,6 +18,7 @@
#include <library.h> #include <library.h>
#include <utils/enumerator.h> #include <utils/enumerator.h>
#include <utils/host.h>
#define TAP_DEVICE "/dev/net/tun" #define TAP_DEVICE "/dev/net/tun"
@@ -46,6 +47,29 @@ struct iface_t {
*/ */
char* (*get_hostif)(iface_t *this); char* (*get_hostif)(iface_t *this);
/**
* Add an address to the interface.
*
* @param addr address to add to interface
* @return TRUE if address added
*/
bool (*add_address)(iface_t *this, host_t *addr);
/**
* Create an enumerator over all installed addresses.
*
* @return enumerator over host_t*
*/
enumerator_t* (*create_address_enumerator)(iface_t *this);
/**
* Remove an address from an interface.
*
* @param addr address to remove
* @return TRUE if address removed
*/
bool (*delete_address)(iface_t *this, host_t *addr);
/** /**
* @brief Set the bridge this interface is attached to. * @brief Set the bridge this interface is attached to.
* *
+73
View File
@@ -170,6 +170,18 @@ static VALUE guest_stop(VALUE self)
return self; return self;
} }
static VALUE guest_exec(VALUE self, VALUE cmd)
{
guest_t *guest;
Data_Get_Struct(self, guest_t, guest);
if (!guest->exec(guest, StringValuePtr(cmd)))
{
rb_raise(rb_eRuntimeError, "executing command failed");
}
return self;
}
static VALUE guest_add_iface(VALUE self, VALUE name) static VALUE guest_add_iface(VALUE self, VALUE name)
{ {
guest_t *guest; guest_t *guest;
@@ -246,6 +258,7 @@ static void guest_init()
rb_define_method(rbc_guest, "to_s", guest_to_s, 0); rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
rb_define_method(rbc_guest, "start", guest_start, 0); rb_define_method(rbc_guest, "start", guest_start, 0);
rb_define_method(rbc_guest, "stop", guest_stop, 0); rb_define_method(rbc_guest, "stop", guest_stop, 0);
rb_define_method(rbc_guest, "exec", guest_exec, 1);
rb_define_method(rbc_guest, "add", guest_add_iface, 1); rb_define_method(rbc_guest, "add", guest_add_iface, 1);
rb_define_method(rbc_guest, "[]", guest_get_iface, 1); rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
rb_define_method(rbc_guest, "each", guest_each_iface, -1); rb_define_method(rbc_guest, "each", guest_each_iface, -1);
@@ -399,6 +412,62 @@ static VALUE iface_disconnect(VALUE self)
return self; return self;
} }
static VALUE iface_add_addr(VALUE self, VALUE name)
{
iface_t *iface;
host_t *addr;
addr = host_create_from_string(StringValuePtr(name), 0);
if (!addr)
{
rb_raise(rb_eRuntimeError, "invalid IP address");
}
Data_Get_Struct(self, iface_t, iface);
if (!iface->add_address(iface, addr))
{
rb_raise(rb_eRuntimeError, "adding address failed");
}
return self;
}
static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
{
enumerator_t *enumerator;
iface_t *iface;
host_t *addr;
char buf[64];
if (!rb_block_given_p())
{
rb_raise(rb_eArgError, "must be called with a block");
}
Data_Get_Struct(self, iface_t, iface);
enumerator = iface->create_address_enumerator(iface);
while (enumerator->enumerate(enumerator, &addr))
{
snprintf(buf, sizeof(buf), "%H", addr);
rb_yield(rb_str_new2(buf));
}
enumerator->destroy(enumerator);
return self;
}
static VALUE iface_del_addr(VALUE self, VALUE vaddr)
{
iface_t *iface;
host_t *addr;
addr = host_create_from_string(StringValuePtr(vaddr), 0);
Data_Get_Struct(self, iface_t, iface);
if (!iface->delete_address(iface, addr))
{
addr->destroy(addr);
rb_raise(rb_eRuntimeError, "address not found");
}
addr->destroy(addr);
return self;
}
static VALUE iface_delete(VALUE self) static VALUE iface_delete(VALUE self)
{ {
guest_t *guest; guest_t *guest;
@@ -416,7 +485,11 @@ static void iface_init()
rb_define_method(rbc_iface, "to_s", iface_to_s, 0); rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
rb_define_method(rbc_iface, "connect", iface_connect, 1); rb_define_method(rbc_iface, "connect", iface_connect, 1);
rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0); rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
rb_define_method(rbc_iface, "add", iface_add_addr, 1);
rb_define_method(rbc_iface, "del", iface_del_addr, 1);
rb_define_method(rbc_iface, "each", iface_each_addr, -1);
rb_define_method(rbc_iface, "delete", iface_delete, 0); rb_define_method(rbc_iface, "delete", iface_delete, 0);
rb_include_module(rbc_iface, rb_mEnumerable);
} }
/** /**
+22
View File
@@ -197,6 +197,27 @@ static bool del_iface(private_mconsole_t *this, char *guest)
return TRUE; return TRUE;
} }
/**
* Implementation of mconsole_t.exec
*/
static bool exec(private_mconsole_t *this, char *cmd)
{
char buf[512];
int len;
len = snprintf(buf, sizeof(buf), "exec %s", cmd);
if (len < 0 || len >= sizeof(buf))
{
return -1;
}
if (request(this, buf, buf, &len) != 0)
{
DBG1("exec failed: %.*s", len, buf);
return FALSE;
}
return TRUE;
}
/** /**
* Poll until guest is ready * Poll until guest is ready
*/ */
@@ -338,6 +359,7 @@ mconsole_t *mconsole_create(char *notify, void(*idle)(void))
this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface; 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.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
this->public.exec = (bool(*)(mconsole_t*, char *cmd))exec;
this->public.destroy = (void*)destroy; this->public.destroy = (void*)destroy;
this->idle = idle; this->idle = idle;
+5
View File
@@ -42,6 +42,11 @@ struct mconsole_t {
*/ */
bool (*del_iface)(mconsole_t *this, char *guest); bool (*del_iface)(mconsole_t *this, char *guest);
/**
* Execute a command in the UML host.
*/
bool (*exec)(mconsole_t *this, char *cmd);
/** /**
* @brief Destroy the mconsole instance * @brief Destroy the mconsole instance
*/ */
@@ -0,0 +1,63 @@
--- a/arch/um/drivers/mconsole_kern.c 2008-04-17 04:49:44.000000000 +0200
+++ b/arch/um/drivers/mconsole_kern.c 2008-07-07 13:55:48.000000000 +0200
@@ -4,6 +4,7 @@
* Licensed under the GPL
*/
+#include "linux/kmod.h"
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/interrupt.h>
@@ -199,6 +200,24 @@
}
#endif
+void mconsole_exec(struct mc_request *req)
+{
+ int res;
+
+ char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+ char *argv[] = { "/bin/sh", "-c", req->request.data + strlen("exec "), NULL };
+ res = call_usermodehelper("/bin/sh", argv, envp, 0);
+
+ if (res < 0) {
+ char buf[60];
+ snprintf(buf, 60, "call_usermodehelper failed in mconsole_exec with error code: %d", -res);
+ mconsole_reply(req, buf, 1, 0);
+ return;
+ }
+
+ mconsole_reply(req, "The command has been started successfully.", 0, 0);
+}
+
void mconsole_proc(struct mc_request *req)
{
char path[64];
@@ -270,6 +289,7 @@
stop - pause the UML; it will do nothing until it receives a 'go' \n\
go - continue the UML after a 'stop' \n\
log <string> - make UML enter <string> into the kernel log\n\
+ exec <string> - pass <string> to /bin/sh -c in guest\n\
proc <file> - returns the contents of the UML's /proc/<file>\n\
stack <pid> - returns the stack of the specified pid\n\
"
--- a/arch/um/drivers/mconsole_user.c 2008-05-21 18:34:47.000000000 +0200
+++ b/arch/um/drivers/mconsole_user.c 2008-07-07 13:47:13.000000000 +0200
@@ -32,6 +32,7 @@
{ "stop", mconsole_stop, MCONSOLE_PROC },
{ "go", mconsole_go, MCONSOLE_INTR },
{ "log", mconsole_log, MCONSOLE_INTR },
+ { "exec", mconsole_exec, MCONSOLE_PROC },
{ "proc", mconsole_proc, MCONSOLE_PROC },
{ "stack", mconsole_stack, MCONSOLE_INTR },
};
--- a/arch/um/include/mconsole.h 2008-04-17 04:49:44.000000000 +0200
+++ b/arch/um/include/mconsole.h 2008-07-07 13:46:56.000000000 +0200
@@ -85,6 +85,7 @@
extern void mconsole_stop(struct mc_request *req);
extern void mconsole_go(struct mc_request *req);
extern void mconsole_log(struct mc_request *req);
+extern void mconsole_exec(struct mc_request *req);
extern void mconsole_proc(struct mc_request *req);
extern void mconsole_stack(struct mc_request *req);