diff --git a/src/Makefile b/src/Makefile index 87a5794dc4524c22dce6e7805e8f1f3b5395e33e..5023b73e0cfdd227eed05c6e766d6b71b397e94c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,6 +11,8 @@ OBJS = \ wifi_opclass.o \ allsta.o \ allmac.o \ + backhaul_topology.o \ + backhaul_topology_dbg.o \ cntlr_ubus.o \ cntlr_ubus_dbg.o \ cntlr.o \ diff --git a/src/backhaul_topology.c b/src/backhaul_topology.c new file mode 100644 index 0000000000000000000000000000000000000000..f5a5b6284d88963008c4f3391fab5862da326f6f --- /dev/null +++ b/src/backhaul_topology.c @@ -0,0 +1,441 @@ + +#include "backhaul_topology.h" +#include "backhaul_topology_dbg.h" +#include "utils/debug.h" +#include "utils/utils.h" + +#include <bufutil.h> +#include <easy/utils.h> +#include <1905_tlvs.h> + +#include <libubox/list.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/** Used to store all discovered easy mesh devices and model tree topology. */ +struct bh_topology_data { + struct list_head dev_list; /* list of struct bh_topology_dev */ + uint32_t bh_topo_devs_number; + bool bh_topology_valid; +}; + +static struct bh_topology_data priv_bh_topo_data; + + +static bool is_wifi(uint16_t media_type) +{ + return (media_type >> 8) == 1; +} + +void init_bh_topology(void) +{ + INIT_LIST_HEAD(&priv_bh_topo_data.dev_list); + priv_bh_topo_data.bh_topo_devs_number = 0; + priv_bh_topo_data.bh_topology_valid = false; +} + +void free_bh_topology(void) +{ + remove_all_bh_topology_devices(); +} + +bool is_bh_topology_valid(void) +{ + return priv_bh_topo_data.bh_topology_valid; +} + +uint32_t bh_topology_devs_number(void) +{ + return priv_bh_topo_data.bh_topo_devs_number; +} + +struct bh_topology_dev *find_bh_topology_device(const uint8_t *al_macaddr) +{ + struct bh_topology_dev *bh_topo_dev = NULL; + + list_for_each_entry(bh_topo_dev, &priv_bh_topo_data.dev_list, list_element) { + if (hwaddr_equal(bh_topo_dev->al_macaddr, al_macaddr)) + return bh_topo_dev; + } + + return NULL; +} + +struct bh_topology_dev *add_bh_topology_device(const uint8_t *al_macaddr) +{ + struct bh_topology_dev *bh_topo_dev = + calloc(1, sizeof(struct bh_topology_dev)); + + if (!bh_topo_dev) + return NULL; + + memcpy(bh_topo_dev->al_macaddr, al_macaddr, 6); + bh_topo_dev->bh_info.level_in_tree = UNKNOWN_TREE_LEVEL; + + list_add(&bh_topo_dev->list_element, &priv_bh_topo_data.dev_list); + + ++priv_bh_topo_data.bh_topo_devs_number; + priv_bh_topo_data.bh_topology_valid = false; + + return bh_topo_dev; +} + +void remove_bh_topology_device(const uint8_t *al_macaddr) +{ + struct bh_topology_dev *bh_topo_dev = NULL, *bh_topo_dev_tmp; + + list_for_each_entry_safe(bh_topo_dev, bh_topo_dev_tmp, + &priv_bh_topo_data.dev_list, list_element) { + + if (hwaddr_equal(bh_topo_dev->al_macaddr, al_macaddr)) { + list_del(&bh_topo_dev->list_element); + free(bh_topo_dev); + + --priv_bh_topo_data.bh_topo_devs_number; + priv_bh_topo_data.bh_topology_valid = false; + } + } +} + +void remove_all_bh_topology_devices(void) +{ + /* cppcheck-suppress uninitvar */ + list_flush(&priv_bh_topo_data.dev_list, struct bh_topology_dev, list_element); + + priv_bh_topo_data.bh_topo_devs_number = 0; + priv_bh_topo_data.bh_topology_valid = false; +} + +bool has_interface_info_changed(const struct tlv_device_info *tlv_dev_info, + const struct bh_topology_dev *bh_topo_dev) +{ + const uint8_t *tlv_iface_p = (uint8_t *)tlv_dev_info->interface; + size_t tlv_iface_offset; + int i; + + if (bh_topo_dev->number_of_interfaces != tlv_dev_info->num_interface) + return true; + + tlv_iface_offset = 0; + for (i = 0; i < bh_topo_dev->number_of_interfaces; ++i) { + const struct local_interface *interface = + (struct local_interface *)(tlv_iface_p + tlv_iface_offset); + + if (!hwaddr_equal(bh_topo_dev->ifaces[i].macaddr, interface->macaddr)) + return true; + + tlv_iface_offset += sizeof(struct local_interface) + + interface->sizeof_mediainfo; + } + + return false; +} + +void copy_interface_info_from_tlv(const struct tlv_device_info *tlv_dev_info, + struct bh_topology_dev *bh_topo_dev) +{ + const uint8_t *tlv_iface_p = (uint8_t *)tlv_dev_info->interface; + size_t tlv_iface_offset; + int i; + + priv_bh_topo_data.bh_topology_valid = false; + + /* Clear device old iface data, including neighbors info */ + memset(bh_topo_dev->ifaces, 0, sizeof(bh_topo_dev->ifaces)); + + bh_topo_dev->num_of_ifaces_with_neighbors = 0; + bh_topo_dev->number_of_interfaces = tlv_dev_info->num_interface; + + if (tlv_dev_info->num_interface > IFACE_MAX_NUM) { + err("%s: Currently max %d interfaces supported!\n", __func__, IFACE_MAX_NUM); + bh_topo_dev->number_of_interfaces = IFACE_MAX_NUM; + } + + tlv_iface_offset = 0; + for (i = 0; i < bh_topo_dev->number_of_interfaces; ++i) { + const struct local_interface *interface = + (struct local_interface *)(tlv_iface_p + tlv_iface_offset); + + memcpy(bh_topo_dev->ifaces[i].macaddr, interface->macaddr, 6); + bh_topo_dev->ifaces[i].media_type = + BUF_GET_BE16(interface->mediatype); + + tlv_iface_offset += sizeof(struct local_interface) + + interface->sizeof_mediainfo; + } +} + +static bool are_neighbor_lists_the_same(const struct local_iface *iface, + const struct tlv_1905neighbor *tlv_1905neighbor, + uint16_t tlv_length) +{ + const uint8_t tlv_neighbors_num = + (tlv_length - sizeof(tlv_1905neighbor->local_macaddr)) / + sizeof(struct i1905_neighbor); + uint8_t i, j; + + if (iface->number_of_neighbors != tlv_neighbors_num) + return false; + + for (i = 0; i < tlv_neighbors_num; ++i) { + bool found = false; + + for (j = 0; j < iface->number_of_neighbors; ++j) { + if (hwaddr_equal(tlv_1905neighbor->nbr[i].aladdr, + &iface->neighbors_al_macs[j][0])) { + found = true; + break; + } + } + + if (!found) + return false; + } + + return true; +} + +bool has_neighbor_info_changed(const struct tlv_1905neighbor **neighbor_tlvs, + const uint16_t *tlv_lengths, + uint8_t tlv_number, + const struct bh_topology_dev *bh_topo_dev) +{ + uint8_t i; + + /* Every TLV provides neighbors for single local interface. */ + if (bh_topo_dev->num_of_ifaces_with_neighbors != tlv_number) + return true; + + for (i = 0; i < tlv_number; ++i) { + const struct tlv_1905neighbor *neighbor_tlv = neighbor_tlvs[i]; + uint8_t j; + bool found = false; + + for (j = 0; j < bh_topo_dev->number_of_interfaces; ++j) { + bool same_mac = hwaddr_equal(bh_topo_dev->ifaces[j].macaddr, + neighbor_tlv->local_macaddr); + + if (same_mac && are_neighbor_lists_the_same( + &bh_topo_dev->ifaces[j], + neighbor_tlv, tlv_lengths[i])) { + + found = true; + break; + } + } + + if (!found) + return true; + } + + return false; + +} + +void copy_neighbor_info_from_tlvs(const struct tlv_1905neighbor **neighbor_tlvs, + const uint16_t *tlv_lengths, + uint8_t tlv_number, + struct bh_topology_dev *bh_topo_dev) +{ + uint8_t i; + + priv_bh_topo_data.bh_topology_valid = false; + bh_topo_dev->num_of_ifaces_with_neighbors = tlv_number; + + /* Clear device old/previous neighbors info */ + for (i = 0; i < bh_topo_dev->number_of_interfaces; ++i) { + if (bh_topo_dev->ifaces[i].number_of_neighbors != 0) { + bh_topo_dev->ifaces[i].number_of_neighbors = 0; + memset(bh_topo_dev->ifaces[i].neighbors_al_macs, 0, + sizeof(bh_topo_dev->ifaces[i].neighbors_al_macs)); + } + + } + + for (i = 0; i < tlv_number; ++i) { + const struct tlv_1905neighbor *neighbor_tlv = neighbor_tlvs[i]; + const uint8_t neighbors_num = + (tlv_lengths[i] - sizeof(neighbor_tlv->local_macaddr)) / + sizeof(struct i1905_neighbor); + struct local_iface *local_iface = NULL; + uint8_t j; + + for (j = 0; j < bh_topo_dev->number_of_interfaces; ++j) { + /* + * Because different local physical interfaces can use the same MAC + * address, find a one with matching MAC and no neighbors added yet. + */ + if (hwaddr_equal(bh_topo_dev->ifaces[j].macaddr, + neighbor_tlv->local_macaddr) && + bh_topo_dev->ifaces[j].number_of_neighbors == 0) { + + local_iface = &bh_topo_dev->ifaces[j]; + break; + } + } + + if (local_iface) { + uint8_t k; + + dbg("%s: adding neighbors for local_iface[%u].macaddr: " MACFMT "\n", + __func__, j, MAC2STR(local_iface->macaddr)); + + local_iface->number_of_neighbors = neighbors_num; + + for (k = 0; k < neighbors_num && k < NEIGHBORS_MAX_NUM; ++k) { + dbg("%s: neighbor[%u].aladdr: " MACFMT "\n", + __func__, k, MAC2STR(neighbor_tlv->nbr[k].aladdr)); + + memcpy(&local_iface->neighbors_al_macs[k][0], + neighbor_tlv->nbr[k].aladdr, 6); + } + + } else { + err("%s: no iface found, adding neighbors failed for local_macaddr: " MACFMT "\n", + __func__, MAC2STR(neighbor_tlv->local_macaddr)); + } + } + +} + + +static void clear_backhaul_tree_relations(struct list_head *bh_topo_dev_list) +{ + struct bh_topology_dev *bh_topo_dev = NULL; + + list_for_each_entry(bh_topo_dev, bh_topo_dev_list, list_element) { + bh_topo_dev->bh_info = + (struct backhaul_info){ UNKNOWN_TREE_LEVEL, 0, NULL, NULL, NULL }; + } +} + +static const struct local_iface * +find_neighbor_local_iface(const struct bh_topology_dev *next_level_neighbor, + const uint8_t *parent_al_macaddr) +{ + int i, j; + + for (i = 0; i < next_level_neighbor->number_of_interfaces; ++i) { + const struct local_iface *iface = &next_level_neighbor->ifaces[i]; + + for (j = 0; j < iface->number_of_neighbors; ++j) { + if (hwaddr_equal(&iface->neighbors_al_macs[j][0], parent_al_macaddr)) + return iface; + } + } + + return NULL; +} + +static bool set_device_child_neighbors(const struct bh_topology_dev *parent_device, + struct list_head *bh_topo_dev_list) +{ + int i, j; + const int8_t child_level = parent_device->bh_info.level_in_tree + 1; + bool has_child_neighbor = false; + + for (i = 0; i < parent_device->number_of_interfaces; ++i) { + const struct local_iface *parent_iface = &parent_device->ifaces[i]; + + for (j = 0; j < parent_iface->number_of_neighbors; ++j) { + + struct bh_topology_dev *child_neighbor_dev = + find_bh_topology_device(&parent_iface->neighbors_al_macs[j][0]); + + if (child_neighbor_dev && + child_neighbor_dev->bh_info.level_in_tree == UNKNOWN_TREE_LEVEL) { + const struct local_iface *child_iface; + + child_neighbor_dev->bh_info.parent_in_tree = parent_device; + child_neighbor_dev->bh_info.parent_iface = parent_iface; + child_neighbor_dev->bh_info.level_in_tree = child_level; + child_neighbor_dev->bh_info.wifi_hops_from_root = + parent_device->bh_info.wifi_hops_from_root; + if (is_wifi(parent_iface->media_type)) + child_neighbor_dev->bh_info.wifi_hops_from_root++; + + child_iface = find_neighbor_local_iface(child_neighbor_dev, + parent_device->al_macaddr); + + if (!child_iface) { + warn("BH:%s: child doens't know about parent neighbor.\n", __func__); + } + + child_neighbor_dev->bh_info.own_iface = child_iface; + + if (child_iface && (child_iface->media_type != parent_iface->media_type)) { + warn("BH:%s: child and parent iface media type differs, parent: %s, child: %s\n", + i1905_media_type_to_str(parent_iface->media_type), + i1905_media_type_to_str(child_iface->media_type), + __func__); + } + + dbg("BH: %s New parent-child link set:\n", __func__); + dbg_dump_bh_topo_link(child_neighbor_dev, INDENT_LVL_0); + + has_child_neighbor = true; + } + } + } + + return has_child_neighbor; +} + +static bool set_next_level_neighbors(int8_t current_level, + struct list_head *bh_topo_dev_list) +{ + struct bh_topology_dev *bh_topo_dev = NULL; + bool new_level_discovered = false; + + list_for_each_entry(bh_topo_dev, bh_topo_dev_list, list_element) { + if (bh_topo_dev->bh_info.level_in_tree == current_level) { + bool has_next_level = + set_device_child_neighbors(bh_topo_dev, bh_topo_dev_list); + + new_level_discovered = new_level_discovered || has_next_level; + } + } + + dbg("BH: %s: current_level: %d, new_level_discovered: %d\n", + __func__, current_level, new_level_discovered); + + return new_level_discovered; +} + +void build_bh_topology_tree(const uint8_t *ctrl_al_macaddr) +{ + struct bh_topology_dev *ctrl_dev = NULL; + bool new_level_discovered = false; + int8_t current_level; + + dbg("BH: %s\n", __func__); + + clear_backhaul_tree_relations(&priv_bh_topo_data.dev_list); + + /* Mark controller as root node in BH tree (level_in_tree = 0) */ + ctrl_dev = find_bh_topology_device(ctrl_al_macaddr); + if (!ctrl_dev) { + err("%s: cannot find controller (root ndode) and build tree.\n", + __func__); + return; + } + ctrl_dev->bh_info.level_in_tree = 0; + ctrl_dev->bh_info.wifi_hops_from_root = 0; + + current_level = ctrl_dev->bh_info.level_in_tree; + + do { + new_level_discovered = + set_next_level_neighbors(current_level, &priv_bh_topo_data.dev_list); + ++current_level; + } while (new_level_discovered); + + priv_bh_topo_data.bh_topology_valid = true; + + info("%s: Backhaul topology tree built. BH topo devs num: %d, cntrl: " MACFMT "\n", + __func__, priv_bh_topo_data.bh_topo_devs_number, MAC2STR(ctrl_al_macaddr)); + + dbg_dump_bh_topo_devs(&priv_bh_topo_data.dev_list, INDENT_LVL_0); +} diff --git a/src/backhaul_topology.h b/src/backhaul_topology.h new file mode 100644 index 0000000000000000000000000000000000000000..fbad280f855fc2f8cca6f24ee461ce0e2b6fcc46 --- /dev/null +++ b/src/backhaul_topology.h @@ -0,0 +1,122 @@ +#ifndef BACKHAUL_TOPOLOGY_H +#define BACKHAUL_TOPOLOGY_H + +#include <libubox/list.h> +#include <stdint.h> + +struct tlv_device_info; +struct tlv_1905neighbor; +struct bh_topology_dev; + +#define IFACE_MAX_NUM 16 +#define NEIGHBORS_MAX_NUM 16 + +struct local_iface { + uint8_t macaddr[6]; + uint16_t media_type; + uint8_t number_of_neighbors; + uint8_t neighbors_al_macs[NEIGHBORS_MAX_NUM][6]; +}; + + /* When populated BH link defined as in TR-181: + * BHDevALMac/BHLocalMac() <-LinkType -< LocalMac + * can be read. Above corresponds to: + * parent_in_tree/parent_iface <--own_iface->media_type-< own_iface + */ +#define UNKNOWN_TREE_LEVEL -1 +struct backhaul_info { + int8_t level_in_tree; /** total number of BH links from root node */ + uint8_t wifi_hops_from_root; /** number of Wi-Fi BH links from root node */ + const struct bh_topology_dev *parent_in_tree; + const struct local_iface *parent_iface; + const struct local_iface *own_iface; +}; + +/** Represents single device and its relation to neighbors in BH tree. */ +struct bh_topology_dev { + struct list_head list_element; + + uint8_t al_macaddr[6]; + uint8_t number_of_interfaces; + uint8_t num_of_ifaces_with_neighbors; + struct local_iface ifaces[IFACE_MAX_NUM]; + struct backhaul_info bh_info; +}; + +/** Initializes internal structures. + * Has to be called once before any other functions are called. + */ +void init_bh_topology(void); + +/** Releases all data and internal structures. */ +void free_bh_topology(void); + +/** Returns tree if backhaul topology tree was already build and is still valid. + * + * It's undefined behaviour to read interface, neighbor and backhaul info + * of any bh_topology_dev when this function returns false. + */ +bool is_bh_topology_valid(void); + +/** Number of devices in backhaul topology tree. */ +uint32_t bh_topology_devs_number(void); + +/** Returns backhaul topology device if exists in the model, NULL otherwise. */ +struct bh_topology_dev *find_bh_topology_device(const uint8_t *al_macaddr); + +/** Adds backhaul topology device to the model, invalidates backhaul tree. */ +struct bh_topology_dev *add_bh_topology_device(const uint8_t *al_macaddr); + +/** Removes backhaul topology device from the model, invalidates backhaul tree. */ +void remove_bh_topology_device(const uint8_t *al_macaddr); + +/** Removes all backhaul topology devices from the model, invalidates backhaul tree. */ +void remove_all_bh_topology_devices(void); + +/** + * Returns true if interface information provided with tlv_device_info differs + * from data already stored in bh_topology_dev (model). + * To reduce time complexity, it's assumed interfaces received in TLV are always ordered + * the same way. Also only number of interfaces and their MAC addresses are compared. + */ +bool has_interface_info_changed(const struct tlv_device_info *tlv_dev_info, + const struct bh_topology_dev *bh_topo_dev); +/** + * Copies interface details from tlv_device_info into bh_topology_dev. + * Invalidates backhaul tree. + */ +void copy_interface_info_from_tlv(const struct tlv_device_info *tlv_dev_info, + struct bh_topology_dev *bh_topo_dev); + +/** + * Returns true if neighbor information provided with 1905 neighbor TLVs differs + * from data already stored in bh_topology_dev (model). + */ +bool has_neighbor_info_changed(const struct tlv_1905neighbor **neighbor_tlvs, + const uint16_t *tlv_lengths, + uint8_t tlv_number, + const struct bh_topology_dev *bh_topo_dev); + +/** + * Copies neighbors details from 1905 neighbor TLVs into bh_topology_dev. + * Invalidates backhaul tree. + */ +void copy_neighbor_info_from_tlvs(const struct tlv_1905neighbor **neighbor_tlvs, + const uint16_t *tlv_lengths, + uint8_t tlv_number, + struct bh_topology_dev *bh_topo_dev); + +/** + * Builds backhaul topology tree from unordered list of bh_topology_dev structs + * by setting backhaul_info fields. + * + * Controller is always root node in tree. Edges between tree nodes represent + * BH links, parent nodes provides BH links to child node - each child node + * can have only one parent (be connected over one BH link). + * + * After calling it, is_bh_topology_valid() will return true, until next + * input data change (device add/remove, interface or neighbor info change.) + */ +void build_bh_topology_tree(const uint8_t *ctrl_al_macaddr); + +#endif /* BACKHAUL_TOPOLOGY_H */ diff --git a/src/backhaul_topology_dbg.c b/src/backhaul_topology_dbg.c new file mode 100644 index 0000000000000000000000000000000000000000..dcd7e2b08702b1a20c0897616742752a2ca7678e --- /dev/null +++ b/src/backhaul_topology_dbg.c @@ -0,0 +1,151 @@ +#include "backhaul_topology_dbg.h" +#include "backhaul_topology.h" +#include "utils/debug.h" + +#include <easy/utils.h> +#include <libubox/list.h> + +#define BH_TOPO_PREFIX "BH:" + +static const char *get_prefix(enum dbg_bh_topo_indent_lvl indent_level) +{ + switch (indent_level) { + case INDENT_LVL_0: return BH_TOPO_PREFIX; + case INDENT_LVL_1: return BH_TOPO_PREFIX" "; + case INDENT_LVL_2: return BH_TOPO_PREFIX" "; + case INDENT_LVL_3: return BH_TOPO_PREFIX" "; + default: return BH_TOPO_PREFIX" "; + } +} + +const char *i1905_media_type_to_str(uint16_t media_type) +{ + switch (media_type >> 8) { + case 0: return "Ethernet"; + case 1: return "Wi-Fi"; + default: return "Other"; + } +} + +void dbg_dump_bh_topo_backhaul_info(const struct backhaul_info *bh_info, + enum dbg_bh_topo_indent_lvl indent_lvl) +{ + const char *pref = get_prefix(indent_lvl); + + dbg("%s backhaul_info:\n", pref); + + if (bh_info->level_in_tree == UNKNOWN_TREE_LEVEL) { + dbg("%s .level_in_tree: %s\n", pref, "UNKNOWN_TREE_LEVEL"); + } else { + dbg("%s .level_in_tree: %d\n", pref, bh_info->level_in_tree); + dbg("%s .wifi_hops_from_root: %d\n", pref, bh_info->wifi_hops_from_root); + } + + if (bh_info->parent_in_tree) { + dbg("%s .parent_in_tree: " MACFMT "\n", pref, + MAC2STR(bh_info->parent_in_tree->al_macaddr)); + } + + if (bh_info->parent_iface) { + dbg("%s .parent_iface: " MACFMT "\n", pref, + MAC2STR(bh_info->parent_iface->macaddr)); + } + + if (bh_info->own_iface) { + dbg("%s .own_iface: " MACFMT "\n", pref, + MAC2STR(bh_info->own_iface->macaddr)); + } +} + +void dbg_dump_bh_topo_local_iface(const struct local_iface *local_iface, + enum dbg_bh_topo_indent_lvl indent_lvl) +{ + const char *pref = get_prefix(indent_lvl); + int i; + + dbg("%s local_iface:\n", pref); + dbg("%s .macaddr: " MACFMT "\n", pref, MAC2STR(local_iface->macaddr)); + dbg("%s .media_type: %s\n", pref, + i1905_media_type_to_str(local_iface->media_type)); + dbg("%s .number_of_neighbors: %u\n", pref, local_iface->number_of_neighbors); + + for (i = 0; i < local_iface->number_of_neighbors; ++i) { + dbg("%s .neigh_al_mac[%d]: " MACFMT "\n", + pref, i, MAC2STR(&local_iface->neighbors_al_macs[i][0])); + } +} + +void dbg_dump_bh_topo_dev(const struct bh_topology_dev *bh_topo_dev, + enum dbg_bh_topo_indent_lvl indent_lvl) +{ + const char *pref = get_prefix(indent_lvl); + int i; + + dbg("%s bh_topology_dev:\n", pref); + dbg("%s .al_macaddr: " MACFMT "\n", pref, MAC2STR(bh_topo_dev->al_macaddr)); + dbg("%s .number_of_interfaces: %d\n", pref, bh_topo_dev->number_of_interfaces); + dbg("%s .num_of_ifaces_with_neighbors: %d\n", pref, bh_topo_dev->num_of_ifaces_with_neighbors); + + for (i = 0; i < bh_topo_dev->number_of_interfaces; ++i) { + dbg("%s .iface[%d]:\n", pref, i); + dbg_dump_bh_topo_local_iface(&bh_topo_dev->ifaces[i], indent_lvl + 1); + } + + dbg("%s .bh_info:\n", pref); + dbg_dump_bh_topo_backhaul_info(&bh_topo_dev->bh_info, indent_lvl + 1); + +} + +void dbg_dump_bh_topo_devs(const struct list_head *bh_topo_dev_list, + enum dbg_bh_topo_indent_lvl indent_lvl) +{ + const char *pref = get_prefix(indent_lvl); + const struct bh_topology_dev *bh_topo_dev = NULL; + int i = 0; + + dbg("%s =============== %s ===============\n", pref, __func__); + + list_for_each_entry(bh_topo_dev, bh_topo_dev_list, list_element) { + dbg("%s bh_topo_dev[%d]:\n", pref, i++); + dbg_dump_bh_topo_dev(bh_topo_dev, ++indent_lvl); + + } + + dbg("%s ============ END %s ==============\n", pref, __func__); +} + +void dbg_dump_bh_topo_link(const struct bh_topology_dev *bh_topo_dev, + enum dbg_bh_topo_indent_lvl indent_lvl) +{ + const char *pref = get_prefix(indent_lvl); + const struct bh_topology_dev *parent_dev = + bh_topo_dev->bh_info.parent_in_tree; + const struct local_iface *parent_iface = + bh_topo_dev->bh_info.parent_iface; + const struct local_iface *own_iface = + bh_topo_dev->bh_info.own_iface; + + if (bh_topo_dev->bh_info.level_in_tree == UNKNOWN_TREE_LEVEL) { + dbg("%s child level: %s\n", pref, "UNKNOWN_TREE_LEVEL"); + } else { + dbg("%s child level: %d\n", pref, bh_topo_dev->bh_info.level_in_tree); + } + + dbg("%s child wifi_hops_from_root: %d\n", pref, bh_topo_dev->bh_info.wifi_hops_from_root); + dbg("%s child almac: " MACFMT "\n", pref, MAC2STR(bh_topo_dev->al_macaddr)); + + if (own_iface) { + dbg("%s child iface: " MACFMT "\n", pref, MAC2STR(own_iface->macaddr)); + } + + if (parent_dev) { + dbg("%s parent level: %d\n", pref, parent_dev->bh_info.level_in_tree); + dbg("%s parent almac: " MACFMT "\n", pref, MAC2STR(parent_dev->al_macaddr)); + } + + if (parent_iface) { + dbg("%s parent iface: " MACFMT "\n", pref, MAC2STR(parent_iface->macaddr)); + dbg("%s media: %s\n", pref, i1905_media_type_to_str(parent_iface->media_type)); + } +} + diff --git a/src/backhaul_topology_dbg.h b/src/backhaul_topology_dbg.h new file mode 100644 index 0000000000000000000000000000000000000000..c9b38a3482c487b7e18ee7e20e02dbdf3c3e9d26 --- /dev/null +++ b/src/backhaul_topology_dbg.h @@ -0,0 +1,35 @@ +#ifndef BACKHAUL_TOPOLOGY_DBG_H +#define BACKHAUL_TOPOLOGY_DBG_H + +#include <stdint.h> + +struct list_head; +struct bh_topology_dev; +struct local_iface; +struct backhaul_info; + +enum dbg_bh_topo_indent_lvl { + INDENT_LVL_0 = 0, + INDENT_LVL_1 = 1, + INDENT_LVL_2 = 2, + INDENT_LVL_3 = 3, +}; + +const char *i1905_media_type_to_str(uint16_t media_type); + +void dbg_dump_bh_topo_backhaul_info(const struct backhaul_info *bh_info, + enum dbg_bh_topo_indent_lvl indent_lvl); + +void dbg_dump_bh_topo_local_iface(const struct local_iface *local_iface, + enum dbg_bh_topo_indent_lvl indent_lvl); + +void dbg_dump_bh_topo_dev(const struct bh_topology_dev *bh_topo_dev, + enum dbg_bh_topo_indent_lvl indent_lvl); + +void dbg_dump_bh_topo_devs(const struct list_head *bh_topo_dev_list, + enum dbg_bh_topo_indent_lvl indent_lvl); + +void dbg_dump_bh_topo_link(const struct bh_topology_dev *bh_topo_dev, + enum dbg_bh_topo_indent_lvl indent_lvl); + +#endif diff --git a/src/cntlr.c b/src/cntlr.c index 1992b6d82ce269cfa2aef00f77c37ef7a6867fd3..09daacc0ad0247611588065129dbbcaa4dbcecab 100644 --- a/src/cntlr.c +++ b/src/cntlr.c @@ -44,6 +44,7 @@ #include "cntlr.h" #include "allsta.h" #include "allmac.h" +#include "backhaul_topology.h" #include "cntlr_ubus.h" #include "cntlr_ubus_dbg.h" #include "cntlr_map.h" @@ -2008,6 +2009,7 @@ void run_controller(void) #endif as_init_table(&c->as_table); allmac_init_table(&c->mac_table); + init_bh_topology(); cmdu_ackq_init(&c->cmdu_ack_q); c->cmdu_ack_q.timeout_cb = cntlr_ackq_timeout_cb; diff --git a/src/cntlr_map.c b/src/cntlr_map.c index 20df08c9d284f30938cf62228461da58e0200afd..7acde1d60fb42766843e818471374437a9d1855a 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -52,6 +52,7 @@ #include "utils/utils.h" #include "utils/debug.h" #include "utils/liblist.h" +#include "backhaul_topology.h" #include "config.h" #include "cntlr.h" #include "cntlr_ubus.h" @@ -301,9 +302,14 @@ static int topology_response_vext(struct controller *c, struct node *n, struct t int handle_topology_response(void *cntlr, struct cmdu_buff *cmdu, struct node *n) { - trace("%s: --->\n", __func__); struct controller *c = (struct controller *) cntlr; struct tlv *tv[12][16] = {0}; + struct bh_topology_dev *bh_topo_dev = NULL; + const struct tlv_1905neighbor *neighbor_tlvs[16] = { NULL }; + uint8_t neigh_tlv_cnt = 0; + uint16_t tlv_lengths[16] = { 0 }; + + trace("%s: --->\n", __func__); cntlr_set_link_profile(c, n, cmdu); @@ -313,6 +319,71 @@ int handle_topology_response(void *cntlr, struct cmdu_buff *cmdu, struct node *n return -1; } + /* Device Information Type TLV */ + if (tv[0][0]) { + const struct tlv_device_info *tlv_dev_info = + (struct tlv_device_info *)tv[0][0]->data; + bool new_bh_topo_dev = false; + + dbg("%s: Device Info TLV from " MACFMT "\n", __func__, + MAC2STR(cmdu->origin)); + + bh_topo_dev = + find_bh_topology_device(tlv_dev_info->aladdr); + + if (!bh_topo_dev) { + dbg("%s: New bh_topology_device\n", __func__); + bh_topo_dev = add_bh_topology_device( + tlv_dev_info->aladdr); + + if (!bh_topo_dev) { + err("%s: Error in memory alloc\n", + __func__); + return -1; + } + + new_bh_topo_dev = true; + } + + if (new_bh_topo_dev || + has_interface_info_changed(tlv_dev_info, + bh_topo_dev)) { + dbg("%s: New interface info for bh_topology_device\n", + __func__); + + /* Copy new info and invalidate the model. */ + copy_interface_info_from_tlv(tlv_dev_info, + bh_topo_dev); + } + } + + if (!bh_topo_dev) { + err("%s: 1905 dev.info is missing. Logical error in\n", + __func__); + return -1; + } + + /* 1905.1 neighbor device TLVs */ + neigh_tlv_cnt = 0; + while (tv[3][neigh_tlv_cnt] && (neigh_tlv_cnt < 16)) { + neighbor_tlvs[neigh_tlv_cnt] = + (struct tlv_1905neighbor *)tv[3][neigh_tlv_cnt]->data; + + tlv_lengths[neigh_tlv_cnt] = + tlv_length(tv[3][neigh_tlv_cnt]); + ++neigh_tlv_cnt; + } + + if (has_neighbor_info_changed(neighbor_tlvs, tlv_lengths, + neigh_tlv_cnt, bh_topo_dev)) { + dbg("%s: New neighbor info for bh_topology_device\n", + __func__); + + /* Copy new info and invalidate the model. */ + copy_neighbor_info_from_tlvs(neighbor_tlvs, tlv_lengths, + neigh_tlv_cnt, bh_topo_dev); + } + if (tv[7][0]) { struct tlv_ap_oper_bss *tlv; uint8_t *tv_data; @@ -562,6 +633,11 @@ int handle_topology_response(void *cntlr, struct cmdu_buff *cmdu, struct node *n cntrl_send_channel_preference_query(c, n->alid); } + /* When all topology responses collected, build topology tree. */ + if (!is_bh_topology_valid() && c->num_nodes == bh_topology_devs_number()) { + build_bh_topology_tree(c->almac); + } + return 0; }