Statistics
| Branch: | Revision:

root / net / tap.c @ 0d09e41a

History | View | Annotate | Download (22.9 kB)

1
/*
2
 * QEMU System Emulator
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 * Copyright (c) 2009 Red Hat, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25

    
26
#include "tap_int.h"
27

    
28
#include "config-host.h"
29

    
30
#include <sys/ioctl.h>
31
#include <sys/stat.h>
32
#include <sys/wait.h>
33
#include <sys/socket.h>
34
#include <net/if.h>
35

    
36
#include "net/net.h"
37
#include "clients.h"
38
#include "monitor/monitor.h"
39
#include "sysemu/sysemu.h"
40
#include "qemu-common.h"
41
#include "qemu/error-report.h"
42

    
43
#include "net/tap.h"
44

    
45
#include "net/vhost_net.h"
46

    
47
typedef struct TAPState {
48
    NetClientState nc;
49
    int fd;
50
    char down_script[1024];
51
    char down_script_arg[128];
52
    uint8_t buf[NET_BUFSIZE];
53
    bool read_poll;
54
    bool write_poll;
55
    bool using_vnet_hdr;
56
    bool has_ufo;
57
    bool enabled;
58
    VHostNetState *vhost_net;
59
    unsigned host_vnet_hdr_len;
60
} TAPState;
61

    
62
static int launch_script(const char *setup_script, const char *ifname, int fd);
63

    
64
static int tap_can_send(void *opaque);
65
static void tap_send(void *opaque);
66
static void tap_writable(void *opaque);
67

    
68
static void tap_update_fd_handler(TAPState *s)
69
{
70
    qemu_set_fd_handler2(s->fd,
71
                         s->read_poll && s->enabled ? tap_can_send : NULL,
72
                         s->read_poll && s->enabled ? tap_send     : NULL,
73
                         s->write_poll && s->enabled ? tap_writable : NULL,
74
                         s);
75
}
76

    
77
static void tap_read_poll(TAPState *s, bool enable)
78
{
79
    s->read_poll = enable;
80
    tap_update_fd_handler(s);
81
}
82

    
83
static void tap_write_poll(TAPState *s, bool enable)
84
{
85
    s->write_poll = enable;
86
    tap_update_fd_handler(s);
87
}
88

    
89
static void tap_writable(void *opaque)
90
{
91
    TAPState *s = opaque;
92

    
93
    tap_write_poll(s, false);
94

    
95
    qemu_flush_queued_packets(&s->nc);
96
}
97

    
98
static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt)
99
{
100
    ssize_t len;
101

    
102
    do {
103
        len = writev(s->fd, iov, iovcnt);
104
    } while (len == -1 && errno == EINTR);
105

    
106
    if (len == -1 && errno == EAGAIN) {
107
        tap_write_poll(s, true);
108
        return 0;
109
    }
110

    
111
    return len;
112
}
113

    
114
static ssize_t tap_receive_iov(NetClientState *nc, const struct iovec *iov,
115
                               int iovcnt)
116
{
117
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
118
    const struct iovec *iovp = iov;
119
    struct iovec iov_copy[iovcnt + 1];
120
    struct virtio_net_hdr_mrg_rxbuf hdr = { };
121

    
122
    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
123
        iov_copy[0].iov_base = &hdr;
124
        iov_copy[0].iov_len =  s->host_vnet_hdr_len;
125
        memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
126
        iovp = iov_copy;
127
        iovcnt++;
128
    }
129

    
130
    return tap_write_packet(s, iovp, iovcnt);
131
}
132

    
133
static ssize_t tap_receive_raw(NetClientState *nc, const uint8_t *buf, size_t size)
134
{
135
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
136
    struct iovec iov[2];
137
    int iovcnt = 0;
138
    struct virtio_net_hdr_mrg_rxbuf hdr = { };
139

    
140
    if (s->host_vnet_hdr_len) {
141
        iov[iovcnt].iov_base = &hdr;
142
        iov[iovcnt].iov_len  = s->host_vnet_hdr_len;
143
        iovcnt++;
144
    }
145

    
146
    iov[iovcnt].iov_base = (char *)buf;
147
    iov[iovcnt].iov_len  = size;
148
    iovcnt++;
149

    
150
    return tap_write_packet(s, iov, iovcnt);
151
}
152

    
153
static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size)
154
{
155
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
156
    struct iovec iov[1];
157

    
158
    if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
159
        return tap_receive_raw(nc, buf, size);
160
    }
161

    
162
    iov[0].iov_base = (char *)buf;
163
    iov[0].iov_len  = size;
164

    
165
    return tap_write_packet(s, iov, 1);
166
}
167

    
168
static int tap_can_send(void *opaque)
169
{
170
    TAPState *s = opaque;
171

    
172
    return qemu_can_send_packet(&s->nc);
173
}
174

    
175
#ifndef __sun__
176
ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
177
{
178
    return read(tapfd, buf, maxlen);
179
}
180
#endif
181

    
182
static void tap_send_completed(NetClientState *nc, ssize_t len)
183
{
184
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
185
    tap_read_poll(s, true);
186
}
187

    
188
static void tap_send(void *opaque)
189
{
190
    TAPState *s = opaque;
191
    int size;
192

    
193
    do {
194
        uint8_t *buf = s->buf;
195

    
196
        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
197
        if (size <= 0) {
198
            break;
199
        }
200

    
201
        if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
202
            buf  += s->host_vnet_hdr_len;
203
            size -= s->host_vnet_hdr_len;
204
        }
205

    
206
        size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
207
        if (size == 0) {
208
            tap_read_poll(s, false);
209
        }
210
    } while (size > 0 && qemu_can_send_packet(&s->nc));
211
}
212

    
213
bool tap_has_ufo(NetClientState *nc)
214
{
215
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
216

    
217
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
218

    
219
    return s->has_ufo;
220
}
221

    
222
int tap_has_vnet_hdr(NetClientState *nc)
223
{
224
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
225

    
226
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
227

    
228
    return !!s->host_vnet_hdr_len;
229
}
230

    
231
int tap_has_vnet_hdr_len(NetClientState *nc, int len)
232
{
233
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
234

    
235
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
236

    
237
    return tap_probe_vnet_hdr_len(s->fd, len);
238
}
239

    
240
void tap_set_vnet_hdr_len(NetClientState *nc, int len)
241
{
242
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
243

    
244
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
245
    assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
246
           len == sizeof(struct virtio_net_hdr));
247

    
248
    tap_fd_set_vnet_hdr_len(s->fd, len);
249
    s->host_vnet_hdr_len = len;
250
}
251

    
252
void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
253
{
254
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
255

    
256
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
257
    assert(!!s->host_vnet_hdr_len == using_vnet_hdr);
258

    
259
    s->using_vnet_hdr = using_vnet_hdr;
260
}
261

    
262
void tap_set_offload(NetClientState *nc, int csum, int tso4,
263
                     int tso6, int ecn, int ufo)
264
{
265
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
266
    if (s->fd < 0) {
267
        return;
268
    }
269

    
270
    tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
271
}
272

    
273
static void tap_cleanup(NetClientState *nc)
274
{
275
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
276

    
277
    if (s->vhost_net) {
278
        vhost_net_cleanup(s->vhost_net);
279
        s->vhost_net = NULL;
280
    }
281

    
282
    qemu_purge_queued_packets(nc);
283

    
284
    if (s->down_script[0])
285
        launch_script(s->down_script, s->down_script_arg, s->fd);
286

    
287
    tap_read_poll(s, false);
288
    tap_write_poll(s, false);
289
    close(s->fd);
290
    s->fd = -1;
291
}
292

    
293
static void tap_poll(NetClientState *nc, bool enable)
294
{
295
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
296
    tap_read_poll(s, enable);
297
    tap_write_poll(s, enable);
298
}
299

    
300
int tap_get_fd(NetClientState *nc)
301
{
302
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
303
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
304
    return s->fd;
305
}
306

    
307
/* fd support */
308

    
309
static NetClientInfo net_tap_info = {
310
    .type = NET_CLIENT_OPTIONS_KIND_TAP,
311
    .size = sizeof(TAPState),
312
    .receive = tap_receive,
313
    .receive_raw = tap_receive_raw,
314
    .receive_iov = tap_receive_iov,
315
    .poll = tap_poll,
316
    .cleanup = tap_cleanup,
317
};
318

    
319
static TAPState *net_tap_fd_init(NetClientState *peer,
320
                                 const char *model,
321
                                 const char *name,
322
                                 int fd,
323
                                 int vnet_hdr)
324
{
325
    NetClientState *nc;
326
    TAPState *s;
327

    
328
    nc = qemu_new_net_client(&net_tap_info, peer, model, name);
329

    
330
    s = DO_UPCAST(TAPState, nc, nc);
331

    
332
    s->fd = fd;
333
    s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
334
    s->using_vnet_hdr = false;
335
    s->has_ufo = tap_probe_has_ufo(s->fd);
336
    s->enabled = true;
337
    tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
338
    /*
339
     * Make sure host header length is set correctly in tap:
340
     * it might have been modified by another instance of qemu.
341
     */
342
    if (tap_probe_vnet_hdr_len(s->fd, s->host_vnet_hdr_len)) {
343
        tap_fd_set_vnet_hdr_len(s->fd, s->host_vnet_hdr_len);
344
    }
345
    tap_read_poll(s, true);
346
    s->vhost_net = NULL;
347
    return s;
348
}
349

    
350
static int launch_script(const char *setup_script, const char *ifname, int fd)
351
{
352
    int pid, status;
353
    char *args[3];
354
    char **parg;
355

    
356
    /* try to launch network script */
357
    pid = fork();
358
    if (pid == 0) {
359
        int open_max = sysconf(_SC_OPEN_MAX), i;
360

    
361
        for (i = 0; i < open_max; i++) {
362
            if (i != STDIN_FILENO &&
363
                i != STDOUT_FILENO &&
364
                i != STDERR_FILENO &&
365
                i != fd) {
366
                close(i);
367
            }
368
        }
369
        parg = args;
370
        *parg++ = (char *)setup_script;
371
        *parg++ = (char *)ifname;
372
        *parg = NULL;
373
        execv(setup_script, args);
374
        _exit(1);
375
    } else if (pid > 0) {
376
        while (waitpid(pid, &status, 0) != pid) {
377
            /* loop */
378
        }
379

    
380
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
381
            return 0;
382
        }
383
    }
384
    fprintf(stderr, "%s: could not launch network script\n", setup_script);
385
    return -1;
386
}
387

    
388
static int recv_fd(int c)
389
{
390
    int fd;
391
    uint8_t msgbuf[CMSG_SPACE(sizeof(fd))];
392
    struct msghdr msg = {
393
        .msg_control = msgbuf,
394
        .msg_controllen = sizeof(msgbuf),
395
    };
396
    struct cmsghdr *cmsg;
397
    struct iovec iov;
398
    uint8_t req[1];
399
    ssize_t len;
400

    
401
    cmsg = CMSG_FIRSTHDR(&msg);
402
    cmsg->cmsg_level = SOL_SOCKET;
403
    cmsg->cmsg_type = SCM_RIGHTS;
404
    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
405
    msg.msg_controllen = cmsg->cmsg_len;
406

    
407
    iov.iov_base = req;
408
    iov.iov_len = sizeof(req);
409

    
410
    msg.msg_iov = &iov;
411
    msg.msg_iovlen = 1;
412

    
413
    len = recvmsg(c, &msg, 0);
414
    if (len > 0) {
415
        memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
416
        return fd;
417
    }
418

    
419
    return len;
420
}
421

    
422
static int net_bridge_run_helper(const char *helper, const char *bridge)
423
{
424
    sigset_t oldmask, mask;
425
    int pid, status;
426
    char *args[5];
427
    char **parg;
428
    int sv[2];
429

    
430
    sigemptyset(&mask);
431
    sigaddset(&mask, SIGCHLD);
432
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
433

    
434
    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
435
        return -1;
436
    }
437

    
438
    /* try to launch bridge helper */
439
    pid = fork();
440
    if (pid == 0) {
441
        int open_max = sysconf(_SC_OPEN_MAX), i;
442
        char fd_buf[6+10];
443
        char br_buf[6+IFNAMSIZ] = {0};
444
        char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15];
445

    
446
        for (i = 0; i < open_max; i++) {
447
            if (i != STDIN_FILENO &&
448
                i != STDOUT_FILENO &&
449
                i != STDERR_FILENO &&
450
                i != sv[1]) {
451
                close(i);
452
            }
453
        }
