From 5541aa41f5bb756048aa3b6c241ebecf8e38b76c Mon Sep 17 00:00:00 2001 From: Jamie Wark Date: Fri, 10 Mar 2023 16:15:35 +1300 Subject: [PATCH] Add wlan tuning (#312) * Add wlan tuning * proxy_arp * bss_transition * fast_roaming_enabled * Fix punctuation * Default `bss_transition` to `true` * Improve tests * Tweak descriptions * Fix tests * Fix tests --------- Co-authored-by: Joshua Spence --- docs/resources/device.md | 2 +- docs/resources/wlan.md | 9 +- internal/provider/resource_wlan.go | 40 ++++-- internal/provider/resource_wlan_test.go | 184 ++++++++++++++++++++---- 4 files changed, 196 insertions(+), 39 deletions(-) diff --git a/docs/resources/device.md b/docs/resources/device.md index 8d9f9268..782694de 100644 --- a/docs/resources/device.md +++ b/docs/resources/device.md @@ -89,7 +89,7 @@ Optional: - `aggregate_num_ports` (Number) Number of ports in the aggregate. - `name` (String) Human-readable name of the port. -- `op_mode` (String) Operating mode of the port, valid values are `switch`, `mirror`, and `aggregate`. +- `op_mode` (String) Operating mode of the port, valid values are `switch`, `mirror`, and `aggregate`. Defaults to `switch`. - `port_profile_id` (String) ID of the Port Profile used on this port. diff --git a/docs/resources/wlan.md b/docs/resources/wlan.md index 437fe13a..bb469789 100644 --- a/docs/resources/wlan.md +++ b/docs/resources/wlan.md @@ -62,9 +62,11 @@ resource "unifi_wlan" "wifi" { ### Optional - `ap_group_ids` (Set of String) IDs of the AP groups to use for this network. +- `bss_transition` (Boolean) Improves client transitions between APs when they have a weak signal. Defaults to `true`. +- `fast_roaming_enabled` (Boolean) Enables 802.11r fast roaming. Defaults to `false`. - `hide_ssid` (Boolean) Indicates whether or not to hide the SSID from broadcast. - `is_guest` (Boolean) Indicates that this is a guest WLAN and should use guest behaviors. -- `l2_isolation` (Boolean) Isolates stations on layer 2 (ethernet) level Defaults to `false`. +- `l2_isolation` (Boolean) Isolates stations on layer 2 (ethernet) level. Defaults to `false`. - `mac_filter_enabled` (Boolean) Indicates whether or not the MAC filter is turned of for the network. - `mac_filter_list` (Set of String) List of MAC addresses to filter (only valid if `mac_filter_enabled` is `true`). - `mac_filter_policy` (String) MAC address filter policy (only valid if `mac_filter_enabled` is `true`). Defaults to `deny`. @@ -72,13 +74,14 @@ resource "unifi_wlan" "wifi" { - `minimum_data_rate_5g_kbps` (Number) Set minimum data rate control for 5G devices, in Kbps. Use `0` to disable minimum data rates. Valid values are: `6000`, `9000`, `12000`, `18000`, `24000`, `36000`, `48000`, and `54000`. - `multicast_enhance` (Boolean) Indicates whether or not Multicast Enhance is turned of for the network. - `network_id` (String) ID of the network for this SSID -- `no2ghz_oui` (Boolean) Connect high performance clients to 5 GHz only Defaults to `true`. +- `no2ghz_oui` (Boolean) Connect high performance clients to 5 GHz only. Defaults to `true`. - `passphrase` (String, Sensitive) The passphrase for the network, this is only required if `security` is not set to `open`. - `pmf_mode` (String) Enable Protected Management Frames. This cannot be disabled if using WPA 3. Valid values are `required`, `optional` and `disabled`. Defaults to `disabled`. +- `proxy_arp` (Boolean) Reduces airtime usage by allowing APs to "proxy" common broadcast frames as unicast. Defaults to `false`. - `radius_profile_id` (String) ID of the RADIUS profile to use when security `wpaeap`. You can query this via the `unifi_radius_profile` data source. - `schedule` (Block List) Start and stop schedules for the WLAN (see [below for nested schema](#nestedblock--schedule)) - `site` (String) The name of the site to associate the wlan with. -- `uapsd` (Boolean) Enable Unscheduled Automatic Power Save Delivery Defaults to `false`. +- `uapsd` (Boolean) Enable Unscheduled Automatic Power Save Delivery. Defaults to `false`. - `wlan_band` (String) Radio band your WiFi network will use. Defaults to `both`. - `wpa3_support` (Boolean) Enable WPA 3 support (security must be `wpapsk` and PMF must be turned on). - `wpa3_transition` (Boolean) Enable WPA 3 and WPA 2 support (security must be `wpapsk` and `wpa3_support` must be true). diff --git a/internal/provider/resource_wlan.go b/internal/provider/resource_wlan.go index b099424f..5c68eee7 100644 --- a/internal/provider/resource_wlan.go +++ b/internal/provider/resource_wlan.go @@ -163,19 +163,37 @@ func resourceWLAN() *schema.Resource { }, }, "no2ghz_oui": { - Description: "Connect high performance clients to 5 GHz only", + Description: "Connect high performance clients to 5 GHz only.", Type: schema.TypeBool, Optional: true, Default: true, }, "l2_isolation": { - Description: "Isolates stations on layer 2 (ethernet) level", + Description: "Isolates stations on layer 2 (ethernet) level.", Type: schema.TypeBool, Optional: true, Default: false, }, + "proxy_arp": { + Description: "Reduces airtime usage by allowing APs to \"proxy\" common broadcast frames as unicast.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "bss_transition": { + Description: "Improves client transitions between APs when they have a weak signal.", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, "uapsd": { - Description: "Enable Unscheduled Automatic Power Save Delivery", + Description: "Enable Unscheduled Automatic Power Save Delivery.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "fast_roaming_enabled": { + Description: "Enables 802.11r fast roaming.", Type: schema.TypeBool, Optional: true, Default: false, @@ -313,11 +331,14 @@ func resourceWLANGetResourceData(d *schema.ResourceData, meta interface{}) (*uni Enabled: true, NameCombineEnabled: true, - GroupRekey: 3600, - DTIMMode: "default", - No2GhzOui: d.Get("no2ghz_oui").(bool), - L2Isolation: d.Get("l2_isolation").(bool), - UapsdEnabled: d.Get("uapsd").(bool), + GroupRekey: 3600, + DTIMMode: "default", + No2GhzOui: d.Get("no2ghz_oui").(bool), + L2Isolation: d.Get("l2_isolation").(bool), + ProxyArp: d.Get("proxy_arp").(bool), + BssTransition: d.Get("bss_transition").(bool), + UapsdEnabled: d.Get("uapsd").(bool), + FastRoamingEnabled: d.Get("fast_roaming_enabled").(bool), MinrateSettingPreference: minrateSettingPreference, @@ -396,7 +417,10 @@ func resourceWLANSetResourceData(resp *unifi.WLAN, d *schema.ResourceData, meta d.Set("wlan_band", resp.WLANBand) d.Set("no2ghz_oui", resp.No2GhzOui) d.Set("l2_isolation", resp.L2Isolation) + d.Set("proxy_arp", resp.ProxyArp) + d.Set("bss_transition", resp.BssTransition) d.Set("uapsd", resp.UapsdEnabled) + d.Set("fast_roaming_enabled", resp.FastRoamingEnabled) d.Set("ap_group_ids", apGroupIDs) d.Set("network_id", resp.NetworkID) d.Set("pmf_mode", resp.PMFMode) diff --git a/internal/provider/resource_wlan_test.go b/internal/provider/resource_wlan_test.go index ec5f18aa..8d5691fc 100644 --- a/internal/provider/resource_wlan_test.go +++ b/internal/provider/resource_wlan_test.go @@ -5,6 +5,7 @@ import ( "net" "testing" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" ) @@ -12,9 +13,7 @@ import ( func TestAccWLAN_wpapsk(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -36,9 +35,7 @@ func TestAccWLAN_wpapsk(t *testing.T) { func TestAccWLAN_open(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -74,9 +71,7 @@ func TestAccWLAN_open(t *testing.T) { func TestAccWLAN_change_security_and_pmf(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -126,9 +121,7 @@ func TestAccWLAN_change_security_and_pmf(t *testing.T) { func TestAccWLAN_schedule(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -159,9 +152,7 @@ func TestAccWLAN_wpaeap(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -183,9 +174,7 @@ func TestAccWLAN_wpaeap(t *testing.T) { func TestAccWLAN_wlan_band(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -207,9 +196,7 @@ func TestAccWLAN_wlan_band(t *testing.T) { func TestAccWLAN_no2ghz_oui(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -228,12 +215,58 @@ func TestAccWLAN_no2ghz_oui(t *testing.T) { }) } -func TestAccWLAN_uapsd(t *testing.T) { +func TestAccWLAN_proxy_arp(t *testing.T) { + name := acctest.RandomWithPrefix("tfacc") subnet, vlan := getTestVLAN(t) + resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: func(*terraform.State) error { + // TODO: actual CheckDestroy + + return nil }, + Steps: []resource.TestStep{ + { + Config: testAccWLANConfig_proxy_arp(name, subnet, vlan, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("unifi_wlan.test", "proxy_arp", "true"), + ), + }, + importStep("unifi_wlan.test"), + }, + }) +} + +func TestAccWLAN_bss_transition(t *testing.T) { + name := acctest.RandomWithPrefix("tfacc") + subnet, vlan := getTestVLAN(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: func(*terraform.State) error { + // TODO: actual CheckDestroy + + return nil + }, + Steps: []resource.TestStep{ + { + Config: testAccWLANConfig_bss_transition(name, subnet, vlan, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("unifi_wlan.test", "bss_transition", "false"), + ), + }, + importStep("unifi_wlan.test"), + }, + }) +} + +func TestAccWLAN_uapsd(t *testing.T) { + subnet, vlan := getTestVLAN(t) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -252,6 +285,30 @@ func TestAccWLAN_uapsd(t *testing.T) { }) } +func TestAccWLAN_fast_roaming_enabled(t *testing.T) { + name := acctest.RandomWithPrefix("tfacc") + subnet, vlan := getTestVLAN(t) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { preCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: func(*terraform.State) error { + // TODO: actual CheckDestroy + + return nil + }, + Steps: []resource.TestStep{ + { + Config: testAccWLANConfig_fast_roaming_enabled(name, subnet, vlan, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("unifi_wlan.test", "fast_roaming_enabled", "true"), + ), + }, + importStep("unifi_wlan.test"), + }, + }) +} + func TestAccWLAN_wpa3(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ @@ -294,9 +351,7 @@ func TestAccWLAN_wpa3(t *testing.T) { func TestAccWLAN_minimum_data_rate(t *testing.T) { subnet, vlan := getTestVLAN(t) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - preCheck(t) - }, + PreCheck: func() { preCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: func(*terraform.State) error { // TODO: actual CheckDestroy @@ -555,6 +610,56 @@ resource "unifi_wlan" "test" { `, subnet, vlan) } +func testAccWLANConfig_proxy_arp(name string, subnet *net.IPNet, vlan int, proxyArp bool) string { + return fmt.Sprintf(` +data "unifi_ap_group" "default" {} + +data "unifi_user_group" "default" {} + +resource "unifi_network" "test" { + name = "%[1]s" + purpose = "corporate" + subnet = "%[2]s" + vlan_id = %[3]d +} + +resource "unifi_wlan" "test" { + name = "%[1]s" + network_id = unifi_network.test.id + passphrase = "12345678" + ap_group_ids = [data.unifi_ap_group.default.id] + user_group_id = data.unifi_user_group.default.id + security = "wpapsk" + proxy_arp = %[4]t +} +`, name, subnet, vlan, proxyArp) +} + +func testAccWLANConfig_bss_transition(name string, subnet *net.IPNet, vlan int, bssTransition bool) string { + return fmt.Sprintf(` +data "unifi_ap_group" "default" {} + +data "unifi_user_group" "default" {} + +resource "unifi_network" "test" { + name = "%[1]s" + purpose = "corporate" + subnet = "%[2]s" + vlan_id = %[3]d +} + +resource "unifi_wlan" "test" { + name = "%[1]s" + network_id = unifi_network.test.id + passphrase = "12345678" + ap_group_ids = [data.unifi_ap_group.default.id] + user_group_id = data.unifi_user_group.default.id + security = "wpapsk" + bss_transition = %[4]t +} +`, name, subnet, vlan, bssTransition) +} + func testAccWLANConfig_uapsd(subnet *net.IPNet, vlan int) string { return fmt.Sprintf(` data "unifi_ap_group" "default" {} @@ -580,6 +685,31 @@ resource "unifi_wlan" "test" { `, subnet, vlan) } +func testAccWLANConfig_fast_roaming_enabled(name string, subnet *net.IPNet, vlan int, fastRoamingEnabled bool) string { + return fmt.Sprintf(` +data "unifi_ap_group" "default" {} + +data "unifi_user_group" "default" {} + +resource "unifi_network" "test" { + name = "%[1]s" + purpose = "corporate" + subnet = "%[2]s" + vlan_id = %[3]d +} + +resource "unifi_wlan" "test" { + name = "%[1]s" + network_id = unifi_network.test.id + passphrase = "12345678" + ap_group_ids = [data.unifi_ap_group.default.id] + user_group_id = data.unifi_user_group.default.id + security = "wpapsk" + fast_roaming_enabled = %[4]t +} +`, name, subnet, vlan, fastRoamingEnabled) +} + func testAccWLANConfig_wpa3(subnet *net.IPNet, vlan int, wpa3Transition bool, pmf string) string { return fmt.Sprintf(` data "unifi_ap_group" "default" {}