diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index f83688fd3..859d0673b 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -166,31 +166,39 @@ LinuxEthernetTap::LinuxEthernetTap( throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); } - _dev = ifr.ifr_name; - ::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here - int sock = socket(AF_INET,SOCK_DGRAM,0); + const int sock = socket(AF_INET,SOCK_DGRAM,0); if (sock <= 0) { ::close(_fd); throw std::runtime_error("unable to open netlink socket"); } - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } + _dev = ifr.ifr_name; - if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to get TAP interface flags"); - } - ifr.ifr_flags |= IFF_UP; - if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { - ::close(_fd); - ::close(sock); - throw std::runtime_error("unable to set TAP interface flags"); + // Set/check loop is a workaround for a weird likely kernel bug in which + // the interface doesn't come up right away when set to up. This causes + // settings like the MAC address to not "take." + for(;;) { + if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { + ::close(_fd); + ::close(sock); + throw std::runtime_error("unable to get TAP interface flags"); + } + ifr.ifr_flags |= IFF_UP; + if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { + ::close(_fd); + ::close(sock); + throw std::runtime_error("unable to bring up TAP interface"); + } + if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { + ::close(_fd); + ::close(sock); + throw std::runtime_error("unable to get TAP interface flags"); + } + usleep(1000); + if ((ifr.ifr_flags & IFF_UP) != 0) + break; } ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; @@ -201,6 +209,7 @@ LinuxEthernetTap::LinuxEthernetTap( throw std::runtime_error("unable to configure TAP hardware (MAC) address"); return; } + ifr.ifr_ifru.ifru_mtu = (int)mtu; if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { ::close(_fd); @@ -208,6 +217,11 @@ LinuxEthernetTap::LinuxEthernetTap( throw std::runtime_error("unable to configure TAP MTU"); } + if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { + ::close(_fd); + throw std::runtime_error("unable to set flags on file descriptor for TAP device"); + } + ::close(sock); // Set close-on-exec so that devices cannot persist if we fork/exec for update @@ -215,19 +229,6 @@ LinuxEthernetTap::LinuxEthernetTap( (void)::pipe(_shutdownSignalPipe); - /* - globalDeviceMap[nwids] = _dev; - devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w"); - if (devmapf) { - gdmEntry = globalDeviceMap.begin(); - while (gdmEntry != globalDeviceMap.end()) { - fprintf(devmapf,"%s=%s\n",gdmEntry->first.c_str(),gdmEntry->second.c_str()); - ++gdmEntry; - } - fclose(devmapf); - } - */ - _thread = Thread::start(this); }