Merge pull request #364 from LibreQoE/uispAirmax

Correct AirMax and LTU Capacities
This commit is contained in:
Robert Chacón 2023-06-02 12:19:22 -06:00 committed by GitHub
commit 099494e729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 38 deletions

View File

@ -10,6 +10,14 @@ try:
except: except:
from ispConfig import uispSite, uispStrategy from ispConfig import uispSite, uispStrategy
overwriteNetworkJSONalways = False overwriteNetworkJSONalways = False
try:
from ispConfig import airMax_capacity
except:
airMax_capacity = 0.65
try:
from ispConfig import ltu_capacity
except:
ltu_capacity = 0.90
def uispRequest(target): def uispRequest(target):
# Sends an HTTP request to UISP and returns the # Sends an HTTP request to UISP and returns the
@ -136,17 +144,46 @@ def findApCapacities(devices, siteBandwidth):
download = int(device['overview'] download = int(device['overview']
['downlinkCapacity'] / 1000000) ['downlinkCapacity'] / 1000000)
upload = int(device['overview']['uplinkCapacity'] / 1000000) upload = int(device['overview']['uplinkCapacity'] / 1000000)
if (download < 15) or (upload < 15): dlRatio = None
print("WARNING: Device '" + device['identification']['hostname'] + "' has unusually low capacity (" + str(download) + '/' + str(upload) + " Mbps). Discarding in favor of parent site rates.") if device['identification']['type'] == 'airMax':
safeToUse = False download, upload = airMaxCapacityCorrection(device, download, upload)
elif device['identification']['model'] == 'LTU-Rocket':
download = download * ltu_capacity
upload = upload * ltu_capacity
if device['identification']['model'] == 'WaveAP': if device['identification']['model'] == 'WaveAP':
if (download < 500) or (upload < 500): if (download < 500) or (upload < 500):
download = 2450 download = 2450
upload = 2450 upload = 2450
if (download < 15) or (upload < 15):
print("WARNING: Device '" + device['identification']['hostname'] + "' has unusually low capacity (" + str(download) + '/' + str(upload) + " Mbps). Discarding in favor of parent site rates.")
safeToUse = False
if safeToUse: if safeToUse:
siteBandwidth[device['identification']['name']] = { siteBandwidth[device['identification']['name']] = {
"download": download, "upload": upload} "download": download, "upload": upload}
def airMaxCapacityCorrection(device, download, upload):
dlRatio = None
for interface in device['interfaces']:
if ('wireless' in interface) and (interface['wireless'] != None):
if 'dlRatio' in interface['wireless']:
dlRatio = interface['wireless']['dlRatio']
# UISP reports unrealistically high capacities for airMax.
# For fixed frame, multiply capacity by the ratio for download/upload.
# For Flexible Frame, use 65% of reported capcity.
# 67/33
if dlRatio == 67:
download = download * 0.67
upload = upload * 0.33
# 50/50
elif dlRatio == 50:
download = download * 0.50
upload = upload * 0.50
# Flexible frame
elif dlRatio == None:
download = download * airMax_capacity
upload = upload * airMax_capacity
return (download, upload)
def findAirfibers(devices, generatedPNDownloadMbps, generatedPNUploadMbps): def findAirfibers(devices, generatedPNDownloadMbps, generatedPNUploadMbps):
foundAirFibersBySite = {} foundAirFibersBySite = {}
for device in devices: for device in devices:
@ -155,19 +192,25 @@ def findAirfibers(devices, generatedPNDownloadMbps, generatedPNUploadMbps):
if device['identification']['type'] == "airFiber" or device['identification']['type'] == "airMax": if device['identification']['type'] == "airFiber" or device['identification']['type'] == "airMax":
if device['overview']['status'] == 'active': if device['overview']['status'] == 'active':
if device['overview']['downlinkCapacity'] is not None and device['overview']['uplinkCapacity'] is not None: if device['overview']['downlinkCapacity'] is not None and device['overview']['uplinkCapacity'] is not None:
download = int(device['overview']['downlinkCapacity']/ 1000000) # Exclude PtMP LTU clients
upload = int(device['overview']['uplinkCapacity']/ 1000000) excludedAsPtMP = ['LTU-LR', 'LTU-PRO', 'LTU-LITE']
# Make sure to factor in gigabit port for AF60/AF60-LRs if (device['identification']['model'] not in excludedAsPtMP):
if (device['identification']['model'] == "AF60-LR") or (device['identification']['model'] == "AF60"): download = int(device['overview']['downlinkCapacity']/ 1000000)
download = min(download,950) upload = int(device['overview']['uplinkCapacity']/ 1000000)
upload = min(upload,950) # Correct AirMax Capacities
if device['identification']['site']['id'] in foundAirFibersBySite: if device['identification']['type'] == 'airMax':
if (download > foundAirFibersBySite[device['identification']['site']['id']]['download']) or (upload > foundAirFibersBySite[device['identification']['site']['id']]['upload']): download, upload = airMaxCapacityCorrection(device, download, upload)
foundAirFibersBySite[device['identification']['site']['id']]['download'] = download # Make sure to factor in gigabit port for AF60/AF60-LRs
foundAirFibersBySite[device['identification']['site']['id']]['upload'] = upload if (device['identification']['model'] == "AF60-LR") or (device['identification']['model'] == "AF60"):
#print(device['identification']['name'] + ' will override bandwidth for site ' + device['identification']['site']['name']) download = min(download,950)
else: upload = min(upload,950)
foundAirFibersBySite[device['identification']['site']['id']] = {'download': download, 'upload': upload} if device['identification']['site']['id'] in foundAirFibersBySite:
if (download > foundAirFibersBySite[device['identification']['site']['id']]['download']) or (upload > foundAirFibersBySite[device['identification']['site']['id']]['upload']):
foundAirFibersBySite[device['identification']['site']['id']]['download'] = download
foundAirFibersBySite[device['identification']['site']['id']]['upload'] = upload
#print(device['identification']['name'] + ' will override bandwidth for site ' + device['identification']['site']['name'])
else:
foundAirFibersBySite[device['identification']['site']['id']] = {'download': download, 'upload': upload}
return foundAirFibersBySite return foundAirFibersBySite
def buildSiteList(sites, dataLinks): def buildSiteList(sites, dataLinks):
@ -257,28 +300,35 @@ def findNodesBranchedOffPtMP(siteList, dataLinks, sites, rootSite, foundAirFiber
if id not in foundAirFibersBySite: if id not in foundAirFibersBySite:
trueParent = findInSiteListById(siteList, id)['parent'] trueParent = findInSiteListById(siteList, id)['parent']
#parent = findInSiteListById(siteList, id)['parent'] #parent = findInSiteListById(siteList, id)['parent']
if site['parent'] is not None: isTrueSite = False
parent = site['parent'] for siteItem in sites:
for link in dataLinks: if siteItem['identification']['id'] == id:
if (link['to']['site'] is not None) and (link['to']['site']['identification'] is not None): if siteItem['identification']['type'] == 'site':
if ('identification' in link['to']['site']) and (link['to']['site']['identification'] is not None): isTrueSite = True
if ('identification' in link['from']['site']) and (link['from']['site']['identification'] is not None): if isTrueSite:
# Respect parent defined by topology and overrides if site['parent'] is not None:
if link['from']['site']['identification']['id'] == trueParent: parent = site['parent']
if link['to']['site']['identification']['id'] == id: for link in dataLinks:
if link['from']['device']['overview']['wirelessMode'] == 'ap-ptmp': if (link['to']['site'] is not None) and (link['to']['site']['identification'] is not None):
if 'overview' in link['to']['device']: if ('identification' in link['to']['site']) and (link['to']['site']['identification'] is not None):
if ('downlinkCapacity' in link['to']['device']['overview']) and ('uplinkCapacity' in link['to']['device']['overview']): if ('identification' in link['from']['site']) and (link['from']['site']['identification'] is not None):
if (link['to']['device']['overview']['downlinkCapacity'] is not None) and (link['to']['device']['overview']['uplinkCapacity'] is not None): # Respect parent defined by topology and overrides
# Capacity of the PtMP client radio feeding the PoP will be used as the site bandwidth limit if link['from']['site']['identification']['id'] == trueParent:
download = int(round(link['to']['device']['overview']['downlinkCapacity']/1000000)) if link['to']['site']['identification']['id'] == id:
upload = int(round(link['to']['device']['overview']['uplinkCapacity']/1000000)) if link['from']['device']['overview']['wirelessMode'] == 'ap-ptmp':
nodeOffPtMP[id] = {'download': download, if 'overview' in link['to']['device']:
'upload': upload if ('downlinkCapacity' in link['to']['device']['overview']) and ('uplinkCapacity' in link['to']['device']['overview']):
} if (link['to']['device']['overview']['downlinkCapacity'] is not None) and (link['to']['device']['overview']['uplinkCapacity'] is not None):
site['parent'] = parent apID = link['from']['device']['identification']['id']
if site['type'] == 'site': # Capacity of the PtMP client radio feeding the PoP will be used as the site bandwidth limit
print('Site ' + name + ' will use PtMP AP as parent.') download = int(round(link['to']['device']['overview']['downlinkCapacity']/1000000))
upload = int(round(link['to']['device']['overview']['uplinkCapacity']/1000000))
nodeOffPtMP[id] = {'download': download,
'upload': upload,
parent: apID
}
site['parent'] = apID
#print('Site ' + name + ' will use PtMP AP as parent.')
return siteList, nodeOffPtMP return siteList, nodeOffPtMP
def handleMultipleInternetNodes(sites, dataLinks, uispSite): def handleMultipleInternetNodes(sites, dataLinks, uispSite):
@ -384,6 +434,7 @@ def buildFullGraph():
if (nodeOffPtMP[id]['download'] >= download) or (nodeOffPtMP[id]['upload'] >= upload): if (nodeOffPtMP[id]['download'] >= download) or (nodeOffPtMP[id]['upload'] >= upload):
download = nodeOffPtMP[id]['download'] download = nodeOffPtMP[id]['download']
upload = nodeOffPtMP[id]['upload'] upload = nodeOffPtMP[id]['upload']
#parent = nodeOffPtMP[id]['parent']
siteBandwidth[name] = { siteBandwidth[name] = {
"download": download, "upload": upload} "download": download, "upload": upload}

View File

@ -97,6 +97,10 @@ uispSite = ''
# or site options. # or site options.
# * "full" - build a complete network map # * "full" - build a complete network map
uispStrategy = "full" uispStrategy = "full"
# Assumed capacity of AirMax and LTU radios vs reported capacity by UISP. For example, 65% would be 0.65.
# For AirMax, this applies to flexible frame only. AirMax fixed frame will have capacity based on ratio.
airMax_capacity = 0.65
ltu_capacity = 0.90
# List any sites that should not be included, with each site name surrounded by '' and separated by commas # List any sites that should not be included, with each site name surrounded by '' and separated by commas
excludeSites = [] excludeSites = []
# If you use IPv6, this can be used to find associated IPv6 prefixes for your clients' IPv4 addresses, and match them # If you use IPv6, this can be used to find associated IPv6 prefixes for your clients' IPv4 addresses, and match them