[<prev] [next>] [day] [month] [year] [list]
Message-Id: <11928036793399-git-send-email-ericvh@gmail.com>
Date: Fri, 19 Oct 2007 09:21:19 -0500
From: ericvh@...il.com
To: lguest@...abds.org, v9fs-developer@...ts.sourceforge.net,
linux-kernel@...r.kernel.org
Cc: Eric Van Hensbergen <ericvh@...il.com>
Subject: [PATCH] lguest: add 9p socket gateway to launcher
From: Eric Van Hensbergen <ericvh@...il.com>
This adds code to setup a gateway between virtio and a 9p server on the other
side of a TCP/IP socket. I looked into trying to come up with more of a
"plug-in" model for such lguest launcher extensions, but wasn't happy with
any of the alternatives I had initially come up with.
Signed-off-by: Eric Van Hensbergen <ericvh@...il.com>
---
Documentation/lguest/lguest.c | 127 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 127 insertions(+), 0 deletions(-)
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index ea88188..eb3707f 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -51,6 +51,7 @@ typedef uint8_t u8;
#include "linux/virtio_net.h"
#include "linux/virtio_blk.h"
#include "linux/virtio_console.h"
+#include "linux/virtio_9p.h"
#include "linux/virtio_ring.h"
#include "asm/e820.h"
/*:*/
@@ -1466,6 +1467,127 @@ static void setup_block_file(const char *filename)
}
/* That's the end of device setup. */
+/* 9p transport code.
+ * This code implements the host side of the 9p transport. Right now
+ * this is heavily based on the console code and just proxies data to
+ * a socket connected to an external server.
+ */
+/* This is the routine proxies 9p channel input */
+static bool handle_9p_input(int fd, struct device *dev)
+{
+ int len;
+ unsigned int head, in_num, out_num;
+ struct iovec iov[dev->vq->vring.num];
+
+ /* First we get the console buffer from the Guest. */
+ head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+
+ /* If they're not ready for input, stop listening to this file
+ * descriptor. We'll start again once they add an input buffer. */
+ if (head == dev->vq->vring.num)
+ return false;
+
+ if (out_num)
+ errx(1, "Output buffers in console in queue?");
+
+ /* This is why we convert to iovecs: the readv() call uses them, and so
+ * it reads straight into the Guest's buffer. */
+ len = readv(dev->fd, iov, in_num);
+ if (len == 0)
+ err(1, "9p: zero length read!");
+
+ if (len < 0) /* Something has gone horribly wrong */
+ errx(1, "9p: input readv returned %d", len);
+
+ /* Now, if we didn't read anything, return failure */
+ if (!len)
+ return false;
+
+ /* Tell the Guest about the new input. */
+ add_used_and_trigger(fd, dev->vq, head, len);
+
+ /* Everything went OK! */
+ return true;
+}
+
+/* Proxy output to socket - similar to console, without the hardcoded fd */
+static void handle_9p_output(int fd, struct virtqueue *vq)
+{
+ unsigned int head, out, in;
+ int len;
+ struct iovec iov[vq->vring.num];
+
+ /* Keep getting output buffers from the Guest until we run out. */
+ while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
+ if (in)
+ errx(1, "Input buffers in output queue?");
+ len = writev(vq->dev->fd, iov, out); /* FIXME: ??? */
+ add_used_and_trigger(fd, vq, head, len);
+ }
+}
+
+/* Connect to 9p server (based on spfsclient by Lucho Ionkov) */
+/* We can't use gethostbyname because it makes us link a shared library */
+static int connect_9p(const char *arg)
+{
+ int fd, port;
+ char *addr, *p, *s;
+ struct sockaddr_in saddr;
+ u32 ipaddr;
+
+ if (!arg)
+ err(1, "9p: problem with args");
+
+ addr = strdup(arg);
+ ipaddr = str2ip(addr);
+
+ port = 567;
+ p = strrchr(addr, ':');
+ if (p) {
+ *p = '\0';
+ p++;
+ port = strtol(p, &s, 10);
+ if (*s != '\0')
+ err(1, "9p: invalid port format");
+ }
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ err(1, "9p: problem allocating socket");
+
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+ saddr.sin_addr.s_addr = htonl(ipaddr);
+
+ if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
+ err(1, "9p: problem connecting to server");
+
+ free(addr);
+
+ return fd;
+}
+
+/* This sets up the 9p transport */
+static void setup_9p(const char *addr)
+{
+ struct device *dev;
+ int fd = connect_9p(addr);
+
+ /* We allocate a page to store or channel info and
+ give a unique offset for our dma key */
+ dev = new_device("9p", VIRTIO_ID_9P,
+ fd, handle_9p_input);
+
+ /* For the moment we use two virtqueues, although we should be able
+ * to get by with one */
+ add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
+ add_virtqueue(dev, VIRTQUEUE_NUM, handle_9p_output);
+
+ verbose("device %u: 9p transport\n", devices.device_num++);
+}
+/* End 9p Additions */
+
/*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves
* its input and output, and finally, lays it to rest. */
static void __attribute__((noreturn)) run_guest(int lguest_fd)
@@ -1512,6 +1634,7 @@ static struct option opts[] = {
{ "tunnet", 1, NULL, 't' },
{ "block", 1, NULL, 'b' },
{ "initrd", 1, NULL, 'i' },
+ { "9p", 1, NULL, '9'},
{ NULL },
};
static void usage(void)
@@ -1519,6 +1642,7 @@ static void usage(void)
errx(1, "Usage: lguest [--verbose] "
"[--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
"|--block=<filename>|--initrd=<filename>]...\n"
+ "[--9p=(<ipaddr>:<port>)] "
"<mem-in-mb> vmlinux [args...]");
}
@@ -1581,6 +1705,9 @@ int main(int argc, char *argv[])
case 'i':
initrd_name = optarg;
break;
+ case '9':
+ setup_9p(optarg);
+ break;
default:
warnx("Unknown argument %s", argv[optind]);
usage();
--
1.5.0.2.gfbe3d-dirty
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists