Skip to content

Instantly share code, notes, and snippets.

@upa
Last active July 9, 2020 11:46
Show Gist options
  • Save upa/5f73eb06fc58834114147522698e6a49 to your computer and use it in GitHub Desktop.
Save upa/5f73eb06fc58834114147522698e6a49 to your computer and use it in GitHub Desktop.

nassoc.py

This script retrieves number of associated clients to APs from Cisco WLC via SNMP.

How to use

$ sudo apt install python3
or
$ sudo yum install python3


$ git clone https://gist.github.com/upa/5f73eb06fc58834114147522698e6a49 nassoc
$ cd nassoc

$ ./nassoc.py -h
usage: nassoc.py [-h] -c COMMUNITY [-v {1,2c}] [-t TIMEOUT] [-j] target

retrieve number of clients per AP from WLC

positional arguments:
  target                SNMP walk target

optional arguments:
  -h, --help            show this help message and exit
  -c COMMUNITY, --community COMMUNITY
                        community
  -v {1,2c}, --version {1,2c}
                        snmp version, default 2c
  -t TIMEOUT, --timeout TIMEOUT
                        timeout
  -j, --json            output in JSON format

$ ./nassoc -c public -v 2c 192.168.0.1
ap-1-1 (location 1): 0
ap-1-2 (location 1): 0
ap-2-1 (location 2): 1
ap-5-1 (location 5): 0

... snipped ...

#!/usr/bin/env python3
import json
import argparse
import subprocess
"""nassoc.py
This script retrieves wlan clients per AP from a WLC via SNMP.
snmpwalk must be installed, and PATH execluting this script
must contain the path to snmpwalk.
It uses following OIDs:
- 1.3.6.1.4.1.9.9.513.1.1.1.1.5 cLApName
- 1.3.6.1.4.1.9.9.513.1.1.1.1.54 cLApAssociatedClientCount
- 1.3.6.1.4.1.9.9.513.1.1.1.1.49 cLApLocation
These object return values with associating OIDs like
".1.3.6.1.4.1.9.9.513.1.1.1.1.49.204.213.57.137.43.144". 6 octets at
the end of the OID indicates an AP (but I don't know what the octets
mean). I need more investigation on Csico SNMP Object Navigator.
https://snmp.cloudapps.cisco.com/Support/SNMP/do/BrowseOID.do?local=en&translate=Translate&objectInput=1.3.6.1.4.1.9.9.513.1.1.1.1.54#oidContent
"""
class AP(object):
def __init__(self, name = None, location = None, nclients = 0):
self.name = name
self.location = location
self.nclients = nclients
def todict(self):
return {
"name": self.name,
"location": self.location,
"nclients": self.nclients,
}
def run_snmpwalk(target, version, community, oid, timeout = 10):
cmd = [ "snmpwalk", "-On", "-v", version, "-c", community, target, oid ]
out = subprocess.check_output(cmd, timeout = timeout).decode()
# OIDs this script uses is generated for associating APs ondemend.
# Thus, if the target WLC has no associated AP, this message returns.
if "No Such Instance currently exists at this OID" in out:
raise RuntimeError("No Such Instance currently exists at " + oid)
return out.strip().split("\n")
def obtain_octs_and_value(line):
"""
parse an output line from snmpwalk. This returns 6 cotets
identifier and value
"""
oid, eq, t, value = line.strip().split(" ")
s = oid.split(".")
apid = ".".join(s[len(s) - 6:])
# string are enclosed by "". remove it.
if value[0] == '"':
value = value.replace('"', '')
return apid, value
def main():
desc = "retrieve number of clients per AP from WLC"
parser = argparse.ArgumentParser(description = desc)
parser.add_argument("-c", "--community", required = True,
help = "community")
parser.add_argument("-v", "--version", default = "2c",
choices = [ "1", "2c" ],
help = "snmp version, default 2c")
parser.add_argument("-t", "--timeout", type = int, default = 5,
help = "timeout")
parser.add_argument("-j", "--json", action = "store_true", default = False,
help = "output in JSON format")
parser.add_argument("target",
help = "SNMP walk target")
args = parser.parse_args()
aps = {} # { "6oct id": AP, "6oct id": AP, ... }
# 1. obtain AP names and make AP instances
lines = run_snmpwalk(args.target, args.version, args.community,
"1.3.6.1.4.1.9.9.513.1.1.1.1.5",
timeout = args.timeout)
for line in lines:
apid, name = obtain_octs_and_value(line)
aps[apid] = AP(name = name)
# 2. obtain number of associated clients
lines = run_snmpwalk(args.target, args.version, args.community,
"1.3.6.1.4.1.9.9.513.1.1.1.1.54",
timeout = args.timeout)
for line in lines:
apid, nclients = obtain_octs_and_value(line)
aps[apid].nclients = int(nclients)
# 3. obtain AP locations
lines = run_snmpwalk(args.target, args.version, args.community,
"1.3.6.1.4.1.9.9.513.1.1.1.1.49",
timeout = args.timeout)
for line in lines:
apid, location = obtain_octs_and_value(line)
aps[apid].location = location
# print in JSON format
if args.json:
l = []
for v in aps.values():
l.append(v.todict())
print(json.dumps(l, indent = 4))
return
# print in a simple way
for ap in sorted(aps.values(), key = lambda ap: ap.name):
print("{} ({}): {}".format(ap.name, ap.location, ap.nclients))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment