A Go SDK for interacting with Cisco Catalyst 9800 Wireless Network Controller.
Cisco Catalyst 9800 Wireless Network Controller running on:
This SDK requires Go 1.27 or newer.
go get github.com/umatare5/cisco-ios-xe-wireless-go
You have to enable RESTCONF and HTTPS on the C9800 before using this SDK. Please see:
Encode your controller credentials as Base64.
# username:password → Base64 echo -n "admin:your-password" | base64 # Output: YWRtaW46eW91ci1wYXNzd29yZA==
Use your controller host and token to fetch AP operational data.
package main import ( "context" "fmt" "os" "time" wnc "github.com/umatare5/cisco-ios-xe-wireless-go" ) func main() { // Load environment variables controller := os.Getenv("WNC_CONTROLLER") token := os.Getenv("WNC_ACCESS_TOKEN") // Create client client, err := wnc.NewClient(controller, token, wnc.WithTimeout(30*time.Second), wnc.WithInsecureSkipVerify(true), // remove for production ) if err != nil { fmt.Fprintf(os.Stderr, "Failed to create client: %v\n", err) os.Exit(1) } // Create simple context with timeout ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() // Request AP operational data apData, err := client.AP().GetOperational(ctx) if err != nil { fmt.Fprintf(os.Stderr, "AP oper request failed: %v\n", err) os.Exit(1) } // Print AP operational data fmt.Printf("Successfully connected! Found %d APs\n", len(apData.CiscoIOSXEWirelessAPOperData.CAPWAPData)) }
Caution
The wnc.WithInsecureSkipVerify(true) option disables TLS certificate verification. This should only be used in development environments or when connecting to controllers with self-signed certificates. Never use this option in production environments as it compromises security. Where the controller presents a certificate from a private CA, pass wnc.WithRootCAs(pool) instead: the certificate is then verified rather than unverified.
# Set environment variables export WNC_CONTROLLER="wnc1.example.internal" export WNC_ACCESS_TOKEN="YWRtaW46eW91ci1wYXNzd29yZA==" # Run the application go run main.go # result: Successfully connected! Found 2 APs
This SDK provides a client to interact with the Cisco Catalyst 9800 Wireless Network Controller's RESTCONF.
To create a new client, use the wnc.NewClient function with the controller address and access token.
| Parameter | Type | Description |
|---|---|---|
controller |
string |
The hostname or IP address of the WNC. |
accessToken |
string |
The Base64-encoded Basic Auth token. |
options... |
...Option |
Optional client configuration options. |
There are several options to customize the client behavior. Each argument type is in the package documentation.
| Option | Default | Description |
|---|---|---|
WithTimeout(d) |
60s |
Whole-request timeout |
WithResponseHeaderTimeout(d) |
5s |
Header wait timeout |
WithTLSHandshakeTimeout(d) |
5s |
TLS handshake wait |
WithRootCAs(pool) |
host roots | Trust a private CA |
WithClientCertificate(cert) |
none | Present a client cert |
WithInsecureSkipVerify(skip) |
false |
Skip TLS verify |
WithProxy(fn) |
nil |
Proxy resolver |
WithLogger(l) |
slog.Default() |
Structured logger |
WithUserAgent(ua) |
cisco-ios-xe-wireless-go/<version> |
Custom User-Agent |
Every read method takes optional GetOption values after ctx, which apply to that single request.
| Option | Value on the wire | Description |
|---|---|---|
WithDefaults(wnc.ReportAll) |
with-defaults=report-all |
Adds the leaves in force at their default. |
WithDefaults(wnc.Explicit) |
with-defaults=explicit |
Adds the leaves a client set to the default. |
WithFields(expr) |
fields=<expr> |
Returns only the nodes named. |
WithDepth(n) |
depth=<n> |
Returns the top n levels only. |
entries, err := client.WLAN().ListWlanCfgEntries(ctx, wnc.WithDefaults(wnc.ReportAll))
Note
RFC 6243 3.3 is why wnc.Explicit differs from a plain GET, which omits any leaf equal to its default. Scope wnc.ReportAll to the container you need, because on a whole-container read the added leaves accumulate across every nested one. A pruned leaf decodes to zero, so WithFields and WithDepth must name every node the caller reads.
Every node this SDK types has an accessor.
For one it does not — a container a later IOS-XE release adds, or an RPC with no typed wrapper — the root client carries untyped methods that share the client's credentials, TLS settings, timeouts and *APIError typing.
| Method | RESTCONF resource | Notes |
|---|---|---|
GetData(ctx, path, opts...) |
/restconf/data |
Read with same GetOption |
GetDataInto[T](ctx, client, path, opts...) |
/restconf/data |
Read into a typed envelope |
PostData / PutData / PatchData / DeleteData |
/restconf/data |
Edit via fixed call verb |
PostRPC(ctx, path, payload) |
/restconf/operations |
Invoke RPC |
Request(ctx, method, path, payload) |
either | Fallback; carries the status |
GetDataInto is the one entry above that validates the envelope, so it takes a T whose outermost tag is the module-qualified node the path reads. It is a function rather than a method because a generic method may not be declared in an interface and is invisible to reflect.
body, err := client.PatchData(ctx, "Cisco-IOS-XE-wireless-wlan-cfg:wlan-cfg-data/wlan-cfg-entries/wlan-cfg-entry=1,demo", payload)
Warning
A []byte or json.RawMessage payload is sent as written once checked for well-formed JSON, and anything else is marshaled. Edit a body read with GetData as bytes, because decoding it into a Go value first rounds a 64-bit number.
Please refer to the Go Reference for the complete reference.
The following table summarizes the supported service APIs and their capabilities.
Legend:
| API | GetOperational() |
GetConfig() |
Other Functions | Notes |
|---|---|---|---|---|
AFC() |
✅️ | ⬜️ | ⬜️ | |
AP() |
✅️ | ✅️ | 🟩 | Issue #47 on 17.15+ |
APF() |
⬜️ | ✅️ | ⬜️ | |
AWIPS() |
✅️ | ⬜️ | ⬜️ | Issue #48 on 17.15+ |
BLE() |
✅️ | ⬜️ | ⬜️ | |
Client() |
✅️ | ⬜️ | ⬜️ | |
Controller() |
⬜️ | ⬜️ | 🟩 | |
CTS() |
⬜️ | ✅️ | ⬜️ | |
Dot11() |
⬜️ | ✅️ | ⬜️ | |
Dot15() |
⬜️ | ✅️ | ⬜️ | |
Fabric() |
⬜️ | ✅️ | ⬜️ | |
Flex() |
⬜️ | ✅️ | ⬜️ | |
General() |
✅️ | ✅️ | ⬜️ | |
Geolocation() |
✅️ | ⬜️ | ⬜️ | |
Hyperlocation() |
✅️ | ⬜️ | ⬜️ | |
LISP() |
✅️ | ⬜️ | ⬜️ | |
Location() |
✅️ | ✅️ | ⬜️ | |
Mcast() |
✅️ | ⬜️ | ⬜️ | |
MDNS() |
✅️ | ⬜️ | ⬜️ | |
Mesh() |
✅️ | ✅️ | ⬜️ | |
Mobility() |
✅️ | ⬜️ | ⬜️ | |
NMSP() |
✅️ | ⬜️ | ⬜️ | |
Radio() |
⬜️ | ✅️ | ⬜️ | |
RF() |
⬜️ | ✅️ | ⬜️ | |
RFTag() |
⬜️ | ⬜️ | 🟩 | |
RFID() |
✅️ | ✅️ | ⬜️ | |
Rogue() |
✅️ | ⬜️ | ⬜️ | |
RRM() |
✅️ | ✅️ | ⬜️ | |
Site() |
✅️ | ✅️ | ⬜️ | |
SiteTag() |
⬜️ | ⬜️ | 🟩 | |
Spaces() |
🟨 | ⬜️ | ⬜️ | Requires 17.15+ |
URWB() |
🟨 | 🟨 | ⬜️ | Requires 17.18+ |
WAT() |
⬜️ | 🟨 | ⬜️ | Requires 17.18+ |
WLAN() |
✅️ | ✅️ | ⬜️ | |
PolicyTag() |
⬜️ | ⬜️ | 🟩 |
Tip
wtpMac is the same as radioMac. WTP (Wireless Termination Point), defined in RFC 5415 denotes an AP.
Runnable examples are available:
example/list_aps/main.go lists APs managed by the controller.
❯ go run example/list_aps/main.go Successfully connected! Found 2 APs AP Name | MAC Address | IP Address | Status ------------------|---------------------|------------------|----------------- TEST-AP01 | aa:bb:cc:dd:ee:01 | 192.168.1.11 | registered TEST-AP02 | aa:bb:cc:dd:ee:02 | 192.168.1.12 | registered
example/list_clients/main.go lists clients associating to wireless networks.
❯ go run example/list_clients/main.go Successfully connected! Found 17 clients MAC Address | IP Address ----------------------|---------------- aa:bb:cc:dd:ee:a1 | 192.168.1.101 aa:bb:cc:dd:ee:a2 | 192.168.1.102 aa:bb:cc:dd:ee:a3 | 192.168.1.103 aa:bb:cc:dd:ee:a4 | 192.168.1.104 <snip>
example/list_wlans/main.go lists WLANs and their BSSIDs.
❯ go run example/list_wlans/main.go Successfully connected! Found 7 WLANs across all APs AP Name | AP MAC Address | Slot | WLAN | BSSID | SSID ------------------|-------------------|------|------|-------------------|------------------------- TEST-AP01 | aa:bb:cc:dd:ee:01 | 0 | 1 | aa:bb:cc:dd:ee:b1 | test-wlan TEST-AP01 | aa:bb:cc:dd:ee:01 | 1 | 2 | aa:bb:cc:dd:ee:b2 | test-psk TEST-AP01 | aa:bb:cc:dd:ee:01 | 1 | 4 | aa:bb:cc:dd:ee:b3 | test-tls <snip>
example/list_neighbors/main.go lists neighboring APs detected by the APs.
❯ go run example/list_neighbors/main.go Successfully connected! Found 11 AP neighbors AP Name | Slot | Neighbor BSSID | Neighbor SSID | RSSI | Channel | Last Heard At ------------------|------|-------------------|------------------------|-------|---------|-------------------------- TEST-AP01 | 0 | aa:bb:cc:dd:ee:f1 | test-rogue-01 | -20 | 11 | 2024-01-15 10:40:00 TEST-AP01 | 0 | aa:bb:cc:dd:ee:f2 | test-rogue-02 | -62 | 4 | 2024-01-15 10:41:00 TEST-AP01 | 1 | aa:bb:cc:dd:ee:f3 | test-rogue-03 | -64 | 36 | 2024-01-15 10:42:00 <snip>
example/reset_ap/main.go resets a specified AP by its MAC address.
❯ go run example/reset_ap/main.go === Access Point Reset Tool === WARNING: This tool will restart access points causing service interruption! Use only in controlled environments with proper authorization. Target Controller: wnc1.example.internal Enter AP MAC address (format: xx:xx:xx:xx:xx:xx or xx-xx-xx-xx-xx-xx): aa:bb:cc:dd:ee:01 Target AP MAC: aa:bb:cc:dd:ee:01 This will restart the specified Access Point(s). Type 'YES' to confirm: YES ✓ WNC client created successfully Executing AP reset for MAC aa:bb:cc:dd:ee:01 WARNING: AP will become unavailable and disconnect all clients during restart... ✓ AP reset command sent successfully for MAC: aa:bb:cc:dd:ee:01 Note: AP is now restarting and will be temporarily unavailable Clients will need to reconnect after AP restart completes
example/reload_controller/main.go reloads the entire wireless controller.
❯ go run ./example/reload_controller/main.go === WNC Controller Reload Tool === WARNING: This tool will restart the wireless controller! Use only in controlled environments with proper authorization. Target Controller: wnc1.example.internal This will restart the WNC controller. Type 'YES' to confirm: YES ✓ WNC client created successfully Executing controller reload with reason: Manual reload via CLI tool at 2024-01-15T10:30:00+09:00 WARNING: Controller will become unavailable during restart... ✓ Controller reload command sent successfully Note: Controller is now restarting and will be temporarily unavailable Wait for controller to complete restart before attempting reconnection
example/save_config/main.go copies the running configuration to the startup configuration.
❯ go run example/save_config/main.go === WNC Configuration Save Tool === WARNING: This tool overwrites the startup configuration and cannot be undone! Use only in controlled environments with proper authorization. Target Controller: wnc1.example.internal This will overwrite the startup configuration. Type 'YES' to confirm: YES ✓ WNC client created successfully Executing configuration save... ✓ Save running-config successful
Please read the Contribution Guide before submitting PRs and issues and also see the following documents:
I launched this project with the help of GitHub Copilot Coding Agent, and I am grateful to the global developer community for their contributions to open source projects and public repositories.
MIT. The module carries no third-party dependency, so LICENSE is the only notice a consumer reproduces.
Owner
Contributors
Categories
NetworkingProducts
Catalyst Access PointsProgramming Languages
GoLicense
Code Exchange Community
Get help, share code, and collaborate with other developers in the Code Exchange community.View Community