1*5281d757SMark McLoughlin /* 2*5281d757SMark McLoughlin * QEMU System Emulator 3*5281d757SMark McLoughlin * 4*5281d757SMark McLoughlin * Copyright (c) 2003-2008 Fabrice Bellard 5*5281d757SMark McLoughlin * Copyright (c) 2009 Red Hat, Inc. 6*5281d757SMark McLoughlin * 7*5281d757SMark McLoughlin * Permission is hereby granted, free of charge, to any person obtaining a copy 8*5281d757SMark McLoughlin * of this software and associated documentation files (the "Software"), to deal 9*5281d757SMark McLoughlin * in the Software without restriction, including without limitation the rights 10*5281d757SMark McLoughlin * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11*5281d757SMark McLoughlin * copies of the Software, and to permit persons to whom the Software is 12*5281d757SMark McLoughlin * furnished to do so, subject to the following conditions: 13*5281d757SMark McLoughlin * 14*5281d757SMark McLoughlin * The above copyright notice and this permission notice shall be included in 15*5281d757SMark McLoughlin * all copies or substantial portions of the Software. 16*5281d757SMark McLoughlin * 17*5281d757SMark McLoughlin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18*5281d757SMark McLoughlin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19*5281d757SMark McLoughlin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20*5281d757SMark McLoughlin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21*5281d757SMark McLoughlin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22*5281d757SMark McLoughlin * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23*5281d757SMark McLoughlin * THE SOFTWARE. 24*5281d757SMark McLoughlin */ 25*5281d757SMark McLoughlin 26*5281d757SMark McLoughlin #include "net/tap.h" 27*5281d757SMark McLoughlin 28*5281d757SMark McLoughlin #include "config-host.h" 29*5281d757SMark McLoughlin 30*5281d757SMark McLoughlin #include <signal.h> 31*5281d757SMark McLoughlin #include <sys/ioctl.h> 32*5281d757SMark McLoughlin #include <sys/stat.h> 33*5281d757SMark McLoughlin #include <sys/wait.h> 34*5281d757SMark McLoughlin #include <net/if.h> 35*5281d757SMark McLoughlin 36*5281d757SMark McLoughlin #include "net.h" 37*5281d757SMark McLoughlin #include "sysemu.h" 38*5281d757SMark McLoughlin #include "qemu-char.h" 39*5281d757SMark McLoughlin #include "qemu-common.h" 40*5281d757SMark McLoughlin 41*5281d757SMark McLoughlin #ifdef __linux__ 42*5281d757SMark McLoughlin #include "net/tap-linux.h" 43*5281d757SMark McLoughlin #endif 44*5281d757SMark McLoughlin 45*5281d757SMark McLoughlin #ifdef __NetBSD__ 46*5281d757SMark McLoughlin #include <net/if_tap.h> 47*5281d757SMark McLoughlin #endif 48*5281d757SMark McLoughlin 49*5281d757SMark McLoughlin #ifdef CONFIG_BSD 50*5281d757SMark McLoughlin #if defined(__FreeBSD__) || defined(__DragonFly__) 51*5281d757SMark McLoughlin #include <libutil.h> 52*5281d757SMark McLoughlin #else 53*5281d757SMark McLoughlin #include <util.h> 54*5281d757SMark McLoughlin #endif 55*5281d757SMark McLoughlin #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) 56*5281d757SMark McLoughlin #include <freebsd/stdlib.h> 57*5281d757SMark McLoughlin #endif 58*5281d757SMark McLoughlin 59*5281d757SMark McLoughlin #if defined(__OpenBSD__) 60*5281d757SMark McLoughlin #include <util.h> 61*5281d757SMark McLoughlin #endif 62*5281d757SMark McLoughlin 63*5281d757SMark McLoughlin #ifdef __sun__ 64*5281d757SMark McLoughlin #include <sys/stat.h> 65*5281d757SMark McLoughlin #include <sys/ethernet.h> 66*5281d757SMark McLoughlin #include <sys/sockio.h> 67*5281d757SMark McLoughlin #include <netinet/arp.h> 68*5281d757SMark McLoughlin #include <netinet/in.h> 69*5281d757SMark McLoughlin #include <netinet/in_systm.h> 70*5281d757SMark McLoughlin #include <netinet/ip.h> 71*5281d757SMark McLoughlin #include <netinet/ip_icmp.h> // must come after ip.h 72*5281d757SMark McLoughlin #include <netinet/udp.h> 73*5281d757SMark McLoughlin #include <netinet/tcp.h> 74*5281d757SMark McLoughlin #include <net/if.h> 75*5281d757SMark McLoughlin #include <syslog.h> 76*5281d757SMark McLoughlin #include <stropts.h> 77*5281d757SMark McLoughlin #endif 78*5281d757SMark McLoughlin 79*5281d757SMark McLoughlin #if !defined(_AIX) 80*5281d757SMark McLoughlin 81*5281d757SMark McLoughlin /* Maximum GSO packet size (64k) plus plenty of room for 82*5281d757SMark McLoughlin * the ethernet and virtio_net headers 83*5281d757SMark McLoughlin */ 84*5281d757SMark McLoughlin #define TAP_BUFSIZE (4096 + 65536) 85*5281d757SMark McLoughlin 86*5281d757SMark McLoughlin typedef struct TAPState { 87*5281d757SMark McLoughlin VLANClientState *vc; 88*5281d757SMark McLoughlin int fd; 89*5281d757SMark McLoughlin char down_script[1024]; 90*5281d757SMark McLoughlin char down_script_arg[128]; 91*5281d757SMark McLoughlin uint8_t buf[TAP_BUFSIZE]; 92*5281d757SMark McLoughlin unsigned int read_poll : 1; 93*5281d757SMark McLoughlin unsigned int write_poll : 1; 94*5281d757SMark McLoughlin unsigned int has_vnet_hdr : 1; 95*5281d757SMark McLoughlin unsigned int using_vnet_hdr : 1; 96*5281d757SMark McLoughlin unsigned int has_ufo: 1; 97*5281d757SMark McLoughlin } TAPState; 98*5281d757SMark McLoughlin 99*5281d757SMark McLoughlin static int launch_script(const char *setup_script, const char *ifname, int fd); 100*5281d757SMark McLoughlin 101*5281d757SMark McLoughlin static int tap_can_send(void *opaque); 102*5281d757SMark McLoughlin static void tap_send(void *opaque); 103*5281d757SMark McLoughlin static void tap_writable(void *opaque); 104*5281d757SMark McLoughlin 105*5281d757SMark McLoughlin static void tap_update_fd_handler(TAPState *s) 106*5281d757SMark McLoughlin { 107*5281d757SMark McLoughlin qemu_set_fd_handler2(s->fd, 108*5281d757SMark McLoughlin s->read_poll ? tap_can_send : NULL, 109*5281d757SMark McLoughlin s->read_poll ? tap_send : NULL, 110*5281d757SMark McLoughlin s->write_poll ? tap_writable : NULL, 111*5281d757SMark McLoughlin s); 112*5281d757SMark McLoughlin } 113*5281d757SMark McLoughlin 114*5281d757SMark McLoughlin static void tap_read_poll(TAPState *s, int enable) 115*5281d757SMark McLoughlin { 116*5281d757SMark McLoughlin s->read_poll = !!enable; 117*5281d757SMark McLoughlin tap_update_fd_handler(s); 118*5281d757SMark McLoughlin } 119*5281d757SMark McLoughlin 120*5281d757SMark McLoughlin static void tap_write_poll(TAPState *s, int enable) 121*5281d757SMark McLoughlin { 122*5281d757SMark McLoughlin s->write_poll = !!enable; 123*5281d757SMark McLoughlin tap_update_fd_handler(s); 124*5281d757SMark McLoughlin } 125*5281d757SMark McLoughlin 126*5281d757SMark McLoughlin static void tap_writable(void *opaque) 127*5281d757SMark McLoughlin { 128*5281d757SMark McLoughlin TAPState *s = opaque; 129*5281d757SMark McLoughlin 130*5281d757SMark McLoughlin tap_write_poll(s, 0); 131*5281d757SMark McLoughlin 132*5281d757SMark McLoughlin qemu_flush_queued_packets(s->vc); 133*5281d757SMark McLoughlin } 134*5281d757SMark McLoughlin 135*5281d757SMark McLoughlin static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt) 136*5281d757SMark McLoughlin { 137*5281d757SMark McLoughlin ssize_t len; 138*5281d757SMark McLoughlin 139*5281d757SMark McLoughlin do { 140*5281d757SMark McLoughlin len = writev(s->fd, iov, iovcnt); 141*5281d757SMark McLoughlin } while (len == -1 && errno == EINTR); 142*5281d757SMark McLoughlin 143*5281d757SMark McLoughlin if (len == -1 && errno == EAGAIN) { 144*5281d757SMark McLoughlin tap_write_poll(s, 1); 145*5281d757SMark McLoughlin return 0; 146*5281d757SMark McLoughlin } 147*5281d757SMark McLoughlin 148*5281d757SMark McLoughlin return len; 149*5281d757SMark McLoughlin } 150*5281d757SMark McLoughlin 151*5281d757SMark McLoughlin static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, 152*5281d757SMark McLoughlin int iovcnt) 153*5281d757SMark McLoughlin { 154*5281d757SMark McLoughlin TAPState *s = vc->opaque; 155*5281d757SMark McLoughlin const struct iovec *iovp = iov; 156*5281d757SMark McLoughlin struct iovec iov_copy[iovcnt + 1]; 157*5281d757SMark McLoughlin struct virtio_net_hdr hdr = { 0, }; 158*5281d757SMark McLoughlin 159*5281d757SMark McLoughlin if (s->has_vnet_hdr && !s->using_vnet_hdr) { 160*5281d757SMark McLoughlin iov_copy[0].iov_base = &hdr; 161*5281d757SMark McLoughlin iov_copy[0].iov_len = sizeof(hdr); 162*5281d757SMark McLoughlin memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov)); 163*5281d757SMark McLoughlin iovp = iov_copy; 164*5281d757SMark McLoughlin iovcnt++; 165*5281d757SMark McLoughlin } 166*5281d757SMark McLoughlin 167*5281d757SMark McLoughlin return tap_write_packet(s, iovp, iovcnt); 168*5281d757SMark McLoughlin } 169*5281d757SMark McLoughlin 170*5281d757SMark McLoughlin static ssize_t tap_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t size) 171*5281d757SMark McLoughlin { 172*5281d757SMark McLoughlin TAPState *s = vc->opaque; 173*5281d757SMark McLoughlin struct iovec iov[2]; 174*5281d757SMark McLoughlin int iovcnt = 0; 175*5281d757SMark McLoughlin struct virtio_net_hdr hdr = { 0, }; 176*5281d757SMark McLoughlin 177*5281d757SMark McLoughlin if (s->has_vnet_hdr) { 178*5281d757SMark McLoughlin iov[iovcnt].iov_base = &hdr; 179*5281d757SMark McLoughlin iov[iovcnt].iov_len = sizeof(hdr); 180*5281d757SMark McLoughlin iovcnt++; 181*5281d757SMark McLoughlin } 182*5281d757SMark McLoughlin 183*5281d757SMark McLoughlin iov[iovcnt].iov_base = (char *)buf; 184*5281d757SMark McLoughlin iov[iovcnt].iov_len = size; 185*5281d757SMark McLoughlin iovcnt++; 186*5281d757SMark McLoughlin 187*5281d757SMark McLoughlin return tap_write_packet(s, iov, iovcnt); 188*5281d757SMark McLoughlin } 189*5281d757SMark McLoughlin 190*5281d757SMark McLoughlin static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) 191*5281d757SMark McLoughlin { 192*5281d757SMark McLoughlin TAPState *s = vc->opaque; 193*5281d757SMark McLoughlin struct iovec iov[1]; 194*5281d757SMark McLoughlin 195*5281d757SMark McLoughlin if (s->has_vnet_hdr && !s->using_vnet_hdr) { 196*5281d757SMark McLoughlin return tap_receive_raw(vc, buf, size); 197*5281d757SMark McLoughlin } 198*5281d757SMark McLoughlin 199*5281d757SMark McLoughlin iov[0].iov_base = (char *)buf; 200*5281d757SMark McLoughlin iov[0].iov_len = size; 201*5281d757SMark McLoughlin 202*5281d757SMark McLoughlin return tap_write_packet(s, iov, 1); 203*5281d757SMark McLoughlin } 204*5281d757SMark McLoughlin 205*5281d757SMark McLoughlin static int tap_can_send(void *opaque) 206*5281d757SMark McLoughlin { 207*5281d757SMark McLoughlin TAPState *s = opaque; 208*5281d757SMark McLoughlin 209*5281d757SMark McLoughlin return qemu_can_send_packet(s->vc); 210*5281d757SMark McLoughlin } 211*5281d757SMark McLoughlin 212*5281d757SMark McLoughlin #ifdef __sun__ 213*5281d757SMark McLoughlin static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) 214*5281d757SMark McLoughlin { 215*5281d757SMark McLoughlin struct strbuf sbuf; 216*5281d757SMark McLoughlin int f = 0; 217*5281d757SMark McLoughlin 218*5281d757SMark McLoughlin sbuf.maxlen = maxlen; 219*5281d757SMark McLoughlin sbuf.buf = (char *)buf; 220*5281d757SMark McLoughlin 221*5281d757SMark McLoughlin return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; 222*5281d757SMark McLoughlin } 223*5281d757SMark McLoughlin #else 224*5281d757SMark McLoughlin static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) 225*5281d757SMark McLoughlin { 226*5281d757SMark McLoughlin return read(tapfd, buf, maxlen); 227*5281d757SMark McLoughlin } 228*5281d757SMark McLoughlin #endif 229*5281d757SMark McLoughlin 230*5281d757SMark McLoughlin static void tap_send_completed(VLANClientState *vc, ssize_t len) 231*5281d757SMark McLoughlin { 232*5281d757SMark McLoughlin TAPState *s = vc->opaque; 233*5281d757SMark McLoughlin tap_read_poll(s, 1); 234*5281d757SMark McLoughlin } 235*5281d757SMark McLoughlin 236*5281d757SMark McLoughlin static void tap_send(void *opaque) 237*5281d757SMark McLoughlin { 238*5281d757SMark McLoughlin TAPState *s = opaque; 239*5281d757SMark McLoughlin int size; 240*5281d757SMark McLoughlin 241*5281d757SMark McLoughlin do { 242*5281d757SMark McLoughlin uint8_t *buf = s->buf; 243*5281d757SMark McLoughlin 244*5281d757SMark McLoughlin size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); 245*5281d757SMark McLoughlin if (size <= 0) { 246*5281d757SMark McLoughlin break; 247*5281d757SMark McLoughlin } 248*5281d757SMark McLoughlin 249*5281d757SMark McLoughlin if (s->has_vnet_hdr && !s->using_vnet_hdr) { 250*5281d757SMark McLoughlin buf += sizeof(struct virtio_net_hdr); 251*5281d757SMark McLoughlin size -= sizeof(struct virtio_net_hdr); 252*5281d757SMark McLoughlin } 253*5281d757SMark McLoughlin 254*5281d757SMark McLoughlin size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed); 255*5281d757SMark McLoughlin if (size == 0) { 256*5281d757SMark McLoughlin tap_read_poll(s, 0); 257*5281d757SMark McLoughlin } 258*5281d757SMark McLoughlin } while (size > 0); 259*5281d757SMark McLoughlin } 260*5281d757SMark McLoughlin 261*5281d757SMark McLoughlin /* sndbuf should be set to a value lower than the tx queue 262*5281d757SMark McLoughlin * capacity of any destination network interface. 263*5281d757SMark McLoughlin * Ethernet NICs generally have txqueuelen=1000, so 1Mb is 264*5281d757SMark McLoughlin * a good default, given a 1500 byte MTU. 265*5281d757SMark McLoughlin */ 266*5281d757SMark McLoughlin #define TAP_DEFAULT_SNDBUF 1024*1024 267*5281d757SMark McLoughlin 268*5281d757SMark McLoughlin static int tap_set_sndbuf(TAPState *s, QemuOpts *opts) 269*5281d757SMark McLoughlin { 270*5281d757SMark McLoughlin int sndbuf; 271*5281d757SMark McLoughlin 272*5281d757SMark McLoughlin sndbuf = qemu_opt_get_size(opts, "sndbuf", TAP_DEFAULT_SNDBUF); 273*5281d757SMark McLoughlin if (!sndbuf) { 274*5281d757SMark McLoughlin sndbuf = INT_MAX; 275*5281d757SMark McLoughlin } 276*5281d757SMark McLoughlin 277*5281d757SMark McLoughlin if (ioctl(s->fd, TUNSETSNDBUF, &sndbuf) == -1 && qemu_opt_get(opts, "sndbuf")) { 278*5281d757SMark McLoughlin qemu_error("TUNSETSNDBUF ioctl failed: %s\n", strerror(errno)); 279*5281d757SMark McLoughlin return -1; 280*5281d757SMark McLoughlin } 281*5281d757SMark McLoughlin return 0; 282*5281d757SMark McLoughlin } 283*5281d757SMark McLoughlin 284*5281d757SMark McLoughlin int tap_has_ufo(VLANClientState *vc) 285*5281d757SMark McLoughlin { 286*5281d757SMark McLoughlin TAPState *s = vc->opaque; 287*5281d757SMark McLoughlin 288*5281d757SMark McLoughlin assert(vc->type == NET_CLIENT_TYPE_TAP); 289*5281d757SMark McLoughlin 290*5281d757SMark McLoughlin return s->has_ufo; 291*5281d757SMark McLoughlin } 292*5281d757SMark McLoughlin 293*5281d757SMark McLoughlin int tap_has_vnet_hdr(VLANClientState *vc) 294*5281d757SMark McLoughlin { 295*5281d757SMark McLoughlin TAPState *s = vc->opaque; 296*5281d757SMark McLoughlin 297*5281d757SMark McLoughlin assert(vc->type == NET_CLIENT_TYPE_TAP); 298*5281d757SMark McLoughlin 299*5281d757SMark McLoughlin return s->has_vnet_hdr; 300*5281d757SMark McLoughlin } 301*5281d757SMark McLoughlin 302*5281d757SMark McLoughlin void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr) 303*5281d757SMark McLoughlin { 304*5281d757SMark McLoughlin TAPState *s = vc->opaque; 305*5281d757SMark McLoughlin 306*5281d757SMark McLoughlin using_vnet_hdr = using_vnet_hdr != 0; 307*5281d757SMark McLoughlin 308*5281d757SMark McLoughlin assert(vc->type == NET_CLIENT_TYPE_TAP); 309*5281d757SMark McLoughlin assert(s->has_vnet_hdr == using_vnet_hdr); 310*5281d757SMark McLoughlin 311*5281d757SMark McLoughlin s->using_vnet_hdr = using_vnet_hdr; 312*5281d757SMark McLoughlin } 313*5281d757SMark McLoughlin 314*5281d757SMark McLoughlin static int tap_probe_vnet_hdr(int fd) 315*5281d757SMark McLoughlin { 316*5281d757SMark McLoughlin struct ifreq ifr; 317*5281d757SMark McLoughlin 318*5281d757SMark McLoughlin if (ioctl(fd, TUNGETIFF, &ifr) != 0) { 319*5281d757SMark McLoughlin qemu_error("TUNGETIFF ioctl() failed: %s\n", strerror(errno)); 320*5281d757SMark McLoughlin return 0; 321*5281d757SMark McLoughlin } 322*5281d757SMark McLoughlin 323*5281d757SMark McLoughlin return ifr.ifr_flags & IFF_VNET_HDR; 324*5281d757SMark McLoughlin } 325*5281d757SMark McLoughlin 326*5281d757SMark McLoughlin void tap_set_offload(VLANClientState *vc, int csum, int tso4, 327*5281d757SMark McLoughlin int tso6, int ecn, int ufo) 328*5281d757SMark McLoughlin { 329*5281d757SMark McLoughlin TAPState *s = vc->opaque; 330*5281d757SMark McLoughlin unsigned int offload = 0; 331*5281d757SMark McLoughlin 332*5281d757SMark McLoughlin if (csum) { 333*5281d757SMark McLoughlin offload |= TUN_F_CSUM; 334*5281d757SMark McLoughlin if (tso4) 335*5281d757SMark McLoughlin offload |= TUN_F_TSO4; 336*5281d757SMark McLoughlin if (tso6) 337*5281d757SMark McLoughlin offload |= TUN_F_TSO6; 338*5281d757SMark McLoughlin if ((tso4 || tso6) && ecn) 339*5281d757SMark McLoughlin offload |= TUN_F_TSO_ECN; 340*5281d757SMark McLoughlin if (ufo) 341*5281d757SMark McLoughlin offload |= TUN_F_UFO; 342*5281d757SMark McLoughlin } 343*5281d757SMark McLoughlin 344*5281d757SMark McLoughlin if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0) { 345*5281d757SMark McLoughlin offload &= ~TUN_F_UFO; 346*5281d757SMark McLoughlin if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0) { 347*5281d757SMark McLoughlin fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n", 348*5281d757SMark McLoughlin strerror(errno)); 349*5281d757SMark McLoughlin } 350*5281d757SMark McLoughlin } 351*5281d757SMark McLoughlin } 352*5281d757SMark McLoughlin 353*5281d757SMark McLoughlin static void tap_cleanup(VLANClientState *vc) 354*5281d757SMark McLoughlin { 355*5281d757SMark McLoughlin TAPState *s = vc->opaque; 356*5281d757SMark McLoughlin 357*5281d757SMark McLoughlin qemu_purge_queued_packets(vc); 358*5281d757SMark McLoughlin 359*5281d757SMark McLoughlin if (s->down_script[0]) 360*5281d757SMark McLoughlin launch_script(s->down_script, s->down_script_arg, s->fd); 361*5281d757SMark McLoughlin 362*5281d757SMark McLoughlin tap_read_poll(s, 0); 363*5281d757SMark McLoughlin tap_write_poll(s, 0); 364*5281d757SMark McLoughlin close(s->fd); 365*5281d757SMark McLoughlin qemu_free(s); 366*5281d757SMark McLoughlin } 367*5281d757SMark McLoughlin 368*5281d757SMark McLoughlin /* fd support */ 369*5281d757SMark McLoughlin 370*5281d757SMark McLoughlin static TAPState *net_tap_fd_init(VLANState *vlan, 371*5281d757SMark McLoughlin const char *model, 372*5281d757SMark McLoughlin const char *name, 373*5281d757SMark McLoughlin int fd, 374*5281d757SMark McLoughlin int vnet_hdr) 375*5281d757SMark McLoughlin { 376*5281d757SMark McLoughlin TAPState *s; 377*5281d757SMark McLoughlin unsigned int offload; 378*5281d757SMark McLoughlin 379*5281d757SMark McLoughlin s = qemu_mallocz(sizeof(TAPState)); 380*5281d757SMark McLoughlin s->fd = fd; 381*5281d757SMark McLoughlin s->has_vnet_hdr = vnet_hdr != 0; 382*5281d757SMark McLoughlin s->using_vnet_hdr = 0; 383*5281d757SMark McLoughlin s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP, 384*5281d757SMark McLoughlin vlan, NULL, model, name, NULL, 385*5281d757SMark McLoughlin tap_receive, tap_receive_raw, 386*5281d757SMark McLoughlin tap_receive_iov, tap_cleanup, s); 387*5281d757SMark McLoughlin s->has_ufo = 0; 388*5281d757SMark McLoughlin /* Check if tap supports UFO */ 389*5281d757SMark McLoughlin offload = TUN_F_CSUM | TUN_F_UFO; 390*5281d757SMark McLoughlin if (ioctl(s->fd, TUNSETOFFLOAD, offload) == 0) 391*5281d757SMark McLoughlin s->has_ufo = 1; 392*5281d757SMark McLoughlin tap_set_offload(s->vc, 0, 0, 0, 0, 0); 393*5281d757SMark McLoughlin tap_read_poll(s, 1); 394*5281d757SMark McLoughlin return s; 395*5281d757SMark McLoughlin } 396*5281d757SMark McLoughlin 397*5281d757SMark McLoughlin #if defined (CONFIG_BSD) || defined (__FreeBSD_kernel__) 398*5281d757SMark McLoughlin static int tap_open(char *ifname, int ifname_size, 399*5281d757SMark McLoughlin int *vnet_hdr, int vnet_hdr_required) 400*5281d757SMark McLoughlin { 401*5281d757SMark McLoughlin int fd; 402*5281d757SMark McLoughlin char *dev; 403*5281d757SMark McLoughlin struct stat s; 404*5281d757SMark McLoughlin 405*5281d757SMark McLoughlin TFR(fd = open("/dev/tap", O_RDWR)); 406*5281d757SMark McLoughlin if (fd < 0) { 407*5281d757SMark McLoughlin fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n"); 408*5281d757SMark McLoughlin return -1; 409*5281d757SMark McLoughlin } 410*5281d757SMark McLoughlin 411*5281d757SMark McLoughlin fstat(fd, &s); 412*5281d757SMark McLoughlin dev = devname(s.st_rdev, S_IFCHR); 413*5281d757SMark McLoughlin pstrcpy(ifname, ifname_size, dev); 414*5281d757SMark McLoughlin 415*5281d757SMark McLoughlin fcntl(fd, F_SETFL, O_NONBLOCK); 416*5281d757SMark McLoughlin return fd; 417*5281d757SMark McLoughlin } 418*5281d757SMark McLoughlin #elif defined(__sun__) 419*5281d757SMark McLoughlin #define TUNNEWPPA (('T'<<16) | 0x0001) 420*5281d757SMark McLoughlin /* 421*5281d757SMark McLoughlin * Allocate TAP device, returns opened fd. 422*5281d757SMark McLoughlin * Stores dev name in the first arg(must be large enough). 423*5281d757SMark McLoughlin */ 424*5281d757SMark McLoughlin static int tap_alloc(char *dev, size_t dev_size) 425*5281d757SMark McLoughlin { 426*5281d757SMark McLoughlin int tap_fd, if_fd, ppa = -1; 427*5281d757SMark McLoughlin static int ip_fd = 0; 428*5281d757SMark McLoughlin char *ptr; 429*5281d757SMark McLoughlin 430*5281d757SMark McLoughlin static int arp_fd = 0; 431*5281d757SMark McLoughlin int ip_muxid, arp_muxid; 432*5281d757SMark McLoughlin struct strioctl strioc_if, strioc_ppa; 433*5281d757SMark McLoughlin int link_type = I_PLINK;; 434*5281d757SMark McLoughlin struct lifreq ifr; 435*5281d757SMark McLoughlin char actual_name[32] = ""; 436*5281d757SMark McLoughlin 437*5281d757SMark McLoughlin memset(&ifr, 0x0, sizeof(ifr)); 438*5281d757SMark McLoughlin 439*5281d757SMark McLoughlin if( *dev ){ 440*5281d757SMark McLoughlin ptr = dev; 441*5281d757SMark McLoughlin while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++; 442*5281d757SMark McLoughlin ppa = atoi(ptr); 443*5281d757SMark McLoughlin } 444*5281d757SMark McLoughlin 445*5281d757SMark McLoughlin /* Check if IP device was opened */ 446*5281d757SMark McLoughlin if( ip_fd ) 447*5281d757SMark McLoughlin close(ip_fd); 448*5281d757SMark McLoughlin 449*5281d757SMark McLoughlin TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); 450*5281d757SMark McLoughlin if (ip_fd < 0) { 451*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); 452*5281d757SMark McLoughlin return -1; 453*5281d757SMark McLoughlin } 454*5281d757SMark McLoughlin 455*5281d757SMark McLoughlin TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); 456*5281d757SMark McLoughlin if (tap_fd < 0) { 457*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't open /dev/tap"); 458*5281d757SMark McLoughlin return -1; 459*5281d757SMark McLoughlin } 460*5281d757SMark McLoughlin 461*5281d757SMark McLoughlin /* Assign a new PPA and get its unit number. */ 462*5281d757SMark McLoughlin strioc_ppa.ic_cmd = TUNNEWPPA; 463*5281d757SMark McLoughlin strioc_ppa.ic_timout = 0; 464*5281d757SMark McLoughlin strioc_ppa.ic_len = sizeof(ppa); 465*5281d757SMark McLoughlin strioc_ppa.ic_dp = (char *)&ppa; 466*5281d757SMark McLoughlin if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) 467*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't assign new interface"); 468*5281d757SMark McLoughlin 469*5281d757SMark McLoughlin TFR(if_fd = open("/dev/tap", O_RDWR, 0)); 470*5281d757SMark McLoughlin if (if_fd < 0) { 471*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't open /dev/tap (2)"); 472*5281d757SMark McLoughlin return -1; 473*5281d757SMark McLoughlin } 474*5281d757SMark McLoughlin if(ioctl(if_fd, I_PUSH, "ip") < 0){ 475*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't push IP module"); 476*5281d757SMark McLoughlin return -1; 477*5281d757SMark McLoughlin } 478*5281d757SMark McLoughlin 479*5281d757SMark McLoughlin if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) 480*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't get flags\n"); 481*5281d757SMark McLoughlin 482*5281d757SMark McLoughlin snprintf (actual_name, 32, "tap%d", ppa); 483*5281d757SMark McLoughlin pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); 484*5281d757SMark McLoughlin 485*5281d757SMark McLoughlin ifr.lifr_ppa = ppa; 486*5281d757SMark McLoughlin /* Assign ppa according to the unit number returned by tun device */ 487*5281d757SMark McLoughlin 488*5281d757SMark McLoughlin if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) 489*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't set PPA %d", ppa); 490*5281d757SMark McLoughlin if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) 491*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't get flags\n"); 492*5281d757SMark McLoughlin /* Push arp module to if_fd */ 493*5281d757SMark McLoughlin if (ioctl (if_fd, I_PUSH, "arp") < 0) 494*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't push ARP module (2)"); 495*5281d757SMark McLoughlin 496*5281d757SMark McLoughlin /* Push arp module to ip_fd */ 497*5281d757SMark McLoughlin if (ioctl (ip_fd, I_POP, NULL) < 0) 498*5281d757SMark McLoughlin syslog (LOG_ERR, "I_POP failed\n"); 499*5281d757SMark McLoughlin if (ioctl (ip_fd, I_PUSH, "arp") < 0) 500*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't push ARP module (3)\n"); 501*5281d757SMark McLoughlin /* Open arp_fd */ 502*5281d757SMark McLoughlin TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); 503*5281d757SMark McLoughlin if (arp_fd < 0) 504*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); 505*5281d757SMark McLoughlin 506*5281d757SMark McLoughlin /* Set ifname to arp */ 507*5281d757SMark McLoughlin strioc_if.ic_cmd = SIOCSLIFNAME; 508*5281d757SMark McLoughlin strioc_if.ic_timout = 0; 509*5281d757SMark McLoughlin strioc_if.ic_len = sizeof(ifr); 510*5281d757SMark McLoughlin strioc_if.ic_dp = (char *)𝔦 511*5281d757SMark McLoughlin if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ 512*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't set ifname to arp\n"); 513*5281d757SMark McLoughlin } 514*5281d757SMark McLoughlin 515*5281d757SMark McLoughlin if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ 516*5281d757SMark McLoughlin syslog(LOG_ERR, "Can't link TAP device to IP"); 517*5281d757SMark McLoughlin return -1; 518*5281d757SMark McLoughlin } 519*5281d757SMark McLoughlin 520*5281d757SMark McLoughlin if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) 521*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't link TAP device to ARP"); 522*5281d757SMark McLoughlin 523*5281d757SMark McLoughlin close (if_fd); 524*5281d757SMark McLoughlin 525*5281d757SMark McLoughlin memset(&ifr, 0x0, sizeof(ifr)); 526*5281d757SMark McLoughlin pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); 527*5281d757SMark McLoughlin ifr.lifr_ip_muxid = ip_muxid; 528*5281d757SMark McLoughlin ifr.lifr_arp_muxid = arp_muxid; 529*5281d757SMark McLoughlin 530*5281d757SMark McLoughlin if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) 531*5281d757SMark McLoughlin { 532*5281d757SMark McLoughlin ioctl (ip_fd, I_PUNLINK , arp_muxid); 533*5281d757SMark McLoughlin ioctl (ip_fd, I_PUNLINK, ip_muxid); 534*5281d757SMark McLoughlin syslog (LOG_ERR, "Can't set multiplexor id"); 535*5281d757SMark McLoughlin } 536*5281d757SMark McLoughlin 537*5281d757SMark McLoughlin snprintf(dev, dev_size, "tap%d", ppa); 538*5281d757SMark McLoughlin return tap_fd; 539*5281d757SMark McLoughlin } 540*5281d757SMark McLoughlin 541*5281d757SMark McLoughlin static int tap_open(char *ifname, int ifname_size, 542*5281d757SMark McLoughlin int *vnet_hdr, int vnet_hdr_required) 543*5281d757SMark McLoughlin { 544*5281d757SMark McLoughlin char dev[10]=""; 545*5281d757SMark McLoughlin int fd; 546*5281d757SMark McLoughlin if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){ 547*5281d757SMark McLoughlin fprintf(stderr, "Cannot allocate TAP device\n"); 548*5281d757SMark McLoughlin return -1; 549*5281d757SMark McLoughlin } 550*5281d757SMark McLoughlin pstrcpy(ifname, ifname_size, dev); 551*5281d757SMark McLoughlin fcntl(fd, F_SETFL, O_NONBLOCK); 552*5281d757SMark McLoughlin return fd; 553*5281d757SMark McLoughlin } 554*5281d757SMark McLoughlin #elif defined (_AIX) 555*5281d757SMark McLoughlin static int tap_open(char *ifname, int ifname_size, 556*5281d757SMark McLoughlin int *vnet_hdr, int vnet_hdr_required) 557*5281d757SMark McLoughlin { 558*5281d757SMark McLoughlin fprintf (stderr, "no tap on AIX\n"); 559*5281d757SMark McLoughlin return -1; 560*5281d757SMark McLoughlin } 561*5281d757SMark McLoughlin #else 562*5281d757SMark McLoughlin static int tap_open(char *ifname, int ifname_size, 563*5281d757SMark McLoughlin int *vnet_hdr, int vnet_hdr_required) 564*5281d757SMark McLoughlin { 565*5281d757SMark McLoughlin struct ifreq ifr; 566*5281d757SMark McLoughlin int fd, ret; 567*5281d757SMark McLoughlin 568*5281d757SMark McLoughlin TFR(fd = open("/dev/net/tun", O_RDWR)); 569*5281d757SMark McLoughlin if (fd < 0) { 570*5281d757SMark McLoughlin fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); 571*5281d757SMark McLoughlin return -1; 572*5281d757SMark McLoughlin } 573*5281d757SMark McLoughlin memset(&ifr, 0, sizeof(ifr)); 574*5281d757SMark McLoughlin ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 575*5281d757SMark McLoughlin 576*5281d757SMark McLoughlin if (*vnet_hdr) { 577*5281d757SMark McLoughlin unsigned int features; 578*5281d757SMark McLoughlin 579*5281d757SMark McLoughlin if (ioctl(fd, TUNGETFEATURES, &features) == 0 && 580*5281d757SMark McLoughlin features & IFF_VNET_HDR) { 581*5281d757SMark McLoughlin *vnet_hdr = 1; 582*5281d757SMark McLoughlin ifr.ifr_flags |= IFF_VNET_HDR; 583*5281d757SMark McLoughlin } 584*5281d757SMark McLoughlin 585*5281d757SMark McLoughlin if (vnet_hdr_required && !*vnet_hdr) { 586*5281d757SMark McLoughlin qemu_error("vnet_hdr=1 requested, but no kernel " 587*5281d757SMark McLoughlin "support for IFF_VNET_HDR available"); 588*5281d757SMark McLoughlin close(fd); 589*5281d757SMark McLoughlin return -1; 590*5281d757SMark McLoughlin } 591*5281d757SMark McLoughlin } 592*5281d757SMark McLoughlin 593*5281d757SMark McLoughlin if (ifname[0] != '\0') 594*5281d757SMark McLoughlin pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); 595*5281d757SMark McLoughlin else 596*5281d757SMark McLoughlin pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); 597*5281d757SMark McLoughlin ret = ioctl(fd, TUNSETIFF, (void *) &ifr); 598*5281d757SMark McLoughlin if (ret != 0) { 599*5281d757SMark McLoughlin fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); 600*5281d757SMark McLoughlin close(fd); 601*5281d757SMark McLoughlin return -1; 602*5281d757SMark McLoughlin } 603*5281d757SMark McLoughlin pstrcpy(ifname, ifname_size, ifr.ifr_name); 604*5281d757SMark McLoughlin fcntl(fd, F_SETFL, O_NONBLOCK); 605*5281d757SMark McLoughlin return fd; 606*5281d757SMark McLoughlin } 607*5281d757SMark McLoughlin #endif 608*5281d757SMark McLoughlin 609*5281d757SMark McLoughlin static int launch_script(const char *setup_script, const char *ifname, int fd) 610*5281d757SMark McLoughlin { 611*5281d757SMark McLoughlin sigset_t oldmask, mask; 612*5281d757SMark McLoughlin int pid, status; 613*5281d757SMark McLoughlin char *args[3]; 614*5281d757SMark McLoughlin char **parg; 615*5281d757SMark McLoughlin 616*5281d757SMark McLoughlin sigemptyset(&mask); 617*5281d757SMark McLoughlin sigaddset(&mask, SIGCHLD); 618*5281d757SMark McLoughlin sigprocmask(SIG_BLOCK, &mask, &oldmask); 619*5281d757SMark McLoughlin 620*5281d757SMark McLoughlin /* try to launch network script */ 621*5281d757SMark McLoughlin pid = fork(); 622*5281d757SMark McLoughlin if (pid == 0) { 623*5281d757SMark McLoughlin int open_max = sysconf(_SC_OPEN_MAX), i; 624*5281d757SMark McLoughlin 625*5281d757SMark McLoughlin for (i = 0; i < open_max; i++) { 626*5281d757SMark McLoughlin if (i != STDIN_FILENO && 627*5281d757SMark McLoughlin i != STDOUT_FILENO && 628*5281d757SMark McLoughlin i != STDERR_FILENO && 629*5281d757SMark McLoughlin i != fd) { 630*5281d757SMark McLoughlin close(i); 631*5281d757SMark McLoughlin } 632*5281d757SMark McLoughlin } 633*5281d757SMark McLoughlin parg = args; 634*5281d757SMark McLoughlin *parg++ = (char *)setup_script; 635*5281d757SMark McLoughlin *parg++ = (char *)ifname; 636*5281d757SMark McLoughlin *parg++ = NULL; 637*5281d757SMark McLoughlin execv(setup_script, args); 638*5281d757SMark McLoughlin _exit(1); 639*5281d757SMark McLoughlin } else if (pid > 0) { 640*5281d757SMark McLoughlin while (waitpid(pid, &status, 0) != pid) { 641*5281d757SMark McLoughlin /* loop */ 642*5281d757SMark McLoughlin } 643*5281d757SMark McLoughlin sigprocmask(SIG_SETMASK, &oldmask, NULL); 644*5281d757SMark McLoughlin 645*5281d757SMark McLoughlin if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 646*5281d757SMark McLoughlin return 0; 647*5281d757SMark McLoughlin } 648*5281d757SMark McLoughlin } 649*5281d757SMark McLoughlin fprintf(stderr, "%s: could not launch network script\n", setup_script); 650*5281d757SMark McLoughlin return -1; 651*5281d757SMark McLoughlin } 652*5281d757SMark McLoughlin 653*5281d757SMark McLoughlin static int net_tap_init(QemuOpts *opts, int *vnet_hdr) 654*5281d757SMark McLoughlin { 655*5281d757SMark McLoughlin int fd, vnet_hdr_required; 656*5281d757SMark McLoughlin char ifname[128] = {0,}; 657*5281d757SMark McLoughlin const char *setup_script; 658*5281d757SMark McLoughlin 659*5281d757SMark McLoughlin if (qemu_opt_get(opts, "ifname")) { 660*5281d757SMark McLoughlin pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname")); 661*5281d757SMark McLoughlin } 662*5281d757SMark McLoughlin 663*5281d757SMark McLoughlin *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1); 664*5281d757SMark McLoughlin if (qemu_opt_get(opts, "vnet_hdr")) { 665*5281d757SMark McLoughlin vnet_hdr_required = *vnet_hdr; 666*5281d757SMark McLoughlin } else { 667*5281d757SMark McLoughlin vnet_hdr_required = 0; 668*5281d757SMark McLoughlin } 669*5281d757SMark McLoughlin 670*5281d757SMark McLoughlin TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required)); 671*5281d757SMark McLoughlin if (fd < 0) { 672*5281d757SMark McLoughlin return -1; 673*5281d757SMark McLoughlin } 674*5281d757SMark McLoughlin 675*5281d757SMark McLoughlin setup_script = qemu_opt_get(opts, "script"); 676*5281d757SMark McLoughlin if (setup_script && 677*5281d757SMark McLoughlin setup_script[0] != '\0' && 678*5281d757SMark McLoughlin strcmp(setup_script, "no") != 0 && 679*5281d757SMark McLoughlin launch_script(setup_script, ifname, fd)) { 680*5281d757SMark McLoughlin close(fd); 681*5281d757SMark McLoughlin return -1; 682*5281d757SMark McLoughlin } 683*5281d757SMark McLoughlin 684*5281d757SMark McLoughlin qemu_opt_set(opts, "ifname", ifname); 685*5281d757SMark McLoughlin 686*5281d757SMark McLoughlin return fd; 687*5281d757SMark McLoughlin } 688*5281d757SMark McLoughlin 689*5281d757SMark McLoughlin int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) 690*5281d757SMark McLoughlin { 691*5281d757SMark McLoughlin TAPState *s; 692*5281d757SMark McLoughlin int fd, vnet_hdr; 693*5281d757SMark McLoughlin 694*5281d757SMark McLoughlin if (qemu_opt_get(opts, "fd")) { 695*5281d757SMark McLoughlin if (qemu_opt_get(opts, "ifname") || 696*5281d757SMark McLoughlin qemu_opt_get(opts, "script") || 697*5281d757SMark McLoughlin qemu_opt_get(opts, "downscript") || 698*5281d757SMark McLoughlin qemu_opt_get(opts, "vnet_hdr")) { 699*5281d757SMark McLoughlin qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n"); 700*5281d757SMark McLoughlin return -1; 701*5281d757SMark McLoughlin } 702*5281d757SMark McLoughlin 703*5281d757SMark McLoughlin fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd")); 704*5281d757SMark McLoughlin if (fd == -1) { 705*5281d757SMark McLoughlin return -1; 706*5281d757SMark McLoughlin } 707*5281d757SMark McLoughlin 708*5281d757SMark McLoughlin fcntl(fd, F_SETFL, O_NONBLOCK); 709*5281d757SMark McLoughlin 710*5281d757SMark McLoughlin vnet_hdr = tap_probe_vnet_hdr(fd); 711*5281d757SMark McLoughlin } else { 712*5281d757SMark McLoughlin if (!qemu_opt_get(opts, "script")) { 713*5281d757SMark McLoughlin qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT); 714*5281d757SMark McLoughlin } 715*5281d757SMark McLoughlin 716*5281d757SMark McLoughlin if (!qemu_opt_get(opts, "downscript")) { 717*5281d757SMark McLoughlin qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT); 718*5281d757SMark McLoughlin } 719*5281d757SMark McLoughlin 720*5281d757SMark McLoughlin fd = net_tap_init(opts, &vnet_hdr); 721*5281d757SMark McLoughlin } 722*5281d757SMark McLoughlin 723*5281d757SMark McLoughlin s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr); 724*5281d757SMark McLoughlin if (!s) { 725*5281d757SMark McLoughlin close(fd); 726*5281d757SMark McLoughlin return -1; 727*5281d757SMark McLoughlin } 728*5281d757SMark McLoughlin 729*5281d757SMark McLoughlin if (tap_set_sndbuf(s, opts) < 0) { 730*5281d757SMark McLoughlin return -1; 731*5281d757SMark McLoughlin } 732*5281d757SMark McLoughlin 733*5281d757SMark McLoughlin if (qemu_opt_get(opts, "fd")) { 734*5281d757SMark McLoughlin snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); 735*5281d757SMark McLoughlin } else { 736*5281d757SMark McLoughlin const char *ifname, *script, *downscript; 737*5281d757SMark McLoughlin 738*5281d757SMark McLoughlin ifname = qemu_opt_get(opts, "ifname"); 739*5281d757SMark McLoughlin script = qemu_opt_get(opts, "script"); 740*5281d757SMark McLoughlin downscript = qemu_opt_get(opts, "downscript"); 741*5281d757SMark McLoughlin 742*5281d757SMark McLoughlin snprintf(s->vc->info_str, sizeof(s->vc->info_str), 743*5281d757SMark McLoughlin "ifname=%s,script=%s,downscript=%s", 744*5281d757SMark McLoughlin ifname, script, downscript); 745*5281d757SMark McLoughlin 746*5281d757SMark McLoughlin if (strcmp(downscript, "no") != 0) { 747*5281d757SMark McLoughlin snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); 748*5281d757SMark McLoughlin snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname); 749*5281d757SMark McLoughlin } 750*5281d757SMark McLoughlin } 751*5281d757SMark McLoughlin 752*5281d757SMark McLoughlin if (vlan) { 753*5281d757SMark McLoughlin vlan->nb_host_devs++; 754*5281d757SMark McLoughlin } 755*5281d757SMark McLoughlin 756*5281d757SMark McLoughlin return 0; 757*5281d757SMark McLoughlin } 758*5281d757SMark McLoughlin 759*5281d757SMark McLoughlin #endif /* !defined(_AIX) */ 760