diff mbox series

[v2,2/4] knownnetworks: sort known frequencies by BSS rank

Message ID 20240124134001.20453-2-prestwoj@gmail.com (mailing list archive)
State New
Headers show
Series [v2,1/4] knownnetworks: pass scan_bss to known_network_add_frequency | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-ci-gitlint success GitLint

Commit Message

James Prestwood Jan. 24, 2024, 1:39 p.m. UTC
Currently a quick scan uses the entire known frequency list so
ordering really doesn't matter but improvements will be made here
to make quick scans "quicker" for large network deployments (with
many known frequencies).

To prepare for this the known frequency list has been changed to
be sorted by BSS rank rather than most recently seen. This makes
a lot more sense because IWD should prefer to scan frequencies
that had higher ranked BSS's, not just frequencies that were scanned
last on the most recent scan.

As far as the disk sync goes the ranking is not included, but
ordering is. This really isn't a limitation because when IWD starts
up there isn't any guarantee its in the same physical location so
old scan ranks are likely not valid anymore. The first set of scans
will begin replacing the frequencies loaded from disk.
---
 src/knownnetworks.c | 16 ++++++++++++++--
 src/knownnetworks.h |  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

Comments

Denis Kenzior Jan. 24, 2024, 6:10 p.m. UTC | #1
Hi James,

On 1/24/24 07:39, James Prestwood wrote:
> Currently a quick scan uses the entire known frequency list so
> ordering really doesn't matter but improvements will be made here
> to make quick scans "quicker" for large network deployments (with
> many known frequencies).
> 
> To prepare for this the known frequency list has been changed to
> be sorted by BSS rank rather than most recently seen. This makes
> a lot more sense because IWD should prefer to scan frequencies
> that had higher ranked BSS's, not just frequencies that were scanned
> last on the most recent scan.

Interesting.  I definitely agree with the argument for treating frequencies with 
higher-ranked candidates as preferred, but I'm not sure that directly basing the 
frequency preference on the bss rank is the right thing to do.  A client might 
start right under an AP, ranking it quite high, but then rapidly move away where 
no APs exist on this frequency.  So you end up always scanning the original AP's 
frequency.  Some sort of temporal rank decay would be needed?

Perhaps an easier way to accomplish this would be to add known frequencies in 
reverse bss->rank sorted order.  That way last seen frequency with best ranked 
BSS would be first?

Do note however that the quick scan approach is really meant for smallish 
networks, to cut down scanning time when moving between Home / Office location 
for example.  It works surprisingly well, but might not be appropriate for rapid 
roaming in a large network.

> 
> As far as the disk sync goes the ranking is not included, but
> ordering is. This really isn't a limitation because when IWD starts
> up there isn't any guarantee its in the same physical location so
> old scan ranks are likely not valid anymore. The first set of scans
> will begin replacing the frequencies loaded from disk.
> ---
>   src/knownnetworks.c | 16 ++++++++++++++--
>   src/knownnetworks.h |  1 +
>   2 files changed, 15 insertions(+), 2 deletions(-)
> 

Regards,
-Denis
James Prestwood Jan. 24, 2024, 6:33 p.m. UTC | #2
Hi Denis,

On 1/24/24 10:10 AM, Denis Kenzior wrote:
> Hi James,
>
> On 1/24/24 07:39, James Prestwood wrote:
>> Currently a quick scan uses the entire known frequency list so
>> ordering really doesn't matter but improvements will be made here
>> to make quick scans "quicker" for large network deployments (with
>> many known frequencies).
>>
>> To prepare for this the known frequency list has been changed to
>> be sorted by BSS rank rather than most recently seen. This makes
>> a lot more sense because IWD should prefer to scan frequencies
>> that had higher ranked BSS's, not just frequencies that were scanned
>> last on the most recent scan.
>
> Interesting.  I definitely agree with the argument for treating 
> frequencies with higher-ranked candidates as preferred, but I'm not 
> sure that directly basing the frequency preference on the bss rank is 
> the right thing to do.  A client might start right under an AP, 
> ranking it quite high, but then rapidly move away where no APs exist 
> on this frequency.  So you end up always scanning the original AP's 
> frequency.  Some sort of temporal rank decay would be needed?
Yeah, I see your point...
>
> Perhaps an easier way to accomplish this would be to add known 
> frequencies in reverse bss->rank sorted order.  That way last seen 
> frequency with best ranked BSS would be first?

