Improved callback logic. Simplified lwip driver.

This commit is contained in:
Joseph Henry
2019-01-31 03:08:48 -08:00
parent d715ebd461
commit 292fcdda2c
12 changed files with 644 additions and 491 deletions

View File

@@ -37,10 +37,11 @@
#include "ZeroTierOne.h"
#include "Constants.hpp"
#include "VirtualTapManager.hpp"
#include "lwIP.h"
#include "OSUtils.hpp"
#include "ServiceControls.hpp"
#include "VirtualTap.hpp"
#include "Defs.hpp"
#include "lwip/stats.h"
@@ -53,8 +54,14 @@ WSADATA wsaData;
#include <jni.h>
#endif
struct zts_network_details;
struct zts_peer_details;
struct zts_network_details;
namespace ZeroTier {
class VirtualTap;
/*
* A lock used to protect any call which relies on the presence of a valid pointer
* to the ZeroTier service.
@@ -91,6 +98,7 @@ Mutex _vtaps_lock;
// Global reference to ZeroTier service
OneService *zt1Service;
// User-provided callback for ZeroTier events
void (*_userCallbackFunc)(uint64_t, int);
#ifdef SDK_JNI
@@ -99,9 +107,8 @@ static JavaVM *jvm = NULL;
jobject objRef = NULL;
jmethodID _userCallbackMethodRef = NULL;
#endif
}
using namespace ZeroTier;
std::map<uint64_t, bool> peerCache;
//////////////////////////////////////////////////////////////////////////////
// Internal ZeroTier Service Controls (user application shall not use these)//
@@ -112,8 +119,8 @@ std::queue<std::pair<uint64_t, int>*> _callbackMsgQueue;
void _push_callback_event(uint64_t nwid, int eventCode)
{
_callback_lock.lock();
if (_callbackMsgQueue.size() >= 128) {
DEBUG_ERROR("too many callback messages in queue");
if (_callbackMsgQueue.size() >= ZTS_CALLBACK_MSG_QUEUE_LEN) {
DEBUG_ERROR("too many callback messages in queue (see: ZTS_CALLBACK_MSG_QUEUE_LEN)");
_callback_lock.unlock();
return;
}
@@ -132,7 +139,7 @@ void _process_callback_event_helper(uint64_t nwid, int eventCode)
}
#else
if (_userCallbackFunc) {
_userCallbackFunc((uint64_t)0, ZTS_EVENT_NODE_OFFLINE);
_userCallbackFunc(nwid, eventCode);
}
#endif
}
@@ -192,11 +199,13 @@ int _zts_can_perform_service_operation()
void _hibernate_if_needed()
{
if (VirtualTapManager::get_vtaps_size()) {
_vtaps_lock.lock();
if (vtapMap.size()) {
lwip_wake_driver();
} else {
lwip_hibernate_driver();
}
_vtaps_lock.unlock();
}
#ifdef SDK_JNI
#endif
@@ -204,7 +213,7 @@ void _hibernate_if_needed()
/*
* Monitors the conditions required for triggering callbacks into user code. This was made
* into its own thread to prevent user application abuse of callbacks from affecting
* the timing of more sensitive aspects of the library such as polling and RX/TX of packets
* the timing of more sensitive aspects of the library such as polling and packet processing
*/
#if defined(_WIN32)
DWORD WINAPI _zts_monitor_callback_conditions(LPVOID thread_id)
@@ -215,74 +224,188 @@ void *_zts_monitor_callback_conditions(void *thread_id)
#if defined(__APPLE__)
pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME);
#endif
while (!_serviceIsShuttingDown)
while (true)
{
if (_serviceIsShuttingDown) {
break;
}
_service_lock.lock();
_callback_lock.lock();
#if ZTS_NODE_CALLBACKS
// ZT Node states
if (!_zts_node_online()) {
if (_nodeIsOnlineToggle) {
_nodeIsOnlineToggle = false;
_process_callback_event((uint64_t)0, ZTS_EVENT_NODE_OFFLINE);
_process_callback_event_helper((uint64_t)0, ZTS_EVENT_NODE_OFFLINE);
}
_service_lock.unlock();
_callback_lock.unlock();
_api_sleep(ZTS_CALLBACK_PROCESSING_INTERVAL);
// Only process pending network callbacks if the node is online
continue;
}
if (_zts_node_online()) {
uint64_t nodeId = 0;
if (_zts_can_perform_service_operation()) {
nodeId = zt1Service->getNode()->address();
}
} if (_zts_node_online()) { // Only process pending network callbacks if the node is online
if (!_nodeIsOnlineToggle) {
_nodeIsOnlineToggle = true;
_process_callback_event((uint64_t)0, ZTS_EVENT_NODE_ONLINE);
_process_callback_event_helper(nodeId, ZTS_EVENT_NODE_ONLINE);
}
}
#endif
// First, handle queued messages from other threads
_callback_lock.lock();
while (_callbackMsgQueue.size()) {
std::pair<uint64_t,int> *msg = _callbackMsgQueue.front();
_callbackMsgQueue.pop();
_process_callback_event_helper(msg->first, msg->second);
delete msg;
}
_callback_lock.unlock();
// Second, inspect network states for changes we should report
_vtaps_lock.lock();
ZT_VirtualNetworkList *nl = zt1Service->getNode()->networks();
for(unsigned long i=0;i<nl->networkCount;++i) {
OneService::NetworkSettings localSettings;
zt1Service->getNetworkSettings(nl->networks[i].nwid,localSettings);
if (vtapMap[nl->networks[i].nwid]->_lastReportedStatus != nl->networks[i].status) {
switch (nl->networks[i].status) {
case ZT_NETWORK_STATUS_NOT_FOUND:
_process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_NOT_FOUND);
break;
case ZT_NETWORK_STATUS_CLIENT_TOO_OLD:
_process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_CLIENT_TOO_OLD);
break;
case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION:
_process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_REQUESTING_CONFIG);
break;
case ZT_NETWORK_STATUS_OK:
_process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_OK);
break;
case ZT_NETWORK_STATUS_ACCESS_DENIED:
_process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_ACCESS_DENIED);
break;
default:
break;
// Handle messages placed in the message queue
while (_callbackMsgQueue.size()) {
std::pair<uint64_t,int> *msg = _callbackMsgQueue.front();
_callbackMsgQueue.pop();
#if ZTS_NETIF_CALLBACKS
// lwIP netif
if (msg->second & (ZTS_EVENT_NETIF_STATUS_CHANGE)) {
_vtaps_lock.lock();
if (!vtapMap.count(msg->first)) {
if (msg->second & (ZTS_EVENT_GENERIC_DOWN)) {
_process_callback_event_helper(msg->first, msg->second);
}
vtapMap[nl->networks[i].nwid]->_lastReportedStatus = nl->networks[i].status;
delete msg;
msg = NULL;
_vtaps_lock.unlock();
continue;
}
if (msg->second == ZTS_EVENT_NETIF_UP_IP4 && vtapMap[msg->first]->_networkStatus == ZTS_EVENT_NETWORK_OK) {
_process_callback_event_helper(msg->first, ZTS_EVENT_NETWORK_READY_IP4);
}
if (msg->second == ZTS_EVENT_NETIF_UP_IP6 && vtapMap[msg->first]->_networkStatus == ZTS_EVENT_NETWORK_OK) {
_process_callback_event_helper(msg->first, ZTS_EVENT_NETWORK_READY_IP6);
}
if (msg->second & (ZTS_EVENT_NETIF_STATUS_CHANGE)) {
vtapMap[msg->first]->_netifStatus = msg->second;
}
_vtaps_lock.unlock();
_process_callback_event_helper(msg->first, msg->second);
}
zt1Service->getNode()->freeQueryResult((void *)nl);
// Finally, check for a more useful definition of "readiness"
#endif // ZTS_NETIF_CALLBACKS
delete msg;
msg = NULL;
}
#if ZTS_NETIF_CALLBACKS // Section for non-queued lwIP netif messages
// lwIP netif states
_vtaps_lock.lock();
if (vtapMap.size()) {
std::map<uint64_t, VirtualTap*>::iterator it;
for (it = vtapMap.begin(); it != vtapMap.end(); it++) {
VirtualTap *tap = it->second;
if (tap->_lastConfigUpdateTime > 0 && !tap->_lastReadyReportTime && tap->_ips.size() > 0) {
tap->_lastReadyReportTime = tap->_lastConfigUpdateTime;
_process_callback_event(tap->_nwid, ZTS_EVENT_NETWORK_READY);
VirtualTap *vtap = (VirtualTap*)it->second;
uint64_t eventCode = vtap->recognizeLowerLevelInterfaceStateChange(vtap->netif4);
if (eventCode != ZTS_EVENT_NONE) {
_process_callback_event_helper(vtap->_nwid, eventCode);
}
eventCode = vtap->recognizeLowerLevelInterfaceStateChange(vtap->netif6);
if (eventCode != ZTS_EVENT_NONE) {
_process_callback_event_helper(vtap->_nwid, eventCode);
}
}
_vtaps_lock.unlock();
}
// Doesn't need to happen as often as other API operations
_api_sleep(ZTS_WRAPPER_CHECK_INTERVAL);
_vtaps_lock.unlock();
#endif // ZTS_NETIF_CALLBACKS
#if ZTS_PEER_CALLBACKS
// TODO: Add peerCache clearning mechanism
// TODO: Add ZTS_EVENT_PEER_NEW message?
ZT_PeerList *pl = zt1Service->getNode()->peers();
if (pl) {
for(unsigned long i=0;i<pl->peerCount;++i) {
if (!peerCache.count(pl->peers[i].address)) { // Add first entry
if (pl->peers[i].pathCount > 0) {
_process_callback_event_helper(pl->peers[i].address, ZTS_EVENT_PEER_P2P);
}
if (pl->peers[i].pathCount == 0) {
_process_callback_event_helper(pl->peers[i].address, ZTS_EVENT_PEER_RELAY);
}
}
else {
if (peerCache[pl->peers[i].address] == 0 && pl->peers[i].pathCount > 0) {
_process_callback_event_helper(pl->peers[i].address, ZTS_EVENT_PEER_P2P);
}
if (peerCache[pl->peers[i].address] > 0 && pl->peers[i].pathCount == 0) {
_process_callback_event_helper(pl->peers[i].address, ZTS_EVENT_PEER_RELAY);
}
}
peerCache[pl->peers[i].address] = pl->peers[i].pathCount;
}
}
zt1Service->getNode()->freeQueryResult((void *)pl);
#endif // ZTS_PEER_CALLBACKS
#if ZTS_NETWORK_CALLBACKS
_vtaps_lock.lock();
// Second, inspect network states for changes we should report
// TODO: Use proper ZT callback mechanism
// TODO: _push_callback_event(_nwid, ZTS_EVENT_NETWORK_DOWN);
ZT_VirtualNetworkList *nl = zt1Service->getNode()->networks();
for(unsigned long i=0;i<nl->networkCount;++i) {
OneService::NetworkSettings localSettings;
zt1Service->getNetworkSettings(nl->networks[i].nwid,localSettings);
if (!vtapMap.count(nl->networks[i].nwid)) {
continue;
}
if (vtapMap[nl->networks[i].nwid]->_networkStatus == nl->networks[i].status) {
continue; // no state change
}
VirtualTap *vtap = vtapMap[nl->networks[i].nwid];
uint64_t nwid = nl->networks[i].nwid;
switch (nl->networks[i].status) {
case ZT_NETWORK_STATUS_NOT_FOUND:
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_NOT_FOUND);
break;
case ZT_NETWORK_STATUS_CLIENT_TOO_OLD:
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_CLIENT_TOO_OLD);
break;
case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION:
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_REQUESTING_CONFIG);
break;
case ZT_NETWORK_STATUS_OK:
if (vtap->netif4 && lwip_is_netif_up(vtap->netif4)) {
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_READY_IP4);
}
if (vtap->netif6 && lwip_is_netif_up(vtap->netif6)) {
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_READY_IP6);
}
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_OK);
break;
case ZT_NETWORK_STATUS_ACCESS_DENIED:
_process_callback_event_helper(nwid, ZTS_EVENT_NETWORK_ACCESS_DENIED);
break;
default:
break;
}
vtapMap[nwid]->_networkStatus = nl->networks[i].status;
}
_vtaps_lock.unlock();
zt1Service->getNode()->freeQueryResult((void *)nl);
#endif // ZTS_NETWORK_CALLBACKS
// Finally, check for a more useful definition of "readiness"
/*
std::map<uint64_t, VirtualTap*>::iterator it;
for (it = vtapMap.begin(); it != vtapMap.end(); it++) {
VirtualTap *tap = it->second;
if (tap->_lastConfigUpdateTime > 0 && !tap->_lastReadyReportTime && tap->_ips.size() > 0) {
tap->_lastReadyReportTime = tap->_lastConfigUpdateTime;
_process_callback_event(tap->_nwid, ZTS_EVENT_NETWORK_READY);
}
}*/
_service_lock.unlock();
_callback_lock.unlock();
_api_sleep(ZTS_CALLBACK_PROCESSING_INTERVAL);
}
DEBUG_ERROR("exiting from monitor loop");
DEBUG_INFO("exited from callback processing loop");
pthread_exit(0);
}
// Starts a ZeroTier service in the background
@@ -306,7 +429,6 @@ void *_zts_start_service(void *thread_id)
DEBUG_INFO("service already started, doing nothing");
retval = NULL;
}
try {
std::vector<std::string> hpsp(OSUtils::split(homeDir.c_str(), ZT_PATH_SEPARATOR_S,"",""));
std::string ptmp;
@@ -367,10 +489,11 @@ void *_zts_start_service(void *thread_id)
_service_lock.unlock();
_serviceIsShuttingDown = false;
_process_callback_event((uint64_t)0, ZTS_EVENT_NODE_DOWN);
DEBUG_INFO("exiting zt service thread");
} catch ( ... ) {
DEBUG_ERROR("unexpected exception starting ZeroTier instance");
}
pthread_exit(NULL);
pthread_exit(0);
}
#ifdef __cplusplus
@@ -434,7 +557,11 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1service_1port(
zts_err_t zts_join(const uint64_t nwid, int blocking)
{
zts_err_t retval = ZTS_ERR_OK;
retval = VirtualTapManager::get_vtaps_size() >= ZTS_MAX_JOINED_NETWORKS ? ZTS_ERR_INVALID_OP : ZTS_ERR_OK;
_vtaps_lock.lock();
retval = vtapMap.size() >= ZTS_MAX_JOINED_NETWORKS ? ZTS_ERR_INVALID_OP : ZTS_ERR_OK;
_vtaps_lock.unlock();
if (retval == ZTS_ERR_OK) {
_service_lock.lock();
if (blocking) {
@@ -463,7 +590,6 @@ zts_err_t zts_join(const uint64_t nwid, int blocking)
}
}
_service_lock.unlock();
_hibernate_if_needed();
}
return retval;
}
@@ -504,8 +630,9 @@ zts_err_t zts_leave(const uint64_t nwid, int blocking)
zt1Service->getNode()->leave(nwid, NULL, NULL);
}
}
VirtualTapManager::remove_by_nwid(nwid);
_hibernate_if_needed();
_vtaps_lock.lock();
vtapMap.erase(nwid);
_vtaps_lock.unlock();
_service_lock.unlock();
return retval;
}
@@ -520,6 +647,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_leave(
zts_err_t zts_leave_all(int blocking)
{
zts_err_t retval = ZTS_ERR_OK;
/*
if (!zt1Service || _freeHasBeenCalled || _serviceIsShuttingDown) {
retval = ZTS_ERR_SERVICE;
}
@@ -531,6 +659,8 @@ zts_err_t zts_leave_all(int blocking)
zts_leave(nds[i].nwid);
}
}
*/
return retval;
}
#ifdef SDK_JNI
@@ -588,7 +718,9 @@ JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_core_1running(
int zts_ready()
{
_service_lock.lock();
bool stackRunning = VirtualTapManager::get_vtaps_size() > 0 ? true : false;
_vtaps_lock.lock();
bool stackRunning = vtapMap.size() > 0 ? true : false;
_vtaps_lock.unlock();
_service_lock.unlock();
return zts_core_running() && stackRunning;
}
@@ -693,8 +825,6 @@ zts_err_t zts_start_with_callback(const char *path, void (*callback)(uint64_t, i
}
}
_startup_lock.unlock();
// if (blocking && retval == ZTS_ERR_OK) { DEBUG_INFO("node=%llx online", (unsigned long long)zts_get_node_id());}
_hibernate_if_needed();
return retval;
}
@@ -754,7 +884,6 @@ zts_err_t zts_startjoin(const char *path, const uint64_t nwid)
retval = ZTS_ERR_SERVICE;
}
}
_hibernate_if_needed();
return retval;
}
#ifdef SDK_JNI
@@ -773,11 +902,26 @@ zts_err_t zts_stop(int blocking)
{
zts_err_t retval = ZTS_ERR_OK;
_service_lock.lock();
// leave all networks
/*
_vtaps_lock.lock();
if (vtapMap.size()) {
std::map<uint64_t, VirtualTap*>::iterator it;
for (it = vtapMap.begin(); it != vtapMap.end(); it++) {
VirtualTap *vtap = (VirtualTap*)it->second;
zt1Service->getNode()->leave(vtap->_nwid, NULL, NULL);
}
vtapMap.clear();
}
_vtaps_lock.unlock();
*/
// begin shutdown
peerCache.clear(); // TODO: Ensure this is locked correctly
bool didStop = false;
if (_zts_can_perform_service_operation()) {
didStop = true;
_serviceIsShuttingDown = true;
zt1Service->terminate();
VirtualTapManager::clear();
didStop = true;
}
else {
// Nothing to do
@@ -791,7 +935,6 @@ zts_err_t zts_stop(int blocking)
// Block until ZT service thread successfully exits
pthread_join(service_thread, NULL);
}
_hibernate_if_needed();
_clear_registered_callback();
return retval;
}
@@ -898,7 +1041,9 @@ zts_err_t zts_get_num_joined_networks()
retval = ZTS_ERR_SERVICE;
}
else {
retval = VirtualTapManager::get_vtaps_size();
_vtaps_lock.lock();
retval = vtapMap.size();
_vtaps_lock.unlock();
}
return retval;
}
@@ -910,8 +1055,50 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1num_1joined_1networ
}
#endif
//////////////////////////////////////////////////////////////////////////////
// Network Details //
//////////////////////////////////////////////////////////////////////////////
void __get_network_details_helper(uint64_t nwid, struct zts_network_details *nd)
{
socklen_t addrlen;
VirtualTap *tap = vtapMap[nwid];
nd->nwid = tap->_nwid;
nd->mtu = tap->_mtu;
// assigned addresses
nd->num_addresses = tap->_ips.size() < ZTS_MAX_ASSIGNED_ADDRESSES ? tap->_ips.size() : ZTS_MAX_ASSIGNED_ADDRESSES;
for (int j=0; j<nd->num_addresses; j++) {
addrlen = tap->_ips[j].isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
memcpy(&(nd->addr[j]), &(tap->_ips[j]), addrlen);
}
// routes
nd->num_routes = ZTS_MAX_NETWORK_ROUTES;;
zt1Service->getRoutes(nwid, (ZT_VirtualNetworkRoute*)&(nd->routes)[0], &(nd->num_routes));
}
void _get_network_details(uint64_t nwid, struct zts_network_details *nd)
{
_vtaps_lock.lock();
__get_network_details_helper(nwid, nd);
_vtaps_lock.unlock();
}
void _get_all_network_details(struct zts_network_details *nds, int *num)
{
_vtaps_lock.lock();
*num = vtapMap.size();
int idx = 0;
std::map<uint64_t, VirtualTap*>::iterator it;
for (it = vtapMap.begin(); it != vtapMap.end(); it++) {
_get_network_details(it->first, &nds[idx]);
idx++;
}
_vtaps_lock.unlock();
}
zts_err_t zts_get_network_details(uint64_t nwid, struct zts_network_details *nd)
{
_service_lock.lock();
zts_err_t retval = ZTS_ERR_OK;
if (!nd || nwid == 0) {
retval = ZTS_ERR_INVALID_ARG;
@@ -920,8 +1107,9 @@ zts_err_t zts_get_network_details(uint64_t nwid, struct zts_network_details *nd)
retval = ZTS_ERR_SERVICE;
}
if (retval == ZTS_ERR_OK) {
VirtualTapManager::get_network_details(zt1Service, nwid, nd);
_get_network_details(nwid, nd);
}
_service_lock.unlock();
return retval;
}
#ifdef SDK_JNI
@@ -929,6 +1117,7 @@ zts_err_t zts_get_network_details(uint64_t nwid, struct zts_network_details *nd)
zts_err_t zts_get_all_network_details(struct zts_network_details *nds, int *num)
{
_service_lock.lock();
zts_err_t retval = ZTS_ERR_OK;
if (!nds || !num) {
retval = ZTS_ERR_INVALID_ARG;
@@ -937,13 +1126,18 @@ zts_err_t zts_get_all_network_details(struct zts_network_details *nds, int *num)
retval = ZTS_ERR_SERVICE;
}
if (retval == ZTS_ERR_OK) {
VirtualTapManager::get_all_network_details(zt1Service, nds, num);
_get_all_network_details(nds, num);
}
_service_lock.unlock();
return retval;
}
#ifdef SDK_JNI
#endif
//////////////////////////////////////////////////////////////////////////////
// HTTP Backplane //
//////////////////////////////////////////////////////////////////////////////
zts_err_t zts_enable_http_backplane_mgmt()
{
zts_err_t retval = ZTS_ERR_OK;
@@ -979,3 +1173,5 @@ zts_err_t zts_disable_http_backplane_mgmt()
#ifdef __cplusplus
}
#endif
} // namespace ZeroTier

