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,19 @@ index 74c22d33..58979e26 100644
if (nqcb->oldQueues[i]->byteLength > maxQueueLength) {
maxQueueLength = nqcb->oldQueues[i]->byteLength;
diff --git a/service/OneService.cpp b/service/OneService.cpp
index a1c53764..757863a8 100644
index a1c53764..e3034059 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -2244,6 +2244,12 @@ public:
@@ -625,6 +625,8 @@ public:
break;
if (!pkt)
break;
+ if (!_run)
+ break;
const ZT_ResultCode rc = _node->processWirePacket(nullptr,pkt->now,pkt->sock,&(pkt->from),pkt->data,pkt->size,&_nextBackgroundTaskDeadline);
{
@@ -2244,6 +2246,12 @@ public:
#endif
syncManagedStuff(n,true,true);
n.tap->setMtu(nwc->mtu);

View File

@@ -33,6 +33,18 @@
#ifndef LIBZT_CONSTANTS_HPP
#define LIBZT_CONSTANTS_HPP
//////////////////////////////////////////////////////////////////////////////
// Callbacks //
//////////////////////////////////////////////////////////////////////////////
#define ZTS_NODE_CALLBACKS 1
#define ZTS_NETWORK_CALLBACKS 1
#define ZTS_NETIF_CALLBACKS 1
#define ZTS_PEER_CALLBACKS 1
#define ZTS_CALLBACK_PROCESSING_INTERVAL ZTS_WRAPPER_CHECK_INTERVAL // 100 // ms
#define ZTS_CALLBACK_MSG_QUEUE_LEN 256
//////////////////////////////////////////////////////////////////////////////
// Error codes returned by ZeroTier and the libzt API //
// See ext/ZeroTierOne/include/ZeroTierOne.h //
@@ -40,25 +52,45 @@
typedef int zts_err_t;
#define ZTS_ERR_OK 0 // Everything is ok
#define ZTS_ERR_INVALID_ARG -1 // A parameter provided by the user application is invalid (e.g. our of range, NULL, etc)
#define ZTS_ERR_SERVICE -2 // The service isn't initialized or is for some other reason currently unavailable
#define ZTS_ERR_INVALID_OP -3 // For some reason this API operation is not permitted (perhaps the service is still starting?)
#define ZTS_ERR_OK 0 // Everything is ok
#define ZTS_ERR_INVALID_ARG -1 // A parameter provided by the user application is invalid (e.g. our of range, NULL, etc)
#define ZTS_ERR_SERVICE -2 // The service isn't initialized or is for some other reason currently unavailable
#define ZTS_ERR_INVALID_OP -3 // For some reason this API operation is not permitted (perhaps the service is still starting?)
#define ZTS_EVENT_NODE_ONLINE 0x01 // Node is online
#define ZTS_EVENT_NODE_OFFLINE 0x02 // Node is offline
#define ZTS_EVENT_NODE_DOWN 0x03 // Node is shutting down
#define ZTS_EVENT_NODE_IDENTITY_COLLISION 0x04 // Identity collision - check for duplicate instances
#define ZTS_EVENT_NODE_UNRECOVERABLE_ERROR 0x05 // Something is seriously wrong
#define ZTS_EVENT_NODE_NORMAL_TERMINATION 0x06 // Service thread has stopped
#define ZTS_EVENT_NETWORK_NOT_FOUND 0x07
#define ZTS_EVENT_NETWORK_CLIENT_TOO_OLD 0x08
#define ZTS_EVENT_NETWORK_REQUESTING_CONFIG 0x09
#define ZTS_EVENT_NETWORK_OK 0x0a
#define ZTS_EVENT_NETWORK_ACCESS_DENIED 0x0b
#define ZTS_EVENT_NETWORK_READY 0x0c
#define ZTS_EVENT_NETWORK_DOWN 0x0d
#define ZTS_EVENT_NONE 0x00000000
// Node-specific events
#define ZTS_EVENT_NODE_ONLINE 0x00000001 // Node is online
#define ZTS_EVENT_NODE_OFFLINE 0x00000002 // Node is offline
#define ZTS_EVENT_NODE_DOWN 0x00000004 // Node is shutting down
#define ZTS_EVENT_NODE_IDENTITY_COLLISION 0x00000008 // Identity collision - check for duplicate instances
#define ZTS_EVENT_NODE_UNRECOVERABLE_ERROR 0x00000010 // Something is seriously wrong
#define ZTS_EVENT_NODE_NORMAL_TERMINATION 0x00000020 // Service thread has stopped
// Network-specific events
#define ZTS_EVENT_NETWORK_NOT_FOUND 0x00000080
#define ZTS_EVENT_NETWORK_CLIENT_TOO_OLD 0x00000100
#define ZTS_EVENT_NETWORK_REQUESTING_CONFIG 0x00000200
#define ZTS_EVENT_NETWORK_OK 0x00000400
#define ZTS_EVENT_NETWORK_ACCESS_DENIED 0x00000800
#define ZTS_EVENT_NETWORK_READY_IP4 0x00001000
#define ZTS_EVENT_NETWORK_READY_IP6 0x00002000
#define ZTS_EVENT_NETWORK_DOWN 0x00004000
#define ZTS_EVENT_NETWORK_STATUS_CHANGE ZTS_EVENT_NETWORK_NOT_FOUND | ZTS_EVENT_NETWORK_CLIENT_TOO_OLD | ZTS_EVENT_NETWORK_REQUESTING_CONFIG | ZTS_EVENT_NETWORK_OK | ZTS_EVENT_NETWORK_ACCESS_DENIED
// lwIP netif events
#define ZTS_EVENT_NETIF_UP_IP4 0x00100000
#define ZTS_EVENT_NETIF_UP_IP6 0x00200000
#define ZTS_EVENT_NETIF_DOWN_IP4 0x00400000
#define ZTS_EVENT_NETIF_DOWN_IP6 0x00800000
#define ZTS_EVENT_NETIF_REMOVED 0x01000000
#define ZTS_EVENT_NETIF_LINK_UP 0x02000000
#define ZTS_EVENT_NETIF_LINK_DOWN 0x04000000
#define ZTS_EVENT_NETIF_NEW_ADDRESS 0x08000000
#define ZTS_EVENT_NETIF_STATUS_CHANGE ZTS_EVENT_NETIF_UP_IP4 | ZTS_EVENT_NETIF_UP_IP6 | ZTS_EVENT_NETIF_DOWN_IP4 | ZTS_EVENT_NETIF_DOWN_IP6 | ZTS_EVENT_NETIF_LINK_UP | ZTS_EVENT_NETIF_LINK_DOWN
//
#define ZTS_EVENT_GENERIC_DOWN ZTS_EVENT_NETWORK_DOWN | ZTS_EVENT_NETIF_DOWN_IP4 | ZTS_EVENT_NETIF_DOWN_IP6 | ZTS_EVENT_NETIF_LINK_DOWN
// Peer events
#define ZTS_EVENT_PEER_P2P 0x20000000
#define ZTS_EVENT_PEER_RELAY 0x40000000
#define ZTS_EVENT_PEER_UNREACHABLE 0x80000000 // Not yet supported
//////////////////////////////////////////////////////////////////////////////
// libzt config //

View File

@@ -39,6 +39,8 @@
#include <sys/socket.h>
#endif
namespace ZeroTier {
//////////////////////////////////////////////////////////////////////////////
// Subset of: ZeroTierOne.h //
// We redefine a few ZT structures here so that we don't need to drag the //
@@ -208,4 +210,6 @@ struct zts_peer_list
unsigned long peerCount;
};
} // namespace ZeroTier
#endif // _H

View File

@@ -33,6 +33,10 @@
#ifndef LIBZT_SERVICE_CONTROLS_HPP
#define LIBZT_SERVICE_CONTROLS_HPP
#include "Constants.hpp"
namespace ZeroTier {
#ifdef _WIN32
#ifdef ADD_EXPORTS
#define ZT_SOCKET_API __declspec(dllexport)
@@ -45,8 +49,6 @@
#define ZTCALL
#endif
void api_sleep(int interval_ms);
//////////////////////////////////////////////////////////////////////////////
// ZeroTier Service Controls //
//////////////////////////////////////////////////////////////////////////////
@@ -386,4 +388,6 @@ void _hibernate_if_needed();
}
#endif
} // namespace ZeroTier
#endif // _H

View File

@@ -78,33 +78,9 @@ public:
~VirtualTap();
/**
* A state will only be reported via callback if it differs from this value. Subsequently this
* value will be updated.
*/
int _lastReportedStatus;
/**
* The last time that this virtual tap received a network config update from the core
*/
uint64_t _lastConfigUpdateTime = 0;
/**
* The last time that a callback notification was sent to the user application signalling
* that this interface is ready to process traffic.
*/
uint64_t _lastReadyReportTime = 0;
void lastConfigUpdate(uint64_t lastConfigUpdateTime);
void setEnabled(bool en);
bool enabled() const;
/**
* Registers a device with the given address
*/
void registerIpWithStack(const InetAddress &ip);
/**
* Adds an address to the userspace stack interface associated with this VirtualTap
* - Starts VirtualTap main thread ONLY if successful
@@ -178,6 +154,48 @@ public:
void phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len);
void phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked);
//////////////////////////////////////////////////////////////////////////////
// Lower-level lwIP netif handling and traffic handling readiness //
//////////////////////////////////////////////////////////////////////////////
void *netif4 = NULL;
void *netif6 = NULL;
bool netif4WasUpLastCheck = false;
bool netif6WasUpLastCheck = false;
/**
* Notes the current state of the lower level lwIP netif and reports if a state change
* has happened since the last check. This method is likely temporary.
*/
uint64_t recognizeLowerLevelInterfaceStateChange(void *n);
/**
* A state will only be reported via callback if it differs from this value. Subsequently this
* value will be updated.
*/
//int _lastReportedStatus;
/**
* The last time that this virtual tap received a network config update from the core
*/
uint64_t _lastConfigUpdateTime = 0;
/**
* The last time that a callback notification was sent to the user application signalling
* that this interface is ready to process traffic.
*/
uint64_t _lastReadyReportTime = 0;
void lastConfigUpdate(uint64_t lastConfigUpdateTime);
int _networkStatus = 0;
int _netifStatus = 0;
/**
* Returns whether or not this interface is ready for traffic.
*/
bool isReady();
//////////////////////////////////////////////////////////////////////////////
// Vars //
//////////////////////////////////////////////////////////////////////////////

