Annotation of qemu/net/tap.c, revision 1.1.1.1

1.1       root        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: /* 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 = 0;
                    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: }

unix.superglobalmegacorp.com