Statistics
| Branch: | Revision:

root / net / tap.c @ 7e680753

History | View | Annotate | Download (18.3 kB)

1 5281d757 Mark McLoughlin
/*
2 5281d757 Mark McLoughlin
 * QEMU System Emulator
3 5281d757 Mark McLoughlin
 *
4 5281d757 Mark McLoughlin
 * Copyright (c) 2003-2008 Fabrice Bellard
5 5281d757 Mark McLoughlin
 * Copyright (c) 2009 Red Hat, Inc.
6 5281d757 Mark McLoughlin
 *
7 5281d757 Mark McLoughlin
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 5281d757 Mark McLoughlin
 * of this software and associated documentation files (the "Software"), to deal
9 5281d757 Mark McLoughlin
 * in the Software without restriction, including without limitation the rights
10 5281d757 Mark McLoughlin
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 5281d757 Mark McLoughlin
 * copies of the Software, and to permit persons to whom the Software is
12 5281d757 Mark McLoughlin
 * furnished to do so, subject to the following conditions:
13 5281d757 Mark McLoughlin
 *
14 5281d757 Mark McLoughlin
 * The above copyright notice and this permission notice shall be included in
15 5281d757 Mark McLoughlin
 * all copies or substantial portions of the Software.
16 5281d757 Mark McLoughlin
 *
17 5281d757 Mark McLoughlin
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 5281d757 Mark McLoughlin
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 5281d757 Mark McLoughlin
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 5281d757 Mark McLoughlin
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 5281d757 Mark McLoughlin
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 5281d757 Mark McLoughlin
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 5281d757 Mark McLoughlin
 * THE SOFTWARE.
24 5281d757 Mark McLoughlin
 */
25 5281d757 Mark McLoughlin
26 5281d757 Mark McLoughlin
#include "net/tap.h"
27 5281d757 Mark McLoughlin
28 5281d757 Mark McLoughlin
#include "config-host.h"
29 5281d757 Mark McLoughlin
30 5281d757 Mark McLoughlin
#include <sys/ioctl.h>
31 5281d757 Mark McLoughlin
#include <sys/stat.h>
32 5281d757 Mark McLoughlin
#include <sys/wait.h>
33 71f4effc Alexander Graf
#include <sys/socket.h>
34 5281d757 Mark McLoughlin
#include <net/if.h>
35 5281d757 Mark McLoughlin
36 5281d757 Mark McLoughlin
#include "net.h"
37 5281d757 Mark McLoughlin
#include "sysemu.h"
38 5281d757 Mark McLoughlin
#include "qemu-char.h"
39 5281d757 Mark McLoughlin
#include "qemu-common.h"
40 2f792016 Markus Armbruster
#include "qemu-error.h"
41 5281d757 Mark McLoughlin
42 5281d757 Mark McLoughlin
#include "net/tap-linux.h"
43 5281d757 Mark McLoughlin
44 82b0d80e Michael S. Tsirkin
#include "hw/vhost_net.h"
45 82b0d80e Michael S. Tsirkin
46 5281d757 Mark McLoughlin
/* Maximum GSO packet size (64k) plus plenty of room for
47 5281d757 Mark McLoughlin
 * the ethernet and virtio_net headers
48 5281d757 Mark McLoughlin
 */
49 5281d757 Mark McLoughlin
#define TAP_BUFSIZE (4096 + 65536)
50 5281d757 Mark McLoughlin
51 5281d757 Mark McLoughlin
typedef struct TAPState {
52 3e35ba93 Mark McLoughlin
    VLANClientState nc;
53 5281d757 Mark McLoughlin
    int fd;
54 5281d757 Mark McLoughlin
    char down_script[1024];
55 5281d757 Mark McLoughlin
    char down_script_arg[128];
56 5281d757 Mark McLoughlin
    uint8_t buf[TAP_BUFSIZE];
57 5281d757 Mark McLoughlin
    unsigned int read_poll : 1;
58 5281d757 Mark McLoughlin
    unsigned int write_poll : 1;
59 5281d757 Mark McLoughlin
    unsigned int using_vnet_hdr : 1;
60 5281d757 Mark McLoughlin
    unsigned int has_ufo: 1;
61 82b0d80e Michael S. Tsirkin
    VHostNetState *vhost_net;
62 ef4252b1 Michael S. Tsirkin
    unsigned host_vnet_hdr_len;
63 5281d757 Mark McLoughlin
} TAPState;
64 5281d757 Mark McLoughlin
65 5281d757 Mark McLoughlin
static int launch_script(const char *setup_script, const char *ifname, int fd);
66 5281d757 Mark McLoughlin
67 5281d757 Mark McLoughlin
static int tap_can_send(void *opaque);
68 5281d757 Mark McLoughlin
static void tap_send(void *opaque);
69 5281d757 Mark McLoughlin
static void tap_writable(void *opaque);
70 5281d757 Mark McLoughlin
71 5281d757 Mark McLoughlin
static void tap_update_fd_handler(TAPState *s)
72 5281d757 Mark McLoughlin
{
73 5281d757 Mark McLoughlin
    qemu_set_fd_handler2(s->fd,
74 5281d757 Mark McLoughlin
                         s->read_poll  ? tap_can_send : NULL,
75 5281d757 Mark McLoughlin
                         s->read_poll  ? tap_send     : NULL,
76 5281d757 Mark McLoughlin
                         s->write_poll ? tap_writable : NULL,
77 5281d757 Mark McLoughlin
                         s);
78 5281d757 Mark McLoughlin
}
79 5281d757 Mark McLoughlin
80 5281d757 Mark McLoughlin
static void tap_read_poll(TAPState *s, int enable)
81 5281d757 Mark McLoughlin
{
82 5281d757 Mark McLoughlin
    s->read_poll = !!enable;
83 5281d757 Mark McLoughlin
    tap_update_fd_handler(s);
84 5281d757 Mark McLoughlin
}
85 5281d757 Mark McLoughlin
86 5281d757 Mark McLoughlin
static void tap_write_poll(TAPState *s, int enable)
87 5281d757 Mark McLoughlin
{
88 5281d757 Mark McLoughlin
    s->write_poll = !!enable;
89 5281d757 Mark McLoughlin
    tap_update_fd_handler(s);
90 5281d757 Mark McLoughlin
}
91 5281d757 Mark McLoughlin
92 5281d757 Mark McLoughlin
static void tap_writable(void *opaque)
93 5281d757 Mark McLoughlin
{
94 5281d757 Mark McLoughlin
    TAPState *s = opaque;
95 5281d757 Mark McLoughlin
96 5281d757 Mark McLoughlin
    tap_write_poll(s, 0);
97 5281d757 Mark McLoughlin
98 3e35ba93 Mark McLoughlin
    qemu_flush_queued_packets(&s->nc);
99 5281d757 Mark McLoughlin
}
100 5281d757 Mark McLoughlin
101 5281d757 Mark McLoughlin
static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt)
102 5281d757 Mark McLoughlin
{
103 5281d757 Mark McLoughlin
    ssize_t len;
104 5281d757 Mark McLoughlin
105 5281d757 Mark McLoughlin
    do {
106 5281d757 Mark McLoughlin
        len = writev(s->fd, iov, iovcnt);
107 5281d757 Mark McLoughlin
    } while (len == -1 && errno == EINTR);
108 5281d757 Mark McLoughlin
109 5281d757 Mark McLoughlin
    if (len == -1 && errno == EAGAIN) {
110 5281d757 Mark McLoughlin
        tap_write_poll(s, 1);
111 5281d757 Mark McLoughlin
        return 0;
112 5281d757 Mark McLoughlin
    }
113 5281d757 Mark McLoughlin
114 5281d757 Mark McLoughlin
    return len;
115 5281d757 Mark McLoughlin
}
116 5281d757 Mark McLoughlin
117 3e35ba93 Mark McLoughlin
static ssize_t tap_receive_iov(VLANClientState *nc, const struct iovec *iov,
118 5281d757 Mark McLoughlin
                               int iovcnt)
