Statistics
| Branch: | Revision:

root / net / tap.c @ 62112d18

History | View | Annotate | Download (11.5 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->info->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->info->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->info->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
static void tap_poll(VLANClientState *nc, bool enable)
266
{
267
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
268
    tap_read_poll(s, enable);
269
    tap_write_poll(s, enable);
270
}
271

    
272
/* fd support */
273

    
274
static NetClientInfo net_tap_info = {
275
    .type = NET_CLIENT_TYPE_TAP,
276
    .size = sizeof(TAPState),
277
    .receive = tap_receive,
278
    .receive_raw = tap_receive_raw,
279
    .receive_iov = tap_receive_iov,
280
    .poll = tap_poll,
281
    .cleanup = tap_cleanup,
282
};
283

    
284
static TAPState *net_tap_fd_init(VLANState *vlan,
285
                                 const char *model,
286
                                 const char *name,
287
                                 int fd,
288
                                 int vnet_hdr)
289
{
290
    VLANClientState *nc;
291
    TAPState *s;
292

    
293
    nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name);
294

    
295
    s = DO_UPCAST(TAPState, nc, nc);
296

    
297
    s->fd = fd;
298
    s->has_vnet_hdr = vnet_hdr != 0;
299
    s->using_vnet_hdr = 0;
300
    s->has_ufo = tap_probe_has_ufo(s->fd);
301
    tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
302
    tap_read_poll(s, 1);
303
    return s;
304
}
305

    
306
static int launch_script(const char *setup_script, const char *ifname, int fd)
307
{
308
    sigset_t oldmask, mask;
309
    int pid, status;
310
    char *args[3];
311
    char **parg;
312

    
313
    sigemptyset(&mask);
314
    sigaddset(&mask, SIGCHLD);
315
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
316

    
317
    /* try to launch network script */
318
    pid = fork();
319
    if (pid == 0) {
320
        int open_max = sysconf(_SC_OPEN_MAX), i;
321

    
322
        for (i = 0; i < open_max; i++) {
323
            if (i != STDIN_FILENO &&
324
                i != STDOUT_FILENO &&
325
                i != STDERR_FILENO &&
326
                i != fd) {
327
                close(i);
328
            }
329
        }
330
        parg = args;
331
        *parg++ = (char *)setup_script;
332
        *parg++ = (char *)ifname;
333
        *parg++ = NULL;
334
        execv(setup_script, args);
335
        _exit(1);
336
    } else if (pid > 0) {
337
        while (waitpid(pid, &status, 0) != pid) {
338
            /* loop */
339
        }
340
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
341

    
342
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
343
            return 0;
344
        }
345
    }
346
    fprintf(stderr, "%s: could not launch network script\n", setup_script);
347
    return -1;
348
}
349

    
350
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
351
{
352
    int fd, vnet_hdr_required;
353
    char ifname[128] = {0,};
354
    const char *setup_script;
355

    
356
    if (qemu_opt_get(opts, "ifname")) {
357
        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
358
    }
359

    
360
    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
361
    if (qemu_opt_get(opts, "vnet_hdr")) {
362
        vnet_hdr_required = *vnet_hdr;
363
    } else {
364
        vnet_hdr_required = 0;
365
    }
366

    
367
    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
368
    if (fd < 0) {
369
        return -1;
370
    }
371

    
372
    setup_script = qemu_opt_get(opts, "script");
373
    if (setup_script &&
374
        setup_script[0] != '\0' &&
375
        strcmp(setup_script, "no") != 0 &&
376
        launch_script(setup_script, ifname, fd)) {
377
        close(fd);
378
        return -1;
379
    }
380

    
381
    qemu_opt_set(opts, "ifname", ifname);
382

    
383
    return fd;
384
}
385

    
386
int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
387
{
388
    TAPState *s;
389
    int fd, vnet_hdr = 0;
390

    
391
    if (qemu_opt_get(opts, "fd")) {
392
        if (qemu_opt_get(opts, "ifname") ||
393
            qemu_opt_get(opts, "script") ||
394
            qemu_opt_get(opts, "downscript") ||
395
            qemu_opt_get(opts, "vnet_hdr")) {
396
            qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n");
397
            return -1;
398
        }
399

    
400
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
401
        if (fd == -1) {
402
            return -1;
403
        }
404

    
405
        fcntl(fd, F_SETFL, O_NONBLOCK);
406

    
407
        vnet_hdr = tap_probe_vnet_hdr(fd);
408
    } else {
409
        if (!qemu_opt_get(opts, "script")) {
410
            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
411
        }
412

    
413
        if (!qemu_opt_get(opts, "downscript")) {
414
            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
415
        }
416

    
417
        fd = net_tap_init(opts, &vnet_hdr);
418
        if (fd == -1) {
419
            return -1;
420
        }
421
    }
422

    
423
    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
424
    if (!s) {
425
        close(fd);
426
        return -1;
427
    }
428

    
429
    if (tap_set_sndbuf(s->fd, opts) < 0) {
430
        return -1;
431
    }
432

    
433
    if (qemu_opt_get(opts, "fd")) {
434
        snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
435
    } else {
436
        const char *ifname, *script, *downscript;
437

    
438
        ifname     = qemu_opt_get(opts, "ifname");
439
        script     = qemu_opt_get(opts, "script");
440
        downscript = qemu_opt_get(opts, "downscript");
441

    
442
        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
443
                 "ifname=%s,script=%s,downscript=%s",
444
                 ifname, script, downscript);
445

    
446
        if (strcmp(downscript, "no") != 0) {
447
            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
448
            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
449
        }
450
    }
451

    
452
    return 0;
453
}