Statistics
| Branch: | Revision:

root / net / tap.c @ 3e35ba93

History | View | Annotate | Download (11.3 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 "net/tap.h"
27

    
28
#include "config-host.h"
29

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

    
37
#include "net.h"
38
#include "sysemu.h"
39
#include "qemu-char.h"
40
#include "qemu-common.h"
41

    
42
#include "net/tap-linux.h"
43

    
44
/* Maximum GSO packet size (64k) plus plenty of room for
45
 * the ethernet and virtio_net headers
46
 */
47
#define TAP_BUFSIZE (4096 + 65536)
48

    
49
typedef struct TAPState {
50
    VLANClientState nc;
51
    int fd;
52
    char down_script[1024];
53
    char down_script_arg[128];
54
    uint8_t buf[TAP_BUFSIZE];
55
    unsigned int read_poll : 1;
56
    unsigned int write_poll : 1;
57
    unsigned int has_vnet_hdr : 1;
58
    unsigned int using_vnet_hdr : 1;
59
    unsigned int has_ufo: 1;
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  ? tap_can_send : NULL,
72
                         s->read_poll  ? tap_send     : NULL,
73
                         s->write_poll ? tap_writable : NULL,
74
                         s);
75
}
76

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

    
83
static void tap_write_poll(TAPState *s, int 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, 0);
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, 1);
108
        return 0;
109
    }
110

    
111
    return len;
112
}
113

    
114
static ssize_t tap_receive_iov(VLANClientState *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 hdr = { 0, };
121

    
122
    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
123
        iov_copy[0].iov_base = &hdr;
124
        iov_copy[0].iov_len =  sizeof(hdr);
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(VLANClientState *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 hdr = { 0, };
139

    
140
    if (s->has_vnet_hdr) {
141
        iov[iovcnt].iov_base = &hdr;
142
        iov[iovcnt].iov_len  = sizeof(hdr);
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(VLANClientState *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->has_vnet_hdr && !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(VLANClientState *nc, ssize_t len)
183
{
184
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
185
    tap_read_poll(s, 1);
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->has_vnet_hdr && !s->using_vnet_hdr) {
202
            buf  += sizeof(struct virtio_net_hdr);
203
            size -= sizeof(struct virtio_net_hdr);
204
        }
205

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

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

    
217
    assert(nc->type == NET_CLIENT_TYPE_TAP);
218

    
219
    return s->has_ufo;
220
}
221

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

    
226
    assert(nc->type == NET_CLIENT_TYPE_TAP);
227

    
228
    return s->has_vnet_hdr;
229
}
230

    
231
void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr)
232
{
233
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
234

    
235
    using_vnet_hdr = using_vnet_hdr != 0;
236

    
237
    assert(nc->type == NET_CLIENT_TYPE_TAP);
238
    assert(s->has_vnet_hdr == using_vnet_hdr);
239

    
240
    s->using_vnet_hdr = using_vnet_hdr;
241
}
242

    
243
void tap_set_offload(VLANClientState *nc, int csum, int tso4,
244
                     int tso6, int ecn, int ufo)
245
{
246
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
247

    
248
    return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
249
}
250

    
251
static void tap_cleanup(VLANClientState *nc)
252
{
253
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
254

    
255
    qemu_purge_queued_packets(nc);
256

    
257
    if (s->down_script[0])
258
        launch_script(s->down_script, s->down_script_arg, s->fd);
259

    
260
    tap_read_poll(s, 0);
261
    tap_write_poll(s, 0);
262
    close(s->fd);
263
}
264

    
265
/* fd support */
266

    
267
static NetClientInfo net_tap_info = {
268
    .type = NET_CLIENT_TYPE_TAP,
269
    .size = sizeof(TAPState),
270
    .receive = tap_receive,
271
    .receive_raw = tap_receive_raw,
272
    .receive_iov = tap_receive_iov,
273
    .cleanup = tap_cleanup,
274
};
275

    
276
static TAPState *net_tap_fd_init(VLANState *vlan,
277
                                 const char *model,
278
                                 const char *name,
279
                                 int fd,
280
                                 int vnet_hdr)
281
{
282
    VLANClientState *nc;
283
    TAPState *s;
284

    
285
    nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name);
286

    
287
    s = DO_UPCAST(TAPState, nc, nc);
288

    
289
    s->fd = fd;
290
    s->has_vnet_hdr = vnet_hdr != 0;
291
    s->using_vnet_hdr = 0;
292
    s->has_ufo = tap_probe_has_ufo(s->fd);
293
    tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
294
    tap_read_poll(s, 1);
295
    return s;
296
}
297

    
298
static int launch_script(const char *setup_script, const char *ifname, int fd)
299
{
300
    sigset_t oldmask, mask;
301
    int pid, status;
302
    char *args[3];
303
    char **parg;
304

    
305
    sigemptyset(&mask);
306
    sigaddset(&mask, SIGCHLD);
307
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
308

    
309
    /* try to launch network script */
310
    pid = fork();
311
    if (pid == 0) {
312
        int open_max = sysconf(_SC_OPEN_MAX), i;
313

    
314
        for (i = 0; i < open_max; i++) {
315
            if (i != STDIN_FILENO &&
316
                i != STDOUT_FILENO &&
317
                i != STDERR_FILENO &&
318
                i != fd) {
319
                close(i);
320
            }
321
        }
322
        parg = args;
323
        *parg++ = (char *)setup_script;
324
        *parg++ = (char *)ifname;
325
        *parg++ = NULL;
326
        execv(setup_script, args);
327
        _exit(1);
328
    } else if (pid > 0) {
329
        while (waitpid(pid, &status, 0) != pid) {
330
            /* loop */
331
        }
332
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
333

    
334
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
335
            return 0;
336
        }
337
    }
