/********************************************************************* 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); }