View File

@@ -1,62 +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
*/
#ifndef LIBZT_VIRTUAL_TAP_MANAGER_H
#define LIBZT_VIRTUAL_TAP_MANAGER_H
#include "VirtualTap.hpp"
#include "OneService.hpp"
namespace ZeroTier {
class VirtualTap;
/**
* @brief Static utility class for safely handling VirtualTap(s)
*/
class VirtualTapManager
{
public:
static void add_tap(VirtualTap *tap);
static VirtualTap *getTapByNWID(uint64_t nwid);
static size_t get_vtaps_size();
static void remove_by_nwid(uint64_t nwid);
static void clear();
static void get_network_details_helper(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd);
static void get_network_details(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd);
static void get_all_network_details(void *zt1ServiceRef, struct zts_network_details *nds, int *num);
};
} // namespace ZeroTier
#endif // _H

View File

@@ -37,11 +37,31 @@
#include "lwip/err.h"
namespace ZeroTier {
class MAC;
class Mutex;
class VirtualTap;
struct InetAddress;
}
class MAC;
class Mutex;
class VirtualTap;
struct InetAddress;
/**
* @brief Structure used to associate packets with interfaces.
*/
struct zts_sorted_packet
{
// lwIP pbuf containing packet (originally encapsulated by ZT packet)
struct pbuf *p;
// ZT VirtualTap from which this packet originates
ZeroTier::VirtualTap *vtap;
// lwIP netif we should accept this packet on
struct netif *n;
};
/**
* @brief Return whether a given netif's NETIF_FLAG_UP flag is set
*
* @usage This is a convenience function to encapsulate a macro
*/
bool lwip_is_netif_up(void *netif);
/**
* @brief Increase the delay multiplier for the main driver loop
@@ -76,15 +96,14 @@ void lwip_driver_init();
void lwip_driver_shutdown();
/**
* @brief Bring all interfaces down belonging to the given virtual tap interface
* @brief Bring down and delete all interfaces belonging to the given virtual tap
*
* @usage This is to be called when the application desires to stop all traffic processing in the
* stack. Unlike lwip_driver_shutdown(), the application can easily resume traffic processing
* by re-adding a virtual tap (and associated lwip netifs)
* @return
*/
void lwip_driver_set_tap_interfaces_down(void *tapref);
void lwip_driver_set_all_interfaces_down();
void lwip_dispose_of_netifs(void *tapref);
/**
* @brief Initialize and start the DNS client
@@ -128,7 +147,7 @@ static void netif_link_callback(struct netif *netif);
* @param ip Virtual IP address for this ZeroTier VirtualTap interface
* @return
*/
void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier::InetAddress &ip);
void lwip_init_interface(void *tapref, const MAC &mac, const InetAddress &ip);
/**
* @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier virtual wire here.
@@ -152,7 +171,9 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p);
* @param len Length of Ethernet frame
* @return
*/
void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const ZeroTier::MAC &to, unsigned int etherType,
void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
const void *data, unsigned int len);
} // namespace ZeroTier
#endif // _H

