Statistics
| Branch: | Revision:

root / hw / vhost_net.c @ 7b370f51

History | View | Annotate | Download (4.7 kB)

1
/*
2
 * vhost-net support
3
 *
4
 * Copyright Red Hat, Inc. 2010
5
 *
6
 * Authors:
7
 *  Michael S. Tsirkin <mst@redhat.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 */
12

    
13
#include "net.h"
14
#include "net/tap.h"
15

    
16
#include "virtio-net.h"
17
#include "vhost_net.h"
18

    
19
#include "config.h"
20

    
21
#ifdef CONFIG_VHOST_NET
22
#include <linux/vhost.h>
23
#include <sys/eventfd.h>
24
#include <sys/socket.h>
25
#include <linux/kvm.h>
26
#include <fcntl.h>
27
#include <sys/ioctl.h>
28
#include <linux/virtio_ring.h>
29
#include <netpacket/packet.h>
30
#include <net/ethernet.h>
31
#include <net/if.h>
32
#include <netinet/in.h>
33

    
34
#include <stdio.h>
35

    
36
#include "vhost.h"
37

    
38
struct vhost_net {
39
    struct vhost_dev dev;
40
    struct vhost_virtqueue vqs[2];
41
    int backend;
42
    VLANClientState *vc;
43
};
44

    
45
unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
46
{
47
    /* Clear features not supported by host kernel. */
48
    if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
49
        features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
50
    }
51
    if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
52
        features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
53
    }
54
    features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
55
    return features;
56
}
57

    
58
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
59
{
60
    net->dev.acked_features = net->dev.backend_features;
61
    if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
62
        net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
63
    }
64
    if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
65
        net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
66
    }
67
}
68

    
69
static int vhost_net_get_fd(VLANClientState *backend)
70
{
71
    switch (backend->info->type) {
72
    case NET_CLIENT_TYPE_TAP:
73
        return tap_get_fd(backend);
74
    default:
75
        fprintf(stderr, "vhost-net requires tap backend\n");
76
        return -EBADFD;
77
    }
78
}
79

    
80
struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
81
{
82
    int r;
83
    struct vhost_net *net = qemu_malloc(sizeof *net);
84
    if (!backend) {
85
        fprintf(stderr, "vhost-net requires backend to be setup\n");
86
        goto fail;
87
    }
88
    r = vhost_net_get_fd(backend);
89
    if (r < 0) {
90
        goto fail;
91
    }
92
    net->vc = backend;
93
    net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
94
        (1 << VHOST_NET_F_VIRTIO_NET_HDR);
95
    net->backend = r;
96

    
97
    r = vhost_dev_init(&net->dev, devfd);
98
    if (r < 0) {
99
        goto fail;
100
    }
101
    if (~net->dev.features & net->dev.backend_features) {
102
        fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
103
                (uint64_t)(~net->dev.features & net->dev.backend_features));
104
        vhost_dev_cleanup(&net->dev);
105
        goto fail;
106
    }
107

    
108
    /* Set sane init value. Override when guest acks. */
109
    vhost_net_ack_features(net, 0);
110
    return net;
111
fail:
112
    qemu_free(net);
113
    return NULL;
114
}
115

    
116
int vhost_net_start(struct vhost_net *net,
117
                    VirtIODevice *dev)
118
{
119
    struct vhost_vring_file file = { };
120
    int r;
121

    
122
    net->dev.nvqs = 2;
123
    net->dev.vqs = net->vqs;
124
    r = vhost_dev_start(&net->dev, dev);
125
    if (r < 0) {
126
        return r;
127
    }
128

    
129
    net->vc->info->poll(net->vc, false);
130
    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
131
    file.fd = net->backend;
132
    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
133
        r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
134
        if (r < 0) {
135
            r = -errno;
136
            goto fail;
137
        }
138
    }
139
    return 0;
140
fail:
141
    file.fd = -1;
142
    while (--file.index >= 0) {
143
        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
144
        assert(r >= 0);
145
    }
146
    net->vc->info->poll(net->vc, true);
147
    vhost_dev_stop(&net->dev, dev);
148
    return r;
149
}
150

    
151
void vhost_net_stop(struct vhost_net *net,
152
                    VirtIODevice *dev)
153
{
154
    struct vhost_vring_file file = { .fd = -1 };
155

    
156
    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
157
        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
158
        assert(r >= 0);
159
    }
160
    net->vc->info->poll(net->vc, true);
161
    vhost_dev_stop(&net->dev, dev);
162
}
163

    
164
void vhost_net_cleanup(struct vhost_net *net)
165
{
166
    vhost_dev_cleanup(&net->dev);
167
    qemu_free(net);
168
}
169
#else
170
struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
171
{
172
        return NULL;
173
}
174

    
175
int vhost_net_start(struct vhost_net *net,
176
                    VirtIODevice *dev)
177
{
178
        return -ENOSYS;
179
}
180
void vhost_net_stop(struct vhost_net *net,
181
                    VirtIODevice *dev)
182
{
183
}
184

    
185
void vhost_net_cleanup(struct vhost_net *net)
186
{
187
}
188

    
189
unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
190
{
191
        return features;
192
}
193
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
194
{
195
}
196
#endif