]> Git Repo - qemu.git/blob - net/tap.c
tap: invoke downscript when we exit abnormally
[qemu.git] / net / tap.c
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 #include "qemu-error.h"
42
43 #include "net/tap-linux.h"
44
45 /* Maximum GSO packet size (64k) plus plenty of room for
46  * the ethernet and virtio_net headers
47  */
48 #define TAP_BUFSIZE (4096 + 65536)
49
50 typedef struct TAPState {
51     VLANClientState nc;
52     int fd;
53     char down_script[1024];
54     char down_script_arg[128];
55     uint8_t buf[TAP_BUFSIZE];
56     Notifier exit_notifier;
57     unsigned int read_poll : 1;
58     unsigned int write_poll : 1;
59     unsigned int has_vnet_hdr : 1;
60     unsigned int using_vnet_hdr : 1;
61     unsigned int has_ufo: 1;
62 } TAPState;
63
64 static int launch_script(const char *setup_script, const char *ifname, int fd);
65
66 static int tap_can_send(void *opaque);
67 static void tap_send(void *opaque);
68 static void tap_writable(void *opaque);
69
70 static void tap_update_fd_handler(TAPState *s)
71 {
72     qemu_set_fd_handler2(s->fd,
73                          s->read_poll  ? tap_can_send : NULL,
74                          s->read_poll  ? tap_send     : NULL,
75                          s->write_poll ? tap_writable : NULL,
76                          s);
77 }
78
79 static void tap_read_poll(TAPState *s, int enable)
80 {
81     s->read_poll = !!enable;
82     tap_update_fd_handler(s);
83 }
84
85 static void tap_write_poll(TAPState *s, int enable)
86 {
87     s->write_poll = !!enable;
88     tap_update_fd_handler(s);
89 }
90
91 static void tap_writable(void *opaque)
92 {
93     TAPState *s = opaque;
94
95     tap_write_poll(s, 0);
96
97     qemu_flush_queued_packets(&s->nc);
98 }
99
100 static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt)
101 {
102     ssize_t len;
103
104     do {
105         len = writev(s->fd, iov, iovcnt);
106     } while (len == -1 && errno == EINTR);
107
108     if (len == -1 && errno == EAGAIN) {
109         tap_write_poll(s, 1);
110         return 0;
111     }
112
113     return len;
114 }
115
116 static ssize_t tap_receive_iov(VLANClientState *nc, const struct iovec *iov,
117                                int iovcnt)
118 {
119     TAPState *s = DO_UPCAST(TAPState, nc, nc);
120     const struct iovec *iovp = iov;
121     struct iovec iov_copy[iovcnt + 1];
122     struct virtio_net_hdr hdr = { 0, };
123
124     if (s->has_vnet_hdr && !s->using_vnet_hdr) {
125         iov_copy[0].iov_base = &hdr;
126         iov_copy[0].iov_len =  sizeof(hdr);
127         memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
128         iovp = iov_copy;
129         iovcnt++;
130     }
131
132     return tap_write_packet(s, iovp, iovcnt);
133 }
134
135 static ssize_t tap_receive_raw(VLANClientState *nc, const uint8_t *buf, size_t size)
136 {
137     TAPState *s = DO_UPCAST(TAPState, nc, nc);
138     struct iovec iov[2];
139     int iovcnt = 0;
140     struct virtio_net_hdr hdr = { 0, };
141
142     if (s->has_vnet_hdr) {
143         iov[iovcnt].iov_base = &hdr;
144         iov[iovcnt].iov_len  = sizeof(hdr);
145         iovcnt++;
146     }
147
148     iov[iovcnt].iov_base = (char *)buf;
149     iov[iovcnt].iov_len  = size;
150     iovcnt++;
151
152     return tap_write_packet(s, iov, iovcnt);
153 }
154
155 static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
156 {
157     TAPState *s = DO_UPCAST(TAPState, nc, nc);
158     struct iovec iov[1];
159
160     if (s->has_vnet_hdr && !s->using_vnet_hdr) {
161         return tap_receive_raw(nc, buf, size);
162     }
163
164     iov[0].iov_base = (char *)buf;
165     iov[0].iov_len  = size;
166
167     return tap_write_packet(s, iov, 1);
168 }
169
170 static int tap_can_send(void *opaque)
171 {
172     TAPState *s = opaque;
173
174     return qemu_can_send_packet(&s->nc);
175 }
176
177 #ifndef __sun__
178 ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
179 {
180     return read(tapfd, buf, maxlen);
181 }
182 #endif
183
184 static void tap_send_completed(VLANClientState *nc, ssize_t len)
185 {
186     TAPState *s = DO_UPCAST(TAPState, nc, nc);
187     tap_read_poll(s, 1);
188 }
189
190 static void tap_send(void *opaque)
191 {
192     TAPState *s = opaque;
193     int size;
194
195     do {
196         uint8_t *buf = s->buf;
197
198         size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
199         if (size <= 0) {
200             break;
201         }
202
203         if (s->has_vnet_hdr && !s->using_vnet_hdr) {
204             buf  += sizeof(struct virtio_net_hdr);
205             size -= sizeof(struct virtio_net_hdr);
206         }
207
208         size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
209         if (size == 0) {
210             tap_read_poll(s, 0);
211         }
212     } while (size > 0 && qemu_can_send_packet(&s->nc));
213 }
214
215 int tap_has_ufo(VLANClientState *nc)
216 {
217     TAPState *s = DO_UPCAST(TAPState, nc, nc);
218
219     assert(nc->info->type == NET_CLIENT_TYPE_TAP);
220
221     return s->has_ufo;
222 }
223
224 int tap_has_vnet_hdr(VLANClientState *nc)
225 {
226     TAPState *s = DO_UPCAST(TAPState, nc, nc);
227
228     assert(nc->info->type == NET_CLIENT_TYPE_TAP);
229
230     return s->has_vnet_hdr;
231 }
232
233 void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr)
234 {
235     TAPState *s = DO_UPCAST(TAPState, nc, nc);
236
237     using_vnet_hdr = using_vnet_hdr != 0;
238
239     assert(nc->info->type == NET_CLIENT_TYPE_TAP);
240     assert(s->has_vnet_hdr == using_vnet_hdr);
241
242     s->using_vnet_hdr = using_vnet_hdr;
243 }
244
245 void tap_set_offload(VLANClientState *nc, int csum, int tso4,
246                      int tso6, int ecn, int ufo)
247 {
248     TAPState *s = DO_UPCAST(TAPState, nc, nc);
249
250     return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
251 }
252
253 static void tap_cleanup(VLANClientState *nc)
254 {
255     TAPState *s = DO_UPCAST(TAPState, nc, nc);
256
257     qemu_purge_queued_packets(nc);
258
259     if (s->down_script[0])
260         launch_script(s->down_script, s->down_script_arg, s->fd);
261
262     tap_read_poll(s, 0);
263     tap_write_poll(s, 0);
264     close(s->fd);
265     exit_notifier_remove(&s->exit_notifier);
266 }
267
268 /* Instead of exiting gracefully, we're exiting because someone called
269  * exit(), make sure to invoke down script at least
270  */
271 static void tap_cleanup_at_exit(Notifier *notifier)
272 {
273     TAPState *s = container_of(notifier, TAPState, exit_notifier);
274
275     if (s->down_script[0]) {
276         launch_script(s->down_script, s->down_script_arg, s->fd);
277     }
278 }
279
280 static void tap_poll(VLANClientState *nc, bool enable)
281 {
282     TAPState *s = DO_UPCAST(TAPState, nc, nc);
283     tap_read_poll(s, enable);
284     tap_write_poll(s, enable);
285 }
286
287 /* fd support */
288
289 static NetClientInfo net_tap_info = {
290     .type = NET_CLIENT_TYPE_TAP,
291     .size = sizeof(TAPState),
292     .receive = tap_receive,
293     .receive_raw = tap_receive_raw,
294     .receive_iov = tap_receive_iov,
295     .poll = tap_poll,
296     .cleanup = tap_cleanup,
297 };
298
299 static TAPState *net_tap_fd_init(VLANState *vlan,
300                                  const char *model,
301                                  const char *name,
302                                  int fd,
303                                  int vnet_hdr)
304 {
305     VLANClientState *nc;
306     TAPState *s;
307
308     nc = qemu_new_net_client(&net_tap_info, vlan, NULL, model, name);
309
310     s = DO_UPCAST(TAPState, nc, nc);
311
312     s->fd = fd;
313     s->has_vnet_hdr = vnet_hdr != 0;
314     s->using_vnet_hdr = 0;
315     s->has_ufo = tap_probe_has_ufo(s->fd);
316     s->exit_notifier.notify = tap_cleanup_at_exit;
317     exit_notifier_add(&s->exit_notifier);
318     tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
319     tap_read_poll(s, 1);
320     return s;
321 }
322
323 static int launch_script(const char *setup_script, const char *ifname, int fd)
324 {
325     sigset_t oldmask, mask;
326     int pid, status;
327     char *args[3];
328     char **parg;
329
330     sigemptyset(&mask);
331     sigaddset(&mask, SIGCHLD);
332     sigprocmask(SIG_BLOCK, &mask, &oldmask);
333
334     /* try to launch network script */
335     pid = fork();
336     if (pid == 0) {
337         int open_max = sysconf(_SC_OPEN_MAX), i;
338
339         for (i = 0; i < open_max; i++) {
340             if (i != STDIN_FILENO &&
341                 i != STDOUT_FILENO &&
342                 i != STDERR_FILENO &&
343                 i != fd) {
344                 close(i);
345             }
346         }
347         parg = args;
348         *parg++ = (char *)setup_script;
349         *parg++ = (char *)ifname;
350         *parg++ = NULL;
351         execv(setup_script, args);
352         _exit(1);
353     } else if (pid > 0) {
354         while (waitpid(pid, &status, 0) != pid) {
355             /* loop */
356         }
357         sigprocmask(SIG_SETMASK, &oldmask, NULL);
358
359         if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
360             return 0;
361         }
362     }
363     fprintf(stderr, "%s: could not launch network script\n", setup_script);
364     return -1;
365 }
366
367 static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
368 {
369     int fd, vnet_hdr_required;
370     char ifname[128] = {0,};
371     const char *setup_script;
372
373     if (qemu_opt_get(opts, "ifname")) {
374         pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
375     }
376
377     *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
378     if (qemu_opt_get(opts, "vnet_hdr")) {
379         vnet_hdr_required = *vnet_hdr;
380     } else {
381         vnet_hdr_required = 0;
382     }
383
384     TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
385     if (fd < 0) {
386         return -1;
387     }
388
389     setup_script = qemu_opt_get(opts, "script");
390     if (setup_script &&
391         setup_script[0] != '\0' &&
392         strcmp(setup_script, "no") != 0 &&
393         launch_script(setup_script, ifname, fd)) {
394         close(fd);
395         return -1;
396     }
397
398     qemu_opt_set(opts, "ifname", ifname);
399
400     return fd;
401 }
402
403 int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
404 {
405     TAPState *s;
406     int fd, vnet_hdr = 0;
407
408     if (qemu_opt_get(opts, "fd")) {
409         if (qemu_opt_get(opts, "ifname") ||
410             qemu_opt_get(opts, "script") ||
411             qemu_opt_get(opts, "downscript") ||
412             qemu_opt_get(opts, "vnet_hdr")) {
413             error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=");
414             return -1;
415         }
416
417         fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
418         if (fd == -1) {
419             return -1;
420         }
421
422         fcntl(fd, F_SETFL, O_NONBLOCK);
423
424         vnet_hdr = tap_probe_vnet_hdr(fd);
425     } else {
426         if (!qemu_opt_get(opts, "script")) {
427             qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
428         }
429
430         if (!qemu_opt_get(opts, "downscript")) {
431             qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
432         }
433
434         fd = net_tap_init(opts, &vnet_hdr);
435         if (fd == -1) {
436             return -1;
437         }
438     }
439
440     s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
441     if (!s) {
442         close(fd);
443         return -1;
444     }
445
446     if (tap_set_sndbuf(s->fd, opts) < 0) {
447         return -1;
448     }
449
450     if (qemu_opt_get(opts, "fd")) {
451         snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
452     } else {
453         const char *ifname, *script, *downscript;
454
455         ifname     = qemu_opt_get(opts, "ifname");
456         script     = qemu_opt_get(opts, "script");
457         downscript = qemu_opt_get(opts, "downscript");
458
459         snprintf(s->nc.info_str, sizeof(s->nc.info_str),
460                  "ifname=%s,script=%s,downscript=%s",
461                  ifname, script, downscript);
462
463         if (strcmp(downscript, "no") != 0) {
464             snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
465             snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
466         }
467     }
468
469     return 0;
470 }
This page took 0.049567 seconds and 4 git commands to generate.