119 5281d757 Mark McLoughlin
{
120 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
121 5281d757 Mark McLoughlin
    const struct iovec *iovp = iov;
122 5281d757 Mark McLoughlin
    struct iovec iov_copy[iovcnt + 1];
123 ef4252b1 Michael S. Tsirkin
    struct virtio_net_hdr_mrg_rxbuf hdr = { };
124 5281d757 Mark McLoughlin
125 ef4252b1 Michael S. Tsirkin
    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
126 5281d757 Mark McLoughlin
        iov_copy[0].iov_base = &hdr;
127 ef4252b1 Michael S. Tsirkin
        iov_copy[0].iov_len =  s->host_vnet_hdr_len;
128 5281d757 Mark McLoughlin
        memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
129 5281d757 Mark McLoughlin
        iovp = iov_copy;
130 5281d757 Mark McLoughlin
        iovcnt++;
131 5281d757 Mark McLoughlin
    }
132 5281d757 Mark McLoughlin
133 5281d757 Mark McLoughlin
    return tap_write_packet(s, iovp, iovcnt);
134 5281d757 Mark McLoughlin
}
135 5281d757 Mark McLoughlin
136 3e35ba93 Mark McLoughlin
static ssize_t tap_receive_raw(VLANClientState *nc, const uint8_t *buf, size_t size)
137 5281d757 Mark McLoughlin
{
138 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
139 5281d757 Mark McLoughlin
    struct iovec iov[2];
140 5281d757 Mark McLoughlin
    int iovcnt = 0;
141 ef4252b1 Michael S. Tsirkin
    struct virtio_net_hdr_mrg_rxbuf hdr = { };
142 5281d757 Mark McLoughlin
143 ef4252b1 Michael S. Tsirkin
    if (s->host_vnet_hdr_len) {
144 5281d757 Mark McLoughlin
        iov[iovcnt].iov_base = &hdr;
145 ef4252b1 Michael S. Tsirkin
        iov[iovcnt].iov_len  = s->host_vnet_hdr_len;
146 5281d757 Mark McLoughlin
        iovcnt++;
147 5281d757 Mark McLoughlin
    }
148 5281d757 Mark McLoughlin
149 5281d757 Mark McLoughlin
    iov[iovcnt].iov_base = (char *)buf;
150 5281d757 Mark McLoughlin
    iov[iovcnt].iov_len  = size;
151 5281d757 Mark McLoughlin
    iovcnt++;
152 5281d757 Mark McLoughlin
153 5281d757 Mark McLoughlin
    return tap_write_packet(s, iov, iovcnt);
154 5281d757 Mark McLoughlin
}
155 5281d757 Mark McLoughlin
156 3e35ba93 Mark McLoughlin
static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
157 5281d757 Mark McLoughlin
{
158 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
159 5281d757 Mark McLoughlin
    struct iovec iov[1];
160 5281d757 Mark McLoughlin
161 ef4252b1 Michael S. Tsirkin
    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
162 3e35ba93 Mark McLoughlin
        return tap_receive_raw(nc, buf, size);
163 5281d757 Mark McLoughlin
    }
164 5281d757 Mark McLoughlin
165 5281d757 Mark McLoughlin
    iov[0].iov_base = (char *)buf;
166 5281d757 Mark McLoughlin
    iov[0].iov_len  = size;
167 5281d757 Mark McLoughlin
168 5281d757 Mark McLoughlin
    return tap_write_packet(s, iov, 1);
169 5281d757 Mark McLoughlin
}
170 5281d757 Mark McLoughlin
171 5281d757 Mark McLoughlin
static int tap_can_send(void *opaque)
172 5281d757 Mark McLoughlin
{
173 5281d757 Mark McLoughlin
    TAPState *s = opaque;
174 5281d757 Mark McLoughlin
175 3e35ba93 Mark McLoughlin
    return qemu_can_send_packet(&s->nc);
176 5281d757 Mark McLoughlin
}
177 5281d757 Mark McLoughlin
178 966ea5ec Mark McLoughlin
#ifndef __sun__
179 966ea5ec Mark McLoughlin
ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
180 5281d757 Mark McLoughlin
{
181 5281d757 Mark McLoughlin
    return read(tapfd, buf, maxlen);
182 5281d757 Mark McLoughlin
}
183 5281d757 Mark McLoughlin
#endif
184 5281d757 Mark McLoughlin
185 3e35ba93 Mark McLoughlin
static void tap_send_completed(VLANClientState *nc, ssize_t len)
186 5281d757 Mark McLoughlin
{
187 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
188 5281d757 Mark McLoughlin
    tap_read_poll(s, 1);
189 5281d757 Mark McLoughlin
}
190 5281d757 Mark McLoughlin
191 5281d757 Mark McLoughlin
static void tap_send(void *opaque)
192 5281d757 Mark McLoughlin
{
193 5281d757 Mark McLoughlin
    TAPState *s = opaque;
194 5281d757 Mark McLoughlin
    int size;
195 5281d757 Mark McLoughlin
196 5819c918 Mark McLoughlin
    do {
197 5819c918 Mark McLoughlin
        uint8_t *buf = s->buf;
198 5819c918 Mark McLoughlin
199 5819c918 Mark McLoughlin
        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
200 5819c918 Mark McLoughlin
        if (size <= 0) {
201 5819c918 Mark McLoughlin
            break;
202 5819c918 Mark McLoughlin
        }
203 5819c918 Mark McLoughlin
204 ef4252b1 Michael S. Tsirkin
        if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
205 ef4252b1 Michael S. Tsirkin
            buf  += s->host_vnet_hdr_len;
206 ef4252b1 Michael S. Tsirkin
            size -= s->host_vnet_hdr_len;
207 5819c918 Mark McLoughlin
        }
208 5819c918 Mark McLoughlin
209 3e35ba93 Mark McLoughlin
        size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
210 5819c918 Mark McLoughlin
        if (size == 0) {
211 5819c918 Mark McLoughlin
            tap_read_poll(s, 0);
212 5819c918 Mark McLoughlin
        }
213 3e35ba93 Mark McLoughlin
    } while (size > 0 && qemu_can_send_packet(&s->nc));
214 5281d757 Mark McLoughlin
}
215 5281d757 Mark McLoughlin
216 3e35ba93 Mark McLoughlin
int tap_has_ufo(VLANClientState *nc)
217 5281d757 Mark McLoughlin
{
218 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
219 5281d757 Mark McLoughlin
220 665a3b07 Mark McLoughlin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
221 5281d757 Mark McLoughlin
222 5281d757 Mark McLoughlin
    return s->has_ufo;
223 5281d757 Mark McLoughlin
}
224 5281d757 Mark McLoughlin
225 3e35ba93 Mark McLoughlin
int tap_has_vnet_hdr(VLANClientState *nc)
226 5281d757 Mark McLoughlin
{
227 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
228 5281d757 Mark McLoughlin
229 665a3b07 Mark McLoughlin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
230 5281d757 Mark McLoughlin
231 ef4252b1 Michael S. Tsirkin
    return !!s->host_vnet_hdr_len;
232 5281d757 Mark McLoughlin
}
233 5281d757 Mark McLoughlin
234 445d892f Michael S. Tsirkin
int tap_has_vnet_hdr_len(VLANClientState *nc, int len)
235 445d892f Michael S. Tsirkin
{
236 445d892f Michael S. Tsirkin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
237 445d892f Michael S. Tsirkin
238 445d892f Michael S. Tsirkin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
239 445d892f Michael S. Tsirkin
240 445d892f Michael S. Tsirkin
    return tap_probe_vnet_hdr_len(s->fd, len);
241 445d892f Michael S. Tsirkin
}
242 445d892f Michael S. Tsirkin
243 445d892f Michael S. Tsirkin
void tap_set_vnet_hdr_len(VLANClientState *nc, int len)
244 445d892f Michael S. Tsirkin
{
245 445d892f Michael S. Tsirkin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
246 445d892f Michael S. Tsirkin
247 445d892f Michael S. Tsirkin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
248 445d892f Michael S. Tsirkin
    assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
249 445d892f Michael S. Tsirkin
           len == sizeof(struct virtio_net_hdr));
250 445d892f Michael S. Tsirkin
251 445d892f Michael S. Tsirkin
    tap_fd_set_vnet_hdr_len(s->fd, len);
252 445d892f Michael S. Tsirkin
    s->host_vnet_hdr_len = len;
253 445d892f Michael S. Tsirkin
}
254 445d892f Michael S. Tsirkin
255 3e35ba93 Mark McLoughlin
void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr)
256 5281d757 Mark McLoughlin
{
257 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
258 5281d757 Mark McLoughlin
259 5281d757 Mark McLoughlin
    using_vnet_hdr = using_vnet_hdr != 0;
260 5281d757 Mark McLoughlin
261 665a3b07 Mark McLoughlin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
262 ef4252b1 Michael S. Tsirkin
    assert(!!s->host_vnet_hdr_len == using_vnet_hdr);
263 5281d757 Mark McLoughlin
264 5281d757 Mark McLoughlin
    s->using_vnet_hdr = using_vnet_hdr;
265 5281d757 Mark McLoughlin
}
266 5281d757 Mark McLoughlin
267 3e35ba93 Mark McLoughlin
void tap_set_offload(VLANClientState *nc, int csum, int tso4,
268 5281d757 Mark McLoughlin
                     int tso6, int ecn, int ufo)
