Setting up usteer and band-steering in OpenWrt

usteer is a daemon for sharing wifi client information amongst APs on the same network, and can be used for band steering.

This can be useful for improved wifi performance when you have a network with multiple APs and 802.11r-based Wifi roaming enabled.

Unfortunately documentation on usteer is seemingly non-existent, so this wiki stub is being established in the hopes that the community adds to it over time.

The following items are required to setup usteer with OpenWrt:

And that's pretty much it.

These instructions have been tested with OpenWrt 21.02.x. For different versions, details may differ.

To setup usteer we need to do 3 things:

  • configure 802.11k and 802.11v on all wifi AP-nodes.
  • install and configure required packages for usteer
  • reboot all nodes (or just restart the network).

SSH into each of your wifi/AP nodes and add the following config-lines in `/etc/config/wireless` to each of your 802.11r enabled SSIDs:

      option bss_transition '1'
      option wnm_sleep_mode '1'
      option time_advertisement '2'
      option time_zone 'GMT0'
      option ieee80211k '1'
      option rrm_neighbor_report '1'
      option rrm_beacon_report '1'

Note: On previous versions of OpenWrt, the config option “bss_transition” used to be called “ieee80211v”. If migrating from an older version, please update this config-option too!

We need to install usteer. This is as simple as:

 opkg update && opkg install usteer

At this point you have all the packages you need, but they may be in need of additional configuration.

usteer's config-file /etc/config/usteer specifies which interface it will listen on for other nodes. By default this is lan.

Config options

Name Type Required Default Description
network string yes lan The network interface for inter-AP communication
syslog boolean yes 1 Log messages to syslog (0/1)
ipv6 boolean yes 0 Use IPv6 for remote exchange
debug_level integer yes 2 Minimum level of logged messages. 0 = Fatal, 1 = Info, 2 = Verbose, 3 = some debug messages, 4 = network packet information, 5 = all debug messages
max_neighbour_reports integer no 8 Maximum number of neighbor reports set for a node
sta_block_timeout integer no 30000 Maximum amount of time (ms) a station may be blocked due to policy decisions
local_sta_timeout integer no 12000 Maximum amount of time (ms) a local unconnected station is tracked
measurement_report_timeout integer no 120000 Maximum amount of time (ms) a measurement report is stored
local_sta_update integer no 1000 Local station information update interval (ms)
max_retry_band integer no 5 Maximum number of consecutive times a station may be blocked by policy
seen_policy_timeout integer no 30000 Maximum idle time of a station entry (ms) to be considered for policy decisions
load_balancing_threshold integer no 5 Minimum number of stations delta between APs before load balancing policy is active
band_steering_threshold integer no 5 Minimum number of stations delta between bands before band steering policy is active
remote_update_interval integer no 1000 Interval (ms) between sending state updates to other APs
remote_node_timeout integer no 10 Number of remote update intervals after which a remote-node is deleted
assoc_steering boolean no 0 Allow rejecting assoc requests for steering purposes (0/1)
min_connect_snr integer no 0 Minimum signal-to-noise ratio or signal level (dBm) to allow connections
min_snr integer no 0 Minimum signal-to-noise ratio or signal level (dBm) to remain connected
min_snr_kick_delay integer no 5000 Timeout after which a station with snr < min_snr will be kicked
roam_process_timeout integer no 5000 Timeout (in ms) after which a association following a disassociation is not seen as a roam
roam_scan_snr integer no 0 Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger client scans for roam
roam_scan_tries integer no 3 Maximum number of client roaming scan trigger attempts
roam_scan_timeout integer no 0 Retry scanning when roam_scan_tries is exceeded after this timeout (in ms). In case this option is set to 0, the client is kicked instead
roam_scan_interval integer no 10000 Minimum time (ms) between client roaming scan trigger attempts
roam_trigger_snr integer no 0 Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger forced client roaming
roam_trigger_interval integer no 60000 Minimum time (ms) between client roaming trigger attempts
roam_kick_delay integer no 100 Timeout (in 100ms beacon intervals) for client roam requests
signal_diff_threshold integer no 0 Minimum signal strength difference until AP steering policy is active
initial_connect_delay integer no 0 Initial delay (ms) before responding to probe requests (to allow other APs to see packets as well)
load_kick_enabled boolean no 0 Enable kicking client on excessive channel load (0/1)
load_kick_threshold integer no 75 Minimum channel load (%) before kicking clients
load_kick_delay integer no 10000 Minimum amount of time (ms) that channel load is above threshold before starting to kick clients
load_kick_min_clients integer no 10 Minimum number of connected clients before kicking based on channel load
load_kick_reason_code integer no 5 Reason code on client kick based on channel load (default: WLAN_REASON_DISASSOC_AP_BUSY)
node_up_script string no blank Script to run after bringing up a node
event_log_types list no blank Message types to include in log. Available types: probe_req_accept probe_req_deny, auth_req_accept, auth_req_deny, assoc_req_accept, assoc_req_deny, load_kick_trigger, load_kick_reset, load_kick_min_clients, load_kick_no_client, load_kick_client, signal_kick
ssid_list list no blank List of SSIDs to enable steering on

After making any change, restart usteer:

  /etc/init.d/usteer restart

Again, do this on all nodes in your network.

There is currently no Luci app for usteer

usteer has a ubus interface that can be accessed by:

  ubus call usteer <command> [args]

Ubus commands

Name Arguments Description
local_info none Prints local wifi network information
remote_hosts none Prints information about remote usteer instances
remote_info none Prints remote wifi network information (same as local_info, but for remote APs)
connected_clients none Prints clients that are connected to local wifi interfaces
get_clients none Prints all clients from all APs (local and remote)
get_client_info MAC address (json) Prints information about a specific client, including capabilities and information about roaming attempts
get_config none Details required
set_config yes (json) Details required
update_config yes (json) Details required
set_node_data yes (json) Details required
delete_node_data yes (json) Details required

local_info

root@AccessPoint:~# ubus call usteer local_info
{
	"hostapd.wlan1-1": {
		"bssid": "11:22:33:44:55:66",
		"freq": 2412,
		"n_assoc": 0,
		"noise": -95,
		"load": 5,
		"max_assoc": 0,
		"roam_events": {
				"source": 0,
				"target": 0
		},
		"rrm_nr": [
			"11:22:33:44:55:66",
			"OpenWrtSSID",
			"<hex string>"
		]
	}
}

remote_hosts

root@AccessPoint:~# ubus call usteer remote_hosts
{
      "192.168.1.1": {
		"id": -525792052
      }
}

remote_info

root@AccessPoint:~# ubus call usteer remote_info
{
      "192.168.1.1#hostapd.wlan0": {
		"bssid": "11:22:33:44:55:66",
		"freq": 5180,
		"n_assoc": 6,
		"noise": -107,
		"load": 3,
		"max_assoc": 0,
		"roam_events": {
			"source": 0,
			"target": 0
		},
		"rrm_nr": [
			"11:22:33:44:55:66",
			"OpenWrtSSID 5GHz",
			"<hex string>"
		]
      },
      "192.168.1.1#hostapd.wlan1": {
		"bssid": "11:22:33:44:55:67",
		"freq": 2412,
		"n_assoc": 7,
		"noise": -90,
		"load": 13,
		"max_assoc": 0,
		"roam_events": {
			"source": 0,
			"target": 0
		},
		"rrm_nr": [
			"11:22:33:44:55:67",
			"OpenWrtSSID",
			"<hex string>"
		]
      }
}

connected_clients