454

    
455
        snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]);
456

    
457
        if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
458
            /* assume helper is a command */
459

    
460
            if (strstr(helper, "--br=") == NULL) {
461
                snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
462
            }
463

    
464
            snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s",
465
                     helper, "--use-vnet", fd_buf, br_buf);
466

    
467
            parg = args;
468
            *parg++ = (char *)"sh";
469
            *parg++ = (char *)"-c";
470
            *parg++ = helper_cmd;
471
            *parg++ = NULL;
472

    
473
            execv("/bin/sh", args);
474
        } else {
475
            /* assume helper is just the executable path name */
476

    
477
            snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
478

    
479
            parg = args;
480
            *parg++ = (char *)helper;
481
            *parg++ = (char *)"--use-vnet";
482
            *parg++ = fd_buf;
483
            *parg++ = br_buf;
484
            *parg++ = NULL;
485

    
486
            execv(helper, args);
487
        }
488
        _exit(1);
489

    
490
    } else if (pid > 0) {
491
        int fd;
492

    
493
        close(sv[1]);
494

    
495
        do {
496
            fd = recv_fd(sv[0]);
497
        } while (fd == -1 && errno == EINTR);
498

    
499
        close(sv[0]);
500

    
501
        while (waitpid(pid, &status, 0) != pid) {
502
            /* loop */
503
        }
504
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
505
        if (fd < 0) {
506
            fprintf(stderr, "failed to recv file descriptor\n");
507
            return -1;
508
        }
509

    
510
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
511
            return fd;
512
        }
513
    }
514
    fprintf(stderr, "failed to launch bridge helper\n");
515
    return -1;
516
}
517

    
518
int net_init_bridge(const NetClientOptions *opts, const char *name,
519
                    NetClientState *peer)
520
{
521
    const NetdevBridgeOptions *bridge;
522
    const char *helper, *br;
523

    
524
    TAPState *s;
525
    int fd, vnet_hdr;
526

    
527
    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_BRIDGE);
528
    bridge = opts->bridge;
529

    
530
    helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
531
    br     = bridge->has_br     ? bridge->br     : DEFAULT_BRIDGE_INTERFACE;
532

    
533
    fd = net_bridge_run_helper(helper, br);
534
    if (fd == -1) {
535
        return -1;
536
    }
537

    
538
    fcntl(fd, F_SETFL, O_NONBLOCK);
539

    
540
    vnet_hdr = tap_probe_vnet_hdr(fd);
541

    
542
    s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
543
    if (!s) {
544
        close(fd);
545
        return -1;
546
    }
547

    
548
    snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper,
549
             br);
550

    
551
    return 0;
552
}
553

    
554
static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr,
555
                        const char *setup_script, char *ifname,
556
                        size_t ifname_sz, int mq_required)
557
{
558
    int fd, vnet_hdr_required;
559

    
560
    if (tap->has_vnet_hdr) {
561
        *vnet_hdr = tap->vnet_hdr;
562
        vnet_hdr_required = *vnet_hdr;
563
    } else {
564
        *vnet_hdr = 1;
565
        vnet_hdr_required = 0;
566
    }
567

    
568
    TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required,
569
                      mq_required));
570
    if (fd < 0) {
571
        return -1;
572
    }
573

    
574
    if (setup_script &&
575
        setup_script[0] != '\0' &&
576
        strcmp(setup_script, "no") != 0 &&
577
        launch_script(setup_script, ifname, fd)) {
578
        close(fd);
579
        return -1;
580
    }
581

    
582
    return fd;
583
}
584

    
585
#define MAX_TAP_QUEUES 1024
586

    
587
static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
588
                            const char *model, const char *name,
589
                            const char *ifname, const char *script,
590
                            const char *downscript, const char *vhostfdname,
591
                            int vnet_hdr, int fd)
592
{
593
    TAPState *s;
594

    
595
    s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
596
    if (!s) {
597
        close(fd);
598
        return -1;
599
    }
600

    
601
    if (tap_set_sndbuf(s->fd, tap) < 0) {
602
        return -1;
603
    }
604

    
605
    if (tap->has_fd || tap->has_fds) {
606
        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
607
    } else if (tap->has_helper) {
608
        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s",
609
                 tap->helper);
610
    } else {
611
        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
612
                 "ifname=%s,script=%s,downscript=%s", ifname, script,
613
                 downscript);
614

    
615
        if (strcmp(downscript, "no") != 0) {
616
            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
617
            snprintf(s->down_script_arg, sizeof(s->down_script_arg),
618
                     "%s", ifname);
619
        }
620
    }
621

    
622
    if (tap->has_vhost ? tap->vhost :
623
        vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
624
        int vhostfd;
625

    
626
        if (tap->has_vhostfd) {
627
            vhostfd = monitor_handle_fd_param(cur_mon, vhostfdname);
628
            if (vhostfd == -1) {
629
                return -1;
630
            }
631
        } else {
632
            vhostfd = -1;
633
        }
634

    
635
        s->vhost_net = vhost_net_init(&s->nc, vhostfd,
636
                                      tap->has_vhostforce && tap->vhostforce);
637
        if (!s->vhost_net) {
638
            error_report("vhost-net requested but could not be initialized");
639
            return -1;
640
        }
641
    } else if (tap->has_vhostfd || tap->has_vhostfds) {
642
        error_report("vhostfd= is not valid without vhost");
643
        return -1;
644
    }
645

    
646
    return 0;
647
}
648

    
649
static int get_fds(char *str, char *fds[], int max)
650
{
651
    char *ptr = str, *this;
652
    size_t len = strlen(str);
653
    int i = 0;
654

    
655
    while (i < max && ptr < str + len) {
656
        this = strchr(ptr, ':');
657

    
658
        if (this == NULL) {
659
            fds[i] = g_strdup(ptr);
660
        } else {
661
            fds[i] = g_strndup(ptr, this - ptr);
662
        }
663

    
664
        i++;
665
        if (this == NULL) {
666
            break;
667
        } else {
668
            ptr = this + 1;
669
        }
670
    }
671

    
672
    return i;
673
}
674

    
675
int net_init_tap(const NetClientOptions *opts, const char *name,
676
                 NetClientState *peer)
677
{
678
    const NetdevTapOptions *tap;
679
    int fd, vnet_hdr = 0, i = 0, queues;
680
    /* for the no-fd, no-helper case */
681
    const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */
682
    const char *downscript = NULL;
683
    const char *vhostfdname;
684
    char ifname[128];
685

    
686
    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP);
687
    tap = opts->tap;
688
    queues = tap->has_queues ? tap->queues : 1;
689
    vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
690

    
691
    /* QEMU vlans does not support multiqueue tap, in this case peer is set.
692
     * For -netdev, peer is always NULL. */
693
    if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
694
        error_report("Multiqueue tap cannot be used with QEMU vlans");
695
        return -1;
696
    }
697

    
698
    if (tap->has_fd) {
699
        if (tap->has_ifname || tap->has_script || tap->has_downscript ||
700
            tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
701
            tap->has_fds) {
702
            error_report("ifname=, script=, downscript=, vnet_hdr=, "
703
                         "helper=, queues=, and fds= are invalid with fd=");
704
            return -1;
705
        }
706

    
707
        fd = monitor_handle_fd_param(cur_mon, tap->fd);
708
        if (fd == -1) {
709
            return -1;
710
        }
711

    
712
        fcntl(fd, F_SETFL, O_NONBLOCK);
713

    
714
        vnet_hdr = tap_probe_vnet_hdr(fd);
715

    
716
        if (net_init_tap_one(tap, peer, "tap", name, NULL,
717
                             script, downscript,
718
                             vhostfdname, vnet_hdr, fd)) {
719
            return -1;
720
        }
721
    } else if (tap->has_fds) {
722
        char *fds[MAX_TAP_QUEUES];
723
        char *vhost_fds[MAX_TAP_QUEUES];
724
        int nfds, nvhosts;
725

    
726
        if (tap->has_ifname || tap->has_script || tap->has_downscript ||
727
            tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
728
            tap->has_fd) {
729
            error_report("ifname=, script=, downscript=, vnet_hdr=, "
730
                         "helper=, queues=, and fd= are invalid with fds=");
731
            return -1;
732
        }
733

    
734
        nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
735
        if (tap->has_vhostfds) {
736
            nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
737
            if (nfds != nvhosts) {
738
                error_report("The number of fds passed does not match the "
739
                             "number of vhostfds passed");
740
                return -1;
741
            }
742
        }
743

    
744
        for (i = 0; i < nfds; i++) {
745
            fd = monitor_handle_fd_param(cur_mon, fds[i]);
746
            if (fd == -1) {
747
                return -1;
748
            }
749

    
750
            fcntl(fd, F_SETFL, O_NONBLOCK);
751

    
752
            if (i == 0) {
753
                vnet_hdr = tap_probe_vnet_hdr(fd);
754
            } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) {
755
                error_report("vnet_hdr not consistent across given tap fds");
756
                return -1;
757
            }
758

    
759
            if (net_init_tap_one(tap, peer, "tap", name, ifname,
760
                                 script, downscript,
761
                                 tap->has_vhostfds ? vhost_fds[i] : NULL,
762
                                 vnet_hdr, fd)) {
763
                return -1;
764
            }
765
        }
