Statistics
| Branch: | Revision:

root / net / tap.c @ 5819c918

History | View | Annotate | Download (11.1 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 *vc;
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->vc);
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 *vc, const struct iovec *iov,
115
                               int iovcnt)
116
{
117
    TAPState *s = vc->opaque;
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 *vc, const uint8_t *buf, size_t size)
134
{
135
    TAPState *s = vc->opaque;
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 *vc, const uint8_t *buf, size_t size)
154
{
155
    TAPState *s = vc->opaque;
156
    struct iovec iov[1];
157

    
158
    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
159
        return tap_receive_raw(vc, 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->vc);
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 *vc, ssize_t len)
183
{
184
    TAPState *s = vc->opaque;
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->vc, 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->vc));
211
}
212

    
213
int tap_has_ufo(VLANClientState *vc)
214
{
215
    TAPState *s = vc->opaque;
216

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

    
219
    return s->has_ufo;
220
}
221

    
222
int tap_has_vnet_hdr(VLANClientState *vc)
223
{
224
    TAPState *s = vc->opaque;
225

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

    
228
    return s->has_vnet_hdr;
229
}
230

    
231
void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
232
{
233
    TAPState *s = vc->opaque;
234

    
235
    using_vnet_hdr = using_vnet_hdr != 0;
236

    
237
    assert(vc->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 *vc, int csum, int tso4,
244
                     int tso6, int ecn, int ufo)
245
{
246
    TAPState *s = vc->opaque;
247

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

    
251
static void tap_cleanup(VLANClientState *vc)
252
{
253
    TAPState *s = vc->opaque;
254

    
255
    qemu_purge_queued_packets(vc);
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
    qemu_free(s);
264
}
265

    
266
/* fd support */
267

    
268
static TAPState *net_tap_fd_init(VLANState *vlan,
269
                                 const char *model,
270
                                 const char *name,
271
                                 int fd,
272
                                 int vnet_hdr)
273
{
274
    TAPState *s;
275

    
276
    s = qemu_mallocz(sizeof(TAPState));
277
    s->fd = fd;
278
    s->has_vnet_hdr = vnet_hdr != 0;
279
    s->using_vnet_hdr = 0;
280
    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
281
                                 vlan, NULL, model, name, NULL,
282
                                 tap_receive, tap_receive_raw,
283
                                 tap_receive_iov, tap_cleanup, s);
284
    s->has_ufo = tap_probe_has_ufo(s->fd);
285
    tap_set_offload(s->vc, 0, 0, 0, 0, 0);
286
    tap_read_poll(s, 1);
287
    return s;
288
}
289

    
290
static int launch_script(const char *setup_script, const char *ifname, int fd)
291
{
292
    sigset_t oldmask, mask;
293
    int pid, status;
294
    char *args[3];
295
    char **parg;
296

    
297
    sigemptyset(&mask);
298
    sigaddset(&mask, SIGCHLD);
299
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
300

    
301
    /* try to launch network script */
302
    pid = fork();
303
    if (pid == 0) {
304
        int open_max = sysconf(_SC_OPEN_MAX), i;
305

    
306
        for (i = 0; i < open_max; i++) {
307
            if (i != STDIN_FILENO &&
308
                i != STDOUT_FILENO &&
309
                i != STDERR_FILENO &&
310
                i != fd) {
311
                close(i);
312
            }
313
        }
314
        parg = args;
315
        *parg++ = (char *)setup_script;
316
        *parg++ = (char *)ifname;
317
        *parg++ = NULL;
318
        execv(setup_script, args);
319
        _exit(1);
320
    } else if (pid > 0) {
321
        while (waitpid(pid, &status, 0) != pid) {
322
            /* loop */
323
        }
324
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
325

    
326
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
327
            return 0;
328
        }
329
    }
330
    fprintf(stderr, "%s: could not launch network script\n", setup_script);
331
    return -1;
332
}
333

    
334
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
335
{
336
    int fd, vnet_hdr_required;
337
    char ifname[128] = {0,};
338
    const char *setup_script;
339

    
340
    if (qemu_opt_get(opts, "ifname")) {
341
        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
342
    }
343

    
344
    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
345
    if (qemu_opt_get(opts, "vnet_hdr")) {
346
        vnet_hdr_required = *vnet_hdr;
347
    } else {
348
        vnet_hdr_required = 0;
349
    }
350

    
351
    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
352
    if (fd < 0) {
353
        return -1;
354
    }
355

    
356
    setup_script = qemu_opt_get(opts, "script");
357
    if (setup_script &&
358
        setup_script[0] != '\0' &&
359
        strcmp(setup_script, "no") != 0 &&
360
        launch_script(setup_script, ifname, fd)) {
361
        close(fd);
362
        return -1;
363
    }
364

    
365
    qemu_opt_set(opts, "ifname", ifname);
366

    
367
    return fd;
368
}
369

    
370
int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
371
{
372
    TAPState *s;
373
    int fd, vnet_hdr;
374

    
375
    if (qemu_opt_get(opts, "fd")) {
376
        if (qemu_opt_get(opts, "ifname") ||
377
            qemu_opt_get(opts, "script") ||
378
            qemu_opt_get(opts, "downscript") ||
379
            qemu_opt_get(opts, "vnet_hdr")) {
380
            qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n");
381
            return -1;
382
        }
383

    
384
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
385
        if (fd == -1) {
386
            return -1;
387
        }
388

    
389
        fcntl(fd, F_SETFL, O_NONBLOCK);
390

    
391
        vnet_hdr = tap_probe_vnet_hdr(fd);
392
    } else {
393
        if (!qemu_opt_get(opts, "script")) {
394
            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
395
        }
396

    
397
        if (!qemu_opt_get(opts, "downscript")) {
398
            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
399
        }
400

    
401
        fd = net_tap_init(opts, &vnet_hdr);
402
    }
403

    
404
    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
405
    if (!s) {
406
        close(fd);
407
        return -1;
408
    }
409

    
410
    if (tap_set_sndbuf(s->fd, opts) < 0) {
411
        return -1;
412
    }
413

    
414
    if (qemu_opt_get(opts, "fd")) {
415
        snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
416
    } else {
417
        const char *ifname, *script, *downscript;
418

    
419
        ifname     = qemu_opt_get(opts, "ifname");
420
        script     = qemu_opt_get(opts, "script");
421
        downscript = qemu_opt_get(opts, "downscript");
422

    
423
        snprintf(s->vc->info_str, sizeof(s->vc->info_str),
424
                 "ifname=%s,script=%s,downscript=%s",
425
                 ifname, script, downscript);
426

    
427
        if (strcmp(downscript, "no") != 0) {
428
            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
429
            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
430
        }
431
    }
432

    
433
    if (vlan) {
434
        vlan->nb_host_devs++;
435
    }
436

    
437
    return 0;
438
}