Another possible workaround for what seems to be a Linux bug in some newer kernels.

This commit is contained in:
Adam Ierymenko 2020-11-11 14:42:56 -05:00
parent d735a1d04c
commit 2d489a8679
No known key found for this signature in database
GPG Key ID: C8877CF2D7A5D7F3

View File

@ -166,21 +166,20 @@ LinuxEthernetTap::LinuxEthernetTap(
throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); 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 ::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) { if (sock <= 0) {
::close(_fd); ::close(_fd);
throw std::runtime_error("unable to open netlink socket"); throw std::runtime_error("unable to open netlink socket");
} }
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { _dev = ifr.ifr_name;
::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device");
}
// 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) { if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
::close(_fd); ::close(_fd);
::close(sock); ::close(sock);
@ -190,7 +189,16 @@ LinuxEthernetTap::LinuxEthernetTap(
if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
::close(_fd); ::close(_fd);
::close(sock); ::close(sock);
throw std::runtime_error("unable to set TAP interface flags"); 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; 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"); throw std::runtime_error("unable to configure TAP hardware (MAC) address");
return; return;
} }
ifr.ifr_ifru.ifru_mtu = (int)mtu; ifr.ifr_ifru.ifru_mtu = (int)mtu;
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
::close(_fd); ::close(_fd);
@ -208,6 +217,11 @@ LinuxEthernetTap::LinuxEthernetTap(
throw std::runtime_error("unable to configure TAP MTU"); 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); ::close(sock);
// Set close-on-exec so that devices cannot persist if we fork/exec for update // Set close-on-exec so that devices cannot persist if we fork/exec for update
@ -215,19 +229,6 @@ LinuxEthernetTap::LinuxEthernetTap(
(void)::pipe(_shutdownSignalPipe); (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); _thread = Thread::start(this);
} }