766
    } else if (tap->has_helper) {
767
        if (tap->has_ifname || tap->has_script || tap->has_downscript ||
768
            tap->has_vnet_hdr || tap->has_queues || tap->has_fds) {
769
            error_report("ifname=, script=, downscript=, and vnet_hdr= "
770
                         "queues=, and fds= are invalid with helper=");
771
            return -1;
772
        }
773

    
774
        fd = net_bridge_run_helper(tap->helper, DEFAULT_BRIDGE_INTERFACE);
775
        if (fd == -1) {
776
            return -1;
777
        }
778

    
779
        fcntl(fd, F_SETFL, O_NONBLOCK);
780
        vnet_hdr = tap_probe_vnet_hdr(fd);
781

    
782
        if (net_init_tap_one(tap, peer, "bridge", name, ifname,
783
                             script, downscript, vhostfdname,
784
                             vnet_hdr, fd)) {
785
            return -1;
786
        }
787
    } else {
788
        script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT;
789
        downscript = tap->has_downscript ? tap->downscript :
790
            DEFAULT_NETWORK_DOWN_SCRIPT;
791

    
792
        if (tap->has_ifname) {
793
            pstrcpy(ifname, sizeof ifname, tap->ifname);
794
        } else {
795
            ifname[0] = '\0';
796
        }
797

    
798
        for (i = 0; i < queues; i++) {
799
            fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script,
800
                              ifname, sizeof ifname, queues > 1);
801
            if (fd == -1) {
802
                return -1;
803
            }
804

    
805
            if (queues > 1 && i == 0 && !tap->has_ifname) {
806
                if (tap_fd_get_ifname(fd, ifname)) {
807
                    error_report("Fail to get ifname");
808
                    return -1;
809
                }
810
            }
811

    
812
            if (net_init_tap_one(tap, peer, "tap", name, ifname,
813
                                 i >= 1 ? "no" : script,
814
                                 i >= 1 ? "no" : downscript,
815
                                 vhostfdname, vnet_hdr, fd)) {
816
                return -1;
817
            }
818
        }
819
    }
820

    
821
    return 0;
822
}
823

    
824
VHostNetState *tap_get_vhost_net(NetClientState *nc)
825
{
826
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
827
    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
828
    return s->vhost_net;
829
}
830

    
831
int tap_enable(NetClientState *nc)
832
{
833
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
834
    int ret;
835

    
836
    if (s->enabled) {
837
        return 0;
838
    } else {
839
        ret = tap_fd_enable(s->fd);
840
        if (ret == 0) {
841
            s->enabled = true;
842
            tap_update_fd_handler(s);
843
        }
844
        return ret;
845
    }
846
}
847

    
848
int tap_disable(NetClientState *nc)
849
{
850
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
851
    int ret;
852

    
853
    if (s->enabled == 0) {
854
        return 0;
855
    } else {
856
        ret = tap_fd_disable(s->fd);
857
        if (ret == 0) {
858
            qemu_purge_queued_packets(nc);
859
            s->enabled = false;
860
            tap_update_fd_handler(s);
861
        }
862
        return ret;
863
    }
864
}