From 532a48d23e28bf104d2886da7b9c88eafe1888f4 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Wed, 29 Sep 2021 00:42:37 +0200 Subject: [PATCH] local-node: prioritize neighbor candidates Prioritize neighbor candidates installed to hostapd. Add a new config option to set a limit for neighbor reports installed to hostapd. This is due to the fact, most devices will only evaluate a certain amount of neighbor reports. Furthermore, the number of neighbor reports possible is limited by the maximum frame size. Signed-off-by: David Bauer --- local_node.c | 38 ++++++--- main.c | 1 + node.c | 104 +++++++++++++++++++++++++ openwrt/usteer/files/etc/config/usteer | 3 + openwrt/usteer/files/etc/init.d/usteer | 2 +- ubus.c | 1 + usteer.h | 3 + 7 files changed, 141 insertions(+), 11 deletions(-) diff --git a/local_node.c b/local_node.c index 3c1b3e1..103e5ee 100644 --- a/local_node.c +++ b/local_node.c @@ -287,35 +287,53 @@ usteer_local_node_req_cb(struct ubus_request *req, int ret) uloop_timeout_set(&ln->req_timer, 1); } -static void +static bool usteer_add_rrm_data(struct usteer_local_node *ln, struct usteer_node *node) { if (node == &ln->node) - return; + return false; if (!node->rrm_nr) - return; + return false; + /* Remote node only adds same SSID. Required for local-node. */ if (strcmp(ln->node.ssid, node->ssid) != 0) - return; + return false; blobmsg_add_field(&b, BLOBMSG_TYPE_ARRAY, "", blobmsg_data(node->rrm_nr), blobmsg_data_len(node->rrm_nr)); + + return true; } static void usteer_local_node_prepare_rrm_set(struct usteer_local_node *ln) { - struct usteer_remote_node *rn; - struct usteer_node *node; + struct usteer_node *node, *last_remote_neighbor = NULL; + int i = 0; void *c; c = blobmsg_open_array(&b, "list"); - for_each_local_node(node) - usteer_add_rrm_data(ln, node); - for_each_remote_node(rn) - usteer_add_rrm_data(ln, &rn->node); + for_each_local_node(node) { + if (i >= config.max_neighbor_reports) + break; + if (usteer_add_rrm_data(ln, node)) + i++; + } + + while (i < config.max_neighbor_reports) { + node = usteer_node_get_next_neighbor(&ln->node, last_remote_neighbor); + if (!node) { + /* No more nodes available */ + break; + } + + last_remote_neighbor = node; + if (usteer_add_rrm_data(ln, node)) + i++; + } + blobmsg_close_array(&b, c); } diff --git a/main.c b/main.c index 9fb6d4a..4e9ffa4 100644 --- a/main.c +++ b/main.c @@ -88,6 +88,7 @@ void usteer_init_defaults(void) config.local_sta_timeout = 120 * 1000; config.local_sta_update = 1 * 1000; config.max_retry_band = 5; + config.max_neighbor_reports = 8; config.seen_policy_timeout = 30 * 1000; config.band_steering_threshold = 5; config.load_balancing_threshold = 5; diff --git a/node.c b/node.c index 2858dac..00ffb99 100644 --- a/node.c +++ b/node.c @@ -17,6 +17,7 @@ * Copyright (C) 2020 John Crispin */ +#include "node.h" #include "usteer.h" void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val) @@ -36,3 +37,106 @@ void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val) *dest = realloc(*dest, new_len); memcpy(*dest, val, new_len); } + +static struct usteer_node * +usteer_node_higher_bssid(struct usteer_node *node1, struct usteer_node *node2) +{ + int i; + + for (i = 0; i < 6; i++) { + if (node1->bssid[i] == node2->bssid[i]) + continue; + if (node1->bssid[i] < node2->bssid[i]) + return node2; + + break; + } + + return node1; +} + +static struct usteer_node * +usteer_node_more_roam_interactions(struct usteer_node *node, struct usteer_node *ref) +{ + int roam_actions_node, roam_actions_ref; + + roam_actions_node = node->roam_source + node->roam_destination; + roam_actions_ref = ref->roam_source + ref->roam_destination; + if (roam_actions_node < roam_actions_ref) + return ref; + + return node; +} + +static struct usteer_node * +usteer_node_better_neighbor(struct usteer_node *node, struct usteer_node *ref) +{ + struct usteer_node *n1, *n2; + + /** + * 1. Return one node if the other one is NULL + * 2. Return the node with the higher roam events. + * 3. Return the node with the higher BSSID. + * 4. Return first method argument. + */ + + if (!ref) + return node; + + if (!node) + return ref; + + n1 = usteer_node_more_roam_interactions(node, ref); + n2 = usteer_node_more_roam_interactions(ref, node); + if (n1 == n2) + return n1; + + /* Identical roam interactions. Check BSSID */ + n1 = usteer_node_higher_bssid(node, ref); + n2 = usteer_node_higher_bssid(ref, node); + if (n1 == n2) + return n1; + + return node; +} + +struct usteer_node * +usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last) +{ + struct usteer_remote_node *rn; + struct usteer_node *next = NULL, *n1, *n2; + + for_each_remote_node(rn) { + if (next == &rn->node) + continue; + + if (strcmp(current_node->ssid, rn->node.ssid)) + continue; + + /* Check if this node is ranked lower than the last one */ + n1 = usteer_node_better_neighbor(last, &rn->node); + n2 = usteer_node_better_neighbor(&rn->node, last); + if (n1 != n2) { + /* Identical rank. Skip. */ + continue; + } else if (last && n1 == &rn->node) { + /* Candidate rank is higher than the last neighbor. Skip. */ + continue; + } + + /* Check with current next candidate */ + n1 = usteer_node_better_neighbor(next, &rn->node); + n2 = usteer_node_better_neighbor(&rn->node, next); + if (n1 != n2) { + /* Identical rank. Skip. */ + continue; + } else if (n1 != &rn->node) { + /* Next candidate ranked higher. */ + continue; + } + + next = n1; + } + + return next; +} diff --git a/openwrt/usteer/files/etc/config/usteer b/openwrt/usteer/files/etc/config/usteer index 9031ea8..2fe1c98 100644 --- a/openwrt/usteer/files/etc/config/usteer +++ b/openwrt/usteer/files/etc/config/usteer @@ -17,6 +17,9 @@ config usteer # 5 = all debug messages option 'debug_level' '2' + # Maximum number of neighbor reports set for a node + #option max_neighbor_reports 8 + # Maximum amount of time (ms) a station may be blocked due to policy decisions #option sta_block_timeout 30000 diff --git a/openwrt/usteer/files/etc/init.d/usteer b/openwrt/usteer/files/etc/init.d/usteer index 65a6b9a..1f9ab06 100755 --- a/openwrt/usteer/files/etc/init.d/usteer +++ b/openwrt/usteer/files/etc/init.d/usteer @@ -75,7 +75,7 @@ uci_usteer() { for opt in \ debug_level \ sta_block_timeout local_sta_timeout local_sta_update \ - max_retry_band seen_policy_timeout \ + max_neighbor_reports max_retry_band seen_policy_timeout \ load_balancing_threshold band_steering_threshold \ remote_update_interval \ min_connect_snr min_snr signal_diff_threshold \ diff --git a/ubus.c b/ubus.c index 776b0bf..d5e11ee 100644 --- a/ubus.c +++ b/ubus.c @@ -146,6 +146,7 @@ struct cfg_item { _cfg(U32, sta_block_timeout), \ _cfg(U32, local_sta_timeout), \ _cfg(U32, local_sta_update), \ + _cfg(U32, max_neighbor_reports), \ _cfg(U32, max_retry_band), \ _cfg(U32, seen_policy_timeout), \ _cfg(U32, load_balancing_threshold), \ diff --git a/usteer.h b/usteer.h index 05dca14..1b9d12c 100644 --- a/usteer.h +++ b/usteer.h @@ -152,6 +152,8 @@ struct usteer_config { bool assoc_steering; + uint32_t max_neighbor_reports; + uint32_t band_steering_threshold; uint32_t load_balancing_threshold; @@ -274,6 +276,7 @@ static inline const char *usteer_node_name(struct usteer_node *node) } void usteer_node_set_blob(struct blob_attr **dest, struct blob_attr *val); +struct usteer_node *usteer_node_get_next_neighbor(struct usteer_node *current_node, struct usteer_node *last); bool usteer_check_request(struct sta_info *si, enum usteer_event_type type); void config_set_interfaces(struct blob_attr *data); -- 2.30.2