dynamic loading of network stack no longer needed

This commit is contained in:
Joseph Henry
2017-04-06 19:16:01 -07:00
parent 997f12a592
commit 08cca3c7aa
463 changed files with 136513 additions and 0 deletions

View File

@@ -0,0 +1,408 @@
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
.
Authors: Daniele Lacamera
*********************************************************************/
#include "pico_config.h"
#include "pico_device.h"
#include "pico_stack.h"
#include "pico_protocol.h"
#include "pico_tree.h"
#include "pico_ipv6.h"
#include "pico_ipv4.h"
#include "pico_icmp6.h"
#include "pico_eth.h"
#define PICO_DEVICE_DEFAULT_MTU (1500)
struct pico_devices_rr_info {
struct pico_tree_node *node_in, *node_out;
};
static struct pico_devices_rr_info Devices_rr_info = {
NULL, NULL
};
static int pico_dev_cmp(void *ka, void *kb)
{
struct pico_device *a = ka, *b = kb;
if (a->hash < b->hash)
return -1;
if (a->hash > b->hash)
return 1;
return 0;
}
PICO_TREE_DECLARE(Device_tree, pico_dev_cmp);
#ifdef PICO_SUPPORT_IPV6
static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal)
{
dev->hostvars.basetime = PICO_ND_REACHABLE_TIME;
/* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */
dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10;
dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER;
pico_icmp6_router_solicitation(dev, linklocal);
dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP;
}
struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix)
{
struct pico_ip6 newaddr;
struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
struct pico_ipv6_link *link;
memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6);
/* modified EUI-64 + invert universal/local bit */
newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02);
newaddr.addr[9] = dev->eth->mac.addr[1];
newaddr.addr[10] = dev->eth->mac.addr[2];
newaddr.addr[11] = 0xff;
newaddr.addr[12] = 0xfe;
newaddr.addr[13] = dev->eth->mac.addr[3];
newaddr.addr[14] = dev->eth->mac.addr[4];
newaddr.addr[15] = dev->eth->mac.addr[5];
link = pico_ipv6_link_add(dev, newaddr, netmask64);
if (link) {
device_init_ipv6_final(dev, &newaddr);
}
return link;
}
#endif
static int device_init_mac(struct pico_device *dev, uint8_t *mac)
{
#ifdef PICO_SUPPORT_IPV6
struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}};
#endif
dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev));
if (dev->eth) {
memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
#ifdef PICO_SUPPORT_IPV6
if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) {
PICO_FREE(dev->q_in);
PICO_FREE(dev->q_out);
PICO_FREE(dev->eth);
return -1;
}
#endif
} else {
pico_err = PICO_ERR_ENOMEM;
return -1;
}
return 0;
}
int pico_device_ipv6_random_ll(struct pico_device *dev)
{
#ifdef PICO_SUPPORT_IPV6
struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}};
struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
uint32_t len = (uint32_t)strlen(dev->name);
if (strcmp(dev->name, "loop")) {
do {
/* privacy extension + unset universal/local and individual/group bit */
len = pico_rand();
linklocal.addr[8] = (uint8_t)((len & 0xffu) & (uint8_t)(~0x03));
linklocal.addr[9] = (uint8_t)(len >> 8);
linklocal.addr[10] = (uint8_t)(len >> 16);
linklocal.addr[11] = (uint8_t)(len >> 24);
len = pico_rand();
linklocal.addr[12] = (uint8_t)len;
linklocal.addr[13] = (uint8_t)(len >> 8);
linklocal.addr[14] = (uint8_t)(len >> 16);
linklocal.addr[15] = (uint8_t)(len >> 24);
pico_rand_feed(dev->hash);
} while (pico_ipv6_link_get(&linklocal));
if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) {
return -1;
}
}
#endif
return 0;
}
static int device_init_nomac(struct pico_device *dev)
{
if (pico_device_ipv6_random_ll(dev) < 0) {
PICO_FREE(dev->q_in);
PICO_FREE(dev->q_out);
return -1;
}
dev->eth = NULL;
return 0;
}
extern int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac)
{
uint32_t len = (uint32_t)strlen(name);
int ret = 0;
if(len > MAX_DEVICE_NAME)
len = MAX_DEVICE_NAME;
memcpy(dev->name, name, len);
dev->hash = pico_hash(dev->name, len);
Devices_rr_info.node_in = NULL;
Devices_rr_info.node_out = NULL;
dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue));
if (!dev->q_in)
return -1;
dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue));
if (!dev->q_out) {
PICO_FREE(dev->q_in);
return -1;
}
pico_tree_insert(&Device_tree, dev);
if (!dev->mtu)
dev->mtu = PICO_DEVICE_DEFAULT_MTU;
if (mac) {
ret = device_init_mac(dev, mac);
} else {
ret = device_init_nomac(dev);
}
return ret;
}
static void pico_queue_destroy(struct pico_queue *q)
{
if (q) {
pico_queue_empty(q);
PICO_FREE(q);
}
}
void pico_device_destroy(struct pico_device *dev)
{
pico_queue_destroy(dev->q_in);
pico_queue_destroy(dev->q_out);
if (dev->eth)
PICO_FREE(dev->eth);
#ifdef PICO_SUPPORT_IPV4
pico_ipv4_cleanup_links(dev);
#endif
#ifdef PICO_SUPPORT_IPV6
pico_ipv6_cleanup_links(dev);
#endif
pico_tree_delete(&Device_tree, dev);
if (dev->destroy)
dev->destroy(dev);
Devices_rr_info.node_in = NULL;
Devices_rr_info.node_out = NULL;
PICO_FREE(dev);
}
static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score)
{
if ((dev->__serving_interrupt) && (dev->dsr)) {
/* call dsr routine */
loop_score = dev->dsr(dev, loop_score);
}
return loop_score;
}
static int check_dev_serve_polling(struct pico_device *dev, int loop_score)
{
if (dev->poll) {
loop_score = dev->poll(dev, loop_score);
}
return loop_score;
}
static int devloop_in(struct pico_device *dev, int loop_score)
{
struct pico_frame *f;
while(loop_score > 0) {
if (dev->q_in->frames == 0)
break;
/* Receive */
f = pico_dequeue(dev->q_in);
if (f) {
if (dev->eth) {
f->datalink_hdr = f->buffer;
(void)pico_ethernet_receive(f);
} else {
f->net_hdr = f->buffer;
pico_network_receive(f);
}
loop_score--;
}
}
return loop_score;
}
static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f)
{
if (dev->eth) {
/* Ethernet: pass management of the frame to the pico_ethernet_send() rdv function */
return pico_ethernet_send(f);
} else {
/* non-ethernet: no post-processing needed */
return (dev->send(dev, f->start, (int)f->len) <= 0); /* Return 0 upon success, which is dev->send() > 0 */
}
}
static int devloop_out(struct pico_device *dev, int loop_score)
{
struct pico_frame *f;
while(loop_score > 0) {
if (dev->q_out->frames == 0)
break;
/* Device dequeue + send */
f = pico_queue_peek(dev->q_out);
if (!f)
break;
if (devloop_sendto_dev(dev, f) == 0) { /* success. */
f = pico_dequeue(dev->q_out);
pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */
loop_score--;
} else
break; /* Don't discard */
}
return loop_score;
}
static int devloop(struct pico_device *dev, int loop_score, int direction)
{
/* If device supports interrupts, read the value of the condition and trigger the dsr */
loop_score = check_dev_serve_interrupt(dev, loop_score);
/* If device supports polling, give control. Loop score is managed internally,
* remaining loop points are returned. */
loop_score = check_dev_serve_polling(dev, loop_score);
if (direction == PICO_LOOP_DIR_OUT)
loop_score = devloop_out(dev, loop_score);
else
loop_score = devloop_in(dev, loop_score);
return loop_score;
}
static struct pico_tree_node *pico_dev_roundrobin_start(int direction)
{
if (Devices_rr_info.node_in == NULL)
Devices_rr_info.node_in = pico_tree_firstNode(Device_tree.root);
if (Devices_rr_info.node_out == NULL)
Devices_rr_info.node_out = pico_tree_firstNode(Device_tree.root);
if (direction == PICO_LOOP_DIR_IN)
return Devices_rr_info.node_in;
else
return Devices_rr_info.node_out;
}
static void pico_dev_roundrobin_end(int direction, struct pico_tree_node *last)
{
if (direction == PICO_LOOP_DIR_IN)
Devices_rr_info.node_in = last;
else
Devices_rr_info.node_out = last;
}
#define DEV_LOOP_MIN 16
int pico_devices_loop(int loop_score, int direction)
{
struct pico_device *start, *next;
struct pico_tree_node *next_node = pico_dev_roundrobin_start(direction);
if (!next_node)
return loop_score;
next = next_node->keyValue;
start = next;
/* round-robin all devices, break if traversed all devices */
while ((loop_score > DEV_LOOP_MIN) && (next != NULL)) {
loop_score = devloop(next, loop_score, direction);
next_node = pico_tree_next(next_node);
next = next_node->keyValue;
if (next == NULL)
{
next_node = pico_tree_firstNode(Device_tree.root);
next = next_node->keyValue;
}
if (next == start)
break;
}
pico_dev_roundrobin_end(direction, next_node);
return loop_score;
}
struct pico_device *pico_get_device(const char*name)
{
struct pico_device *dev;
struct pico_tree_node *index;
pico_tree_foreach(index, &Device_tree){
dev = index->keyValue;
if(strcmp(name, dev->name) == 0)
return dev;
}
return NULL;
}
int32_t pico_device_broadcast(struct pico_frame *f)
{
struct pico_tree_node *index;
int32_t ret = -1;
pico_tree_foreach(index, &Device_tree)
{
struct pico_device *dev = index->keyValue;
if(dev != f->dev)
{
struct pico_frame *copy = pico_frame_copy(f);
if(!copy)
break;
copy->dev = dev;
copy->dev->send(copy->dev, copy->start, (int)copy->len);
pico_frame_discard(copy);
}
else
{
ret = f->dev->send(f->dev, f->start, (int)f->len);
}
}
return ret;
}
int pico_device_link_state(struct pico_device *dev)
{
if (!dev->link_state)
return 1; /* Not supported, assuming link is always up */
return dev->link_state(dev);
}