338
    fprintf(stderr, "%s: could not launch network script\n", setup_script);
339
    return -1;
340
}
341

    
342
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
343
{
344
    int fd, vnet_hdr_required;
345
    char ifname[128] = {0,};
346
    const char *setup_script;
347

    
348
    if (qemu_opt_get(opts, "ifname")) {
349
        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
350
    }
351

    
352
    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
353
    if (qemu_opt_get(opts, "vnet_hdr")) {
354
        vnet_hdr_required = *vnet_hdr;
355
    } else {
356
        vnet_hdr_required = 0;
357
    }
358

    
359
    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
360
    if (fd < 0) {
361
        return -1;
362
    }
363

    
364
    setup_script = qemu_opt_get(opts, "script");
365
    if (setup_script &&
366
        setup_script[0] != '\0' &&
367
        strcmp(setup_script, "no") != 0 &&
368
        launch_script(setup_script, ifname, fd)) {
369
        close(fd);
370
        return -1;
371
    }
372

    
373
    qemu_opt_set(opts, "ifname", ifname);
374

    
375
    return fd;
376
}
377

    
378
int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
379
{
380
    TAPState *s;
381
    int fd, vnet_hdr;
382

    
383
    if (qemu_opt_get(opts, "fd")) {
384
        if (qemu_opt_get(opts, "ifname") ||
385
            qemu_opt_get(opts, "script") ||
386
            qemu_opt_get(opts, "downscript") ||
387
            qemu_opt_get(opts, "vnet_hdr")) {
388
            qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n");
389
            return -1;
390
        }
391

    
392
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
393
        if (fd == -1) {
394
            return -1;
395
        }
396

    
397
        fcntl(fd, F_SETFL, O_NONBLOCK);
398

    
399
        vnet_hdr = tap_probe_vnet_hdr(fd);
400
    } else {
401
        if (!qemu_opt_get(opts, "script")) {
402
            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
403
        }
404

    
405
        if (!qemu_opt_get(opts, "downscript")) {
406
            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
407
        }
408

    
409
        fd = net_tap_init(opts, &vnet_hdr);
410
        if (fd == -1) {
411
            return -1;
412
        }
413
    }
414

    
415
    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
416
    if (!s) {
417
        close(fd);
418
        return -1;
419
    }
420

    
421
    if (tap_set_sndbuf(s->fd, opts) < 0) {
422
        return -1;
423
    }
424

    
425
    if (qemu_opt_get(opts, "fd")) {
426
        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
427
    } else {
428
        const char *ifname, *script, *downscript;
429

    
430
        ifname     = qemu_opt_get(opts, "ifname");
431
        script     = qemu_opt_get(opts, "script");
432
        downscript = qemu_opt_get(opts, "downscript");
433

    
434
        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
435
                 "ifname=%s,script=%s,downscript=%s",
436
                 ifname, script, downscript);
437

    
438
        if (strcmp(downscript, "no") != 0) {
439
            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
440
            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
441
        }
442
    }
443

    
444
    if (vlan) {
445
        vlan->nb_host_devs++;
446
    }
447

    
448
    return 0;
449
}