Statistics
| Branch: | Revision:

root / net / tap.c @ 9c17d615

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