partially-working picoTCP integration

This commit is contained in:
Joseph Henry
2016-10-14 14:03:06 -07:00
parent d9033ba2f3
commit 8514c6bcab
164 changed files with 47767 additions and 56 deletions

View File

@@ -38,8 +38,20 @@
#include "SDK_EthernetTap.hpp"
#include "SDK_Utils.hpp"
#include "SDK.h"
#include "SDK_defs.h"
#include "SDK_Debug.h"
#include "SDK_LWIPStack.hpp"
#if defined(SDK_LWIP)
#include "SDK_lwip.hpp"
#elif defined(SDK_PICOTCP)
#include "SDK_pico.hpp"
#include "pico_stack.h"
#include "pico_ipv4.h"
#include "pico_icmp4.h"
#include "pico_dev_tap.h"
#elif defined(SDK_JIP)
#include "SDK_jip.hpp"
#endif
#include "Utils.hpp"
#include "OSUtils.hpp"
@@ -71,6 +83,7 @@
namespace ZeroTier {
// ---------------------------------------------------------------------------
static ZeroTier::NetconEthernetTap *picotap;
static err_t tapif_init(struct netif *netif)
{
@@ -78,6 +91,73 @@ static err_t tapif_init(struct netif *netif)
return ERR_OK;
}
static void cb_ping(struct pico_icmp4_stats *s)
{
char host[30];
picotap->picostack->__pico_ipv4_to_string(host, s->dst.addr);
if (s->err == 0) {
// if all is well, print some pretty info
printf("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%lu ms\n", s->size,
host, s->seq, s->ttl, (long unsigned int)s->time);
//if (s->seq >= NUM_PING)
//finished = 1;
} else {
// if something went wrong, print it and signal we want to stop
printf("PING %lu to %s: Error %d\n", s->seq, host, s->err);
//finished = 1;
}
}
static int pico_eth_send(struct pico_device *dev, void *buf, int len)
{
DEBUG_INFO("len = %d", len);
struct eth_hdr *ethhdr;
ethhdr = (struct eth_hdr *)buf;
ZeroTier::MAC src_mac;
ZeroTier::MAC dest_mac;
src_mac.setTo(ethhdr->src.addr, 6);
dest_mac.setTo(ethhdr->dest.addr, 6);
picotap->_handler(picotap->_arg,picotap->_nwid,src_mac,dest_mac,
Utils::ntoh((uint16_t)ethhdr->type),0, ((char*)buf) + sizeof(struct eth_hdr),len - sizeof(struct eth_hdr));
return len;
}
static int pico_eth_poll(struct pico_device *dev, int loop_score)
{
// OPTIMIZATION: The copy logic and/or buffer structure should be reworked for better performance after the BETA
// DEBUG_INFO();
// ZeroTier::NetconEthernetTap *tap = (ZeroTier::NetconEthernetTap*)netif->state;
Mutex::Lock _l(picotap->_pico_frame_rxbuf_m);
uint8_t *buf = NULL;
uint32_t len = 0;
struct eth_hdr ethhdr;
unsigned char frame[ZT_MAX_MTU];
while (picotap->pico_frame_rxbuf_tot > 0) {
memset(frame, 0, sizeof(frame));
unsigned int len = 0;
memcpy(&len, picotap->pico_frame_rxbuf, sizeof(len)); // get frame len
DEBUG_ATTN("reading frame len = %ld", len);
memcpy(frame, picotap->pico_frame_rxbuf + sizeof(len), len); // get frame data
memmove(picotap->pico_frame_rxbuf, picotap->pico_frame_rxbuf + sizeof(len) + len, ZT_MAX_MTU-(sizeof(len) + len));
int rx_ret = picotap->picostack->__pico_stack_recv(dev, (uint8_t*)frame, len);
picotap->pico_frame_rxbuf_tot-=(sizeof(len) + len);
DEBUG_ATTN("rx_ret = %d", rx_ret);
DEBUG_EXTRA("RX frame buffer %3f full", (float)(picotap->pico_frame_rxbuf_tot) / (float)(MAX_PICO_FRAME_RX_BUF_SZ));
loop_score--;
}
//DEBUG_ATTN("loop_score = %d", loop_score);
return loop_score;
}
/*
* Outputs data from the pbuf queue to the interface
*/
@@ -107,7 +187,7 @@ static err_t low_level_output(struct netif *netif, struct pbuf *p)
dest_mac.setTo(ethhdr->dest.addr, 6);
tap->_handler(tap->_arg,tap->_nwid,src_mac,dest_mac,
Utils::ntoh((uint16_t)ethhdr->type),0,buf + sizeof(struct eth_hdr),totalLength - sizeof(struct eth_hdr));
Utils::ntoh((uint16_t)ethhdr->type),0,buf + sizeof(struct eth_hdr),totalLength - sizeof(struct eth_hdr));
return ERR_OK;
}
@@ -134,21 +214,42 @@ NetconEthernetTap::NetconEthernetTap(
_run(true)
{
sockstate = -1;
char sockPath[4096],lwipPath[4096];
char sockPath[4096],stackPath[4096];
Utils::snprintf(sockPath,sizeof(sockPath),"%s%snc_%.16llx",homePath,ZT_PATH_SEPARATOR_S,_nwid,ZT_PATH_SEPARATOR_S,(unsigned long long)nwid);
_dev = sockPath; // in SDK mode, set device to be just the network ID
Utils::snprintf(lwipPath,sizeof(lwipPath),"%s%sliblwip.so",homePath,ZT_PATH_SEPARATOR_S);
lwipstack = new LWIPStack(lwipPath);
if(!lwipstack)
throw std::runtime_error("unable to dynamically load a new instance of liblwip.so (searched ZeroTier home path)");
lwipstack->__lwip_init();
_unixListenSocket = _phy.unixListen(sockPath,(void *)this);
DEBUG_INFO("tap initialized on: path=%s", sockPath);
if (!_unixListenSocket)
DEBUG_ERROR("unable to bind to: path=%s", sockPath);
_thread = Thread::start(this);
// SIP-0
// Load and initialize network stack library
#if defined(SDK_LWIP)
Utils::snprintf(stackPath,sizeof(stackPath),"%s%sliblwip.so",homePath,ZT_PATH_SEPARATOR_S);
lwipstack = new lwIP_stack(stackPath);
#elif defined(SDK_PICOTCP)
Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibpicotcp.so",homePath,ZT_PATH_SEPARATOR_S);
picostack = new picoTCP_stack(stackPath);
#elif defined(SDK_JIP)
Utils::snprintf(stackPath,sizeof(stackPath),"%s%slibjip.so",homePath,ZT_PATH_SEPARATOR_S);
jipstack = new jip_stack(stackPath);
#endif
if(!lwipstack && !picostack && !jipstack) {
DEBUG_ERROR("unable to dynamically load a new instance of (%s) (searched ZeroTier home path)", stackPath);
throw std::runtime_error("");
}
else {
if(lwipstack)
lwipstack->__lwip_init();
if(picostack)
picostack->__pico_stack_init();
//if(jipstack)
// jipstack->__jip_init();
_unixListenSocket = _phy.unixListen(sockPath,(void *)this);
DEBUG_INFO("tap initialized on: path=%s", sockPath);
if (!_unixListenSocket)
DEBUG_ERROR("unable to bind to: path=%s", sockPath);
_thread = Thread::start(this);
}
}
NetconEthernetTap::~NetconEthernetTap()
@@ -171,10 +272,14 @@ bool NetconEthernetTap::enabled() const
return _enabled;
}
bool NetconEthernetTap::addIp(const InetAddress &ip)
void NetconEthernetTap::lwIP_init_interface(const InetAddress &ip)
{
DEBUG_INFO("local_addr=%s", ip.toString().c_str());
Mutex::Lock _l(_ips_m);
// SIP-1
// Initialize network stack's interface, assign addresses
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) {
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
@@ -231,6 +336,62 @@ bool NetconEthernetTap::addIp(const InetAddress &ip)
interface6.flags = NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
}
}
}
void NetconEthernetTap::picoTCP_init_interface(const InetAddress &ip)
{
// TODO: Move this somewhere more appropriate
picotap = this;
DEBUG_INFO();
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) {
_ips.push_back(ip);
std::sort(_ips.begin(),_ips.end());
if(ip.isV4())
{
int id;
struct pico_ip4 ipaddr, netmask;
ipaddr.addr = *((u32_t *)ip.rawIpData());
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
picostack->__pico_ipv4_link_add(&picodev, ipaddr, netmask);
picodev.send = pico_eth_send; // tx
picodev.poll = pico_eth_poll; // rx
// Register the device in picoTCP
uint8_t mac[PICO_SIZE_ETH];
_mac.copyTo(mac, PICO_SIZE_ETH);
DEBUG_ATTN("mac = %s", _mac.toString().c_str());
if( 0 != picostack->__pico_device_init(&picodev, "p0", mac)) {
DEBUG_ERROR("device init failed");
return;
}
DEBUG_INFO("successfully initialized device");
// picostack->__pico_icmp4_ping("10.8.8.1", 20, 1000, 10000, 64, cb_ping);
}
if(ip.isV6())
{
}
}
}
void NetconEthernetTap::jip_init_interface(const InetAddress &ip)
{
// will be similar to lwIP initialization process
}
bool NetconEthernetTap::addIp(const InetAddress &ip)
{
// SIP-3
// Initialize a new interface in the stack, assign an address
#if defined(SDK_LWIP)
lwIP_init_interface(ip);
#elif defined(SDK_PICOTCP)
picoTCP_init_interface(ip);
#elif defined(SDK_JIP)
jip_init_interface(ip);
#endif
return true;
}
@@ -253,13 +414,13 @@ std::vector<InetAddress> NetconEthernetTap::ips() const
return _ips;
}
void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
void NetconEthernetTap::lwIP_rx(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
DEBUG_EXTRA("RX packet: len=%d, etherType=%d", len, etherType);
DEBUG_INFO();
struct pbuf *p,*q;
if (!_enabled)
return;
DEBUG_EXTRA("IPV6");
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
@@ -295,6 +456,58 @@ void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType
}
}
void NetconEthernetTap::picoTCP_rx(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
DEBUG_INFO();
// Since picoTCP only allows the reception of frames from within the polling function, we
// must enqueue each frame into a memory structure shared by both threads. This structure will
Mutex::Lock _l(_pico_frame_rxbuf_m);
if(len > ((1024 * 1024) - pico_frame_rxbuf_tot)) {
DEBUG_ERROR("dropping packet (len = %d) - not enough space left on RX frame buffer", len);
return;
}
//if(len != memcpy(pico_frame_rxbuf, data, len)) {
// DEBUG_ERROR("dropping packet (len = %d) - unable to copy contents of frame to RX frame buffer", len);
// return;
//}
// assemble new eth header
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
ethhdr.type = Utils::hton((uint16_t)etherType);
int newlen = len+sizeof(struct eth_hdr);
memcpy(pico_frame_rxbuf + pico_frame_rxbuf_tot, &newlen, sizeof(newlen)); // size of frame
memcpy(pico_frame_rxbuf + pico_frame_rxbuf_tot + sizeof(newlen), &ethhdr, sizeof(ethhdr)); // new eth header
memcpy(pico_frame_rxbuf + pico_frame_rxbuf_tot + sizeof(newlen) + sizeof(ethhdr), data, len); // frame data
pico_frame_rxbuf_tot += len + sizeof(len) + sizeof(ethhdr);
DEBUG_INFO("RX frame buffer %3f full", (float)pico_frame_rxbuf_tot / (float)(1024 * 1024));
}
void NetconEthernetTap::jip_rx(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
DEBUG_INFO();
}
void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
DEBUG_EXTRA("RX packet: len=%d, etherType=%d", len, etherType);
// SIP-
// RX packet
#if defined(SDK_LWIP)
lwIP_rx(from,to,etherType,data,len);
#elif defined(SDK_PICOTCP)
picoTCP_rx(from,to,etherType,data,len);
#elif defined(SDK_JIP)
jip_rx(from,to,etherType,data,len);
#endif
}
std::string NetconEthernetTap::deviceName() const
{
return _dev;
@@ -326,13 +539,12 @@ void NetconEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,s
_multicastGroups.swap(newGroups);
}
void NetconEthernetTap::threadMain()
throw()
void NetconEthernetTap::lwIP_loop()
{
DEBUG_INFO();
uint64_t prev_tcp_time = 0, prev_status_time = 0, prev_discovery_time = 0;
// Main timer loop
while (_run) {
uint64_t now = OSUtils::now();
uint64_t since_tcp = now - prev_tcp_time;
uint64_t since_discovery = now - prev_discovery_time;
@@ -407,6 +619,40 @@ void NetconEthernetTap::threadMain()
lwipstack->close();
}
void NetconEthernetTap::picoTCP_loop()
{
DEBUG_INFO();
while(_run)
{
//DEBUG_INFO("pico_tick");
usleep(1000);
picostack->__pico_stack_tick();
}
}
void NetconEthernetTap::jip_loop()
{
DEBUG_INFO();
while(_run)
{
}
}
void NetconEthernetTap::threadMain()
throw()
{
// SIP-2
// Enter main thread loop for network stack
#if defined(SDK_LWIP)
lwIP_loop();
#elif defined(SDK_PICOTCP)
picoTCP_loop();
#elif defined(SDK_JIP)
jip_loop();
#endif
}
Connection *NetconEthernetTap::getConnection(PhySocket *sock)
{
for(size_t i=0;i<_Connections.size();++i) {