~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/vhost_net.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "qemu-error.h"
 
19
 
 
20
#include "config.h"
 
21
 
 
22
#ifdef CONFIG_VHOST_NET
 
23
#include <linux/vhost.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
    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
 
55
        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
 
56
    }
 
57
    if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
 
58
        features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
 
59
    }
 
60
    return features;
 
61
}
 
62
 
 
63
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
 
64
{
 
65
    net->dev.acked_features = net->dev.backend_features;
 
66
    if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
 
67
        net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
 
68
    }
 
69
    if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
 
70
        net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
 
71
    }
 
72
    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
 
73
        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
 
74
    }
 
75
    if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
 
76
        net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
 
77
    }
 
78
}
 
79
 
 
80
static int vhost_net_get_fd(VLANClientState *backend)
 
81
{
 
82
    switch (backend->info->type) {
 
83
    case NET_CLIENT_TYPE_TAP:
 
84
        return tap_get_fd(backend);
 
85
    default:
 
86
        fprintf(stderr, "vhost-net requires tap backend\n");
 
87
        return -EBADFD;
 
88
    }
 
89
}
 
90
 
 
91
struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
 
92
                                 bool force)
 
93
{
 
94
    int r;
 
95
    struct vhost_net *net = qemu_malloc(sizeof *net);
 
96
    if (!backend) {
 
97
        fprintf(stderr, "vhost-net requires backend to be setup\n");
 
98
        goto fail;
 
99
    }
 
100
    r = vhost_net_get_fd(backend);
 
101
    if (r < 0) {
 
102
        goto fail;
 
103
    }
 
104
    net->vc = backend;
 
105
    net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
 
106
        (1 << VHOST_NET_F_VIRTIO_NET_HDR);
 
107
    net->backend = r;
 
108
 
 
109
    r = vhost_dev_init(&net->dev, devfd, force);
 
110
    if (r < 0) {
 
111
        goto fail;
 
112
    }
 
113
    if (!tap_has_vnet_hdr_len(backend,
 
114
                              sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
 
115
        net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
 
116
    }
 
117
    if (~net->dev.features & net->dev.backend_features) {
 
118
        fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
 
119
                (uint64_t)(~net->dev.features & net->dev.backend_features));
 
120
        vhost_dev_cleanup(&net->dev);
 
121
        goto fail;
 
122
    }
 
123
 
 
124
    /* Set sane init value. Override when guest acks. */
 
125
    vhost_net_ack_features(net, 0);
 
126
    return net;
 
127
fail:
 
128
    qemu_free(net);
 
129
    return NULL;
 
130
}
 
131
 
 
132
bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
 
133
{
 
134
    return vhost_dev_query(&net->dev, dev);
 
135
}
 
136
 
 
137
int vhost_net_start(struct vhost_net *net,
 
138
                    VirtIODevice *dev)
 
139
{
 
140
    struct vhost_vring_file file = { };
 
141
    int r;
 
142
    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
 
143
        tap_set_vnet_hdr_len(net->vc,
 
144
                             sizeof(struct virtio_net_hdr_mrg_rxbuf));
 
145
    }
 
146
 
 
147
    net->dev.nvqs = 2;
 
148
    net->dev.vqs = net->vqs;
 
149
    r = vhost_dev_start(&net->dev, dev);
 
150
    if (r < 0) {
 
151
        return r;
 
152
    }
 
153
 
 
154
    net->vc->info->poll(net->vc, false);
 
155
    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
 
156
    file.fd = net->backend;
 
157
    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
 
158
        r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
 
159
        if (r < 0) {
 
160
            r = -errno;
 
161
            goto fail;
 
162
        }
 
163
    }
 
164
    return 0;
 
165
fail:
 
166
    file.fd = -1;
 
167
    while (file.index-- > 0) {
 
168
        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
 
169
        assert(r >= 0);
 
170
    }
 
171
    net->vc->info->poll(net->vc, true);
 
172
    vhost_dev_stop(&net->dev, dev);
 
173
    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
 
174
        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
 
175
    }
 
176
    return r;
 
177
}
 
178
 
 
179
void vhost_net_stop(struct vhost_net *net,
 
180
                    VirtIODevice *dev)
 
181
{
 
182
    struct vhost_vring_file file = { .fd = -1 };
 
183
 
 
184
    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
 
185
        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
 
186
        assert(r >= 0);
 
187
    }
 
188
    net->vc->info->poll(net->vc, true);
 
189
    vhost_dev_stop(&net->dev, dev);
 
190
    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
 
191
        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
 
192
    }
 
193
}
 
194
 
 
195
void vhost_net_cleanup(struct vhost_net *net)
 
196
{
 
197
    vhost_dev_cleanup(&net->dev);
 
198
    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
 
199
        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
 
200
    }
 
201
    qemu_free(net);
 
202
}
 
203
#else
 
204
struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd,
 
205
                                 bool force)
 
206
{
 
207
    error_report("vhost-net support is not compiled in");
 
208
    return NULL;
 
209
}
 
210
 
 
211
bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
 
212
{
 
213
    return false;
 
214
}
 
215
 
 
216
int vhost_net_start(struct vhost_net *net,
 
217
                    VirtIODevice *dev)
 
218
{
 
219
    return -ENOSYS;
 
220
}
 
221
void vhost_net_stop(struct vhost_net *net,
 
222
                    VirtIODevice *dev)
 
223
{
 
224
}
 
225
 
 
226
void vhost_net_cleanup(struct vhost_net *net)
 
227
{
 
228
}
 
229
 
 
230
unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
 
231
{
 
232
    return features;
 
233
}
 
234
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
 
235
{
 
236
}
 
237
#endif