qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] Secure KVM


From: Rusty Russell
Subject: Re: [Qemu-devel] Secure KVM
Date: Tue, 08 Nov 2011 09:36:44 +1030
User-agent: Notmuch/0.6.1-1 (http://notmuchmail.org) Emacs/23.3.1 (i686-pc-linux-gnu)

On Mon, 07 Nov 2011 12:03:38 -0600, Anthony Liguori <address@hidden> wrote:
> So the sandbox loop would look like:
> 
> void main() {
>    setup_devices();
> 
>    read_from_event_channel(main_channel);
>    for i in vrings:
>       check_vring_notification(i);
> }

lguest uses a model where you attach an eventfd to a given virtqueue.
(If you don't have an eventfd registered for a vq, the main process
 returns from the read() of /dev/lguest with the info).

At the moment we use a process per virtqueue, but you could attach the
same eventfd to multiple vqs.

Since you can't select() inside seccomp, the main process could write to
the eventfd to wake up the thread to respond to IPC.

Here's the net output code:

/*
 * The Network
 *
 * Handling output for network is also simple: we get all the output buffers
 * and write them to /dev/net/tun.
 */
struct net_info {
        int tunfd;
};

static void net_output(struct virtqueue *vq)
{
        struct net_info *net_info = vq->dev->priv;
        unsigned int head, out, in;
        struct iovec iov[vq->vring.num];

        /* We usually wait in here for the Guest to give us a packet. */
        head = wait_for_vq_desc(vq, iov, &out, &in);
        if (in)
                errx(1, "Input buffers in net output queue?");
        /*
         * Send the whole thing through to /dev/net/tun.  It expects the exact
         * same format: what a coincidence!
         */
        if (writev(net_info->tunfd, iov, out) < 0)
                warnx("Write to tun failed (%d)?", errno);

        /*
         * Done with that one; wait_for_vq_desc() will send the interrupt if
         * all packets are processed.
         */
        add_used(vq, head, 0);
}

Here's the input thread:

/*
 * Handling network input is a bit trickier, because I've tried to optimize it.
 *
 * First we have a helper routine which tells is if from this file descriptor
 * (ie. the /dev/net/tun device) will block:
 */
static bool will_block(int fd)
{
        fd_set fdset;
        struct timeval zero = { 0, 0 };
        FD_ZERO(&fdset);
        FD_SET(fd, &fdset);
        return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
}

/*
 * This handles packets coming in from the tun device to our Guest.  Like all
 * service routines, it gets called again as soon as it returns, so you don't
 * see a while(1) loop here.
 */
static void net_input(struct virtqueue *vq)
{
        int len;
        unsigned int head, out, in;
        struct iovec iov[vq->vring.num];
        struct net_info *net_info = vq->dev->priv;

        /*
         * Get a descriptor to write an incoming packet into.  This will also
         * send an interrupt if they're out of descriptors.
         */
        head = wait_for_vq_desc(vq, iov, &out, &in);
        if (out)
                errx(1, "Output buffers in net input queue?");

        /*
         * If it looks like we'll block reading from the tun device, send them
         * an interrupt.
         */
        if (vq->pending_used && will_block(net_info->tunfd))
                trigger_irq(vq);

        /*
         * Read in the packet.  This is where we normally wait (when there's no
         * incoming network traffic).
         */
        len = readv(net_info->tunfd, iov, in);
        if (len <= 0)
                warn("Failed to read from tun (%d).", errno);

        /*
         * Mark that packet buffer as used, but don't interrupt here.  We want
         * to wait until we've done as much work as we can.
         */
        add_used(vq, head, len);
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]