View File

@@ -0,0 +1,286 @@
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
.
Authors: Daniele Lacamera
*********************************************************************/
#include "pico_config.h"
#include "pico_frame.h"
#include "pico_protocol.h"
#include "pico_stack.h"
#ifdef PICO_SUPPORT_DEBUG_MEMORY
static int n_frames_allocated;
#endif
/** frame alloc/dealloc/copy **/
void pico_frame_discard(struct pico_frame *f)
{
if (!f)
return;
(*f->usage_count)--;
if (*f->usage_count == 0) {
if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
PICO_FREE(f->usage_count);
#ifdef PICO_SUPPORT_DEBUG_MEMORY
dbg("Discarded buffer @%p, caller: %p\n", f->buffer, __builtin_return_address(3));
dbg("DEBUG MEMORY: %d frames in use.\n", --n_frames_allocated);
#endif
if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
PICO_FREE(f->buffer);
else if (f->notify_free)
f->notify_free(f->buffer);
if (f->info)
PICO_FREE(f->info);
}
#ifdef PICO_SUPPORT_DEBUG_MEMORY
else {
dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count);
}
#endif
PICO_FREE(f);
}
struct pico_frame *pico_frame_copy(struct pico_frame *f)
{
struct pico_frame *new = PICO_ZALLOC(sizeof(struct pico_frame));
if (!new)
return NULL;
memcpy(new, f, sizeof(struct pico_frame));
*(new->usage_count) += 1;
#ifdef PICO_SUPPORT_DEBUG_MEMORY
dbg("Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
#endif
new->next = NULL;
return new;
}
static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int ext_buffer)
{
struct pico_frame *p = PICO_ZALLOC(sizeof(struct pico_frame));
uint32_t frame_buffer_size = size;
if (!p)
return NULL;
if (ext_buffer && !zerocopy) {
/* external buffer implies zerocopy flag! */
PICO_FREE(p);
return NULL;
}
if (!zerocopy) {
unsigned int align = size % sizeof(uint32_t);
/* Ensure that usage_count starts on an aligned address */
if (align) {
frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
}
p->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t));
if (!p->buffer) {
PICO_FREE(p);
return NULL;
}
p->usage_count = (uint32_t *)((void *)(((uint8_t*)p->buffer) + frame_buffer_size));
} else {
p->buffer = NULL;
p->flags |= PICO_FRAME_FLAG_EXT_USAGE_COUNTER;
p->usage_count = PICO_ZALLOC(sizeof(uint32_t));
if (!p->usage_count) {
PICO_FREE(p);
return NULL;
}
}
p->buffer_len = size;
/* By default, frame content is the full buffer. */
p->start = p->buffer;
p->len = p->buffer_len;
*p->usage_count = 1;
if (ext_buffer)
p->flags |= PICO_FRAME_FLAG_EXT_BUFFER;
#ifdef PICO_SUPPORT_DEBUG_MEMORY
dbg("Allocated buffer @%p, len= %d caller: %p\n", p->buffer, p->buffer_len, __builtin_return_address(2));
dbg("DEBUG MEMORY: %d frames in use.\n", ++n_frames_allocated);
#endif
return p;
}
struct pico_frame *pico_frame_alloc(uint32_t size)
{
return pico_frame_do_alloc(size, 0, 0);
}
int pico_frame_grow(struct pico_frame *f, uint32_t size)
{
uint8_t *oldbuf;
uint32_t usage_count, *p_old_usage;
uint32_t frame_buffer_size;
uint32_t oldsize;
unsigned int align;
int addr_diff = 0;
if (!f || (size < f->buffer_len)) {
return -1;
}
align = size % sizeof(uint32_t);
frame_buffer_size = size;
if (align) {
frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
}
oldbuf = f->buffer;
oldsize = f->buffer_len;
usage_count = *(f->usage_count);
p_old_usage = f->usage_count;
f->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t));
if (!f->buffer) {
f->buffer = oldbuf;
return -1;
}
f->usage_count = (uint32_t *)((void *)(((uint8_t*)f->buffer) + frame_buffer_size));
*f->usage_count = usage_count;
f->buffer_len = size;
memcpy(f->buffer, oldbuf, oldsize);
/* Update hdr fields to new buffer*/
addr_diff = (int)(f->buffer - oldbuf);
f->net_hdr += addr_diff;
f->datalink_hdr += addr_diff;
f->transport_hdr += addr_diff;
f->app_hdr += addr_diff;
f->start += addr_diff;
f->payload += addr_diff;
if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
PICO_FREE(p_old_usage);
if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
PICO_FREE(oldbuf);
else if (f->notify_free)
f->notify_free(oldbuf);
f->flags = 0;
/* Now, the frame is not zerocopy anymore, and the usage counter has been moved within it */
return 0;
}
struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer)
{
return pico_frame_do_alloc(size, 1, ext_buffer);
}
int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf)
{
if (!buf)
return -1;
f->buffer = (uint8_t *) buf;
f->start = f->buffer;
return 0;
}
struct pico_frame *pico_frame_deepcopy(struct pico_frame *f)
{
struct pico_frame *new = pico_frame_alloc(f->buffer_len);
int addr_diff;
unsigned char *buf;
uint32_t *uc;
if (!new)
return NULL;
/* Save the two key pointers... */
buf = new->buffer;
uc = new->usage_count;
/* Overwrite all fields with originals */
memcpy(new, f, sizeof(struct pico_frame));
/* ...restore the two key pointers */
new->buffer = buf;
new->usage_count = uc;
/* Update in-buffer pointers with offset */
addr_diff = (int)(new->buffer - f->buffer);
new->datalink_hdr += addr_diff;
new->net_hdr += addr_diff;
new->transport_hdr += addr_diff;
new->app_hdr += addr_diff;
new->start += addr_diff;
new->payload += addr_diff;
#ifdef PICO_SUPPORT_DEBUG_MEMORY
dbg("Deep-Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
#endif
new->next = NULL;
return new;
}
static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t len)
{
uint16_t *buf = (uint16_t *)data;
uint16_t *stop;
if (len & 0x01) {
--len;
#ifdef PICO_BIGENDIAN
sum += (((uint8_t *)data)[len]) << 8;
#else
sum += ((uint8_t *)data)[len];
#endif
}
stop = (uint16_t *)((void *)(((uint8_t *)data) + len));
while (buf < stop) {
sum += *buf++;
}
return sum;
}
static inline uint16_t pico_checksum_finalize(uint32_t sum)
{
while (sum >> 16) { /* a second carry is possible! */
sum = (sum & 0x0000FFFF) + (sum >> 16);
}
return short_be((uint16_t) ~sum);
}
/**
* Calculate checksum of a given string
*/
uint16_t pico_checksum(void *inbuf, uint32_t len)
{
uint32_t sum;
sum = pico_checksum_adder(0, inbuf, len);
return pico_checksum_finalize(sum);
}
/* WARNING: len1 MUST be an EVEN number */
uint16_t pico_dualbuffer_checksum(void *inbuf1, uint32_t len1, void *inbuf2, uint32_t len2)
{
uint32_t sum;
sum = pico_checksum_adder(0, inbuf1, len1);
sum = pico_checksum_adder(sum, inbuf2, len2);
return pico_checksum_finalize(sum);
}

View File

@@ -0,0 +1,43 @@
/*********************************************************************
* PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved.
* See LICENSE and COPYING for usage.
*
* Authors: Daniele Lacamera
* *********************************************************************/
#include <pico_md5.h>
#if defined (PICO_SUPPORT_CYASSL)
#include <cyassl/ctaocrypt/md5.h>
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
{
Md5 md5;
InitMd5(&md5);
Md5Update(&md5, src, len);
Md5Final(&md5, dst);
}
#elif defined (PICO_SUPPORT_POLARSSL)
#include <polarssl/md5.h>
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
{
md5(src, len, dst);
}
#else
static void (*do_pico_md5sum)(uint8_t *dst, const uint8_t *src, size_t len);
void pico_md5sum(uint8_t *dst, const uint8_t *src, size_t len)
{
if (do_pico_md5sum) {
do_pico_md5sum(dst, src, len);
}
}
void pico_register_md5sum(void (*md5)(uint8_t *, const uint8_t *, size_t))
{
do_pico_md5sum = md5;
}
#endif

View File

@@ -0,0 +1,214 @@
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
.
Authors: Daniele Lacamera
*********************************************************************/
#include "pico_protocol.h"
#include "pico_tree.h"
struct pico_proto_rr
{
struct pico_tree *t;
struct pico_tree_node *node_in, *node_out;
};
static int pico_proto_cmp(void *ka, void *kb)
{
struct pico_protocol *a = ka, *b = kb;
if (a->hash < b->hash)
return -1;
if (a->hash > b->hash)
return 1;
return 0;
}
PICO_TREE_DECLARE(Datalink_proto_tree, pico_proto_cmp);
PICO_TREE_DECLARE(Network_proto_tree, pico_proto_cmp);
PICO_TREE_DECLARE(Transport_proto_tree, pico_proto_cmp);
PICO_TREE_DECLARE(Socket_proto_tree, pico_proto_cmp);
/* Static variables to keep track of the round robin loop */
static struct pico_proto_rr proto_rr_datalink = {
&Datalink_proto_tree, NULL, NULL
};
static struct pico_proto_rr proto_rr_network = {
&Network_proto_tree, NULL, NULL
};
static struct pico_proto_rr proto_rr_transport = {
&Transport_proto_tree, NULL, NULL
};
static struct pico_proto_rr proto_rr_socket = {
&Socket_proto_tree, NULL, NULL
};
static int proto_loop_in(struct pico_protocol *proto, int loop_score)
{
struct pico_frame *f;
while(loop_score > 0) {
if (proto->q_in->frames == 0)
break;
f = pico_dequeue(proto->q_in);
if ((f) && (proto->process_in(proto, f) > 0)) {
loop_score--;
}
}
return loop_score;
}
static int proto_loop_out(struct pico_protocol *proto, int loop_score)
{
struct pico_frame *f;
while(loop_score > 0) {
if (proto->q_out->frames == 0)
break;
f = pico_dequeue(proto->q_out);
if ((f) && (proto->process_out(proto, f) > 0)) {
loop_score--;
}
}
return loop_score;
}
static int proto_loop(struct pico_protocol *proto, int loop_score, int direction)
{
if (direction == PICO_LOOP_DIR_IN)
loop_score = proto_loop_in(proto, loop_score);
else if (direction == PICO_LOOP_DIR_OUT)
loop_score = proto_loop_out(proto, loop_score);
return loop_score;
}
static struct pico_tree_node *roundrobin_init(struct pico_proto_rr *rr, int direction)
{
struct pico_tree_node *next_node = NULL;
/* Initialization (takes place only once) */
if (rr->node_in == NULL)
rr->node_in = pico_tree_firstNode(rr->t->root);
if (rr->node_out == NULL)
rr->node_out = pico_tree_firstNode(rr->t->root);
if (direction == PICO_LOOP_DIR_IN)
next_node = rr->node_in;
else
next_node = rr->node_out;
return next_node;
}
static void roundrobin_end(struct pico_proto_rr *rr, int direction, struct pico_tree_node *last)
{
if (direction == PICO_LOOP_DIR_IN)
rr->node_in = last;
else
rr->node_out = last;
}
static int pico_protocol_generic_loop(struct pico_proto_rr *rr, int loop_score, int direction)
{
struct pico_protocol *start, *next;
struct pico_tree_node *next_node = roundrobin_init(rr, direction);
if (!next_node)
return loop_score;
next = next_node->keyValue;
/* init start node */
start = next;
/* round-robin all layer protocols, break if traversed all protocols */
while (loop_score > 1 && next != NULL) {
loop_score = proto_loop(next, loop_score, direction);
next_node = pico_tree_next(next_node);
next = next_node->keyValue;
if (next == NULL)
{
next_node = pico_tree_firstNode(rr->t->root);
next = next_node->keyValue;
}
if (next == start)
break;
}
roundrobin_end(rr, direction, next_node);
return loop_score;
}
int pico_protocol_datalink_loop(int loop_score, int direction)
{
return pico_protocol_generic_loop(&proto_rr_datalink, loop_score, direction);
}
int pico_protocol_network_loop(int loop_score, int direction)
{
return pico_protocol_generic_loop(&proto_rr_network, loop_score, direction);
}
int pico_protocol_transport_loop(int loop_score, int direction)
{
return pico_protocol_generic_loop(&proto_rr_transport, loop_score, direction);
}
int pico_protocol_socket_loop(int loop_score, int direction)
{
return pico_protocol_generic_loop(&proto_rr_socket, loop_score, direction);
}
int pico_protocols_loop(int loop_score)
{
/*
loop_score = pico_protocol_datalink_loop(loop_score);
loop_score = pico_protocol_network_loop(loop_score);
loop_score = pico_protocol_transport_loop(loop_score);
loop_score = pico_protocol_socket_loop(loop_score);
*/
return loop_score;
}
static void proto_layer_rr_reset(struct pico_proto_rr *rr)
{
rr->node_in = NULL;
rr->node_out = NULL;
}
void pico_protocol_init(struct pico_protocol *p)
{
if (!p)
return;
p->hash = pico_hash(p->name, (uint32_t)strlen(p->name));
switch (p->layer) {
case PICO_LAYER_DATALINK:
pico_tree_insert(&Datalink_proto_tree, p);
proto_layer_rr_reset(&proto_rr_datalink);
break;
case PICO_LAYER_NETWORK:
pico_tree_insert(&Network_proto_tree, p);
proto_layer_rr_reset(&proto_rr_network);
break;
case PICO_LAYER_TRANSPORT:
pico_tree_insert(&Transport_proto_tree, p);
proto_layer_rr_reset(&proto_rr_transport);
break;
case PICO_LAYER_SOCKET:
pico_tree_insert(&Socket_proto_tree, p);
proto_layer_rr_reset(&proto_rr_socket);
break;
}
//dbg("Protocol %s registered (layer: %d).\n", p->name, p->layer);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,575 @@
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
Author: Andrei Carp <andrei.carp@tass.be>
*********************************************************************/
#include "pico_tree.h"
#include "pico_config.h"
#include "pico_protocol.h"
#include "pico_mm.h"
#define RED 0
#define BLACK 1
/* By default the null leafs are black */
struct pico_tree_node LEAF = {
NULL, /* key */
&LEAF, &LEAF, &LEAF, /* parent, left,right */
BLACK, /* color */
};
#define IS_LEAF(x) (x == &LEAF)
#define IS_NOT_LEAF(x) (x != &LEAF)
#define INIT_LEAF (&LEAF)
#define AM_I_LEFT_CHILD(x) (x == x->parent->leftChild)
#define AM_I_RIGHT_CHILD(x) (x == x->parent->rightChild)
#define PARENT(x) (x->parent)
#define GRANPA(x) (x->parent->parent)
/*
* Local Functions
*/
static struct pico_tree_node *create_node(struct pico_tree *tree, void *key, uint8_t allocator);
static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node);
static void rotateToRight(struct pico_tree*root, struct pico_tree_node*node);
static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node);
static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node);
static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB);
void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
#ifdef PICO_SUPPORT_MM
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
* These nodes should be placed in the manager page which is in a different memory region then the nodes
* which are used for the pico stack in general.
* Therefore the following 2 functions are created so that pico_tree can use them to to put these nodes
* into the correct memory regions.
* If pico_tree_insert is called from the memory manager module, then create_node should use
* pico_mem_page0_zalloc to create a node. The same for pico_tree_delete.
*/
extern void*pico_mem_page0_zalloc(size_t len);
extern void pico_mem_page0_free(void*ptr);
#endif /* PICO_SUPPORT_MM */
/*
* Exported functions
*/
struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node)
{
while(IS_NOT_LEAF(node->leftChild))
node = node->leftChild;
return node;
}
struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node)
{
while(IS_NOT_LEAF(node->rightChild))
node = node->rightChild;
return node;
}
struct pico_tree_node *pico_tree_next(struct pico_tree_node *node)
{
if (!node)
return NULL;
if(IS_NOT_LEAF(node->rightChild))
{
node = node->rightChild;
while(IS_NOT_LEAF(node->leftChild))
node = node->leftChild;
}
else
{
if (IS_NOT_LEAF(node->parent) && AM_I_LEFT_CHILD(node))
node = node->parent;
else {
while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
node = node->parent;
node = node->parent;
}
}
return node;
}
struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node)
{
if (IS_NOT_LEAF(node->leftChild)) {
node = node->leftChild;
while (IS_NOT_LEAF(node->rightChild))
node = node->rightChild;
} else {
if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
node = node->parent;
else {
while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node))
node = node->parent;
node = node->parent;
}
}
return node;
}
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
* These nodes should be placed in the manager page which is in a different memory region then the nodes
* which are used for the pico stack in general.
* Therefore the following wrapper for pico_tree_insert is created.
* The actual implementation can be found in pico_tree_insert_implementation.
*/
void *pico_tree_insert(struct pico_tree *tree, void *key)
{
return pico_tree_insert_implementation(tree, key, USE_PICO_ZALLOC);
}
void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator)
{
struct pico_tree_node *last_node = INIT_LEAF;
struct pico_tree_node *temp = tree->root;
struct pico_tree_node *insert;
void *LocalKey;
int result = 0;
LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree, key) : NULL);
/* if node already in, bail out */
if(LocalKey) {
return LocalKey;
}
else
{
if(allocator == USE_PICO_PAGE0_ZALLOC)
insert = create_node(tree, key, USE_PICO_PAGE0_ZALLOC);
else
insert = create_node(tree, key, USE_PICO_ZALLOC);
if(!insert)
{
pico_err = PICO_ERR_ENOMEM;
/* to let the user know that it couldn't insert */
return (void *)&LEAF;
}
}
/* search for the place to insert the new node */
while(IS_NOT_LEAF(temp))
{
last_node = temp;
result = tree->compare(insert->keyValue, temp->keyValue);
temp = (result < 0) ? (temp->leftChild) : (temp->rightChild);
}
/* make the needed connections */
insert->parent = last_node;
if(IS_LEAF(last_node))
tree->root = insert;
else{
result = tree->compare(insert->keyValue, last_node->keyValue);
if(result < 0)
last_node->leftChild = insert;
else
last_node->rightChild = insert;
}
/* fix colour issues */
fix_insert_collisions(tree, insert);
return NULL;
}
struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key)
{
struct pico_tree_node *found;
found = tree->root;
while(IS_NOT_LEAF(found))
{
int result;
result = tree->compare(found->keyValue, key);
if(result == 0)
{
return found;
}
else if(result < 0)
found = found->rightChild;
else
found = found->leftChild;
}
return NULL;
}
void *pico_tree_findKey(struct pico_tree *tree, void *key)
{
struct pico_tree_node *found;
found = tree->root;
while(IS_NOT_LEAF(found))
{
int result;
result = tree->compare(found->keyValue, key);
if(result == 0)
return found->keyValue;
else if(result < 0)
found = found->rightChild;
else
found = found->leftChild;
}
return NULL;
}
void *pico_tree_first(struct pico_tree *tree)
{
return pico_tree_firstNode(tree->root)->keyValue;
}
void *pico_tree_last(struct pico_tree *tree)
{
return pico_tree_lastNode(tree->root)->keyValue;
}
static uint8_t pico_tree_delete_node(struct pico_tree *tree, struct pico_tree_node *d, struct pico_tree_node **temp)
{
struct pico_tree_node *min;
struct pico_tree_node *ltemp = d;
uint8_t nodeColor;
min = pico_tree_firstNode(d->rightChild);
nodeColor = min->color;
*temp = min->rightChild;
if(min->parent == ltemp && IS_NOT_LEAF(*temp))
(*temp)->parent = min;
else{
switchNodes(tree, min, min->rightChild);
min->rightChild = ltemp->rightChild;
if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min;
}
switchNodes(tree, ltemp, min);
min->leftChild = ltemp->leftChild;
if(IS_NOT_LEAF(min->leftChild))
min->leftChild->parent = min;
min->color = ltemp->color;
return nodeColor;
}
static uint8_t pico_tree_delete_check_switch(struct pico_tree *tree, struct pico_tree_node *delete, struct pico_tree_node **temp)
{
struct pico_tree_node *ltemp = delete;
uint8_t nodeColor = delete->color;
if(IS_LEAF(delete->leftChild))
{
*temp = ltemp->rightChild;
switchNodes(tree, ltemp, ltemp->rightChild);
}
else
if(IS_LEAF(delete->rightChild))
{
struct pico_tree_node *_ltemp = delete;
*temp = _ltemp->leftChild;
switchNodes(tree, _ltemp, _ltemp->leftChild);
}
else{
nodeColor = pico_tree_delete_node(tree, delete, temp);
}
return nodeColor;
}
/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
* These nodes should be placed in the manager page which is in a different memory region then the nodes
* which are used for the pico stack in general.
* Therefore the following wrapper for pico_tree_delete is created.
* The actual implementation can be found in pico_tree_delete_implementation.
*/
void *pico_tree_delete(struct pico_tree *tree, void *key)
{
return pico_tree_delete_implementation(tree, key, USE_PICO_ZALLOC);
}
static inline void if_nodecolor_black_fix_collisions(struct pico_tree *tree, struct pico_tree_node *temp, uint8_t nodeColor)
{
/* deleted node is black, this will mess up the black path property */
if(nodeColor == BLACK)
fix_delete_collisions(tree, temp);
}
void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator)
{
struct pico_tree_node *temp;
uint8_t nodeColor; /* keeps the color of the node to be deleted */
void *lkey; /* keeps a copy of the key which will be removed */
struct pico_tree_node *delete; /* keeps a copy of the node to be extracted */
if (!key)
return NULL;
delete = pico_tree_findNode(tree, key);
/* this key isn't in the tree, bail out */
if(!delete)
return NULL;
lkey = delete->keyValue;
nodeColor = pico_tree_delete_check_switch(tree, delete, &temp);
if_nodecolor_black_fix_collisions(tree, temp, nodeColor);
if(allocator == USE_PICO_ZALLOC)
PICO_FREE(delete);
#ifdef PICO_SUPPORT_MM
else
pico_mem_page0_free(delete);
#endif
return lkey;
}
int pico_tree_empty(struct pico_tree *tree)
{
return (!tree->root || IS_LEAF(tree->root));
}
/*
* Private functions
*/
static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node)
{
struct pico_tree_node*temp;
temp = node->rightChild;
if(temp == &LEAF) return;
node->rightChild = temp->leftChild;
if(IS_NOT_LEAF(temp->leftChild))
temp->leftChild->parent = node;
temp->parent = node->parent;
if(IS_LEAF(node->parent))
tree->root = temp;
else
if(node == node->parent->leftChild)
node->parent->leftChild = temp;
else
node->parent->rightChild = temp;
temp->leftChild = node;
node->parent = temp;
}
static void rotateToRight(struct pico_tree *tree, struct pico_tree_node *node)
{
struct pico_tree_node*temp;
temp = node->leftChild;
node->leftChild = temp->rightChild;
if(temp == &LEAF) return;
if(IS_NOT_LEAF(temp->rightChild))
temp->rightChild->parent = node;
temp->parent = node->parent;
if(IS_LEAF(node->parent))
tree->root = temp;
else
if(node == node->parent->rightChild)
node->parent->rightChild = temp;
else
node->parent->leftChild = temp;
temp->rightChild = node;
node->parent = temp;
return;
}
static struct pico_tree_node *create_node(struct pico_tree *tree, void*key, uint8_t allocator)
{
struct pico_tree_node *temp = NULL;
IGNORE_PARAMETER(tree);
if(allocator == USE_PICO_ZALLOC)
temp = (struct pico_tree_node *)PICO_ZALLOC(sizeof(struct pico_tree_node));
#ifdef PICO_SUPPORT_MM
else
temp = (struct pico_tree_node *)pico_mem_page0_zalloc(sizeof(struct pico_tree_node));
#endif
if(!temp)
return NULL;
temp->keyValue = key;
temp->parent = &LEAF;
temp->leftChild = &LEAF;
temp->rightChild = &LEAF;
/* by default every new node is red */
temp->color = RED;
return temp;
}
/*
* This function fixes the possible collisions in the tree.
* Eg. if a node is red his children must be black !
*/
static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node)
{
struct pico_tree_node*temp;
while(node->parent->color == RED && IS_NOT_LEAF(GRANPA(node)))
{
if(AM_I_RIGHT_CHILD(node->parent))
{
temp = GRANPA(node)->leftChild;
if(temp->color == RED) {
node->parent->color = BLACK;
temp->color = BLACK;
GRANPA(node)->color = RED;
node = GRANPA(node);
}
else if(temp->color == BLACK) {
if(node == node->parent->leftChild) {
node = node->parent;
rotateToRight(tree, node);
}
node->parent->color = BLACK;
GRANPA(node)->color = RED;
rotateToLeft(tree, GRANPA(node));
}
}
else if(AM_I_LEFT_CHILD(node->parent))
{
temp = GRANPA(node)->rightChild;
if(temp->color == RED) {
node->parent->color = BLACK;
temp->color = BLACK;
GRANPA(node)->color = RED;
node = GRANPA(node);
}
else if(temp->color == BLACK) {
if(AM_I_RIGHT_CHILD(node)) {
node = node->parent;
rotateToLeft(tree, node);
}
node->parent->color = BLACK;
GRANPA(node)->color = RED;
rotateToRight(tree, GRANPA(node));
}
}
}
/* make sure that the root of the tree stays black */
tree->root->color = BLACK;
}
static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB)
{
if(IS_LEAF(nodeA->parent))
tree->root = nodeB;
else
if(IS_NOT_LEAF(nodeA))
{
if(AM_I_LEFT_CHILD(nodeA))
nodeA->parent->leftChild = nodeB;
else
nodeA->parent->rightChild = nodeB;
}
if(IS_NOT_LEAF(nodeB)) nodeB->parent = nodeA->parent;
}
/*
* This function fixes the possible collisions in the tree.
* Eg. if a node is red his children must be black !
* In this case the function fixes the constant black path property.
*/
static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node)
{
struct pico_tree_node*temp;
while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node))
{
if(AM_I_LEFT_CHILD(node)) {
temp = node->parent->rightChild;
if(temp->color == RED)
{
temp->color = BLACK;
node->parent->color = RED;
rotateToLeft(tree, node->parent);
temp = node->parent->rightChild;
}
if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK)
{
temp->color = RED;
node = node->parent;
}
else
{
if(temp->rightChild->color == BLACK)
{
temp->leftChild->color = BLACK;
temp->color = RED;
rotateToRight(tree, temp);
temp = temp->parent->rightChild;
}
temp->color = node->parent->color;
node->parent->color = BLACK;
temp->rightChild->color = BLACK;
rotateToLeft(tree, node->parent);
node = tree->root;
}
}
else{
temp = node->parent->leftChild;
if(temp->color == RED)
{
temp->color = BLACK;
node->parent->color = RED;
rotateToRight(tree, node->parent);
temp = node->parent->leftChild;
}
if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK)
{
temp->color = RED;
node = node->parent;
}
else{
if(temp->leftChild->color == BLACK)
{
temp->rightChild->color = BLACK;
temp->color = RED;
rotateToLeft(tree, temp);
temp = temp->parent->leftChild;
}
temp->color = node->parent->color;
node->parent->color = BLACK;
temp->leftChild->color = BLACK;
rotateToRight(tree, node->parent);
node = tree->root;
}
}
}
node->color = BLACK;
}