Hi list,
Attached is a patch that I developed in Rusty's lguest hacking session
at LCA. It adds a remote control port to the launcher. There's plenty
wrong with this patch but I'm not going to have time to clean it up
anytime soon and I figured it was better to offer it to you for
inspiration or amusement rather than leave it forgotten on my laptop.
Things that need doing:
- If the control FIFO gets closed, reopen it so we can accept more
commands from it. This would allow "echo command > control.fifo".
- Make the command "parser" (such that it is) smarter and probably give
it a table of command handler functions, otherwise the code is going
to get really messy really fast.
- To implement the "status" command I needed to get at the device list.
The fastest way to do that was to make it global. All the code that
currently passes a pointer to the list around should be pruned to use
the global list. Alternatively, remove the global and find another
way to let the control handler get the list (perhaps making devices
point back to their list). Ultimately its a design question that I
can't answer.
I'm not currently subscribed to this list. I may subscribe later if I
find time to hack on lguest a bit more. I do have some ideas :)
Cheers,
Rob.
diff -U3 linux-plastic-2.6.23.12/Documentation/lguest/lguest.c linux-plastic-2.6.23.12-lguest/Documentation/lguest/lguest.c
--- linux-plastic-2.6.23.12/Documentation/lguest/lguest.c 2007-12-19 08:55:57.000000000 +1100
+++ linux-plastic-2.6.23.12-lguest/Documentation/lguest/lguest.c 2008-01-31 11:53:47.000000000 +1100
@@ -85,11 +85,18 @@
struct device **lastdev;
};
+/* The list of Guest devices, based on command line arguments. */
+struct device_list device_list;
+
/* The device structure describes a single device. */
struct device
{
/* The linked-list pointer. */
struct device *next;
+
+ /* The name of the device. */
+ const char *name;
+
/* The descriptor for this device, as mapped into the Guest. */
struct lguest_device_desc *desc;
/* The memory page(s) of this device, if any. Also mapped in Guest. */
@@ -780,6 +787,43 @@
return writev(STDOUT_FILENO, iov, num);
}
+static bool handle_control_input(int fd, struct device *dev)
+{
+ char buf[1024];
+ int nread;
+ struct device *scan;
+
+ nread = read(dev->fd, buf, 1024);
+ if (nread < 0) {
+ warn("launcher: Couldn't read from control fifo");
+ return false;
+ }
+
+ /* XXX They disconnected. This is dead forevermore. If you like, you could
+ * close our end, reopen it, dup the new fd back onto dev->fd (which is in
+ * a select set) then return true and carry on as before. If you like.
+ */
+ if (nread == 0)
+ return false;
+
+ if (nread >= 6 && !strncmp(buf, "status", 6)) {
+ for (scan = device_list.dev; scan != NULL; scan = scan->next) {
+ printf("device status: %s\n", scan->name);
+ printf(" type: 0x%04x\n", scan->desc->type);
+ printf("features: 0x%04x\n", scan->desc->features);
+ printf(" status: 0x%04x\n", scan->desc->status);
+ if (scan->desc->num_pages)
+ printf(" memory: %d pages at %p\n", scan->desc->num_pages, scan->mem);
+
+ }
+ return true;
+ }
+
+ printf("control: %.*s\n", nread, buf);
+
+ return true;
+}
+
/* Guest->Host network output is also pretty easy. */
static u32 handle_tun_output(int fd, const struct iovec *iov,
unsigned num, struct device *dev)
@@ -1011,6 +1055,7 @@
* including caling new_dev_desc() to allocate the descriptor and device
* memory. */
static struct device *new_device(struct device_list *devices,
+ const char *name,
u16 type, u16 num_pages, u16 features,
int fd,
bool (*handle_input)(int, struct device *),
@@ -1031,6 +1076,7 @@
devices->lastdev = &dev->next;
/* Now we populate the fields one at a time. */
+ dev->name = name;
dev->fd = fd;
/* If we have an input handler for this file descriptor, then we add it
* to the device_list's fdset and maxfd. */
@@ -1044,6 +1090,18 @@
return dev;
}
+static void setup_control(const char *control_fifo_name, struct device_list *devices)
+{
+ int fd;
+
+ if (mkfifo(control_fifo_name, 0600) < 0 && errno != EEXIST)
+ err(1, "Couldn't create control fifo %s", control_fifo_name);
+
+ fd = open_or_die(control_fifo_name, O_RDONLY | O_NONBLOCK);
+
+ new_device(devices, "control", 0xffff, 0, 0, fd, handle_control_input, 0, NULL);
+}
+
/* Our first setup routine is the console. It's a fairly simple device, but
* UNIX tty handling makes it uglier than it could be. */
static void setup_console(struct device_list *devices)
@@ -1064,7 +1122,7 @@
/* We don't currently require any memory for the console, so we ask for
* 0 pages. */
- dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
+ dev = new_device(devices, "console", LGUEST_DEVICE_T_CONSOLE, 0, 0,
STDIN_FILENO, handle_console_input,
LGUEST_CONSOLE_DMA_KEY, handle_console_output);
/* We store the console state in dev->priv, and initialize it. */
@@ -1090,7 +1148,7 @@
/* We want one page, and have no input handler (the block file never
* has anything interesting to say to us). Our timing will be quite
* random, so it should be a reasonable randomness source. */
- dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
+ dev = new_device(devices, "block", LGUEST_DEVICE_T_BLOCK, 1,
LGUEST_DEVICE_F_RANDOMNESS,
fd, NULL, 0, handle_block_output);
@@ -1170,7 +1228,7 @@
* no checksum is needed. We never touch this device again; it's
* between the Guests on the network, so we don't register input or
* output handlers. */
- dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+ dev = new_device(devices, "net", LGUEST_DEVICE_T_NET, 1,
find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
-1, NULL, 0, NULL);
@@ -1277,7 +1335,7 @@
*
* We will put our MAC address is slot 0 for the Guest to see, so
* it will send packets to us using the key "peer_offset(0)": */
- dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+ dev = new_device(devices, "net", LGUEST_DEVICE_T_NET, 1,
NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
handle_tun_input, peer_offset(0), handle_tun_output);
@@ -1369,13 +1427,14 @@
{ "tunnet", 1, NULL, 't' },
{ "block", 1, NULL, 'b' },
{ "initrd", 1, NULL, 'i' },
+ { "control", 1, NULL, 'c' },
{ NULL },
};
static void usage(void)
{
errx(1, "Usage: lguest [--verbose] "
"[--sharenet=<filename>|--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
- "|--block=<filename>|--initrd=<filename>]...\n"
+ "|--block=<filename>|--initrd=<filename>|--control=<fifo>]...\n"
"<mem-in-mb> vmlinux [args...]");
}
@@ -1401,12 +1460,12 @@
unsigned long mem = 0, pgdir, start, page_offset, initrd_size = 0;
/* A temporary and the /dev/lguest file descriptor. */
int i, c, lguest_fd;
- /* The list of Guest devices, based on command line arguments. */
- struct device_list device_list;
/* The boot information for the Guest: at guest-physical address 0. */
void *boot = (void *)0;
/* If they specify an initrd file to load. */
const char *initrd_name = NULL;
+ /* If they specify a control fifo to open. */
+ const char *control_fifo_name = NULL;
/* First we initialize the device list. Since console and network
* device receive input from a file descriptor, we keep an fdset
@@ -1449,6 +1508,9 @@
case 'i':
initrd_name = optarg;
break;
+ case 'c':
+ control_fifo_name = optarg;
+ break;
default:
warnx("Unknown argument %s", argv[optind]);
usage();
@@ -1459,6 +1521,9 @@
if (optind + 2 > argc)
usage();
+ if (control_fifo_name)
+ setup_control(control_fifo_name, &device_list);
+
/* We always have a console device */
setup_console(&device_list);
_______________________________________________
Lguest mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/lguest