View File

@@ -53,7 +53,7 @@
*/
#if __ANDROID__
#define LWIP_PROVIDE_ERRNO 1
//#define SOCKLEN_T_DEFINED
#define SOCKLEN_T_DEFINED
#elif !defined(_MSC_VER)
#define LWIP_PROVIDE_ERRNO 1
#endif
@@ -61,7 +61,7 @@
/**
* Disable assertions
*/
#define LWIP_NOASSERT 0
#define LWIP_NOASSERT 1
/**
* Don't redefine byte-order functions if they're already available
@@ -103,6 +103,33 @@
*/
#define LWIP_DBG_HALT 0x08U
/*------------------------------------------------------------------------------
---------------------------------- Timers --------------------------------------
------------------------------------------------------------------------------*/
/*
Be careful about setting this too small. lwIP just counts the number
of times its timer is called and uses this to control time sensitive
operations (such as TCP retransmissions), rather than actually
measuring time using something more accurate. If you call the timer
functions very frequently you may see things (such as retransmissions)
happening sooner than they should.
*/
/* these are originally defined in tcp_impl.h */
#ifndef TCP_TMR_INTERVAL
/* The TCP timer interval in milliseconds. */
#define TCP_TMR_INTERVAL 250
#endif /* TCP_TMR_INTERVAL */
#ifndef TCP_FAST_INTERVAL
/* the fine grained timeout in milliseconds */
#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL
#endif /* TCP_FAST_INTERVAL */
#ifndef TCP_SLOW_INTERVALs
/* the coarse grained timeout in milliseconds */
#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL)
#endif /* TCP_SLOW_INTERVAL */
/*------------------------------------------------------------------------------
----------------------- Below: Modified contents of opt.h ----------------------
------------------------------------------------------------------------------*/
@@ -243,7 +270,7 @@
* Your system should provide mutexes supporting priority inversion to use this.
*/
#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__
#define LWIP_TCPIP_CORE_LOCKING 0
#define LWIP_TCPIP_CORE_LOCKING 1
#endif
/**
@@ -350,7 +377,7 @@
* a lot of data that needs to be copied, this should be set high.
*/
#if !defined MEM_SIZE || defined __DOXYGEN__
#define MEM_SIZE 1600
#define MEM_SIZE 1024 * 1024
#endif
/**
@@ -464,7 +491,7 @@
* this should be set high.
*/
#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__
#define MEMP_NUM_PBUF 16
#define MEMP_NUM_PBUF 1024
#endif
/**
@@ -472,7 +499,7 @@
* (requires the LWIP_RAW option)
*/
#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__
#define MEMP_NUM_RAW_PCB 4
#define MEMP_NUM_RAW_PCB 1024
#endif
/**
@@ -481,7 +508,7 @@
* (requires the LWIP_UDP option)
*/
#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__
#define MEMP_NUM_UDP_PCB 4
#define MEMP_NUM_UDP_PCB 1024
#endif
/**
@@ -489,7 +516,7 @@
* (requires the LWIP_TCP option)
*/
#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__
#define MEMP_NUM_TCP_PCB 5
#define MEMP_NUM_TCP_PCB 1024
#endif
/**
@@ -497,7 +524,7 @@
* (requires the LWIP_TCP option)
*/
#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__
#define MEMP_NUM_TCP_PCB_LISTEN 8
#define MEMP_NUM_TCP_PCB_LISTEN 1024
#endif
/**
@@ -505,7 +532,7 @@
* (requires the LWIP_TCP option)
*/
#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__
#define MEMP_NUM_TCP_SEG 16
#define MEMP_NUM_TCP_SEG 1024
#endif
/**
@@ -523,7 +550,7 @@
* reassembly (whole packets, not fragments!)
*/
#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__
#define MEMP_NUM_REASSDATA 5
#define MEMP_NUM_REASSDATA 16
#endif
/**
@@ -585,7 +612,7 @@
* (only needed if you use the sequential API, like api_lib.c)
*/
#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__
#define MEMP_NUM_NETCONN 4
#define MEMP_NUM_NETCONN 256
#endif
/**
@@ -603,7 +630,7 @@
* (only needed if you use tcpip.c)
*/
#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__
#define MEMP_NUM_TCPIP_MSG_API 8
#define MEMP_NUM_TCPIP_MSG_API 64
#endif
/**
@@ -612,7 +639,7 @@
* (only needed if you use tcpip.c)
*/
#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__
#define MEMP_NUM_TCPIP_MSG_INPKT 8
#define MEMP_NUM_TCPIP_MSG_INPKT 64
#endif
/**
@@ -635,7 +662,7 @@
* PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
*/
#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__
#define PBUF_POOL_SIZE 16
#define PBUF_POOL_SIZE 128
#endif
/** MEMP_NUM_API_MSG: the number of concurrently active calls to various
@@ -689,7 +716,7 @@
* ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.
*/
#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__
#define ARP_TABLE_SIZE 10
#define ARP_TABLE_SIZE 64
#endif
/** the time an ARP entry stays valid after its last update,
@@ -847,7 +874,7 @@
* (PBUF_POOL_SIZE > 2 * IP_REASS_MAX_PBUFS)!
*/
#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__
#define IP_REASS_MAX_PBUFS 10
#define IP_REASS_MAX_PBUFS 32
#endif
/**
@@ -1292,7 +1319,7 @@
* will be TCP_WND >> TCP_RCV_SCALE
*/
#if !defined TCP_WND || defined __DOXYGEN__
#define TCP_WND (4 * TCP_MSS)
#define TCP_WND 0xffff // (4 * TCP_MSS)
#endif
/**
@@ -1306,7 +1333,7 @@
* TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
*/
#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__
#define TCP_SYNMAXRTX 6
#define TCP_SYNMAXRTX 12 // 6
#endif
/**
@@ -1367,7 +1394,7 @@
* To achieve good performance, this should be at least 2 * TCP_MSS.
*/
#if !defined TCP_SND_BUF || defined __DOXYGEN__
#define TCP_SND_BUF (2 * TCP_MSS)
#define TCP_SND_BUF 1024 * 32 // (2 * TCP_MSS)
#endif
/**
@@ -1375,7 +1402,7 @@
* as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
*/
#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
#define TCP_SND_QUEUELEN 1024 // ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
#endif
/**
@@ -1689,7 +1716,7 @@
* if you have a tiny ARP table or if there never are concurrent connections.
*/
#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__
#define LWIP_NETIF_HWADDRHINT 0
#define LWIP_NETIF_HWADDRHINT 1
#endif
/**
@@ -2005,7 +2032,7 @@
* (only used if you use sockets.c)
*/
#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__
#define LWIP_COMPAT_SOCKETS 1
#define LWIP_COMPAT_SOCKETS 0
#endif
/**
@@ -2014,7 +2041,7 @@
* names (read, write & close). (only used if you use sockets.c)
*/
#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__
#define LWIP_POSIX_SOCKETS_IO_NAMES 1
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
#endif
/**
@@ -2152,7 +2179,7 @@
* LWIP_STATS==1: Enable statistics collection in lwip_stats.
*/
#if !defined LWIP_STATS || defined __DOXYGEN__
#define LWIP_STATS 1
#define LWIP_STATS 0
#endif
#if LWIP_STATS
@@ -2161,7 +2188,7 @@
* LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.
*/
#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__
#define LWIP_STATS_DISPLAY 1
#define LWIP_STATS_DISPLAY 0
#endif
/**
@@ -3572,4 +3599,4 @@
* @}
*/
#endif /* LWIP_HDR_OPT_H */
#endif /* LWIP_HDR_OPT_H */

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