local-node: prioritize neighbor candidates
authorDavid Bauer <mail@david-bauer.net>
Tue, 28 Sep 2021 22:42:37 +0000 (00:42 +0200)
committerDavid Bauer <mail@david-bauer.net>
Thu, 25 Nov 2021 21:28:04 +0000 (22:28 +0100)
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 <mail@david-bauer.net>
local_node.c
main.c
node.c
openwrt/usteer/files/etc/config/usteer
openwrt/usteer/files/etc/init.d/usteer
ubus.c
usteer.h

index 3c1b3e174304b6c678a7c5f0e8649ebd166b02cf..103e5eed2d862b08f2f7b635dd4189ffb96f42ff 100644 (file)
@@ -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 9fb6d4afe9150bbe266bf16cf6bc36effcd3cd37..4e9ffa4084abb685c4df0f0d3bc43643e7aa33d5 100644 (file)
--- 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 2858dac8ae119ec8d9ed71a263e537731cfc5f73..00ffb99fc78931a731540b8b780748a20514d55c 100644 (file)
--- a/node.c
+++ b/node.c
@@ -17,6 +17,7 @@
  *   Copyright (C) 2020 John Crispin <john@phrozen.org> 
  */
 
+#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;
+}
index 9031ea8a4fbcc9d0b692b6151b1a7cd1c5d9e6b2..2fe1c983d066d1a570a07ce8c39d430aca7e5215 100644 (file)
@@ -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
 
index 65a6b9a69a84980f833fdfabb21e16a200207017..1f9ab0621673c6e7ff1dce6b0f1e6d7bd8676c73 100755 (executable)
@@ -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 776b0bf5708f81676d074efcd4054776ef0bb523..d5e11eeaac564da256779a664a89338bfb329ae9 100644 (file)
--- 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), \
index 05dca140c3fd7242b8440a241a3240e3feb37efe..1b9d12c017f459c60d710fc5e8b4f565ed56a0c4 100644 (file)
--- 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);