aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/x300/lib/link_state_route_proto.c
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2014-10-07 09:39:25 +0200
committerMartin Braun <martin.braun@ettus.com>2014-10-07 09:39:25 +0200
commit5bd58bc309e959537e3e820abfa39ee629b140a5 (patch)
tree81e3a611134e02d9118f0aa846b7146234849fe8 /firmware/x300/lib/link_state_route_proto.c
parent9f6a11173aef5e661100268bd746963d713adb91 (diff)
downloaduhd-5bd58bc309e959537e3e820abfa39ee629b140a5.tar.gz
uhd-5bd58bc309e959537e3e820abfa39ee629b140a5.tar.bz2
uhd-5bd58bc309e959537e3e820abfa39ee629b140a5.zip
Reorganized firmware/ subdirectory (x300->usrp3, zpu->usrp2)
Diffstat (limited to 'firmware/x300/lib/link_state_route_proto.c')
-rw-r--r--firmware/x300/lib/link_state_route_proto.c441
1 files changed, 0 insertions, 441 deletions
diff --git a/firmware/x300/lib/link_state_route_proto.c b/firmware/x300/lib/link_state_route_proto.c
deleted file mode 100644
index 30cfd73cb..000000000
--- a/firmware/x300/lib/link_state_route_proto.c
+++ /dev/null
@@ -1,441 +0,0 @@
-
-// Copyright 2013 Ettus Research LLC
-
-#include <link_state_route_proto.h>
-#include <u3_net_stack.h>
-#include <ethernet.h>
-#include <string.h>
-#include <printf.h>
-#include <print_addrs.h>
-
-#define lengthof(a) (sizeof(a)/sizeof(*(a)))
-
-/***********************************************************************
- * global constants
- **********************************************************************/
-#define LS_PROTO_VERSION 6
-
-//shift the proto version into the ID so only matching fw responds
-#define LS_ID_DISCOVER (0 | (8 << LS_PROTO_VERSION))
-#define LS_ID_INFORM (1 | (8 << LS_PROTO_VERSION))
-
-#define LS_PAYLOAD_MTU 1024
-#define LS_NUM_NBOR_ENTRIES 16
-#define LS_NUM_NODE_ENTRIES 64
-#define LS_NUM_MAP_ENTRIES 128
-
-#define NETHS 4 //max eths supported in this file
-
-/***********************************************************************
- * wire format for table communication
- **********************************************************************/
-typedef struct
-{
- uint32_t num_nbors; //number of entries in neighbors list
- uint32_t num_ports; //first few neighbors are local ports
- struct ip_addr node;
- struct ip_addr nbors[];
-} ls_data_t;
-
-static inline size_t sizeof_ls_data(const ls_data_t *ls_data)
-{
- return 0
- + sizeof(uint32_t)/*num neighbors*/
- + sizeof(uint32_t)/*num ports*/
- + sizeof(struct ip_addr)/*source node*/
- + sizeof(struct ip_addr)*ls_data->num_nbors;
-}
-
-/***********************************************************************
- * sequence and tick counter monitor
- **********************************************************************/
-static uint16_t ticker = 0;
-
-void link_state_route_proto_tick(void)
-{
- ticker++;
-}
-
-static inline bool is_tick_expired(const uint16_t tick)
-{
- const uint16_t delta = ticker - tick;
- return delta > 2; //have not talked in a while, you are deaf to me
-}
-
-static uint16_t current_seq = 0;
-
-static inline bool is_seq_newer(const uint16_t seq, const uint16_t entry_seq)
-{
- if (seq == entry_seq) return false; //not newer if equal
- const uint16_t delta = seq - entry_seq;
- return (delta & (1 << 15)) == 0; //newer when subtraction did not overflow
-}
-
-/***********************************************************************
- * node entry api
- **********************************************************************/
-typedef struct
-{
- uint16_t seq;
- uint16_t tick;
- uint8_t ethno;
- struct ip_addr ip_addr;
-} ls_node_entry_t;
-
-static bool ls_node_entry_valid(const ls_node_entry_t *entry)
-{
- return entry->ip_addr.addr != 0 && !is_tick_expired(entry->tick);
-}
-
-static void ls_node_entry_update(ls_node_entry_t *entry, const int8_t ethno, const uint16_t seq, const struct ip_addr *ip_addr)
-{
- entry->seq = seq;
- entry->tick = ticker;
- entry->ethno = ethno;
- entry->ip_addr.addr = ip_addr->addr;
-}
-
-static bool ls_node_entries_update(
- ls_node_entry_t *entries, const size_t num_entries,
- const int8_t ethno, const uint16_t seq, const struct ip_addr *ip_addr
-)
-{
- for (size_t i = 0; i < num_entries; i++)
- {
- if (!ls_node_entry_valid(&entries[i]))
- {
- ls_node_entry_update(entries+i, ethno, seq, ip_addr);
- return true;
- }
-
- if (entries[i].ip_addr.addr == ip_addr->addr && entries[i].ethno == ethno)
- {
- if (is_seq_newer(seq, entries[i].seq))
- {
- ls_node_entry_update(entries+i, ethno, seq, ip_addr);
- return true;
- }
- return false;
- }
- }
-
- //no space, shift the table down and take entry 0
- memmove(entries+1, entries, (num_entries-1)*sizeof(ls_node_entry_t));
- ls_node_entry_update(entries+0, ethno, seq, ip_addr);
- return true;
-}
-
-/***********************************************************************
- * storage for nodes in the network
- **********************************************************************/
-static ls_node_entry_t ls_nbors[LS_NUM_NBOR_ENTRIES];
-static ls_node_entry_t ls_nodes[LS_NUM_NODE_ENTRIES];
-
-/***********************************************************************
- * node table
- **********************************************************************/
-static ls_node_mapping_t ls_node_maps[LS_NUM_MAP_ENTRIES];
-
-const ls_node_mapping_t *link_state_route_get_node_mapping(size_t *length)
-{
- *length = lengthof(ls_node_maps);
- return ls_node_maps;
-}
-
-static void add_node_mapping(const struct ip_addr *node, const struct ip_addr *nbor)
-{
- //printf("add_node_mapping: %s -> %s\n", ip_addr_to_str(node), ip_addr_to_str(nbor));
-
- //write into the first available slot
- for (size_t i = 0; i < lengthof(ls_node_maps); i++)
- {
- if (ls_node_maps[i].node.addr == 0)
- {
- ls_node_maps[i].node.addr = node->addr;
- ls_node_maps[i].nbor.addr = nbor->addr;
- return;
- }
- }
-
- //otherwise, shift down the table and take slot0
- memmove(ls_node_maps+1, ls_node_maps, sizeof(ls_node_maps) - sizeof(ls_node_mapping_t));
- ls_node_maps[0].node.addr = node->addr;
- ls_node_maps[0].nbor.addr = nbor->addr;
-}
-
-static void remove_node_matches(const struct ip_addr *node)
-{
- //printf("remove_node_matches: %s\n", ip_addr_to_str(node));
-
- for (size_t j = 0; j < lengthof(ls_node_maps); j++)
- {
- //if the address is a match, clear the entry
- if (ls_node_maps[j].node.addr == node->addr)
- {
- ls_node_maps[j].node.addr = 0;
- ls_node_maps[j].nbor.addr = 0;
- }
- }
-}
-
-static void update_node_mappings(const ls_data_t *ls_data)
-{
- //printf("update_node_mappings: %s\n", ip_addr_to_str(&ls_data->node));
-
- //remove any expired entries
- for (size_t i = 0; i < lengthof(ls_nodes); i++)
- {
- if (ls_nodes[i].ip_addr.addr != 0 && is_tick_expired(ls_nodes[i].tick))
- {
- remove_node_matches(&ls_nodes[i].ip_addr);
- }
- }
-
- //remove any matches for the current node
- remove_node_matches(&ls_data->node);
-
- //is this a local packet?
- bool is_local = false;
- for (size_t e = 0; e < ethernet_ninterfaces(); e++)
- {
- if (ls_data->node.addr == u3_net_stack_get_ip_addr(e)->addr) is_local = true;
- }
-
- //load entries from ls data into array
- for (size_t i = 0; i < ls_data->num_nbors; i++)
- {
- if (is_local && i < ls_data->num_ports) continue; //ignore local ports
- add_node_mapping(&ls_data->node, &ls_data->nbors[i]);
- }
-}
-
-/***********************************************************************
- * forward link state data onto all neighbors on the given port
- **********************************************************************/
-static void send_link_state_data_to_all_neighbors(
- const uint8_t ethno, const uint16_t seq, const ls_data_t *ls_data
-){
- //exit and dont forward if the information is stale
- if (!ls_node_entries_update(ls_nodes, lengthof(ls_nodes), ethno, seq, &ls_data->node)) return;
-
- //update the mappings with new info
- update_node_mappings(ls_data);
-
- //forward to all neighbors
- for (size_t i = 0; i < lengthof(ls_nbors); i++)
- {
- if (ls_nbors[i].ip_addr.addr == ls_data->node.addr) continue; //dont forward to sender
- if (ls_node_entry_valid(&ls_nbors[i]))
- {
- if (ethernet_get_link_up(ls_nbors[i].ethno)) u3_net_stack_send_icmp_pkt(
- ls_nbors[i].ethno, ICMP_IRQ, 0,
- LS_ID_INFORM, seq,
- &(ls_nbors[i].ip_addr), ls_data, sizeof_ls_data(ls_data)
- );
- }
- }
-
- //a change may have occured, update the cache
- link_state_route_proto_update_cycle_cache(ethno);
-}
-
-/***********************************************************************
- * handler for information reply
- **********************************************************************/
-static void handle_icmp_ir(
- const uint8_t ethno,
- const struct ip_addr *src, const struct ip_addr *dst,
- const uint16_t id, const uint16_t seq,
- const void *buff, const size_t num_bytes
-){
- switch (id)
- {
- //received a reply directly from the neighbor, add to neighbor list
- case LS_ID_DISCOVER:
- //printf("GOT LS_ID_DISCOVER REPLY - ID 0x%x - IP%u: %s\n", id, (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno)));
- if (ls_node_entries_update(ls_nbors, lengthof(ls_nbors), ethno, seq, src)) link_state_route_proto_flood(ethno);
- break;
- }
-}
-
-/***********************************************************************
- * handler for information request
- **********************************************************************/
-static void handle_icmp_irq(
- const uint8_t ethno,
- const struct ip_addr *src, const struct ip_addr *dst,
- const uint16_t id, const uint16_t seq,
- const void *buff, const size_t num_bytes
-){
- switch (id)
- {
- //replies to discovery packets
- case LS_ID_DISCOVER:
- //printf("GOT LS_ID_DISCOVER REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno)));
- //printf("SEND LS_ID_DISCOVER REPLY - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno)));
- u3_net_stack_send_icmp_pkt(ethno, ICMP_IR, 0, id, seq, src, buff, num_bytes);
- break;
-
- //handle and forward information
- case LS_ID_INFORM:
- //printf("GOT LS_ID_INFORM REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno)));
- send_link_state_data_to_all_neighbors(ethno, seq, (const ls_data_t *)buff);
- break;
- };
-}
-
-/***********************************************************************
- * initiate a periodic update to the table
- **********************************************************************/
-void link_state_route_proto_update(const uint8_t ethno)
-{
- //send a discovery packet
- //printf("SEND LS_ID_DISCOVER REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno)));
- u3_net_stack_send_icmp_pkt(
- ethno, ICMP_IRQ, 0,
- LS_ID_DISCOVER, current_seq++,
- u3_net_stack_get_bcast(ethno), NULL, 0
- );
-}
-
-void link_state_route_proto_flood(const uint8_t ethno)
-{
- for (size_t e = 0; e < ethernet_ninterfaces(); e++)
- {
- //fill link state data buffer
- uint8_t buff[LS_PAYLOAD_MTU] = {};
- ls_data_t *ls_data = (ls_data_t *)buff;
- ls_data->node.addr = u3_net_stack_get_ip_addr(e)->addr;
- ls_data->num_nbors = 0;
- ls_data->num_ports = 0;
-
- //first the local port links
- for (size_t ej = 0; ej < ethernet_ninterfaces(); ej++)
- {
- if (e == ej) continue; //dont include our own port
- ls_data->nbors[ls_data->num_nbors++].addr = u3_net_stack_get_ip_addr(ej)->addr;
- ls_data->num_ports++;
- }
-
- //now list the neighbors
- for (size_t i = 0; i < lengthof(ls_nbors); i++)
- {
- if ((sizeof_ls_data(ls_data) + 4) >= LS_PAYLOAD_MTU) break;
- if (ls_node_entry_valid(&ls_nbors[i]) && ls_nbors[i].ethno == e)
- {
- ls_data->nbors[ls_data->num_nbors++].addr = ls_nbors[i].ip_addr.addr;
- }
- }
-
- //send this data to all neighbors
- send_link_state_data_to_all_neighbors(ethno, current_seq++, ls_data);
- }
-}
-
-/***********************************************************************
- * cycle detection logic
- **********************************************************************/
-static void follow_links(const size_t current, struct ip_addr *nodes, bool *visited, const size_t num_nodes)
-{
- if (visited[current]) return; //end the recursion
- visited[current] = true;
-
- //follow all links where current node is the source
- for (size_t i = 0; i < lengthof(ls_node_maps); i++)
- {
- if (ls_node_maps[i].node.addr != nodes[current].addr) continue;
-
- //find the index of the neighbor in the node list to recurse
- for (size_t j = 0; j < num_nodes; j++)
- {
- if (nodes[j].addr != ls_node_maps[i].nbor.addr) continue;
- follow_links(j, nodes, visited, num_nodes);
- }
- }
-}
-
-bool link_state_route_proto_causes_cycle(const struct ip_addr *src, const struct ip_addr *dst)
-{
- //printf("is there a cycle? %s -> %s: \n", ip_addr_to_str(src), ip_addr_to_str(dst));
-
- //make a set of all nodes
- size_t num_nodes = 0;
- struct ip_addr nodes[LS_NUM_MAP_ENTRIES];
- for (size_t i = 0; i < lengthof(ls_node_maps); i++)
- {
- if (ls_node_maps[i].node.addr == 0 || ls_node_maps[i].nbor.addr == 0) continue;
- //printf(" Link %s -> %s\n", ip_addr_to_str(&ls_node_maps[i].node), ip_addr_to_str(&ls_node_maps[i].nbor));
- const struct ip_addr *node = &ls_node_maps[i].node;
-
- //check if we have an entry
- for (size_t j = 0; j < num_nodes; j++)
- {
- if (nodes[j].addr == node->addr) goto skip_add;
- }
-
- //otherwise, we add the node
- nodes[num_nodes++].addr = node->addr;
- //printf(" Add to node set: %s\n", ip_addr_to_str(node));
- skip_add: continue;
- }
-
- //and stateful tracking info for each node
- bool visited[LS_NUM_MAP_ENTRIES];
- for (size_t i = 0; i < num_nodes; i++) visited[i] = false;
-
- //find our src node in the set and follow
- for (size_t i = 0; i < num_nodes; i++)
- {
- if (nodes[i].addr == src->addr) follow_links(i, nodes, visited, num_nodes);
- }
-
- //did we visit the destination? if so, there is a cycle
- for (size_t i = 0; i < num_nodes; i++)
- {
- if (nodes[i].addr == dst->addr && visited[i])
- {
- //printf("CAUSES CYCLE!\n");
- return true;
- }
- }
-
- //printf("no cycle found.\n");
- return false;
-}
-
-static bool ls_causes_cycle[NETHS][NETHS];
-
-void link_state_route_proto_update_cycle_cache(const uint8_t eth_src)
-{
- for (size_t eth_dst = 0; eth_dst < ethernet_ninterfaces(); eth_dst++)
- {
- if (eth_src == eth_dst) continue;
- ls_causes_cycle[eth_src][eth_dst] = link_state_route_proto_causes_cycle(
- u3_net_stack_get_ip_addr(eth_src),
- u3_net_stack_get_ip_addr(eth_dst)
- );
- }
-}
-
-bool link_state_route_proto_causes_cycle_cached(const uint8_t eth_src, const uint8_t eth_dst)
-{
- return ls_causes_cycle[eth_src][eth_dst];
-}
-
-/***********************************************************************
- * init and registration code
- **********************************************************************/
-void link_state_route_proto_init(void)
-{
- u3_net_stack_register_icmp_handler(ICMP_IRQ, 0, &handle_icmp_irq);
- u3_net_stack_register_icmp_handler(ICMP_IR, 0, &handle_icmp_ir);
-
- //default to causing a cycle, let the algorithm set this correctly
- for (size_t i = 0; i < NETHS; i++)
- {
- for (size_t j = 0; j < NETHS; j++)
- {
- ls_causes_cycle[i][j] = true;
- }
- }
-}