mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Try another approach...
This commit is contained in:
parent
ca428233ba
commit
414c248cc5
1 changed files with 102 additions and 98 deletions
|
@ -184,118 +184,122 @@ LinuxEthernetTap::LinuxEthernetTap(
|
||||||
|
|
||||||
(void)::pipe(_shutdownSignalPipe);
|
(void)::pipe(_shutdownSignalPipe);
|
||||||
|
|
||||||
_tapReaderThread = std::thread([this]{
|
for(unsigned int t=0;t<2;++t) {
|
||||||
fd_set readfds,nullfds;
|
_tapReaderThread = std::thread([this, t]{
|
||||||
int n,nfds,r;
|
fd_set readfds,nullfds;
|
||||||
void *buf = nullptr;
|
int n,nfds,r;
|
||||||
std::vector<void *> buffers;
|
void *buf = nullptr;
|
||||||
|
std::vector<void *> buffers;
|
||||||
|
|
||||||
{
|
if (t == 0) {
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
memset(&ifr,0,sizeof(ifr));
|
memset(&ifr,0,sizeof(ifr));
|
||||||
strcpy(ifr.ifr_name,_dev.c_str());
|
strcpy(ifr.ifr_name,_dev.c_str());
|
||||||
|
|
||||||
const int sock = socket(AF_INET,SOCK_DGRAM,0);
|
const int sock = socket(AF_INET,SOCK_DGRAM,0);
|
||||||
if (sock <= 0)
|
if (sock <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
|
||||||
|
::close(sock);
|
||||||
|
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
|
||||||
|
::close(sock);
|
||||||
|
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some kernel versions seem to require you to yield while the device comes up
|
||||||
|
// before they will accept MTU and MAC. For others it doesn't matter, but is
|
||||||
|
// harmless. This was moved to the worker thread though so as not to block the
|
||||||
|
// main ZeroTier loop.
|
||||||
|
usleep(500000);
|
||||||
|
|
||||||
|
ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
|
||||||
|
_mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
|
||||||
|
if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
|
||||||
|
::close(sock);
|
||||||
|
printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifr.ifr_ifru.ifru_mtu = (int)_mtu;
|
||||||
|
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
|
||||||
|
::close(sock);
|
||||||
|
printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcntl(_fd,F_SETFL,O_NONBLOCK);
|
||||||
|
|
||||||
if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
|
|
||||||
::close(sock);
|
::close(sock);
|
||||||
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
|
} else {
|
||||||
return;
|
usleep(1500000);
|
||||||
}
|
|
||||||
ifr.ifr_flags |= IFF_UP;
|
|
||||||
if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
|
|
||||||
::close(sock);
|
|
||||||
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some kernel versions seem to require you to yield while the device comes up
|
FD_ZERO(&readfds);
|
||||||
// before they will accept MTU and MAC. For others it doesn't matter, but is
|
FD_ZERO(&nullfds);
|
||||||
// harmless. This was moved to the worker thread though so as not to block the
|
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
|
||||||
// main ZeroTier loop.
|
|
||||||
usleep(500000);
|
|
||||||
|
|
||||||
ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
|
r = 0;
|
||||||
_mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
|
for(;;) {
|
||||||
if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
|
FD_SET(_shutdownSignalPipe[0],&readfds);
|
||||||
::close(sock);
|
FD_SET(_fd,&readfds);
|
||||||
printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n");
|
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ifr.ifr_ifru.ifru_mtu = (int)_mtu;
|
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
|
||||||
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
|
break;
|
||||||
::close(sock);
|
|
||||||
printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fcntl(_fd,F_SETFL,O_NONBLOCK);
|
if (FD_ISSET(_fd,&readfds)) {
|
||||||
|
for(;;) { // read until there are no more packets, then return to outer select() loop
|
||||||
::close(sock);
|
if (!buf) {
|
||||||
}
|
// To reduce use of the mutex, we keep a local buffer vector and
|
||||||
|
// swap (which is a pointer swap) with the global one when it's
|
||||||
FD_ZERO(&readfds);
|
// empty. This retrieves a batch of buffers to use.
|
||||||
FD_ZERO(&nullfds);
|
if (buffers.empty()) {
|
||||||
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
|
std::lock_guard<std::mutex> l(_buffers_l);
|
||||||
|
buffers.swap(_buffers);
|
||||||
r = 0;
|
}
|
||||||
for(;;) {
|
if (buffers.empty()) {
|
||||||
FD_SET(_shutdownSignalPipe[0],&readfds);
|
buf = malloc(ZT_TAP_BUF_SIZE);
|
||||||
FD_SET(_fd,&readfds);
|
if (!buf)
|
||||||
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
|
break;
|
||||||
|
} else {
|
||||||
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
|
buf = buffers.back();
|
||||||
break;
|
buffers.pop_back();
|
||||||
|
|
||||||
if (FD_ISSET(_fd,&readfds)) {
|
|
||||||
for(;;) { // read until there are no more packets, then return to outer select() loop
|
|
||||||
if (!buf) {
|
|
||||||
// To reduce use of the mutex, we keep a local buffer vector and
|
|
||||||
// swap (which is a pointer swap) with the global one when it's
|
|
||||||
// empty. This retrieves a batch of buffers to use.
|
|
||||||
if (buffers.empty()) {
|
|
||||||
std::lock_guard<std::mutex> l(_buffers_l);
|
|
||||||
buffers.swap(_buffers);
|
|
||||||
}
|
|
||||||
if (buffers.empty()) {
|
|
||||||
buf = malloc(ZT_TAP_BUF_SIZE);
|
|
||||||
if (!buf)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
buf = buffers.back();
|
|
||||||
buffers.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n = (int)::read(_fd,reinterpret_cast<uint8_t *>(buf) + r,ZT_TAP_BUF_SIZE - r);
|
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
// Some tap drivers like to send the ethernet frame and the
|
|
||||||
// payload in two chunks, so handle that by accumulating
|
|
||||||
// data until we have at least a frame.
|
|
||||||
r += n;
|
|
||||||
if (r > 14) {
|
|
||||||
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
|
|
||||||
r = _mtu + 14;
|
|
||||||
|
|
||||||
if (_enabled) {
|
|
||||||
_tapq.post(std::pair<void *,int>(buf,r));
|
|
||||||
buf = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
r = 0;
|
n = (int)::read(_fd,reinterpret_cast<uint8_t *>(buf) + r,ZT_TAP_BUF_SIZE - r);
|
||||||
break;
|
|
||||||
|
if (n > 0) {
|
||||||
|
// Some tap drivers like to send the ethernet frame and the
|
||||||
|
// payload in two chunks, so handle that by accumulating
|
||||||
|
// data until we have at least a frame.
|
||||||
|
r += n;
|
||||||
|
if (r > 14) {
|
||||||
|
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
|
||||||
|
r = _mtu + 14;
|
||||||
|
|
||||||
|
if (_enabled) {
|
||||||
|
_tapq.post(std::pair<void *,int>(buf,r));
|
||||||
|
buf = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
_tapProcessorThread = std::thread([this] {
|
_tapProcessorThread = std::thread([this] {
|
||||||
MAC to,from;
|
MAC to,from;
|
||||||
|
|
Loading…
Add table
Reference in a new issue