View File

@@ -36,10 +36,11 @@
#include "OSUtils.hpp"
#include "Constants.hpp" // libzt
#include "ServiceControls.hpp"
#include "OneService.hpp"
extern void _push_callback_event(uint64_t nwid, int eventCode);
#include "Mutex.hpp"
#include "VirtualTapManager.hpp"
#include "lwIP.h"
#ifdef _MSC_VER
@@ -48,8 +49,12 @@ extern void _push_callback_event(uint64_t nwid, int eventCode);
namespace ZeroTier {
class VirtualTap;
extern OneService *zt1Service;
extern void (*_userCallbackFunc)(uint64_t, int);
extern std::map<uint64_t, VirtualTap*> vtapMap;
extern Mutex _vtaps_lock;
/**
* A virtual tap device. The ZeroTier core service creates one of these for each
@@ -77,28 +82,59 @@ VirtualTap::VirtualTap(
_unixListenSocket((PhySocket *)0),
_phy(this,false,true)
{
VirtualTapManager::add_tap(this);
memset(vtap_full_name, 0, sizeof(vtap_full_name));
snprintf(vtap_full_name, sizeof(vtap_full_name), "libzt%llx", (unsigned long long)_nwid);
_dev = vtap_full_name;
::pipe(_shutdownSignalPipe);
_vtaps_lock.lock();
vtapMap[_nwid] = this;
_vtaps_lock.unlock();
lwip_driver_init();
// start virtual tap thread and stack I/O loops
// Start virtual tap thread and stack I/O loops
_thread = Thread::start(this);
}
VirtualTap::~VirtualTap()
{
_push_callback_event(_nwid, ZTS_EVENT_NETWORK_DOWN);
lwip_driver_set_tap_interfaces_down(this);
_run = false;
::write(_shutdownSignalPipe[1],"\0",1);
_phy.whack();
lwip_dispose_of_netifs(this);
Thread::join(_thread);
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
}
uint64_t VirtualTap::recognizeLowerLevelInterfaceStateChange(void *n)
{
if (!n) {
return ZTS_EVENT_NONE;
}
if (n == netif4) {
if (netif4WasUpLastCheck && !lwip_is_netif_up(netif4)) {
netif4WasUpLastCheck = false;
return ZTS_EVENT_NETIF_DOWN_IP4;
}
if (!netif4WasUpLastCheck && lwip_is_netif_up(netif4)) {
netif4WasUpLastCheck = true;
return ZTS_EVENT_NETIF_UP_IP4;
}
}
if (n == netif6) {
if (netif6WasUpLastCheck && !lwip_is_netif_up(netif6)) {
netif6WasUpLastCheck = false;
return ZTS_EVENT_NETIF_DOWN_IP6;
}
if (!netif6WasUpLastCheck && lwip_is_netif_up(netif6)) {
netif6WasUpLastCheck = true;
return ZTS_EVENT_NETIF_UP_IP6;
}
}
return ZTS_EVENT_NONE;
}
void VirtualTap::lastConfigUpdate(uint64_t lastConfigUpdateTime)
{
_lastConfigUpdateTime = lastConfigUpdateTime;
@@ -114,20 +150,15 @@ bool VirtualTap::enabled() const
return _enabled;
}
void VirtualTap::registerIpWithStack(const InetAddress &ip)
{
lwip_init_interface((void*)this, this->_mac, ip);
}
bool VirtualTap::addIp(const InetAddress &ip)
{
char ipbuf[INET6_ADDRSTRLEN];
Mutex::Lock _l(_ips_m);
registerIpWithStack(ip);
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) {
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
}
lwip_init_interface((void*)this, this->_mac, ip);
return true;
}
@@ -231,7 +262,8 @@ void VirtualTap::threadMain()
while (true) {
FD_SET(_shutdownSignalPipe[0],&readfds);
select(nfds,&readfds,&nullfds,&nullfds,&tv);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) { // writes to shutdown pipe terminate thread
// writes to shutdown pipe terminate thread
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) {
break;
}
#ifdef _MSC_VER

View File

@@ -1,116 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
/**
* @file
*
* Management of virtual tap interfaces
*/
#include "VirtualTap.hpp"
#include "VirtualTapManager.hpp"
#include "ServiceControls.hpp"
#include "OneService.hpp"
namespace ZeroTier {
extern std::map<uint64_t, VirtualTap*> vtapMap;
extern Mutex _vtaps_lock;
extern void (*_userCallbackFunc)(uint64_t, int);
class VirtualTap;
void VirtualTapManager::add_tap(VirtualTap *tap) {
_vtaps_lock.lock();
vtapMap[tap->_nwid] = tap;
_vtaps_lock.unlock();
}
VirtualTap *VirtualTapManager::getTapByNWID(uint64_t nwid) {
_vtaps_lock.lock();
VirtualTap *s, *tap = vtapMap[nwid];
_vtaps_lock.unlock();
return tap;
}
size_t VirtualTapManager::get_vtaps_size() {
size_t sz;
_vtaps_lock.lock();
sz = vtapMap.size();
_vtaps_lock.unlock();
return sz;
}
void VirtualTapManager::remove_by_nwid(uint64_t nwid) {
_vtaps_lock.lock();
vtapMap.erase(nwid);
_vtaps_lock.unlock();
}
void VirtualTapManager::clear() {
_vtaps_lock.lock();
vtapMap.clear();
_vtaps_lock.unlock();
}
void VirtualTapManager::get_network_details_helper(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd)
{
socklen_t addrlen;
VirtualTap *tap = vtapMap[nwid];
nd->nwid = tap->_nwid;
nd->mtu = tap->_mtu;
// assigned addresses
nd->num_addresses = tap->_ips.size() < ZTS_MAX_ASSIGNED_ADDRESSES ? tap->_ips.size() : ZTS_MAX_ASSIGNED_ADDRESSES;
for (int j=0; j<nd->num_addresses; j++) {
addrlen = tap->_ips[j].isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
memcpy(&(nd->addr[j]), &(tap->_ips[j]), addrlen);
}
// routes
nd->num_routes = ZTS_MAX_NETWORK_ROUTES;
OneService *zt1Service = (OneService*)zt1ServiceRef;
zt1Service->getRoutes(nwid, (ZT_VirtualNetworkRoute*)&(nd->routes)[0], &(nd->num_routes));
}
void VirtualTapManager::get_network_details(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd) {
_vtaps_lock.lock();
get_network_details_helper(zt1ServiceRef, nwid, nd);
_vtaps_lock.unlock();
}
void VirtualTapManager::get_all_network_details(void *zt1ServiceRef, struct zts_network_details *nds, int *num) {
_vtaps_lock.lock();
*num = vtapMap.size();
int idx = 0;
std::map<uint64_t, VirtualTap*>::iterator it;
for (it = vtapMap.begin(); it != vtapMap.end(); it++) {
get_network_details(zt1ServiceRef, it->first, &nds[idx]);
idx++;
}
_vtaps_lock.unlock();
}
} // namespace ZeroTier

View File

@@ -60,28 +60,22 @@
#if defined(_WIN32)
#include <time.h>
void ms_sleep(unsigned long ms)
{
Sleep(ms);
}
#endif
std::queue<struct pbuf *> rx_queue;
ZeroTier::Mutex _rx_input_lock_m;
namespace ZeroTier {
bool main_loop_exited = false;
bool lwip_driver_initialized = false;
bool has_already_been_initialized = false;
int hibernationDelayMultiplier = 1;
ZeroTier::Mutex driver_m;
Mutex driver_m;
ZeroTier::MAC _mac; // TODO: Should remove this
std::vector<struct netif *> lwip_netifs;
std::queue<struct zts_sorted_packet*> rx_queue;
ZeroTier::Mutex _rx_input_lock_m;
extern void _push_callback_event(uint64_t nwid, int eventCode);
extern void _process_callback_event_helper(uint64_t nwid, int eventCode);
void lwip_hibernate_driver()
{
@@ -108,10 +102,8 @@ void my_tcpip_callback(void *arg)
if (main_loop_exited) {
return;
}
// stats_display();
err_t err = ERR_OK;
int loop_score = LWIP_FRAMES_HANDLED_PER_CORE_CALL; // max num of packets to read per polling call
// TODO: Optimize (use Ringbuffer)
while (loop_score > 0) {
// TODO: Swap this block out for a thread-safe container
_rx_input_lock_m.lock();
@@ -119,75 +111,32 @@ void my_tcpip_callback(void *arg)
_rx_input_lock_m.unlock();
return;
}
struct pbuf *p = rx_queue.front();
struct zts_sorted_packet *sp = rx_queue.front();
struct pbuf *p = sp->p;
rx_queue.pop();
_rx_input_lock_m.unlock();
// Packet routing logic. Inputs packet into correct lwip netif interface depending on protocol type
struct ip_hdr *iphdr;
switch (((struct eth_hdr *)p->payload)->type)
{
case PP_HTONS(ETHTYPE_IPV6): {
iphdr = (struct ip_hdr *)((char *)p->payload + SIZEOF_ETH_HDR);
for (size_t i=0; i<lwip_netifs.size(); i++) {
if (lwip_netifs[i]->output_ip6 &&
lwip_netifs[i]->output_ip6 == ethip6_output) {
// TODO: Check prefix match?
if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) {
DEBUG_ERROR("packet input error (ipv6, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err);
pbuf_free(p);
}
break;
}
}
} break;
case PP_HTONS(ETHTYPE_IP): {
iphdr = (struct ip_hdr *)((char *)p->payload + SIZEOF_ETH_HDR);
for (size_t i=0; i<lwip_netifs.size(); i++) {
if (lwip_netifs[i]->output &&
lwip_netifs[i]->output == etharp_output) {
if (lwip_netifs[i]->ip_addr.u_addr.ip4.addr == iphdr->dest.addr ||
ip4_addr_isbroadcast_u32(iphdr->dest.addr, lwip_netifs[i])) {
if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) {
DEBUG_ERROR("packet input error (ipv4, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err);
pbuf_free(p);
}
break;
}
}
}
} break;
case PP_HTONS(ETHTYPE_ARP): {
for (size_t i=0; i<lwip_netifs.size(); i++) {
if (lwip_netifs[i]->state) {
//pbuf_ref(p);
if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) {
DEBUG_ERROR("packet input error (arp, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err);
pbuf_free(p);
}
break;
}
}
break;
} break;
default:
DEBUG_INFO("unhandled packet type (p=%p)", p);
break;
// Feed packet into appropriate lwIP netif
if (sp->p && sp->n) {
if ((err = sp->n->input(sp->p, sp->n)) != ERR_OK) {
DEBUG_ERROR("packet input error (p=%p, n=%p)=%d", p, sp->n, err);
pbuf_free(p);
}
sp->p = NULL;
}
//
p = NULL;
delete sp;
sp = NULL;
loop_score--;
}
}
// main thread which starts the initialization process
// Main thread which starts the initialization process
static void main_lwip_driver_loop(void *arg)
{
#if defined(__linux__)
pthread_setname_np(pthread_self(), "lwip_driver_loop");
pthread_setname_np(pthread_self(), "lwipDriver");
#endif
#if defined(__APPLE__)
pthread_setname_np("lwip_driver_loop");
pthread_setname_np("lwipDriver");
#endif
sys_sem_t sem;
LWIP_UNUSED_ARG(arg);
@@ -199,7 +148,7 @@ static void main_lwip_driver_loop(void *arg)
sys_sem_wait(&sem);
while(lwip_driver_initialized) {
#if defined(_WIN32)
ms_sleep(LWIP_GUARDED_BUF_CHECK_INTERVAL*hibernationDelayMultiplier);
Sleep(LWIP_GUARDED_BUF_CHECK_INTERVAL*hibernationDelayMultiplier);
#else
usleep(LWIP_GUARDED_BUF_CHECK_INTERVAL*1000*hibernationDelayMultiplier);
#endif
@@ -247,34 +196,22 @@ void lwip_driver_shutdown()
}
}
void lwip_driver_set_all_interfaces_down()
void lwip_dispose_of_netifs(void *tapref)
{
for (size_t i=0; i<lwip_netifs.size(); i++) {
if (lwip_netifs[i]) {
netif_remove(lwip_netifs[i]);
netif_set_down(lwip_netifs[i]);
netif_set_link_down(lwip_netifs[i]);
delete lwip_netifs[i];
}
ZeroTier::VirtualTap *vtap = (ZeroTier::VirtualTap*)tapref;
if (vtap->netif4) {
netif_remove((struct netif*)(vtap->netif4));
netif_set_down((struct netif*)(vtap->netif4));
netif_set_link_down((struct netif*)(vtap->netif4));
delete vtap->netif4;
vtap->netif4 = NULL;
}
lwip_netifs.clear();
}
void lwip_driver_set_tap_interfaces_down(void *tapref)
{
int sz_i = lwip_netifs.size();
std::vector<struct netif*>::iterator iter;
for (iter = lwip_netifs.begin(); iter != lwip_netifs.end(); ) {
struct netif *lp = *(iter);
if (lp->state == tapref) {
netif_remove(lp);
netif_set_down(lp);
netif_set_link_down(lp);
iter = lwip_netifs.erase(iter);
}
else {
++iter;
}
if (vtap->netif6) {
netif_remove((struct netif*)(vtap->netif6));
netif_set_down((struct netif*)(vtap->netif6));
netif_set_link_down((struct netif*)(vtap->netif6));
delete vtap->netif6;
vtap->netif6 = NULL;
}
}
@@ -304,7 +241,7 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p)
int len = totalLength - sizeof(struct eth_hdr);
int proto = ZeroTier::Utils::ntoh((uint16_t)ethhdr->type);
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len);
/*
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
@@ -318,6 +255,7 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p)
DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] proto=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(),
ZeroTier::Utils::ntoh(ethhdr->type), flagbuf);
}
*/
return ERR_OK;
@@ -326,23 +264,18 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p)
void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const ZeroTier::MAC &to, unsigned int etherType,
const void *data, unsigned int len)
{
if (!lwip_netifs.size()) {
DEBUG_ERROR("there are no netifs set up to handle this packet. ignoring.");
return;
}
struct pbuf *p,*q;
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
ethhdr.type = ZeroTier::Utils::hton((uint16_t)etherType);
/*
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[ZTS_ID_LEN];
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2],
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2],
ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]);
ZeroTier::MAC mac;
mac.setTo(ethhdr.src.addr, 6);
@@ -350,7 +283,20 @@ void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const Zer
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(),
ZeroTier::Utils::ntoh(ethhdr.type), flagbuf);
}
*/
if (etherType == 0x0800 || etherType == 0x0806) { // ip4 or ARP
if (!tap->netif4) {
DEBUG_ERROR("dropped packet: no netif to accept this packet (etherType=%x) on this vtap (%p)", etherType, tap);
return;
}
}
if (etherType == 0x86DD) { // ip6
if (!tap->netif6) {
DEBUG_ERROR("dropped packet: no netif to accept this packet (etherType=%x) on this vtap (%p)", etherType, tap);
return;
}
}
p = pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_RAM);
if (!p) {
DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf");
@@ -374,6 +320,7 @@ void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const Zer
memcpy(q->payload,dataptr,q->len);
dataptr += q->len;
}
_rx_input_lock_m.lock();
if (rx_queue.size() >= LWIP_MAX_GUARDED_RX_BUF_SZ) {
DEBUG_INFO("dropped packet: rx_queue is full (>= %d)", LWIP_MAX_GUARDED_RX_BUF_SZ);
@@ -382,7 +329,26 @@ void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const Zer
p = NULL;
return;
}
rx_queue.push(p);
// Construct a pre-sorted packet for lwIP packet feeder timeout
struct zts_sorted_packet *sp = new struct zts_sorted_packet;
sp->p = p;
sp->vtap=tap;
switch (etherType)
{
case 0x0800: // ip4
case 0x0806: // ARP
sp->n = (struct netif *)tap->netif4;
break;
case 0x86DD: // ip6
sp->n = (struct netif *)tap->netif6;
break;
default:
DEBUG_ERROR("dropped packet: unhandled (etherType=%x)", etherType);
break;
}
rx_queue.push(sp);
_rx_input_lock_m.unlock();
}
@@ -406,6 +372,11 @@ static void print_netif_info(struct netif *netif) {
);
}
bool lwip_is_netif_up(void *netif)
{
return netif_is_up((struct netif*)netif);
}
/**
* Called when the status of a netif changes:
* - Interface is up/down (ZTS_EVENT_NETIF_UP, ZTS_EVENT_NETIF_DOWN)
@@ -413,21 +384,33 @@ static void print_netif_info(struct netif *netif) {
*/
static void netif_status_callback(struct netif *netif)
{
// TODO: It appears that there may be a bug in lwIP's handling of callbacks for netifs
// configured to handle ipv4 traffic. For this reason a temporary measure of checking
// the status of the interfaces ourselves from the service is used.
if (!netif->state) {
return;
}
ZeroTier::VirtualTap *tap = (ZeroTier::VirtualTap *)netif->state;
// TODO: The following events may be triggered when there's simply a new
// address assignment, state will be kept in the virtual tap instead of
// at this lower level. This will allow us to filter out redundant events
if (netif->flags & NETIF_FLAG_UP) {
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_UP);
ZeroTier::VirtualTap *vtap = (ZeroTier::VirtualTap*)netif->state;
if (netif == vtap->netif6) {
// DEBUG_INFO("netif=%p, vtap->netif6=%p", netif, vtap->netif6);
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_UP_IP6);
}
if (netif == vtap->netif4) {
// DEBUG_INFO("netif=%p, vtap->netif4=%p", netif, vtap->netif4);
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_UP_IP4);
}
}
if (!(netif->flags & NETIF_FLAG_UP)) {
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_DOWN);
if (netif->flags & NETIF_FLAG_MLD6) {
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_DOWN_IP6);
} else {
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_DOWN_IP4);
}
}
// TODO: ZTS_EVENT_NETIF_NEW_ADDRESS
print_netif_info(netif);
//print_netif_info(netif);
}
/**
@@ -440,7 +423,7 @@ static void netif_remove_callback(struct netif *netif)
}
ZeroTier::VirtualTap *tap = (ZeroTier::VirtualTap *)netif->state;
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_REMOVED);
print_netif_info(netif);
//print_netif_info(netif);
}
/**
@@ -458,14 +441,14 @@ static void netif_link_callback(struct netif *netif)
if (netif->flags & NETIF_FLAG_LINK_UP) {
_push_callback_event(tap->_nwid, ZTS_EVENT_NETIF_LINK_DOWN);
}
print_netif_info(netif);
//print_netif_info(netif);
}
static err_t netif_init_4(struct netif *netif)
{
netif->hwaddr_len = 6;
netif->name[0] = 'e';
netif->name[1] = '0'+lwip_netifs.size();
netif->name[0] = 'z';
netif->name[1] = '4';
netif->linkoutput = lwip_eth_tx;
netif->output = etharp_output;
netif->mtu = ZT_MAX_MTU;
@@ -475,7 +458,6 @@ static err_t netif_init_4(struct netif *netif)
| NETIF_FLAG_IGMP
| NETIF_FLAG_LINK_UP
| NETIF_FLAG_UP;
_mac.copyTo(netif->hwaddr, netif->hwaddr_len);
netif->hwaddr_len = sizeof(netif->hwaddr);
return ERR_OK;
}
@@ -483,8 +465,8 @@ static err_t netif_init_4(struct netif *netif)
static err_t netif_init_6(struct netif *netif)
{
netif->hwaddr_len = 6;
netif->name[0] = 'e';
netif->name[1] = '0'+(char)lwip_netifs.size();
netif->name[0] = 'z';
netif->name[1] = '6';
netif->linkoutput = lwip_eth_tx;
netif->output = etharp_output;
netif->output_ip6 = ethip6_output;
@@ -494,7 +476,6 @@ static err_t netif_init_6(struct netif *netif)
| NETIF_FLAG_ETHERNET
| NETIF_FLAG_IGMP
| NETIF_FLAG_MLD6;
_mac.copyTo(netif->hwaddr, netif->hwaddr_len);
netif->hwaddr_len = sizeof(netif->hwaddr);
return ERR_OK;
}
@@ -503,10 +484,7 @@ void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier:
{
char ipbuf[INET6_ADDRSTRLEN];
char macbuf[ZTS_MAC_ADDRSTRLEN];
struct netif *lwipdev = new struct netif;
lwip_netifs.push_back(lwipdev);
_mac = mac;
struct netif *n = new struct netif;
if (ip.isV4()) {
char nmbuf[INET6_ADDRSTRLEN];
@@ -514,37 +492,47 @@ void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier:
IP4_ADDR(&gw,127,0,0,1);
ipaddr.addr = *((u32_t *)ip.rawIpData());
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
netif_add(lwipdev, &ipaddr, &netmask, &gw, NULL, netif_init_4, tcpip_input);
lwipdev->state = tapref;
netif_add(n, &ipaddr, &netmask, &gw, NULL, netif_init_4, tcpip_input);
n->state = tapref;
mac.copyTo(n->hwaddr, n->hwaddr_len);
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
lwipdev->hwaddr[0], lwipdev->hwaddr[1], lwipdev->hwaddr[2],
lwipdev->hwaddr[3], lwipdev->hwaddr[4], lwipdev->hwaddr[5]);
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
DEBUG_INFO("initialized netif as [mac=%s, addr=%s, nm=%s]",
macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf));
netif_set_up(n);
netif_set_link_up(n);
ZeroTier::VirtualTap *vtap = (ZeroTier::VirtualTap*)tapref;
vtap->netif4 = (void*)n;
}
if (ip.isV6())
{
static ip6_addr_t ipaddr;
memcpy(&(ipaddr.addr), ip.rawIpData(), sizeof(ipaddr.addr));
lwipdev->ip6_autoconfig_enabled = 1;
netif_add(lwipdev, NULL, NULL, NULL, NULL, netif_init_6, tcpip_input);
netif_ip6_addr_set(lwipdev, 1, &ipaddr);
lwipdev->state = tapref;
netif_create_ip6_linklocal_address(lwipdev, 1);
netif_ip6_addr_set_state(lwipdev, 0, IP6_ADDR_TENTATIVE);
netif_ip6_addr_set_state(lwipdev, 1, IP6_ADDR_TENTATIVE);
netif_set_default(lwipdev);
netif_set_up(lwipdev);
netif_set_link_up(lwipdev);
n->ip6_autoconfig_enabled = 1;
netif_add(n, NULL, NULL, NULL, NULL, netif_init_6, tcpip_input);
netif_ip6_addr_set(n, 1, &ipaddr);
n->state = tapref;
mac.copyTo(n->hwaddr, n->hwaddr_len);
netif_create_ip6_linklocal_address(n, 1);
netif_ip6_addr_set_state(n, 0, IP6_ADDR_TENTATIVE);
netif_ip6_addr_set_state(n, 1, IP6_ADDR_TENTATIVE);
netif_set_default(n);
netif_set_up(n);
netif_set_link_up(n);
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
lwipdev->hwaddr[0], lwipdev->hwaddr[1], lwipdev->hwaddr[2],
lwipdev->hwaddr[3], lwipdev->hwaddr[4], lwipdev->hwaddr[5]);
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
DEBUG_INFO("initialized netif as [mac=%s, addr=%s]",
macbuf, ip.toString(ipbuf));
ZeroTier::VirtualTap *vtap = (ZeroTier::VirtualTap*)tapref;
vtap->netif6 = (void*)n;
}
// Set netif callbacks, these will be used to inform decisions made
// by the higher level callback monitor thread
netif_set_status_callback(lwipdev, netif_status_callback);
netif_set_remove_callback(lwipdev, netif_remove_callback);
netif_set_link_callback(lwipdev, netif_link_callback);
netif_set_status_callback(n, netif_status_callback);
netif_set_remove_callback(n, netif_remove_callback);
netif_set_link_callback(n, netif_link_callback);
}
} // namespace ZeroTier