/* * QEMU System Emulator * * Copyright (c) 2003-2008 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "qemu/osdep.h" #include "qapi/error.h" #include "tap_int.h" #include "qemu/cutils.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" #if defined(__NetBSD__) || defined(__FreeBSD__) #include <sys/ioctl.h> #include <net/if.h> #include <net/if_tap.h> #endif #ifndef __FreeBSD__ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required, int mq_required, Error **errp) { int fd; #ifdef TAPGIFNAME struct ifreq ifr; #else char *dev; struct stat s; #endif /* if no ifname is given, always start the search from tap0/tun0. */ int i; char dname[100]; for (i = 0; i < 10; i++) { if (*ifname) { snprintf(dname, sizeof dname, "/dev/%s", ifname); } else { #if defined(__OpenBSD__) snprintf(dname, sizeof dname, "/dev/tun%d", i); #else snprintf(dname, sizeof dname, "/dev/tap%d", i); #endif } TFR(fd = open(dname, O_RDWR)); if (fd >= 0) { break; } else if (errno == ENXIO || errno == ENOENT) { break; } if (*ifname) { break; } } if (fd < 0) { error_setg_errno(errp, errno, "could not open %s", dname); return -1; } #ifdef TAPGIFNAME if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) { error_setg_errno(errp, errno, "could not get tap name"); return -1; } pstrcpy(ifname, ifname_size, ifr.ifr_name); #else if (fstat(fd, &s) < 0) { error_setg_errno(errp, errno, "could not stat %s", dname); return -1; } dev = devname(s.st_rdev, S_IFCHR); pstrcpy(ifname, ifname_size, dev); #endif if (*vnet_hdr) { /* BSD doesn't have IFF_VNET_HDR */ *vnet_hdr = 0; if (vnet_hdr_required && !*vnet_hdr) { error_setg(errp, "vnet_hdr=1 requested, but no kernel " "support for IFF_VNET_HDR available"); close(fd); return -1; } } fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } #else /* __FreeBSD__ */ #define PATH_NET_TAP "/dev/tap" static int tap_open_clone(char *ifname, int ifname_size, Error **errp) { int fd, s, ret; struct ifreq ifr; TFR(fd = open(PATH_NET_TAP, O_RDWR)); if (fd < 0) { error_setg_errno(errp, errno, "could not open %s", PATH_NET_TAP); return -1; } memset(&ifr, 0, sizeof(ifr)); ret = ioctl(fd, TAPGIFNAME, (void *)&ifr); if (ret < 0) { error_setg_errno(errp, errno, "could not get tap interface name"); close(fd); return -1; } if (ifname[0] != '\0') { /* User requested the interface to have a specific name */ s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s < 0) { error_setg_errno(errp, errno, "could not open socket to set interface name"); close(fd); return -1; } ifr.ifr_data = ifname; ret = ioctl(s, SIOCSIFNAME, (void *)&ifr); close(s); if (ret < 0) { error_setg(errp, "could not set tap interface name"); close(fd); return -1; } } else { pstrcpy(ifname, ifname_size, ifr.ifr_name); } return fd; } int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required, int mq_required, Error **errp) { int fd = -1; /* If the specified tap device already exists just use it. */ if (ifname[0] != '\0') { char dname[100]; snprintf(dname, sizeof dname, "/dev/%s", ifname); TFR(fd = open(dname, O_RDWR)); if (fd < 0 && errno != ENOENT) { error_setg_errno(errp, errno, "could not open %s", dname); return -1; } } if (fd < 0) { /* Tap device not specified or does not exist. */ if ((fd = tap_open_clone(ifname, ifname_size, errp)) < 0) { return -1; } } if (*vnet_hdr) { /* BSD doesn't have IFF_VNET_HDR */ *vnet_hdr = 0; if (vnet_hdr_required && !*vnet_hdr) { error_setg(errp, "vnet_hdr=1 requested, but no kernel " "support for IFF_VNET_HDR available"); goto error; } } if (mq_required) { error_setg(errp, "mq_required requested, but no kernel support" " for IFF_MULTI_QUEUE available"); goto error; } fcntl(fd, F_SETFL, O_NONBLOCK); return fd; error: close(fd); return -1; } #endif /* __FreeBSD__ */ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) { } int tap_probe_vnet_hdr(int fd) { return 0; } int tap_probe_has_ufo(int fd) { return 0; } int tap_probe_vnet_hdr_len(int fd, int len) { return 0; } void tap_fd_set_vnet_hdr_len(int fd, int len) { } int tap_fd_set_vnet_le(int fd, int is_le) { return -EINVAL; } int tap_fd_set_vnet_be(int fd, int is_be) { return -EINVAL; } void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { } int tap_fd_enable(int fd) { return -1; } int tap_fd_disable(int fd) { return -1; } int tap_fd_get_ifname(int fd, char *ifname) { return -1; }