I'm not sure I understand, how would this be any different than just 
reversing the list I already have? Or are you saying sort by both rank 
and last seen? Essentially have the list segmented into chunks of 
frequencies found with prior scans:

[Last Scan] [N - 1] [N - 2] [ etc ]

And if a duplicate is found, move it to the front, sorted by rank?

>
> Do note however that the quick scan approach is really meant for 
> smallish networks, to cut down scanning time when moving between Home 
> / Office location for example.  It works surprisingly well, but might 
> not be appropriate for rapid roaming in a large network.
Exactly, e.g. with 50 APs (assuming you've seen them all) a "quick" scan 
takes 5 seconds.
>
>>
>> As far as the disk sync goes the ranking is not included, but
>> ordering is. This really isn't a limitation because when IWD starts
>> up there isn't any guarantee its in the same physical location so
>> old scan ranks are likely not valid anymore. The first set of scans
>> will begin replacing the frequencies loaded from disk.
>> ---
>>   src/knownnetworks.c | 16 ++++++++++++++--
>>   src/knownnetworks.h |  1 +
>>   2 files changed, 15 insertions(+), 2 deletions(-)
>>
>
> Regards,
> -Denis
>
Denis Kenzior Jan. 24, 2024, 6:44 p.m. UTC | #3
Hi James,

>> Perhaps an easier way to accomplish this would be to add known frequencies in 
>> reverse bss->rank sorted order.  That way last seen frequency with best ranked 
>> BSS would be first?
> 
> I'm not sure I understand, how would this be any different than just reversing

Well, right now we maintain the least recently seen frequency list in a very 
simple way:

- When scan results become available
	- Walk the result list (which is sorted by bss_rank?)
	- Add each result's frequency to the frequency cache
		- Remove any matching entry in the cache
		- Add it to head

Since the result list is sorted, the top entry in the frequency cache is the 
least ranked.  This doesn't matter for small networks since there would only be 
a couple results.

What we should do is to add the frequencies to the frequency cache in reverse 
order.  That way the highest ranked bss is at the top of the frequency cache.

Hope that made sense.
  Regards,
-Denis
James Prestwood Jan. 24, 2024, 6:55 p.m. UTC | #4
On 1/24/24 10:44 AM, Denis Kenzior wrote:
> Hi James,
>
>>> Perhaps an easier way to accomplish this would be to add known 
>>> frequencies in reverse bss->rank sorted order.  That way last seen 
>>> frequency with best ranked BSS would be first?
>>
>> I'm not sure I understand, how would this be any different than just 
>> reversing
>
> Well, right now we maintain the least recently seen frequency list in 
> a very simple way:
>
> - When scan results become available
>     - Walk the result list (which is sorted by bss_rank?)
>     - Add each result's frequency to the frequency cache
>         - Remove any matching entry in the cache
>         - Add it to head
>
> Since the result list is sorted, the top entry in the frequency cache 
> is the least ranked.  This doesn't matter for small networks since 
> there would only be a couple results.
>
> What we should do is to add the frequencies to the frequency cache in 
> reverse order.  That way the highest ranked bss is at the top of the 
> frequency cache.

Oh I see, I didn't realize the list was already sorted since its coming 
from network->bss_list. But wouldn't we have the same problem here? Old 
frequencies with a high rank would remain at the front unless they were 
seen by a recent scan. So if you saw a really high ranked AP once then 
never again it would always stay at the front.

Another thing I didn't consider is multiple BSS's on the same frequency :)

Maybe introducing a last seen time would help, though that adds even 
more complication.

>
> Hope that made sense.
>  Regards,
> -Denis
>
Denis Kenzior Jan. 24, 2024, 7:06 p.m. UTC | #5
Hi James,

