Statistics
| Branch: | Revision:

root / hw / vhost_net.c @ 3b4b86aa

History | View | Annotate | Download (4.6 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
    return features;
55
}
56

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

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

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

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

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

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

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

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

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

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

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

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

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

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