Skip to content
Snippets Groups Projects
Commit 23623919 authored by Kamil Zulewski's avatar Kamil Zulewski
Browse files

Limiting length of Wi-Fi BH link chains

Add initial logic needed for BH topology modeling
parent 770123a0
No related branches found
No related tags found
No related merge requests found
Pipeline #100070 passed
......@@ -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 \
......
#include "backhaul_topology.h"
#include "backhaul_topology_dbg.h"
#include "utils/debug.h"
#include "utils/utils.h"
#include <easy/utils.h>
#include <libubox/list.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static bool is_wifi(uint16_t media_type)
{
return (media_type >> 8) == 1;
}
static struct bh_topology_dev *
find_bh_topology_device_priv(const uint8_t *al_macaddr,
const 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) {
if (hwaddr_equal(bh_topo_dev->al_macaddr, al_macaddr))
return bh_topo_dev;
}
return NULL;
}
struct bh_topology_dev *
find_bh_topology_device(const uint8_t *al_macaddr,
const struct bh_topology_dev_list *bh_topo_dev_list)
{
return find_bh_topology_device_priv(al_macaddr, &bh_topo_dev_list->list_head);
}
struct bh_topology_dev *add_bh_topology_device(const uint8_t *al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list)
{
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, &bh_topo_dev_list->list_head);
++bh_topo_dev_list->bh_topo_devs_number;
bh_topo_dev_list->bh_topology_updated = false;
return bh_topo_dev;
}
void remove_bh_topology_device(const uint8_t *al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list)
{
struct bh_topology_dev *bh_topo_dev = NULL, *bh_topo_dev_tmp;
list_for_each_entry_safe(bh_topo_dev, bh_topo_dev_tmp, &bh_topo_dev_list->list_head,
list_element) {
if (hwaddr_equal(bh_topo_dev->al_macaddr, al_macaddr)) {
list_del(&bh_topo_dev->list_element);
free(bh_topo_dev);
--bh_topo_dev_list->bh_topo_devs_number;
bh_topo_dev_list->bh_topology_updated = false;
}
}
}
void remove_all_bh_topology_devices(struct bh_topology_dev_list *bh_topo_dev_list)
{
/* cppcheck-suppress uninitvar */
list_flush(&bh_topo_dev_list->list_head, struct bh_topology_dev, list_element);
bh_topo_dev_list->bh_topo_devs_number = 0;
bh_topo_dev_list->bh_topology_updated = false;
}
void clear_bh_topology_device_info(struct bh_topology_dev *bh_topo_dev)
{
bh_topo_dev->number_of_interfaces = 0;
memset(bh_topo_dev->ifaces, 0, sizeof(bh_topo_dev->ifaces));
bh_topo_dev->bh_info =
(struct backhaul_info){ UNKNOWN_TREE_LEVEL, 0, NULL, NULL, NULL };
}
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_priv(
&parent_iface->neighbors_al_macs[j][0], bh_topo_dev_list);
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 set_backhaul_tree_relations(const uint8_t *ctrl_al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list)
{
struct bh_topology_dev *ctrl_dev = NULL;
bool new_level_discovered = false;
int8_t current_level;
clear_backhaul_tree_relations(&bh_topo_dev_list->list_head);
/* Mark controller as root node in BH tree (level_in_tree = 0) */
ctrl_dev = find_bh_topology_device(ctrl_al_macaddr, bh_topo_dev_list);
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, &bh_topo_dev_list->list_head);
++current_level;
} while (new_level_discovered);
bh_topo_dev_list->bh_topology_updated = true;
info("%s: Backhaul topology tree built. BH topo devs num: %d, cntrl: " MACFMT "\n",
__func__, bh_topo_dev_list->bh_topo_devs_number, MAC2STR(ctrl_al_macaddr));
dbg_dump_bh_topo_devs(&bh_topo_dev_list->list_head, INDENT_LVL_0);
}
#ifndef BACKHAUL_TOPOLOGY_H
#define BACKHAUL_TOPOLOGY_H
#include <libubox/list.h>
#include <stdint.h>
#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];
};
struct bh_topology_dev;
#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.
*
* When bh_info is populated the list of bh_topology_dev can be traversed
* and for each device bh link defined as below can be read.
*
* TR-181 BH link definition:
* BHDevALMac/BHLocalMac <-LinkType -< LocalMac (EM device)
*/
struct bh_topology_dev {
struct list_head list_element;
uint8_t al_macaddr[6];
uint8_t number_of_interfaces;
struct local_iface ifaces[IFACE_MAX_NUM];
struct backhaul_info bh_info;
};
/** Used to store all discovered easy mesh devices and model tree topology. */
struct bh_topology_dev_list {
struct list_head list_head; /* list of struct bh_topology_dev */
uint32_t bh_topo_devs_number;
bool bh_topology_updated;
};
struct bh_topology_dev *find_bh_topology_device(const uint8_t *al_macaddr,
const struct bh_topology_dev_list *bh_topo_dev_list);
struct bh_topology_dev *add_bh_topology_device(const uint8_t *al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list);
void remove_bh_topology_device(const uint8_t *al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list);
void remove_all_bh_topology_devices(struct bh_topology_dev_list *bh_topo_dev_list);
/**
* Clear all information about device interfaces, neighbors and its position in
* backhaul topolgy tree.
*/
void clear_bh_topology_device_info(struct bh_topology_dev *bh_topo_dev);
/**
* Builds backhaul topolgy 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).
*/
void set_backhaul_tree_relations(const uint8_t *ctrl_al_macaddr,
struct bh_topology_dev_list *bh_topo_dev_list);
#endif /* BACKHAUL_TOPOLOGY_H */
#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);
}
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);
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));
}
}
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment