Nrsyncd: 802.11k Neighbor Report Sync Daemon

Hello OpenWrt community,

Over the weekend, @kissadamfkut and I discussed the future of the openwrt-rrm-nr-distributor project. For context, Adam started that work in August 2021, inspired by this forum, and I’ve been a regular user and occasional contributor ever since.

The project is continuing and evolving under a new name: nrsyncd

  • What it is: a small service that distributes per‑BSS 802.11k Neighbor Report data across your OpenWrt APs via mDNS so clients (and higher‑level steering logic) can discover other BSSes in the same ESS quickly.

The original goal remains unchanged:

Distribute per‑BSS 802.11k Neighbor Report data across a set of OpenWrt APs using mDNS so clients (and higher‑level steering logic) can discover other BSSes of the same ESS quickly.

Acknowledgements:

  • Huge thanks to Adam for creating and stewarding the original project, and for supporting its continued evolution.

Get started and migration:

Feedback:

  • Please try it on your APs and share results or issues. Bug reports and ideas are welcome.
  • If reporting issues

    Please include:
    - Device model + OpenWrt version
    - Output of /etc/init.d/nrsyncd metadata
    - umdns announcements TXT (jsonfilter array selector [*] tip)
    ubus call umdns announcements | jsonfilter -e '@["_nrsyncd_v1._udp.local"][*].txt[*]'
    - Relevant logread | grep nrsyncd

Cheers!


Coming Soon

Native package for inclusion in the OpenWrt build system!

6 Likes

< Hold for future >

I noticed some things happening on GitHub, will update/migrate somewhere next week!

–EDIT–

upgraded earlier today. I enabled the debug option. If anything unexpected happens, I’ll update this post.

1 Like

Thank you for putting this together! I have played a bit and it looks promising. It seems I need to stop and start it again to pick up SSIDs which where enabled/disabled while it was running. Is it supposed to do it by itself?

It definitely should be picking that up on its own without any need to restart the service. Let me look into that and see what’s going on. Thanks for bringing that forward!

Sure. Let me know if I can help.

Thanks for this, it’s great!

I’m wondering if I’ve run into a problem though. I’ve just tested on my setup which has two SSIDs across both 2.4 and 5ghz bands, but I’m only seeing one of the SSIDs (“Jaculu”) in the neighbors command output.

@_FailSafe does this seem to be working on both my SSDIs “Russell Family” and “Jaculu” to you?

$ cat /etc/config/wireless

config wifi-device 'radio0'
	option type 'mac80211'
	option path '1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0'
	option band '2g'
	option channel '1'
	option htmode 'HE20'
	option country 'CH'
	option cell_density '1'

config wifi-device 'radio1'
	option type 'mac80211'
	option path '1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0+1'
	option band '5g'
	option channel '36'
	option htmode 'HE80'
	option country 'CH'
	option cell_density '1'

config wifi-iface 'wifinet00'
	option device 'radio0'
	option mode 'ap'
	option network 'lan'
	option ssid 'Russell Family'
	option encryption 'sae'
	option key 'xxxx'
	option dtim_period '3'
	option ieee80211r '1'
	option reassociation_deadline '20000'
	option ft_over_ds '0'
	option ieee80211k '1'
	option bss_transition '1'
	option time_advertisement '2'

config wifi-iface 'wifinet01'
	option device 'radio1'
	option mode 'ap'
	option network 'lan'
	option ssid 'Russell Family'
	option encryption 'sae'
	option key 'xxxx'
	option dtim_period '3'
	option ieee80211r '1'
	option reassociation_deadline '20000'
	option ft_over_ds '0'
	option ieee80211k '1'
	option bss_transition '1'
	option time_advertisement '2'

config wifi-iface 'wifinet10'
	option device 'radio0'
	option mode 'ap'
	option network 'lan'
	option ssid 'Jaculu'
	option encryption 'psk2+ccmp'
	option key 'xxxx'
	option dtim_period '3'
	option ieee80211r '1'
	option reassociation_deadline '20000'
	option ft_over_ds '0'
	option ieee80211k '1'
	option bss_transition '1'
	option time_advertisement '2'

config wifi-iface 'wifinet11'
	option device 'radio1'
	option mode 'ap'
	option network 'lan'
	option ssid 'Jaculu'
	option encryption 'psk2+ccmp'
	option key 'xxxx'
	option dtim_period '3'
	option ieee80211r '1'
	option reassociation_deadline '20000'
	option ft_over_ds '0'
	option ieee80211k '1'
	option bss_transition '1'
	option time_advertisement '2'

$ service nrsyncd neighbors

phy0-ap0:
  {
  	"list": [
        // Why no "Russell Family" SSID here?
  	]
  }
phy0-ap1:
  {
  	"list": [
  		[
  			"xx:xx:xx:xx:5d:63",
  			"Jaculu",
  			"xxxxxxxx5d63ef5900008024090603022a00"
  		]
  	]
  }
phy1-ap0:
  {
  	"list": [
        // Why no "Russell Family" SSID here?
  	]
  }
phy1-ap1:
  {
  	"list": [
  		[
  			"xx:xx:xx:xx:5d:62",
  			"Jaculu",
  			"xxxxxxxx5d62ef4900005101070603000100"
  		]
  	]
  }
$ ubus call umdns browse
{

}
$ service nrsyncd status

nrsyncd status:
  update_interval=60
  jitter_max=10
  umdns_refresh_interval=30
  umdns_settle_delay=0
  debug=1
  skip_ifaces=
  last_reload=1757856909
  cycle=13
  last_update_time=1757856910
  primary_service=nrsyncd_v1
  initial_positional_ssids=4
  metrics:
    cycle=13
    cache_hits=13
    cache_misses=0
    nr_sets_sent=2
    nr_sets_suppressed=24
    remote_entries_merged=0
    remote_unique_cycle=0
    remote_unique_total=0
    last_update_time=1757856910
    baseline_ssids=1
    suppression_ratio_pct=92
    nr_set_failures=0
    neighbor_count_phy0-ap1=1
    neighbor_count_phy1-ap1=1
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: Removed hash map directory: /tmp/tmp.OcLAKF
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: Removed hash map directory: /tmp/tmp.OcLAKF
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: Starting (init ver=1.0.2)
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: Waiting for all wireless interfaces to initialize.
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: All wireless interfaces are initialized.
Sun Sep 14 15:35:08 2025 daemon.info nrsyncd: Assembled 4 SSID entries (no skips)
Sun Sep 14 15:35:08 2025 daemon.debug nrsyncd: Prepared SSID args: SSID1=[ "xx:xx:xx:xx:5d:62", "Russell Family", "xxxxxxxx5d62ef4900005101070603000100" ] SSID2=[ "xx:xx:xx:xx:5d:62", "Jaculu", "xxxxxxxx5d62ef4900005101070603000100" ] SSID3=[ "xx:xx:xx:xx:5d:63", "Russell Family", "xxxxxxxx5d63ef5900008024090603022a00" ] SSID4=[ "xx:xx:xx:xx:5d:63", "Jaculu", "xxxxxxxx5d63ef5900008024090603022a00" ] (total 4)
Sun Sep 14 15:35:09 2025 daemon.debug nrsyncd: startup: interval=60 jitter=10 umdns=30 max_cycles=0
Sun Sep 14 15:35:10 2025 daemon.debug nrsyncd: group_build: ssid='Jaculu' canon_count=2
Sun Sep 14 15:35:10 2025 daemon.debug nrsyncd: cache_hit: ssid='Jaculu'
Sun Sep 14 15:35:10 2025 daemon.debug nrsyncd: phy0-ap1: updated list=[["xx:xx:xx:xx:5d:63","Jaculu","xxxxxxxx5d63ef5900008024090603022a00"]] rc=0
Sun Sep 14 15:35:10 2025 daemon.debug nrsyncd: phy1-ap1: updated list=[["xx:xx:xx:xx:5d:62","Jaculu","xxxxxxxx5d62ef4900005101070603000100"]] rc=0
Sun Sep 14 15:36:10 2025 daemon.debug nrsyncd: group_build: ssid='Jaculu' canon_count=2
Sun Sep 14 15:36:10 2025 daemon.debug nrsyncd: cache_hit: ssid='Jaculu'
$ service nrsyncd mapping
  iface        bssid             chan freq   width c1     SSID
  phy0-ap0     xx:xx:xx:xx:5d:62 1    2412   20    2412   Russell Family
  phy0-ap1     xx:xx:xx:xx:5d:62 1    2412   20    2412   Jaculu
  phy1-ap0     xx:xx:xx:xx:5d:63 36   5180   80    5210   Russell Family
  phy1-ap1     xx:xx:xx:xx:5d:63 36   5180   80    5210   Jaculu

So what's this about /bin/nrsyncd being "prebuilt; no source here"? As far as I can see it's a shell script, not a binary?

Documentation oversight. Will get this corrected in an upcoming release. :+1:t2:

2 Likes

Sorry about the delayed reply. I've been under the weather the past few days and slow to dig into this and a few other issues/updates.

I will dig into this ASAP. Thanks for your patience!

1 Like

Thank you, I appreciate it. Feel better soon!

@qunvureze and @jasrusable Apologies again for the delay in any visible progress toward your questions. I ended up having COVID, so recovery has been (and continues to be) slow-going.

That said, I am working on an updated testing version that I will put out on a separate project branch ASAP (hopefully within just a few more days). If you're willing to test, you're welcome to pull that branch when it's ready and provide any feedback as you try it out.


@qunvureze and @jasrusable If you feel willing, you could begin testing this branch for me and let me know if you have successes or hit any issues: https://github.com/Fail-Safe/nrsyncd/tree/feature/activity-overlay-and-parsing

2 Likes

Sorry to hear, get well soon. Happy to help test and share feedback.