Achievement Unlocked: Patent!

Way back in the olden days before the world shut down (but only very shortly before), I had an inkling of an idea whilst returning to the USA aboard a cruise ship whose Wi-Fi refit I was commissioning. After letting the idea percolate in the ocean breeze, it dawned on me that my frustration over why nobody had done this before was because it had apparently not occurred to anyone to do it before, and I started down the long and complicated road of getting official confirmation and recognition that I was the first person to have this idea and had in fact invented something!

Because it was work-related and I had the idea while working, I had to file a disclosure with my employer, which was HPE at the time. The various branches of the corporate family tree founded in a garage by Bill Hewlett and David Packard back in 1939 have a long legacy of engineering and innovation, and a dizzying number of patents. Filing a disclosure informs the people that deal with such things that you think you have a novel idea, and as your employer, they get first dibs on it. If they think it’s potentially valuable to the company, then they will pursue a patent filing. If it’s outside the scope of the company’s business, they will take a pass on it and you are free to pursue a patent filing on your own, at your own expense (which is reportedly north of $10,000 these days), and you don’t have to assign it to the company. But if they decide it’s germane to the business, they will pursue a filing, which involves a lot of e-mails and phone calls with the patent legal team. Their objective is to submit an application to the USPTO that will get approved with no further modifications or explanations.

(Fun fact: My grandfather was granted a patent in 1965, and my mom’s late cousin Jack was a patent inspector after a long career at Bell Labs. Jack’s area of practice focused on things like memory architecture. One might even get the impression that I come from a long line of nerds.)

The timeline went something like this:

  • Early February 2020: Light Bulb!
  • Late February 2020: Disclosure
  • Late April 2020: clarification and refinement requested
  • May-December 2020: preparing the filing
  • January 2021: Filed with the USPTO
  • February 2021-February 2024: Waiting. SO MUCH WAITING.
  • February 2024: Patent 11910368 is granted

Why am I just posting this now? Because by February 2024, I was no longer at HPE, and if the USPTO sent out a notice, it would have gone to an email address that was long defunct. I just happened to check on it last week, after idly wondering if it had ever gone anywhere… Turns out that it did.

And just this week, a couple of interesting tidbits of industry news:

The first, that the FCC was looking to approve a new power mode for 6 GHz Wi-Fi known as Geofenced Variable Power (GVP) that changes RF behaviour of a network based on its location (previously, AFC for outdoor power was only allowed for fixed location installations, and anything mobile or battery powered was not allowed – GVP allows for things like hotspots and other battery-powered APs to run 6 GHz at power levels that are dependent on their location.

The second, that Cisco has been working with the FCC since January 2024 to figure out ways of allowing 6GHz on cruise ships in ways that don’t run afoul of local regulations wherever the ship may be, which is pretty much the whole idea (and even the specific use case) behind this invention.

It’s actually really cool to see that this progressed beyond “it’s a neat idea but only on paper, with no practical application in the real world” and into something that may well become a part of how wifi is done on 6 GHz. Because it’s assigned to HPE, I will of course never see royalties for it (HPE did give me a cash bonus for filing and a nice “Inventor 2021” polo shirt for Invention Day 2022), but at this point I’m perfectly content to have the nerd cred that is a patent with my name next to those of Messrs. Hewlett and Packard.

Ubiquiti: The Next Generation

(Apologies, this was stuck in the draft queue for a hot minute, I mean, year… )

OK, so it’s been a few months since my original post about the new generation of Ubiquiti gear, but in that time I started a new job that has me traveling every other week, and so I’ve been swamped with work and less time to work on my home network. But I finally got a week off and performed the long-awaited overhaul to the home network and the lab.

My existing Aruba InstantON network (Wifi 6, 3x AP22 and 1xAP11D, and a 1930 switch) was beginning to be problematic and requiring everything to be rebooted periodically for the wifi to keep working happily. I was also having some issues with my IoT devices communicating with their motherships through the OPNsense gateway I was using (because using the InstantON AP11D as a router is… not great). And since I now have multiple devices that support 6GHz, I decided it was time to take all that out and put in the shiny new Wifi 7 gear that Ubiquiti sent me back in May.

Now, I was already quite familiar with Unifi, having deployed a considerable amount of it over the years, and my current job has me deploying Ubiquiti 60GHz gear. Since the Wifi was Layer 2 only, the first thing I did was deploy the Dream Machine Pro SE. I racked it, plugged it in to power, and into one of the ports on my ISP hardware. Provisioning the system with the mobile app on my iPhone was quick and easy, and I was able to replicate the multiple VLANs and subnets I had on the OPNsense box. once I validated that they were working correctly, I moved the InstantON switch uplink from the OPNsense box to the Dream Machine. This transition was almost completely seamless, because the DHCP server on the Dream Machine will ping any IP address being requested by a client before issuing it, to prevent duplicate IPs.

So at this point, I’ve got the core of the network and the routing moved over to the Ubiquiti gateway. Since the InstantON wifi and switch weren’t handling anything at Layer 3, they didn’t really notice anything different. Everything was humming along smoothly. Next step was to deploy the 24-port Pro Max switch. The Pro Max line supports 2.5 Gigabit Ethernet (although only on 8 ports) and PoE++ (on 16 ports). Downside: It’s not readily apparent from looking at the unit which ports are 2.5G (17-24, and identified by a very small gray bar below the ports that blends in to the chassis metal color).

But these switches also support Ubiquiti’s EtherLighting, which has an RGB LED located inside the port and shines out through clear patch cable ends and boots. I had suggested/requested something like this from another switch vendor over a decade ago, but it was dismissed as “not useful, because colorless ports are the future”. I’m here to tell you that not only does this make the switches look really freaking cool, but it’s also very useful in that the color can be configured to show either the link speed or the native VLAN on the port. It would be nice if there were additional options such as PoE status/draw, traffic utilization, or simply just make them whatever color I want. It shows this color on the status lights of the SFP+ ports as well. Sadly, the Dream Machine does not have this feature, and its 8 ports are only gigabit.

Once the switch got provisioned, I started moving stuff over from the InstantON switch, after a quick provisioning of the ports for the IoT network, and then moved the AP patches over to the 2.5G PoE++ ports. One thing I noticed was that my LG washer and dryer, which had lost their connection during a power outage and never were able to recover it (they were able to connect to the LAN, but not their notoriously flaky backend cloud service), both came online in the app, suggesting that there was something in the routing or firewall on OPNsense that was blocking them from reaching their mothership.

Other IOT stuff (most of which is wired) was popping up in the UniFi dashboard right away, and the system was correctly identifying the types of device. It knew what my Hue bridge and Lutron bridge were without any additional configuration. There’s some device fingerprinting going on there that seems to be quite good.

And then the last step, once the AP ports were repatched to the switch, was to go upstairs and do the AP swap. At least for the two I had APs for. Ubiquiti’s included mounting plate is vastly better than the mounting option on the InstantOn, which is a badly rehashed version of Aruba’s 2XX and 3XX mounting solution. The Ubiquiti mounting plate is metal and predrilled for a 3.5″ round electrical box, which is what one of the locations terminates to, and which I will be installing at the other fairly soon. A quick swap of those APs and removal of the AP11D in the living room, and they were quickly provisioned and running.

Once the APs were up, it was time for the requisite speed test, and while my internet connection is nominally 500 Mbps, Ubiquiti’s hardware and Wifiman app allow for a local speed test. The new 6GHz capability was quickly in evidence, and ridiculously fast.

3 Ubiquiti Pro Max switches in a rack, demonstrating the Etherlighting feature that makes cable ends glow.

Taking a fresh look at Ubiquiti

Having spent most of the last 5 years steeped in the HPE/Aruba networking ecosystem, I didn’t pay much attention to what Ubiquiti has been doing, as their primarily Prosumer and small business market segment didn’t significantly overlap with the large global customers I was working with at Aruba. HPE did venture into the SMB space with the InstantON product line, and have been reasonably successful at it, but the consulting work I was doing rarely went anywhere near that space. Now that I’m free of any competitive constraints. I’m taking another look at a product line that has clearly evolved.

About a year or so ago, I saw a marketing slide that surprised me, indicating that the #3 player in the Wi-Fi space (measured by total access points deployed) behind 800-pound gorilla Cisco and #2 Aruba, was, in fact, Ubiquiti.

Ubiquiti is a company that originally made a name for themselves by selling proprietary (AirMax) Wi-Fi-ish point-to-point and service provider gear, and eventually jumped into Wi-Fi. They quietly built themselves into a nearly US$2B/year operation by selling inexpensive (but broadly adequate) Wi-Fi hardware that appealed to small businesses, and they were largely ignored by the “Big Players” for years.

It had long been my own experience that the Ubiquiti ecosystem was decent but had some significant scalability limitations in terms of their management platform. This was especially clear after I got down and dirty with some absolutely massive deployments while working at Aruba. Over the years prior, I’ve deployed a number of Ubiquiti-based solutions and periodically watched them release a few products that were real stinkers (both hardware and software) or distractions from the core product line (anyone remember mFi? their solar product? the first 802.11ac access point to ship?). They gained a reputation (and it was largely deserved) by marketing the product as plug-and-play that required minimal engineering skill, along with a bunch of defaults that really weren’t doing anyone much good. They were the “cheap” brand, preferred by minimally competent “trunk-slammers” and customer bean counters and IT departments who didn’t really understand Wi-Fi, leading to a lot of really bad installations. They were also plagued by supply chain and quality challenges for a very long time.

But over the last several years, other consumer-focused companies like Netgear, TP-Link, Linksys (fresh off the utter debacle that was Cisco’s ownership of the brand), new players like Google (Nest) and Amazon (Eero), and eventually larger legacy players like Aruba (InstantON) started realizing that Ubiquiti did in fact have the prosumer market largely locked up. They decided they wanted a piece of that pie, right around the same time that the consumer market started realizing that it needed multi-AP solutions, especially in the US market where homes were growing ever larger, and all the while, ISPs were providing equipment was almost criminally cheap and awful.

This new competition ultimately proved to be a good thing for Ubiquiti, as complacency had been taking hold. The competition breathed new life into the company, who began to make some really smart hiring decisions on the product and development side.

Meanwhile, the founder of Ubiquiti, Robert Pera, decided to do as so many company founders with mountains of wealth do, and invested some of it into a professional sports team, the Memphis Grizzlies of the National Basketball Association. Along with the team came the management and operation of their home arena, the FedExForum. As it would never do for a competitor’s networking product to be in the arena, the team set about deploying Ubiquiti’s Wi-Fi product to serve the arena, at a scale that the product had never been deployed before. This ultimately proved that the product can in fact scale, if given the proper engineering attention by someone who actually knows what they’re doing (their lead network architect is a good friend and colleague), and product support and development that can integrate feedback and the unique challenges posed by Large Public Venues. This gave the hardware and software some much-needed improvements.

Most recently, Ubiquiti put in a long-awaited appearance at Mobility Field Day 11, and got to present their product portfolio and roadmap to deeply experienced professionals in the wireless network space. They came to announce that they have been listening to extensive feedback from Wi-Fi pros (including yours truly), and how they’re starting to make moves into offering truly enterprise-grade products and services. In doing so, they’ve announced that they’re coming to play, and I’m hopeful that they provide some much-needed competition to the likes of Cisco (especially Meraki), Aruba, Juniper, Extreme, and Ruckus, in the same way the consumer players did for them. The big players have gotten complacent too, and it’s high time the market got shaken up.

I was fortunate enough to be part of the beta test audience for their MFD presentation and received a rather generous shipment of lab equipment in exchange for my time and expertise. Over the next several posts, I’ll go over the unboxing and commissioning of the gear and provide my thoughts on it. Stay tuned!

Setting up an Aruba Wireless Bridge using Wi-Fi Uplink

A while back, I posted about how to set up an Aruba wireless bridge using the built-in mesh method. Today I’ll show you how to accomplish a similar goal, but using the Wi-Fi Uplink approach. You’ll need to do it this way if you:

  • Need to connect an Ethernet Bridge to a non-Aruba network such as Starlink or a cellular hotspot
  • Need to connect to a network that is using 802.1X/EAP enterprise authentication
  • Need to connect to an Aruba network but can’t deploy dedicated mesh portals (because deploying an AP as a mesh portal disables any other VAPs configured on that AP’s group)

The setup is much like you would for a mesh AP, except we’re going straight to the mesh point, since the root is your existing infrastructure.

Perform the initial setup in the boot loader. IP address is optional, but since the AP will be in bridge mode, you may want an IP address to be able to manage it either manually or by adding it to Airwave. This IP address will exist on the uplink VLAN, and won’t be reachable even on the ethernet side until the uplink is active:

factory_reset
purgeenv
setenv standalone_mode 1
setenv uap_controller_less 1
setenv enet0_bridging 1
setenv enet1_downlink 1
setenv uplink_vlan 1
setenv ipaddr 11.22.33.44
setenv netmask 255.255.255.0
setenv gatewayip 11.22.33.1
saveenv
boot

Power up the AP, either via PoE or external DC power (If your AP has a 12V input, I’ve found that a Type C PD to 12V cable is very handy for powering an AP off a standard Type C battery). Make sure you also have something like a laptop connected to the eth0 port because Instant gets a little cranky about operating when it doesn’t have Ethernet.

Your boot time will vary by your specific AP model, but I’ve observed the following boot times to be typical:

  • AP-514/515: 3-4 minutes
  • AP-303H: 8-10 minutes

Once the AP has booted up and the CLI is ready and not in degraded mode, log in.

  • Default credentials:
    • standalone mode : admin/admin
    • virtual controller mode : admin/<serial number>

Start with the initial configuration (initial clock set time is in UTC). If you need to configure DST, follow the instructions for clock summer-time:

clock set <year> <month 1-12> <day> <hour (24)> <minutes> <seconds>

configure

virtual-controller-country US

name AP-OPLECTIC
terminal-access
clock timezone EST -05 00
rf-band 5.0
no extended-ssid

wlan ssid-profile dummy_ssid_to_disable_setup_mode
 disable
 index 0
 type employee
 essid "Literally Anything, Nobody will ever see this"
 wpa-passphrase aruba123
 opmode wpa2-psk-aes
 max-authentication-failures 0
 rf-band all
 captive-portal disable
 dtim-period 1
 broadcast-filter arp
 dmo-channel-utilization-threshold 90
 local-probe-req-thresh 0
 max-clients-threshold 64
exit

This section is critical for two reasons:

The first is that you are setting your regulatory domain for RF operation. The access point will not turn on the radio until you set a regulatory domain. Any radio operations will still look like they’re running even if they’re not, and it won’t tell you that you forgot to set it… Ask me how I know, and which hairs turned gray from this!

The second is that you are creating a dummy SSID profile to tell Instant that you’ve configured the AP and so it will stop trying to enter SetMeUp mode. Disabling extended-ssid is critical to the ability to act as a wifi client, and it will not take effect until the AP is out of setup mode.

Continue with the following configuration. This establishes and applies your Ethernet port profiles. Your native-vlan number should match whatever you configured in the boot loader for the uplink-vlan:

wlan access-rule IAP_DownLink
 index 4
 rule any any match any any any permit
exit

wired-port-profile IAP_DownLink
 switchport-mode access
 allowed-vlan all
 native-vlan 1
 trusted
 no shutdown
 access-rule-name IAP_DownLink
 speed auto
 duplex auto
 no poe
 type employee
 auth-server InternalServer
 captive-portal disable
 no dot1x
exit

enet0-port-profile IAP_DownLink
enet1-port-profile IAP_DownLink
enet2-port-profile IAP_DownLink
enet3-port-profile IAP_DownLink
enet4-port-profile IAP_DownLink

You only need to apply this profile to the ports that exist on your particular AP. If you’re using a 303H or 505H, or an outdoor AP with PoE output, you will want to make sure the poe setting reflects what you need. Applying poe to a port that doesn’t support it won’t hurt anything, it just won’t output PoE on those ports.

Continuing with the configuration of the WLAN station profile (for an SSID with enterprise auth). Your username will be in whatever format the NAC backend is expecting.

wlan sta-profile
essid CorporateWifi
cipher-suite wpa2-ccmp
uplink-band dot11a
wifi1x peap domain\username aruba123
exit

If your target network is using WPA2-PSK, use the following instead:

wlan sta-profile
essid CorporateWifi
cipher-suite wpa2-ccmp-psk
uplink-band dot11a
wpa-passphrase SSIDPassphrase!!!
exit

As of this writing, the CLI bank documentation does not correctly reflect the acceptable values for uplink-band, which are dot11g for 2.4 GHz and dot11a for 5 GHz. Make sure the allowed-band that you set up earlier matches this or it won’t work. Generally speaking, stick to 5 GHz.

Then follow with this to establish uplink priorities

uplink
 preemption
 enforce none
 failover-internet-pkt-lost-cnt 10
 failover-internet-pkt-send-freq 30
 failover-vpn-timeout 180
 uplink-priority ethernet 9
 uplink-priority wifi 8
 uplink-priority cellular 10
exit

exit out of the configuration context, save with write memory and then apply with commit apply, and reboot the AP with reload.

Once it’s back up, log back in and check that wifi uplink is configured with show wifi-uplink configuration.

Check to see the connection status with show wifi-uplink status. If it’s still in PROBE mode, run show wifi-uplink candidates to see if it’s found any APs to connect to. If it shows none, make sure you’ve got sufficient signal, and that you have in fact set your country code. If it’s showing that it’s associated, check the device connected to the e0 port and see if it can get an address (if you’re using DHCP), or configure one manually and try pinging both the AP and the gateway IP addresses. If that’s working, you’re done!

Working With the Aruba Central API

Yep. Another post about code. No, I’m not a software developer, I’m just a lazy network engineer who has an allergic reaction to doing GUI-based management of large environments. And thus I code because that’s a growing part of being a network engineer in the 2022.

A recent client project involving deploying a large fleet of Remote Access Points for teleworkers has required me to look at the Aruba Central API as a way of simplifying and streamlining the deployment of these APs to ensure consistency and completeness of the deployment. If you’re going to do anything more than about 5 times, it’s worth trying to automate it. If you’re going to do it 5000 times, you should automate it. I’m starting to get the hang of the AOS8 API and its many quirks, but Central is much more API-first than AOS8 which uses the API primarily as a frontend to the CLI.

If you have a remote workforce that depends on secure connections back to the corporate network, you should definitely check out the Aruba RAP solution. It beats the pants off software VPN clients (and at this point, how many teleworkers are even still wearing pants?). This solution has been available since almost the very beginning of Aruba nearly 2 decades ago and is mature and robust.

Like all of Aruba’s platforms, Central has a REST API that allows automation. The web frontend is essentially leveraging this API to work its magic. Aaron Scott, an Aruba CSE in Australia, has even built his own frontend to Aruba Central, because you can do that sort of thing when you have an API.

It’s got Swagger!

The Central API, like most, is documented with Swagger which allows you to browse and try various API calls to see how they behave.

I won’t rehash how to get access to it here, because Aruba documents the process very well in the Developer Hub page:

Note: once you’ve generated your token, make sure you download it by clicking “Download Token”. It will open a new window containing the JSON text with the actual token in it. Save this to a text file which you can use with your scripts later. Note the expiration time on this: 7200 seconds. This token is only good for two hours. You will need to use the refresh token in there to keep it alive past the 2 hour window. The refresh token is good for 15 days. How? It’s in the docs listed above (yeah, I just dropped an RTFM on you!)

Programming with the API

(and a gratuitous plug for the Aruba Developer Hub)

If you want to access the API programmatically, you’ll want to use Python, although anything capable of making HTTP calls and processing JSON responses will work. Fortunately, Aruba has provided a Python library (again, on the Aruba Developer Hub – this site has a wealth of great stuff).

The documentation on how to install the Python libraries can be found on the Developer Hub. At some point, you’ll likely be referred to the documentation for the library on Read The Docs. This documentation is broadly good, but in some places omits a few key points. Most notably, any time you need to send data to the API in a POST call, it’s not immediately apparent that body data needs to go into the apiData parameter.

Plenty of examples on the Dev Hub, and what you do will depend on your workflow and what you’re trying to accomplish. It may be helpful to draw yourself a mind map of what steps are needed to perform a task, and then map out what API calls and Python classes are required to make them, as well as what input data it depends on. Practice good code hygiene and don’t ever put your tokens in your code lest you accidentally share it to the world when you share your code (this is partly why the tokens on Aruba Central are only good for 2 hours!). Instead refer to the token file I suggested you download earlier (which you can do simply by opening the file and doing a json.load to import the contents into a dict.)

It’s also worth noting that the Aruba Central API does not provide you with any access to the Aruba Activate provisioning system (this is a bit of an annoyance to me, but out of my control). This has recently been given a major overhaul and has been migrated to the HPE GreenLake Platform and is now under the GreenLake device management function. There is an API for many GreenLake functions (see also: the HPE Developer Hub), but from what I understand, the platform is presently still migrating the API. I’ll update the post as soon as it’s available. (and did you know that if you have HPE servers, the ILO management subsystem also has a REST API? API ALL THE THINGS!)

Ekahau AP List Report

If you’ve been using Ekahau for a while, you probably already know how painful it can be to generate a list of APs from within a custom report template – and even then, it’s not the most useful thing in the world just for being in Word format.

But here’s some relief: I’ve written a Python script to crack open the data file and generate that report in CSV format (maybe I’ll even update it to spit out native Excel data one of these days).

Caveat: Currently only supports surveyed APs. Stay tuned for a version that will also do planned/simulated APs.

Setting Up An Aruba Wireless Bridge

One of the most underrated features of Aruba wireless hardware is its ability to be used as a wireless bridge. Running a cable to provide power and data to an AP is always the best way, but sometimes you just can’t get one there and have to go wirelessly.

With the release of Instant v 8.4, the concept of a mesh cluster name and key was introduced along with the AP-387 5/60GHz outdoor bridge. This mesh cluster mode lets the APs in the cluster establish their own mesh SSID and encryption, without the brain damage of provisioning those parameters on each device. This also introduced the concept of a standalone Instant AP, which allows you to run a point-to-point bridge or a multipoint mesh without the AP trying to join an existing Instant Virtual Cluster (VC).

Once a bridge is established, it is fully transparent at L2. Anything that shows up on the interface on the Mesh Portal AP will pop out the other side on the Mesh Point’s bridged Ethernet interface. You can optionally prune VLANs if you need to.

Key Terms:

  • WIRELESS MESH : one or more access points that connect to the network wirelessly.
  • MESH PORTAL/MESH ROOT: an access point in a mesh network that is connected to the network via an Ethernet connection. An Aruba AP configured for mesh will determine if it is a portal by listening for traffic on the Ethernet port. a given mesh cluster can have multiple portals.
  • MESH POINT: an access point in a mesh network that is connected to the network via one or more wireless connections to a Mesh Portal. Mesh points can also provide a wireless connection to another mesh point, but you don’t want to go more than one or two hops to a root bridge. If you have to go long distances, a linear mesh topology may be more useful. An Aruba AP will determine it is a mesh point in a cluster by either not seeing traffic on the Ethernet ports, or if the Ethernet port is set to bridging mode and has devices downstream.
  • MESH CLUSTER: A group of Aruba APs that are configured for the same mesh.

What you will need:

  • two Aruba APs that support Instant 8.4 or higher. Update them to the latest 8.10 or 8.7 LTS code trains if you can. I labbed this up on a pair of AP-515s, but the APs don’t necessarily have to be the same model of hardware, just the same software version. The Aruba mesh will operate on 5GHz.
  • A means of powering both APs. This can be PoE, but you’ll want the network on the Mesh Point side of the link to be an isolated Layer 2 segment from the one on the Mesh Portal, otherwise you’ll create a loop when the bridge comes up. It’s generally easiest to put a separate PoE switch on each end, making it easier to connect devices to troubleshoot. If using PoE, make sure it’s sufficient to run the AP.
  • Not strictly necessary, but helpful: A console cable for each AP. The 570 series APs use a standard USB Type C connection and ship with the requisite cable. Otherwise you’ll need either the “Orange Cable” (JY728A AP-CBL-SERU) that has a Micro-B connector on the end (this isn’t actually USB, so don’t even bother trying to use a standard MicroUSB cable), or the older TTL pin header to DB9 cable.

To start, hook up the console cable to the AP, and power it on. When prompted, stop the boot loader. Once at the boot loader prompt, issue the following commands:

factory_reset
setenv standalone_mode 1
setenv uap_controller_less 1
saveenv
boot

This does the following:

  • resets the AP to factory defaults
  • sets the AP to standalone mode (ignores any incoming L2 Instant VC broadcasts and suppresses any outgoing ones)
  • Sets the AP to Controllerless (Instant)
  • Saves the environment variables
  • Boots the AP.

You can also do this from a booted AP on the AOS CLI by issuing the following commands:

write erase all
swarm-mode standalone
reload

Once the AP is booted up into standalone mode, you’ll need to log in via the GUI or the CLI (console or ssh) using the default credentials (admin/admin or admin/serial#), and set a new admin password. Once you’ve done this, you’ll need to create an access SSID to get it out of Instant’s SetMeUp mode. You can disable this later if the AP is not also being used for access (generally not a good idea on a mesh bridge, unless you’re restricting it to the 2.4GHz radio which is unused by the mesh.) If you’re using an AP-387, you don’t need to do this.

Once you’ve created this dummy/temporary SSID (easiest from the Web UI), go to Configuration>System>Show Advanced Settings, disable Extended SSID and reboot.

On the CLI:

conf t
virtual-controller-country US
name Mesh-Portal (or name of your choice)
no extended-ssid
exit
commit apply
reload

virtual-controller-country is vital here. The AP will not do anything on RF until this is set.

Once the AP is back up, configure the mesh:

no mesh-disable
mesh-cluster-name <cluster name> (If doing multiple bridge links, each one must have a unique name)
mesh-cluster-key <cluster-key>
commit apply

If you’re in a multi-VLAN environment, this is also a good time to set VLANs and such. If you’re just running a flat network, skip this part.

uplink-vlan <VLAN ID> (this is the VLAN the AP listens on)

#If configuring a static IP: 
ip-address <ip-address> <subnet-mask> <nexthop-ip-address> <dns-ip-address> <domain-name>

conf t
wired-port-profile Mesh_Portal_Uplink-wpp
 switchport-mode trunk
 allowed-vlan <list of VLANs or "all">
 native-vlan <port Native VLAN>
 trusted
 no shutdown
 type employee
 auth-server InternalServer
 captive-portal disable
 no dot1x
exit

enet0-port-profile Mesh_Portal_Uplink-wpp
enet1-port-profile Mesh_Portal_Uplink-wpp

exit
commit apply

Check the status of the mesh cluster settings with:

show ap mesh cluster status

It should look something like this:

Mesh cluster      :Enabled
Mesh cluster name :Mesh_Lab
Mesh role         :Mesh Portal
Mesh Split5G Band Range :full
Mesh mobility     :Disabled

Now you’ll want to do the same process on the Mesh Point AP, plus the following to enable the bridging (you can also do this in the boot loader by doing setenv enet0_bridging 1 and savenv):

enet0-bridging
commit apply
reload

Once everything is booted back up, give it a few minutes to establish the mesh link, and then run:

show ap mesh link

Which will give you information about the link. the RSSI column is the SNR in dB. You can see from the flags that the link is running an 802.11ax/HE PHY (E), that legacy PHYs are allowed (L), and that it is connected to the mesh portal (K).

# show ap mesh link

Neighbor list
-------------
Radio  MAC                AP Name          Portal  Channel  Age  Hops  Cost  Relation                 Flags  RSSI  Rate Tx/Rx  A-Req  A-Resp  A-Fail  HT-Details    Cluster ID
-----  ---                -------          ------  -------  ---  ----  ----  -----------------        -----  ----  ----------  -----  ------  ------  ----------    ----------
0      aa:bb:cc:dd:ee:ff  Mesh_Lab_Portal  Yes     116E     0    0     4.00  P 22h:18m:57s            ELK    55    1531/1701   1      1       0       HE-80MHz-4ss  29c8af3dec64e7c278bfcbfab07a2a3

Total count: 1, Children: 0
Relation: P = Parent; C = Child; N = Neighbor; B = Blacklisted-neighbor
Flags: R = Recovery-mode; S = Sub-threshold link; D = Reselection backoff; F = Auth-failure; H = High Throughput; V = Very High Throughput, E= High efficient, L = Legacy allowed
        K = Connected; U = Upgrading; G = Descendant-upgrading; Z = Config pending; Y = Assoc-resp/Auth pending
        a = SAE Accepted; b = SAE Blacklisted-neighbour; e = SAE Enabled; u = portal-unreachable; o = opensystem

From this point, you should be able to send traffic across the link, and you’re ready to go install the bridge in its permanent home. If running outdoors, don’t forget to ensure a clear line of sight and unobstructed Fresnel Zone.

ArubaOS 8 API: AP Database

In my previous posts about the ArubaOS API, I’ve given a general framework for pulling data from the AOS Mobility Conductor or a Mobility Controller. Today I’m going to show how to retrieve the AP database and dump it into a CSV file which you can then open in Excel or anything else and work all kinds of magic (yes, I know, Excel is not a database engine, but it still works rather well with tabular data)

The long-form AP database command (show ap database long) provides lots of useful information about the APs in the system:

  • AP Name
  • AP Group
  • AP Model
  • AP IP Address
  • Status (and uptime if it’s up)
  • Flags
  • Switch IP (primary AP Anchor Controller)
  • Standby IP (standby AAC)
  • AP Wired MAC Address
  • AP Serial #
  • Port
  • FQLN
  • Outer IP (Public IP when it is a RAP)
  • User

This script will take the human-readable uptime string (“100d:12h:34m:28s”) and convert that to seconds so uptime can be sorted in your favorite spreadsheet. It will also create a grid of all the AP flags so that you can sort/filter on those after converting the CSV to a data table.

The code is extensively commented so you should be able to follow along. Also available on github.

#!/usr/bin/python3

# ArubaOS 8 AP Database to CSV output via API call
# (c) 2021 Ian Beyer, Aruba Networks <canerdian@hpe.com>
# This code is provided as-is with no warranties. Use at your own risk. 

import requests
import json
import csv
import sys
import warnings
import sys
import xmltodict
import datetime


aosDevice = "1.2.3.4"
username = "admin"
password = "password"
httpsVerify = False

outfile="outputfilename.csv"


#Set things up

if httpsVerify == False :
    warnings.filterwarnings('ignore', message='Unverified HTTPS request')

baseurl = "https://"+aosDevice+":4343/v1/"


headers = {}
payload = ""
cookies = ""

session=requests.Session()
## Log in and get session token

loginparams = {'username': username, 'password' : password}
response = session.get(baseurl+"api/login", params = loginparams, headers=headers, data=payload, verify = httpsVerify)
jsonData = response.json()['_global_result']

if response.status_code == 200 :

    #print(jsonData['status_str'])
    sessionToken = jsonData['UIDARUBA']

else :
    sys.exit("Login Failed")

reqParams = {'UIDARUBA':sessionToken}

def showCmd(command, datatype):
    showParams = {
        'command' : 'show '+command,
        'UIDARUBA':sessionToken
            }
    response = session.get(baseurl+"configuration/showcommand", params = showParams, headers=headers, data=payload, verify = httpsVerify)
 
    if datatype == 'JSON' :
        #Returns JSON
        returnData=response.json()
    elif datatype == 'XML' :
        # Returns XML as a dict
        returnData = xmltodict.parse(response.content)['my_xml_tag3xxx']
    elif datatype == 'Text' :
        # Returns an array
        returnData =response.json()['_data']
    return returnData

apdb=showCmd('ap database long', 'JSON')

# This is the list of status flags in 'show ap database long'

apflags=['1','1+','1-','2','B','C','D','E','F','G','I','J','L','M','N','P','R','R-','S','U','X','Y','c','e','f','i','o','s','u','z','p','4']

# Create file handle and open for write. 
with open(outfile, 'w') as csvfile:
 write=csv.writer(csvfile)
 
 # Get list of data fields from the returned list
 fields=apdb['_meta']
 
 # Add new fields for parsed Data
 fields.insert(5,"Uptime")
 fields.insert(6,"Uptime_Seconds")
 
 # Add fields for expanding flags
 for flag in apflags:
  fields.append("Flag_"+flag)
 write.writerow(fields)
 
 # Iterate through the list of APs
 for ap in apdb["AP Database"]:
 
   # Parse Status field into status, uptime, and uptime in seconds
   utseconds=0
   ap['Uptime']=""
   ap['Uptime_Seconds']=""
   
   # Split the status field on a space - if anything other than "Up", it will only contain one element, first element is status description. 
   status=ap['Status'].split(' ')
   ap['Status']=status[0]

   # Additional processing of the status field if the AP is up as it will report uptime in human-readable form in the second half of the Status field we just split
   if len(status)>1:
    ap['Uptime']=status[1]

    #Split the Uptime field into each time field and strip off the training character, multiply by the requisite number of seconds an tally it up. 
    timefields=status[1].split(':')
    # If by some stroke of luck you have an AP that's been up for over a year, you might have to add a row here - I haven't seen how it presents it in that case
    if len(timefields)>3 :
        days=int(timefields.pop(0)[0:-1])
        utseconds+=days*86400
    if len(timefields)>2 :
        hours=int(timefields.pop(0)[0:-1])
        utseconds+=hours*3600
    if len(timefields)>1 :
        minutes=int(timefields.pop(0)[0:-1])
        utseconds+=minutes*60
    if len(timefields)>0 :
        seconds=int(timefields.pop(0)[0:-1])
        utseconds+=seconds
    ap['Uptime_Seconds']=utseconds

   # FUN WITH FLAGS
   # Bust apart the flags into their own fields 
   for flag in apflags:

    # Set field to None so that it exists in the dict
    ap["Flag_"+flag]=None
    
    # Check to see if the flags field contains data
    if ap['Flags'] != None :

     # Iterate through the list of possible flags and mark that field with an X if present
     if flag in ap['Flags'] :
      ap["Flag_"+flag]="X"
   
   # Start assembling the row to write out to the CSV, and maintain order and tranquility. 
   datarow=[]

   # Iterate through the list of fields used to create the header row and append each one
   for f in fields:
    datarow.append(ap[f])

   # Put it in the CSV 
   write.writerow(datarow)

   #Move on to the next AP

# Close the file handle
csvfile.close()

## Log out and remove session

response = session.get(baseurl+"api/logout", verify=False)
jsonData = response.json()['_global_result']

if response.status_code == 200 :

    #remove 
    token = jsonData['UIDARUBA']
    del sessionToken

else :
    del sessionToken
    sys.exit("Logout failed:")

The human-readable output of the show ap database gives you a list of what the flags are, but the API call does not, so in case you want a handy reference, here it is in JSON format so that you can easily adapt it. (Github)

sheldon={
'1':'802.1x authenticated AP use EAP-PEAP',
'1+':'802.1x use EST',
'1-':'802.1x use factory cert',
'2':'Using IKE version 2',
'B':'Built-in AP',
'C':'Cellular RAP',
'D':'Dirty or no config',
'E':'Regulatory Domain Mismatch',
'F':'AP failed 802.1x authentication',
'G':'No such group',
'I':'Inactive',
'J':'USB cert at AP',
'L':'Unlicensed',
'M':'Mesh node',
'N':'Duplicate name',
'P':'PPPoe AP',
'R':'Remote AP',
'R-':'Remote AP requires Auth',
'S':'Standby-mode AP',
'U':'Unprovisioned',
'X':'Maintenance Mode',
'Y':'Mesh Recovery',
'c':'CERT-based RAP',
'e':'Custom EST cert',
'f':'No Spectrum FFT support',
'i':'Indoor',
'o':'Outdoor',
's':'LACP striping',
'u':'Custom-Cert RAP',
'z':'Datazone AP',
'p':'In deep-sleep status',
'4':'WiFi Uplink'
}

Working with the ArubaOS API: Reading Data

Another quick bit today – this is the basic framework for using the REST API in ArubaOS. Lots of info at the Aruba Developer Hub. This is primarily for executing show commands and getting the data back in a structured JSON format.

However, be aware that not all show commands return structured JSON – some will return something vaguely XMLish, and some will return the regular text output inside a JSON wrapper (originally the showcommand API endpoint was just a wrapper for the actual commands and would just return the CLI output, as it still does for several commands)

You can always go to https://<controller IP>:4343/api (after logging in) and get a Swagger doc for all the available API calls – although owing to system limitations, the description of those endpoints isn’t generally there, but it can be found in the full AOS8 API reference.

This blog entry does not deal with sending data to the ArubaOS device.

#!/usr/bin/python3

import requests
import json
import warnings
import sys
import xmltodict


aosDevice = "1.2.3.4"
username = "admin"
password = "password"
httpsVerify = False



#Set things up

if httpsVerify == False :
	warnings.filterwarnings('ignore', message='Unverified HTTPS request')

baseurl = "https://"+aosDevice+":4343/v1/"


headers = {}
payload = ""
cookies = ""

session=requests.Session()
## Log in and get session token

loginparams = {'username': username, 'password' : password}
response = session.get(baseurl+"api/login", params = loginparams, headers=headers, data=payload, verify = httpsVerify)
jsonData = response.json()['_global_result']

if response.status_code == 200 :

	#print(jsonData['status_str'])
	sessionToken = jsonData['UIDARUBA']

#	print(sessionToken)
else :
	sys.exit("Login Failed")

reqParams = {'UIDARUBA':sessionToken}

def showCmd(command, datatype):
	showParams = {
		'command' : 'show '+command,
		'UIDARUBA':sessionToken
			}
	response = session.get(baseurl+"configuration/showcommand", params = showParams, headers=headers, data=payload, verify = httpsVerify)
	#print(response.url)
	#print(response.text)
	if datatype == 'JSON' :
		#Returns JSON
		returnData=response.json()
	elif datatype == 'XML' :
		# Returns XML as a dict
		print(response.content)
		returnData = xmltodict.parse(response.content)['my_xml_tag3xxx']
	elif datatype == 'Text' :
		# Returns an array
		returnData =response.json()['_data']
	return returnData




print(showCmd('clock', 'Text')[0])


print(json.dumps(showCmd('dds debug peers', 'JSON'),indent=2, sort_keys=False))



## Log out and remove session


response = session.get(baseurl+"api/logout", verify=False)
jsonData = response.json()['_global_result']

if response.status_code == 200 :

	#remove 
	token = jsonData['UIDARUBA']
	del sessionToken
	#print("Logout successful. Token deleted.")
else :
	del sessionToken
	sys.exit("Logout failed:")

If you prefer, I have shared a Postman collection for working with the basics.