root@AccessPoint:~# ubus call usteer connected_clients
{
      "hostapd.wlan0": {
		"aa:bb:cc:dd:ee:ff": {
			"signal": -91,
			"created": 604990289,
			"seen": 610827895,
			"last_connected": 610827895,
			"snr-kick": {
				"seen-below": 0
			},
			"load-kick": {
				"count": 0
			},
			"roam-state-machine": {
				"tries": 0,
				"event": 0,
				"kick": 0,
				"scan_start": 0,
				"scan_timeout_start": 0
			},
			"bss-transition-response": {
				"status-code": 0,
				"timestamp": 0
			},
			"beacon-measurement-modes": [
				
			],
			"bss-transition-management": false,
			"measurements": [
				
			]
		},
		...
		"aa:bb:cc:dd:ee:fe": {
			"signal": -81,
			"created": 600282172,
			"seen": 610827895,
			"last_connected": 610827895,
			"snr-kick": {
				"seen-below": 0
			},
			"load-kick": {
				"count": 0
			},
			"roam-state-machine": {
				"tries": 0,
				"event": 0,
				"kick": 0,
				"scan_start": 0,
				"scan_timeout_start": 0
			},
			"bss-transition-response": {
				"status-code": 0,
				"timestamp": 0
			},
			"beacon-measurement-modes": [
				
			],
			"bss-transition-management": false,
			"measurements": [
				
			]
		}
      },
      "hostapd.wlan1": {
		"aa:bb:cc:dd:ee:fd": {
			"signal": -58,
			"created": 600282173,
			"seen": 610827901,
			"last_connected": 610827896,
			"snr-kick": {
				"seen-below": 0
			},
			"load-kick": {
				"count": 0
			},
			"roam-state-machine": {
				"tries": 0,
				"event": 0,
				"kick": 0,
				"scan_start": 0,
				"scan_timeout_start": 0
			},
			"bss-transition-response": {
				"status-code": 0,
				"timestamp": 0
			},
			"beacon-measurement-modes": [
				
			],
			"bss-transition-management": false,
			"measurements": [
				
			]
		}
      }
}

get_clients

root@AccessPoint:~# ubus call usteer get_clients
{
	"aa:bb:cc:dd:ee:ff": {
		"192.168.1.1#hostapd.wlan0": {
			"connected": true,
			"signal": -77
		}
	},
	...
	"aa:bb:cc:dd:ee:fe": {
		"192.168.1.1#hostapd.wlan1": {
			"connected": false,
			"signal": -74
		},
		"hostapd.wlan1-1": {
			"connected": false,
			"signal": -86
		}
	},
	"aa:bb:cc:dd:ee:fd": {
		"192.168.1.1#hostapd.wlan0": {
			"connected": false,
			"signal": -70
		},
		"192.168.1.1#hostapd.wlan1": {
			"connected": false,
			"signal": -81
		},
		"hostapd.wlan1-1": {
			"connected": false,
			"signal": -76
		}
	},
	...
	"aa:bb:cc:dd:ee:fc": {
		"hostapd.wlan0": {
			"connected": true,
			"signal": -74
		}
	}
}

get_client_info

A host that is connected locally

root@AccessPoint:~# ubus call usteer get_client_info "{'address':'aa:bb:cc:dd:ee:ff'}"
{
	"2ghz": true,
	"5ghz": true,
	"nodes": {
		"hostapd.wlan0": {
			"connected": true,
			"signal": -54,
			"stats": {
				"probe": {
					"requests": 5,
					"blocked_cur": 0,
					"blocked_total": 0
				},
				"assoc": {
					"requests": 5,
					"blocked_cur": 0,
					"blocked_total": 0
				},
				"auth": {
					"requests": 5,
					"blocked_cur": 0,
					"blocked_total": 0
				}
			}
		}
	}
}

A host that is connected remotely

root@AccessPoint:~# ubus call usteer get_client_info "{'address':'aa:bb:cc:dd:ee:fe'}"
{
	"2ghz": true,
	"5ghz": false,
	"nodes": {
		"192.168.1.32#hostapd.wlan1": {
			"connected": true,
			"signal": -38,
			"stats": {
				"probe": {
					"requests": 0,
					"blocked_cur": 0,
					"blocked_total": 0
				},
				"assoc": {
					"requests": 0,
					"blocked_cur": 0,
					"blocked_total": 0
				},
				"auth": {
					"requests": 0,
					"blocked_cur": 0,
					"blocked_total": 0
				}
			}
		}
	}
}

get_config

Details required

set_config

Details required

update_config

Details required

set_node_data

Details required

delete_node_data

Details required
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2022/08/25 01:38
  • by tmomas