269 5281d757 Mark McLoughlin
{
270 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
271 27a6375d Michael S. Tsirkin
    if (s->fd < 0) {
272 27a6375d Michael S. Tsirkin
        return;
273 27a6375d Michael S. Tsirkin
    }
274 5281d757 Mark McLoughlin
275 27a6375d Michael S. Tsirkin
    tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
276 5281d757 Mark McLoughlin
}
277 5281d757 Mark McLoughlin
278 3e35ba93 Mark McLoughlin
static void tap_cleanup(VLANClientState *nc)
279 5281d757 Mark McLoughlin
{
280 3e35ba93 Mark McLoughlin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
281 5281d757 Mark McLoughlin
282 82b0d80e Michael S. Tsirkin
    if (s->vhost_net) {
283 82b0d80e Michael S. Tsirkin
        vhost_net_cleanup(s->vhost_net);
284 43849424 Michael S. Tsirkin
        s->vhost_net = NULL;
285 82b0d80e Michael S. Tsirkin
    }
286 82b0d80e Michael S. Tsirkin
287 3e35ba93 Mark McLoughlin
    qemu_purge_queued_packets(nc);
288 5281d757 Mark McLoughlin
289 5281d757 Mark McLoughlin
    if (s->down_script[0])
290 5281d757 Mark McLoughlin
        launch_script(s->down_script, s->down_script_arg, s->fd);
291 5281d757 Mark McLoughlin
292 5281d757 Mark McLoughlin
    tap_read_poll(s, 0);
293 5281d757 Mark McLoughlin
    tap_write_poll(s, 0);
294 5281d757 Mark McLoughlin
    close(s->fd);
295 27a6375d Michael S. Tsirkin
    s->fd = -1;
296 5281d757 Mark McLoughlin
}
297 5281d757 Mark McLoughlin
298 ceb69615 Michael S. Tsirkin
static void tap_poll(VLANClientState *nc, bool enable)
299 ceb69615 Michael S. Tsirkin
{
300 ceb69615 Michael S. Tsirkin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
301 ceb69615 Michael S. Tsirkin
    tap_read_poll(s, enable);
302 ceb69615 Michael S. Tsirkin
    tap_write_poll(s, enable);
303 ceb69615 Michael S. Tsirkin
}
304 ceb69615 Michael S. Tsirkin
305 95d528a2 Michael S. Tsirkin
int tap_get_fd(VLANClientState *nc)
306 95d528a2 Michael S. Tsirkin
{
307 95d528a2 Michael S. Tsirkin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
308 95d528a2 Michael S. Tsirkin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
309 95d528a2 Michael S. Tsirkin
    return s->fd;
310 95d528a2 Michael S. Tsirkin
}
311 95d528a2 Michael S. Tsirkin
312 5281d757 Mark McLoughlin
/* fd support */
313 5281d757 Mark McLoughlin
314 3e35ba93 Mark McLoughlin
static NetClientInfo net_tap_info = {
315 3e35ba93 Mark McLoughlin
    .type = NET_CLIENT_TYPE_TAP,
316 3e35ba93 Mark McLoughlin
    .size = sizeof(TAPState),
317 3e35ba93 Mark McLoughlin
    .receive = tap_receive,
318 3e35ba93 Mark McLoughlin
    .receive_raw = tap_receive_raw,
319 3e35ba93 Mark McLoughlin
    .receive_iov = tap_receive_iov,
320 ceb69615 Michael S. Tsirkin
    .poll = tap_poll,
321 3e35ba93 Mark McLoughlin
    .cleanup = tap_cleanup,
322 3e35ba93 Mark McLoughlin
};
323 3e35ba93 Mark McLoughlin
324 5281d757 Mark McLoughlin
static TAPState *net_tap_fd_init(VLANState *vlan,
325 5281d757 Mark McLoughlin
                                 const char *model,
326 5281d757 Mark McLoughlin
                                 const char *name,
327 5281d757 Mark McLoughlin
                                 int fd,
328 5281d757 Mark McLoughlin
                                 int vnet_hdr)
329 5281d757 Mark McLoughlin
{
330 3e35ba93 Mark McLoughlin
    VLANClientState *nc;
331 5281d757 Mark McLoughlin
    TAPState *s;
332 5281d757 Mark McLoughlin
333 3e35ba93 Mark McLoughlin
    nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name);
334 3e35ba93 Mark McLoughlin
335 3e35ba93 Mark McLoughlin
    s = DO_UPCAST(TAPState, nc, nc);
336 3e35ba93 Mark McLoughlin
337 5281d757 Mark McLoughlin
    s->fd = fd;
338 ef4252b1 Michael S. Tsirkin
    s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
339 5281d757 Mark McLoughlin
    s->using_vnet_hdr = 0;
340 9c282718 Mark McLoughlin
    s->has_ufo = tap_probe_has_ufo(s->fd);
341 3e35ba93 Mark McLoughlin
    tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
342 5281d757 Mark McLoughlin
    tap_read_poll(s, 1);
343 82b0d80e Michael S. Tsirkin
    s->vhost_net = NULL;
344 5281d757 Mark McLoughlin
    return s;
345 5281d757 Mark McLoughlin
}
346 5281d757 Mark McLoughlin
347 5281d757 Mark McLoughlin
static int launch_script(const char *setup_script, const char *ifname, int fd)
348 5281d757 Mark McLoughlin
{
349 5281d757 Mark McLoughlin
    int pid, status;
350 5281d757 Mark McLoughlin
    char *args[3];
351 5281d757 Mark McLoughlin
    char **parg;
352 5281d757 Mark McLoughlin
353 5281d757 Mark McLoughlin
    /* try to launch network script */
354 5281d757 Mark McLoughlin
    pid = fork();
355 5281d757 Mark McLoughlin
    if (pid == 0) {
356 5281d757 Mark McLoughlin
        int open_max = sysconf(_SC_OPEN_MAX), i;
357 5281d757 Mark McLoughlin
358 5281d757 Mark McLoughlin
        for (i = 0; i < open_max; i++) {
359 5281d757 Mark McLoughlin
            if (i != STDIN_FILENO &&
360 5281d757 Mark McLoughlin
                i != STDOUT_FILENO &&
361 5281d757 Mark McLoughlin
                i != STDERR_FILENO &&
362 5281d757 Mark McLoughlin
                i != fd) {
363 5281d757 Mark McLoughlin
                close(i);
364 5281d757 Mark McLoughlin
            }
365 5281d757 Mark McLoughlin
        }
366 5281d757 Mark McLoughlin
        parg = args;
367 5281d757 Mark McLoughlin
        *parg++ = (char *)setup_script;
368 5281d757 Mark McLoughlin
        *parg++ = (char *)ifname;
369 9678d950 Blue Swirl
        *parg = NULL;
370 5281d757 Mark McLoughlin
        execv(setup_script, args);
371 5281d757 Mark McLoughlin
        _exit(1);
372 5281d757 Mark McLoughlin
    } else if (pid > 0) {
373 5281d757 Mark McLoughlin
        while (waitpid(pid, &status, 0) != pid) {
374 5281d757 Mark McLoughlin
            /* loop */
375 5281d757 Mark McLoughlin
        }
376 5281d757 Mark McLoughlin
377 5281d757 Mark McLoughlin
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
378 5281d757 Mark McLoughlin
            return 0;
379 5281d757 Mark McLoughlin
        }
380 5281d757 Mark McLoughlin
    }