On 1/24/24 12:55, James Prestwood wrote:
> 
> On 1/24/24 10:44 AM, Denis Kenzior wrote:
>> Hi James,
>>
>>>> Perhaps an easier way to accomplish this would be to add known frequencies 
>>>> in reverse bss->rank sorted order.  That way last seen frequency with best 
>>>> ranked BSS would be first?
>>>
>>> I'm not sure I understand, how would this be any different than just reversing
>>
>> Well, right now we maintain the least recently seen frequency list in a very 
>> simple way:
>>
>> - When scan results become available
>>     - Walk the result list (which is sorted by bss_rank?)
>>     - Add each result's frequency to the frequency cache
>>         - Remove any matching entry in the cache
>>         - Add it to head
>>
>> Since the result list is sorted, the top entry in the frequency cache is the 
>> least ranked.  This doesn't matter for small networks since there would only 
>> be a couple results.
>>
>> What we should do is to add the frequencies to the frequency cache in reverse 
>> order.  That way the highest ranked bss is at the top of the frequency cache.
> 
> Oh I see, I didn't realize the list was already sorted since its coming from 
> network->bss_list. But wouldn't we have the same problem here? Old frequencies 

There are a few paths.  One if network becoming promoted from unknown -> known, 
one for scan results being reported.  But in all or most cases the order is 
predetermined and would be by bss rank.

> with a high rank would remain at the front unless they were seen by a recent 

No, because each time the frequency cache is updated, new entries are put at the 
top of the list.  This automatically pushes older (as in least recently seen 
order) entries further down.

> scan. So if you saw a really high ranked AP once then never again it would 
> always stay at the front.

Nope.  Not in the current used implementation.

> 
> Another thing I didn't consider is multiple BSS's on the same frequency :)

This is generally not a problem since frequencies are stored per SSID, so for 
well planned networks you wouldn't have this.  But yes, this possibility is 
something you need to take into account.  My suggestion would still handle this 
nicely.

> 
> Maybe introducing a last seen time would help, though that adds even more 
> complication.

Yep.  Only reason to do so would be for serialization to disk I think.

Regards,
-Denis
James Prestwood Jan. 25, 2024, 1:21 p.m. UTC | #6
Hi Denis,

On 1/24/24 11:06 AM, Denis Kenzior wrote:
> Hi James,
>
> On 1/24/24 12:55, James Prestwood wrote:
>>
>> On 1/24/24 10:44 AM, Denis Kenzior wrote:
>>> Hi James,
>>>
>>>>> Perhaps an easier way to accomplish this would be to add known 
>>>>> frequencies in reverse bss->rank sorted order.  That way last seen 
>>>>> frequency with best ranked BSS would be first?
>>>>
>>>> I'm not sure I understand, how would this be any different than 
>>>> just reversing
>>>
>>> Well, right now we maintain the least recently seen frequency list 
>>> in a very simple way:
>>>
>>> - When scan results become available
>>>     - Walk the result list (which is sorted by bss_rank?)
>>>     - Add each result's frequency to the frequency cache
>>>         - Remove any matching entry in the cache
>>>         - Add it to head
>>>
>>> Since the result list is sorted, the top entry in the frequency 
>>> cache is the least ranked.  This doesn't matter for small networks 
>>> since there would only be a couple results.
>>>
>>> What we should do is to add the frequencies to the frequency cache 
>>> in reverse order.  That way the highest ranked bss is at the top of 
>>> the frequency cache.

Ok I understand what your getting at now, but providing the list in 
reverse order is somewhat problematic. The majority of additions are 
going to be from station's can results, via network_bss_add(). We 
_could_ reverse the BSS list in station but that seems like an expensive 
operation for each scan, and I really don't want to muck with that code. 
The only somewhat simple place to reverse the list is when a known 
network is added. But again its expensive.

To avoid refactoring elsewhere, I think the only way would be to 
timestamp entries (based on bss->time_stamp) and sort by both rank and 
timestamp. We could also limit the list to e.g. 5 values if we wanted to 
avoid storing a ton of u64's in memory.

Thanks,

James

>>
> Regards,
> -Denis
Denis Kenzior Jan. 25, 2024, 3:39 p.m. UTC | #7
Hi James,