381 5281d757 Mark McLoughlin
    fprintf(stderr, "%s: could not launch network script\n", setup_script);
382 5281d757 Mark McLoughlin
    return -1;
383 5281d757 Mark McLoughlin
}
384 5281d757 Mark McLoughlin
385 a7c36ee4 Corey Bryant
static int recv_fd(int c)
386 a7c36ee4 Corey Bryant
{
387 a7c36ee4 Corey Bryant
    int fd;
388 a7c36ee4 Corey Bryant
    uint8_t msgbuf[CMSG_SPACE(sizeof(fd))];
389 a7c36ee4 Corey Bryant
    struct msghdr msg = {
390 a7c36ee4 Corey Bryant
        .msg_control = msgbuf,
391 a7c36ee4 Corey Bryant
        .msg_controllen = sizeof(msgbuf),
392 a7c36ee4 Corey Bryant
    };
393 a7c36ee4 Corey Bryant
    struct cmsghdr *cmsg;
394 a7c36ee4 Corey Bryant
    struct iovec iov;
395 a7c36ee4 Corey Bryant
    uint8_t req[1];
396 a7c36ee4 Corey Bryant
    ssize_t len;
397 a7c36ee4 Corey Bryant
398 a7c36ee4 Corey Bryant
    cmsg = CMSG_FIRSTHDR(&msg);
399 a7c36ee4 Corey Bryant
    cmsg->cmsg_level = SOL_SOCKET;
400 a7c36ee4 Corey Bryant
    cmsg->cmsg_type = SCM_RIGHTS;
401 a7c36ee4 Corey Bryant
    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
402 a7c36ee4 Corey Bryant
    msg.msg_controllen = cmsg->cmsg_len;
403 a7c36ee4 Corey Bryant
404 a7c36ee4 Corey Bryant
    iov.iov_base = req;
405 a7c36ee4 Corey Bryant
    iov.iov_len = sizeof(req);
406 a7c36ee4 Corey Bryant
407 a7c36ee4 Corey Bryant
    msg.msg_iov = &iov;
408 a7c36ee4 Corey Bryant
    msg.msg_iovlen = 1;
409 a7c36ee4 Corey Bryant
410 a7c36ee4 Corey Bryant
    len = recvmsg(c, &msg, 0);
411 a7c36ee4 Corey Bryant
    if (len > 0) {
412 a7c36ee4 Corey Bryant
        memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
413 a7c36ee4 Corey Bryant
        return fd;
414 a7c36ee4 Corey Bryant
    }
415 a7c36ee4 Corey Bryant
416 a7c36ee4 Corey Bryant
    return len;
417 a7c36ee4 Corey Bryant
}
418 a7c36ee4 Corey Bryant
419 a7c36ee4 Corey Bryant
static int net_bridge_run_helper(const char *helper, const char *bridge)
420 a7c36ee4 Corey Bryant
{
421 a7c36ee4 Corey Bryant
    sigset_t oldmask, mask;
422 a7c36ee4 Corey Bryant
    int pid, status;
423 a7c36ee4 Corey Bryant
    char *args[5];
424 a7c36ee4 Corey Bryant
    char **parg;
425 a7c36ee4 Corey Bryant
    int sv[2];
426 a7c36ee4 Corey Bryant
427 a7c36ee4 Corey Bryant
    sigemptyset(&mask);
428 a7c36ee4 Corey Bryant
    sigaddset(&mask, SIGCHLD);
429 a7c36ee4 Corey Bryant
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
430 a7c36ee4 Corey Bryant
431 a7c36ee4 Corey Bryant
    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
432 a7c36ee4 Corey Bryant
        return -1;
433 a7c36ee4 Corey Bryant
    }
434 a7c36ee4 Corey Bryant
435 a7c36ee4 Corey Bryant
    /* try to launch bridge helper */
436 a7c36ee4 Corey Bryant
    pid = fork();
437 a7c36ee4 Corey Bryant
    if (pid == 0) {
438 a7c36ee4 Corey Bryant
        int open_max = sysconf(_SC_OPEN_MAX), i;
439 a7c36ee4 Corey Bryant
        char fd_buf[6+10];
440 a7c36ee4 Corey Bryant
        char br_buf[6+IFNAMSIZ] = {0};
441 a7c36ee4 Corey Bryant
        char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15];
442 a7c36ee4 Corey Bryant
443 a7c36ee4 Corey Bryant
        for (i = 0; i < open_max; i++) {
444 a7c36ee4 Corey Bryant
            if (i != STDIN_FILENO &&
445 a7c36ee4 Corey Bryant
                i != STDOUT_FILENO &&
446 a7c36ee4 Corey Bryant
                i != STDERR_FILENO &&
447 a7c36ee4 Corey Bryant
                i != sv[1]) {
448 a7c36ee4 Corey Bryant
                close(i);
449 a7c36ee4 Corey Bryant
            }
450 a7c36ee4 Corey Bryant
        }
451 a7c36ee4 Corey Bryant
452 a7c36ee4 Corey Bryant
        snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]);
453 a7c36ee4 Corey Bryant
454 a7c36ee4 Corey Bryant
        if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
455 a7c36ee4 Corey Bryant
            /* assume helper is a command */
456 a7c36ee4 Corey Bryant
457 a7c36ee4 Corey Bryant
            if (strstr(helper, "--br=") == NULL) {
458 a7c36ee4 Corey Bryant
                snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
459 a7c36ee4 Corey Bryant
            }
460 a7c36ee4 Corey Bryant
461 a7c36ee4 Corey Bryant
            snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s",
462 a7c36ee4 Corey Bryant
                     helper, "--use-vnet", fd_buf, br_buf);
463 a7c36ee4 Corey Bryant
464 a7c36ee4 Corey Bryant
            parg = args;
465 a7c36ee4 Corey Bryant
            *parg++ = (char *)"sh";
466 a7c36ee4 Corey Bryant
            *parg++ = (char *)"-c";
467 a7c36ee4 Corey Bryant
            *parg++ = helper_cmd;
468 a7c36ee4 Corey Bryant
            *parg++ = NULL;
469 a7c36ee4 Corey Bryant
470 a7c36ee4 Corey Bryant
            execv("/bin/sh", args);
471 a7c36ee4 Corey Bryant
        } else {
472 a7c36ee4 Corey Bryant
            /* assume helper is just the executable path name */
473 a7c36ee4 Corey Bryant
474 a7c36ee4 Corey Bryant
            snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
475 a7c36ee4 Corey Bryant
476 a7c36ee4 Corey Bryant
            parg = args;
477 a7c36ee4 Corey Bryant
            *parg++ = (char *)helper;
478 a7c36ee4 Corey Bryant
            *parg++ = (char *)"--use-vnet";
479 a7c36ee4 Corey Bryant
            *parg++ = fd_buf;
480 a7c36ee4 Corey Bryant
            *parg++ = br_buf;
481 a7c36ee4 Corey Bryant
            *parg++ = NULL;
482 a7c36ee4 Corey Bryant
483 a7c36ee4 Corey Bryant
            execv(helper, args);
484 a7c36ee4 Corey Bryant
        }
485 a7c36ee4 Corey Bryant
        _exit(1);
486 a7c36ee4 Corey Bryant
487 a7c36ee4 Corey Bryant
    } else if (pid > 0) {
488 a7c36ee4 Corey Bryant
        int fd;
489 a7c36ee4 Corey Bryant
490 a7c36ee4 Corey Bryant
        close(sv[1]);
491 a7c36ee4 Corey Bryant
492 a7c36ee4 Corey Bryant
        do {
493 a7c36ee4 Corey Bryant
            fd = recv_fd(sv[0]);
494 a7c36ee4 Corey Bryant
        } while (fd == -1 && errno == EINTR);
495 a7c36ee4 Corey Bryant
496 a7c36ee4 Corey Bryant
        close(sv[0]);
497 a7c36ee4 Corey Bryant
498 a7c36ee4 Corey Bryant
        while (waitpid(pid, &status, 0) != pid) {
499 a7c36ee4 Corey Bryant
            /* loop */
500 a7c36ee4 Corey Bryant
        }
501 a7c36ee4 Corey Bryant
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
502 a7c36ee4 Corey Bryant
        if (fd < 0) {
503 a7c36ee4 Corey Bryant
            fprintf(stderr, "failed to recv file descriptor\n");
504 a7c36ee4 Corey Bryant
            return -1;
505 a7c36ee4 Corey Bryant
        }
506 a7c36ee4 Corey Bryant
507 a7c36ee4 Corey Bryant
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
508 a7c36ee4 Corey Bryant
            return fd;
509 a7c36ee4 Corey Bryant
        }
510 a7c36ee4 Corey Bryant
    }
511 a7c36ee4 Corey Bryant
    fprintf(stderr, "failed to launch bridge helper\n");
512 a7c36ee4 Corey Bryant
    return -1;
513 a7c36ee4 Corey Bryant
}
514 a7c36ee4 Corey Bryant
515 a7c36ee4 Corey Bryant
int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
516 a7c36ee4 Corey Bryant
                    VLANState *vlan)
517 a7c36ee4 Corey Bryant
{
518 a7c36ee4 Corey Bryant
    TAPState *s;
519 a7c36ee4 Corey Bryant
    int fd, vnet_hdr;
520 a7c36ee4 Corey Bryant
521 a7c36ee4 Corey Bryant
    if (!qemu_opt_get(opts, "br")) {
522 a7c36ee4 Corey Bryant
        qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE);
523 a7c36ee4 Corey Bryant
    }
524 a7c36ee4 Corey Bryant
    if (!qemu_opt_get(opts, "helper")) {
525 a7c36ee4 Corey Bryant
        qemu_opt_set(opts, "helper", DEFAULT_BRIDGE_HELPER);
526 a7c36ee4 Corey Bryant
    }
527 a7c36ee4 Corey Bryant
528 a7c36ee4 Corey Bryant
    fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
529 a7c36ee4 Corey Bryant
                               qemu_opt_get(opts, "br"));
530 a7c36ee4 Corey Bryant
    if (fd == -1) {
531 a7c36ee4 Corey Bryant
        return -1;
532 a7c36ee4 Corey Bryant
    }
533 a7c36ee4 Corey Bryant
534 a7c36ee4 Corey Bryant
    fcntl(fd, F_SETFL, O_NONBLOCK);
535 a7c36ee4 Corey Bryant
536 a7c36ee4 Corey Bryant
    vnet_hdr = tap_probe_vnet_hdr(fd);
537 a7c36ee4 Corey Bryant
538 a7c36ee4 Corey Bryant
    s = net_tap_fd_init(vlan, "bridge", name, fd, vnet_hdr);
539 a7c36ee4 Corey Bryant
    if (!s) {
540 a7c36ee4 Corey Bryant
        close(fd);
541 a7c36ee4 Corey Bryant
        return -1;
542 a7c36ee4 Corey Bryant
    }
543 a7c36ee4 Corey Bryant
544 a7c36ee4 Corey Bryant
    snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s",