On 1/25/24 07:21, James Prestwood wrote:
> Hi Denis,
> 
> On 1/24/24 11:06 AM, Denis Kenzior wrote:
>> Hi James,
>>
>> On 1/24/24 12:55, James Prestwood wrote:
>>>
>>> On 1/24/24 10:44 AM, Denis Kenzior wrote:
>>>> Hi James,
>>>>
>>>>>> Perhaps an easier way to accomplish this would be to add known frequencies 
>>>>>> in reverse bss->rank sorted order.  That way last seen frequency with best 
>>>>>> ranked BSS would be first?
>>>>>
>>>>> I'm not sure I understand, how would this be any different than just reversing
>>>>
>>>> Well, right now we maintain the least recently seen frequency list in a very 
>>>> simple way:
>>>>
>>>> - When scan results become available
>>>>     - Walk the result list (which is sorted by bss_rank?)
>>>>     - Add each result's frequency to the frequency cache
>>>>         - Remove any matching entry in the cache
>>>>         - Add it to head
>>>>
>>>> Since the result list is sorted, the top entry in the frequency cache is the 
>>>> least ranked.  This doesn't matter for small networks since there would only 
>>>> be a couple results.
>>>>
>>>> What we should do is to add the frequencies to the frequency cache in 
>>>> reverse order.  That way the highest ranked bss is at the top of the 
>>>> frequency cache.
> 
> Ok I understand what your getting at now, but providing the list in reverse 
> order is somewhat problematic. The majority of additions are going to be from 
> station's can results, via network_bss_add(). We _could_ reverse the BSS list in 
> station but that seems like an expensive operation for each scan, and I really 

Nah, it is a trivial operation.  In fact, l_queue_reverse() already exists.

What you can also do is remove the known frequency update from network_bss_add() 
and have station manage it explicitly.  You can then do all sorts of fancy 
things in station_set_scan_results().  Couple of examples.

example 1
   - allocate array of l_queue_size(new_bss_list) pairs: [network, frequency]
   - After calling station_add_seen_bss, jot down network/frequency into the array
   - Run another loop after to add the frequencies in reverse bss rank order

example 2:
   - Allocate array of l_queue_size(new_bss_list) struct scan_bss pointers
   - run qsort and sort the entries however you want (say by bss->time_stamp)

> don't want to muck with that code. The only somewhat simple place to reverse the 
> list is when a known network is added. But again its expensive.
> 
> To avoid refactoring elsewhere, I think the only way would be to timestamp 
> entries (based on bss->time_stamp) and sort by both rank and timestamp. We could 
> also limit the list to e.g. 5 values if we wanted to avoid storing a ton of 
> u64's in memory.
> 

See above.  I'm really not sure that sorting by timestamp AND rank will do 
anything.  If the driver does things properly then it will report 
NL80211_BSS_LAST_SEEN_BOOTTIME value, so all entries will have a unique time_stamp.

Another thing I thought of is that we probably should be updating the known 
frequency list based on any neighbor reports we obtain.  Just in case we get 
disconnected for whatever reason before we attempt to roam.

Regards,
-Denis
diff mbox series

Patch

diff --git a/src/knownnetworks.c b/src/knownnetworks.c
index f6284fdc..6e549e02 100644
--- a/src/knownnetworks.c
+++ b/src/knownnetworks.c
@@ -562,9 +562,19 @@  static bool known_frequency_match(const void *a, const void *b)
 	return known_freq->frequency == *frequency;
 }
 
+static int known_frequency_compare(const void *a, const void *b,
+					void *user_data)
+{
+	const struct known_frequency *kf_a = a;
+	const struct known_frequency *kf_b = b;
+
+	return (kf_b->rank > kf_a->rank) ? 1 : -1;
+}
+
 /*
  * Adds a frequency to the 'known' set of frequencies that this network
- * operates on.  The list is sorted according to most-recently seen
+ * operates on.  The list is sorted according to the rank of the BSS on that
+ * frequency.
  */
 int known_network_add_frequency(struct network_info *info, struct scan_bss *bss)
 {
@@ -578,9 +588,11 @@  int known_network_add_frequency(struct network_info *info, struct scan_bss *bss)
 	if (!known_freq) {
 		known_freq = l_new(struct known_frequency, 1);
 		known_freq->frequency = bss->frequency;
+		known_freq->rank = bss->rank;
 	}
 
-	l_queue_push_head(info->known_frequencies, known_freq);
+	l_queue_insert(info->known_frequencies, known_freq,
+			known_frequency_compare, NULL);
 
 	return 0;
 }
diff --git a/src/knownnetworks.h b/src/knownnetworks.h
index 9f81e308..36106501 100644
--- a/src/knownnetworks.h
+++ b/src/knownnetworks.h
@@ -96,6 +96,7 @@  typedef void (*known_networks_destroy_func_t)(void *user_data);
 
 struct known_frequency {
 	uint32_t frequency;
+	uint16_t rank;
 };
 
 void __network_config_parse(const struct l_settings *settings,