545 a7c36ee4 Corey Bryant
             qemu_opt_get(opts, "helper"), qemu_opt_get(opts, "br"));
546 a7c36ee4 Corey Bryant
547 a7c36ee4 Corey Bryant
    return 0;
548 a7c36ee4 Corey Bryant
}
549 a7c36ee4 Corey Bryant
550 5281d757 Mark McLoughlin
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
551 5281d757 Mark McLoughlin
{
552 5281d757 Mark McLoughlin
    int fd, vnet_hdr_required;
553 5281d757 Mark McLoughlin
    char ifname[128] = {0,};
554 5281d757 Mark McLoughlin
    const char *setup_script;
555 5281d757 Mark McLoughlin
556 5281d757 Mark McLoughlin
    if (qemu_opt_get(opts, "ifname")) {
557 5281d757 Mark McLoughlin
        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
558 5281d757 Mark McLoughlin
    }
559 5281d757 Mark McLoughlin
560 5281d757 Mark McLoughlin
    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
561 5281d757 Mark McLoughlin
    if (qemu_opt_get(opts, "vnet_hdr")) {
562 5281d757 Mark McLoughlin
        vnet_hdr_required = *vnet_hdr;
563 5281d757 Mark McLoughlin
    } else {
564 5281d757 Mark McLoughlin
        vnet_hdr_required = 0;
565 5281d757 Mark McLoughlin
    }
566 5281d757 Mark McLoughlin
567 5281d757 Mark McLoughlin
    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
568 5281d757 Mark McLoughlin
    if (fd < 0) {
569 5281d757 Mark McLoughlin
        return -1;
570 5281d757 Mark McLoughlin
    }
571 5281d757 Mark McLoughlin
572 5281d757 Mark McLoughlin
    setup_script = qemu_opt_get(opts, "script");
573 5281d757 Mark McLoughlin
    if (setup_script &&
574 5281d757 Mark McLoughlin
        setup_script[0] != '\0' &&
575 5281d757 Mark McLoughlin
        strcmp(setup_script, "no") != 0 &&
576 5281d757 Mark McLoughlin
        launch_script(setup_script, ifname, fd)) {
577 5281d757 Mark McLoughlin
        close(fd);
578 5281d757 Mark McLoughlin
        return -1;
579 5281d757 Mark McLoughlin
    }
580 5281d757 Mark McLoughlin
581 5281d757 Mark McLoughlin
    qemu_opt_set(opts, "ifname", ifname);
582 5281d757 Mark McLoughlin
583 5281d757 Mark McLoughlin
    return fd;
584 5281d757 Mark McLoughlin
}
585 5281d757 Mark McLoughlin
586 5281d757 Mark McLoughlin
int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
587 5281d757 Mark McLoughlin
{
588 5281d757 Mark McLoughlin
    TAPState *s;
589 df6c2a0f Mark McLoughlin
    int fd, vnet_hdr = 0;
590 a7c36ee4 Corey Bryant
    const char *model;
591 5281d757 Mark McLoughlin
592 5281d757 Mark McLoughlin
    if (qemu_opt_get(opts, "fd")) {
593 5281d757 Mark McLoughlin
        if (qemu_opt_get(opts, "ifname") ||
594 5281d757 Mark McLoughlin
            qemu_opt_get(opts, "script") ||
595 5281d757 Mark McLoughlin
            qemu_opt_get(opts, "downscript") ||
596 a7c36ee4 Corey Bryant
            qemu_opt_get(opts, "vnet_hdr") ||
597 a7c36ee4 Corey Bryant
            qemu_opt_get(opts, "helper")) {
598 a7c36ee4 Corey Bryant
            error_report("ifname=, script=, downscript=, vnet_hdr=, "
599 a7c36ee4 Corey Bryant
                         "and helper= are invalid with fd=");
600 5281d757 Mark McLoughlin
            return -1;
601 5281d757 Mark McLoughlin
        }
602 5281d757 Mark McLoughlin
603 5281d757 Mark McLoughlin
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
604 5281d757 Mark McLoughlin
        if (fd == -1) {
605 5281d757 Mark McLoughlin
            return -1;
606 5281d757 Mark McLoughlin
        }
607 5281d757 Mark McLoughlin
608 5281d757 Mark McLoughlin
        fcntl(fd, F_SETFL, O_NONBLOCK);
609 5281d757 Mark McLoughlin
610 5281d757 Mark McLoughlin
        vnet_hdr = tap_probe_vnet_hdr(fd);
611 a7c36ee4 Corey Bryant
612 a7c36ee4 Corey Bryant
        model = "tap";
613 a7c36ee4 Corey Bryant
614 a7c36ee4 Corey Bryant
    } else if (qemu_opt_get(opts, "helper")) {
615 a7c36ee4 Corey Bryant
        if (qemu_opt_get(opts, "ifname") ||
616 a7c36ee4 Corey Bryant
            qemu_opt_get(opts, "script") ||
617 a7c36ee4 Corey Bryant
            qemu_opt_get(opts, "downscript") ||
618 a7c36ee4 Corey Bryant
            qemu_opt_get(opts, "vnet_hdr")) {
619 a7c36ee4 Corey Bryant
            error_report("ifname=, script=, downscript=, and vnet_hdr= "
620 a7c36ee4 Corey Bryant
                         "are invalid with helper=");
621 a7c36ee4 Corey Bryant
            return -1;
622 a7c36ee4 Corey Bryant
        }
623 a7c36ee4 Corey Bryant
624 a7c36ee4 Corey Bryant
        fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
625 a7c36ee4 Corey Bryant
                                   DEFAULT_BRIDGE_INTERFACE);
626 a7c36ee4 Corey Bryant
        if (fd == -1) {
627 a7c36ee4 Corey Bryant
            return -1;
628 a7c36ee4 Corey Bryant
        }
629 a7c36ee4 Corey Bryant
630 a7c36ee4 Corey Bryant
        fcntl(fd, F_SETFL, O_NONBLOCK);
631 a7c36ee4 Corey Bryant
632 a7c36ee4 Corey Bryant
        vnet_hdr = tap_probe_vnet_hdr(fd);
633 a7c36ee4 Corey Bryant
634 a7c36ee4 Corey Bryant
        model = "bridge";
635 a7c36ee4 Corey Bryant
636 5281d757 Mark McLoughlin
    } else {
637 5281d757 Mark McLoughlin
        if (!qemu_opt_get(opts, "script")) {
638 5281d757 Mark McLoughlin
            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
639 5281d757 Mark McLoughlin
        }
640 5281d757 Mark McLoughlin
641 5281d757 Mark McLoughlin
        if (!qemu_opt_get(opts, "downscript")) {
642 5281d757 Mark McLoughlin
            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
643 5281d757 Mark McLoughlin
        }
644 5281d757 Mark McLoughlin
645 5281d757 Mark McLoughlin
        fd = net_tap_init(opts, &vnet_hdr);
646 929fe497 Juergen Lock
        if (fd == -1) {
647 929fe497 Juergen Lock
            return -1;
648 929fe497 Juergen Lock
        }
649 a7c36ee4 Corey Bryant
650 a7c36ee4 Corey Bryant
        model = "tap";
651 5281d757 Mark McLoughlin
    }
652 5281d757 Mark McLoughlin
653 a7c36ee4 Corey Bryant
    s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
654 5281d757 Mark McLoughlin
    if (!s) {
655 5281d757 Mark McLoughlin
        close(fd);
656 5281d757 Mark McLoughlin
        return -1;
657 5281d757 Mark McLoughlin
    }
658 5281d757 Mark McLoughlin
659 15ac913b Mark McLoughlin
    if (tap_set_sndbuf(s->fd, opts) < 0) {
660 5281d757 Mark McLoughlin
        return -1;
661 5281d757 Mark McLoughlin
    }
662 5281d757 Mark McLoughlin
663 5281d757 Mark McLoughlin
    if (qemu_opt_get(opts, "fd")) {
664 3e35ba93 Mark McLoughlin
        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
665 a7c36ee4 Corey Bryant
    } else if (qemu_opt_get(opts, "helper")) {
666 a7c36ee4 Corey Bryant
        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
667 a7c36ee4 Corey Bryant
                 "helper=%s", qemu_opt_get(opts, "helper"));
668 5281d757 Mark McLoughlin
    } else {
669 5281d757 Mark McLoughlin
        const char *ifname, *script, *downscript;
670 5281d757 Mark McLoughlin
671 5281d757 Mark McLoughlin
        ifname     = qemu_opt_get(opts, "ifname");
672 5281d757 Mark McLoughlin
        script     = qemu_opt_get(opts, "script");
673 5281d757 Mark McLoughlin
        downscript = qemu_opt_get(opts, "downscript");
674 5281d757 Mark McLoughlin
675 3e35ba93 Mark McLoughlin
        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
676 5281d757 Mark McLoughlin
                 "ifname=%s,script=%s,downscript=%s",
677 5281d757 Mark McLoughlin
                 ifname, script, downscript);
678 5281d757 Mark McLoughlin
679 5281d757 Mark McLoughlin
        if (strcmp(downscript, "no") != 0) {
680 5281d757 Mark McLoughlin
            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
681 5281d757 Mark McLoughlin
            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
682 5281d757 Mark McLoughlin
        }
683 5281d757 Mark McLoughlin
    }
684 5281d757 Mark McLoughlin
685 5430a28f mst@redhat.com
    if (qemu_opt_get_bool(opts, "vhost", !!qemu_opt_get(opts, "vhostfd") ||
686 5430a28f mst@redhat.com
                          qemu_opt_get_bool(opts, "vhostforce", false))) {
687 82b0d80e Michael S. Tsirkin
        int vhostfd, r;
688 5430a28f mst@redhat.com
        bool force = qemu_opt_get_bool(opts, "vhostforce", false);
689 82b0d80e Michael S. Tsirkin
        if (qemu_opt_get(opts, "vhostfd")) {
690 82b0d80e Michael S. Tsirkin
            r = net_handle_fd_param(mon, qemu_opt_get(opts, "vhostfd"));
691 82b0d80e Michael S. Tsirkin
            if (r == -1) {
692 82b0d80e Michael S. Tsirkin
                return -1;
693 82b0d80e Michael S. Tsirkin
            }
694 82b0d80e Michael S. Tsirkin
            vhostfd = r;
695 82b0d80e Michael S. Tsirkin
        } else {
696 82b0d80e Michael S. Tsirkin
            vhostfd = -1;
697 82b0d80e Michael S. Tsirkin
        }
698 5430a28f mst@redhat.com
        s->vhost_net = vhost_net_init(&s->nc, vhostfd, force);
699 82b0d80e Michael S. Tsirkin
        if (!s->vhost_net) {
700 82b0d80e Michael S. Tsirkin
            error_report("vhost-net requested but could not be initialized");
701 82b0d80e Michael S. Tsirkin
            return -1;
702 82b0d80e Michael S. Tsirkin
        }
703 82b0d80e Michael S. Tsirkin
    } else if (qemu_opt_get(opts, "vhostfd")) {
704 82b0d80e Michael S. Tsirkin
        error_report("vhostfd= is not valid without vhost");
705 82b0d80e Michael S. Tsirkin
        return -1;
706 82b0d80e Michael S. Tsirkin
    }
707 82b0d80e Michael S. Tsirkin
708 5281d757 Mark McLoughlin
    return 0;
709 5281d757 Mark McLoughlin
}
710 b202554c Michael S. Tsirkin
711 b202554c Michael S. Tsirkin
VHostNetState *tap_get_vhost_net(VLANClientState *nc)
712 b202554c Michael S. Tsirkin
{
713 b202554c Michael S. Tsirkin
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
714 b202554c Michael S. Tsirkin
    assert(nc->info->type == NET_CLIENT_TYPE_TAP);
715 b202554c Michael S. Tsirkin
    return s->vhost_net;
716 b202554c Michael S. Tsirkin
}