From 8ea5d4bdbca69e5744182480e6dfe2207fc4568c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 11:04:56 -0600 Subject: [PATCH 1/6] Update integrationUISP.py --- src/integrationUISP.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/integrationUISP.py b/src/integrationUISP.py index 84438904..d88270ef 100644 --- a/src/integrationUISP.py +++ b/src/integrationUISP.py @@ -10,6 +10,10 @@ try: except: from ispConfig import uispSite, uispStrategy overwriteNetworkJSONalways = False +try: + from ispConfig import airMax_capacity +except: + airMax_capacity = 0.65 def uispRequest(target): # Sends an HTTP request to UISP and returns the @@ -136,6 +140,9 @@ def findApCapacities(devices, siteBandwidth): download = int(device['overview'] ['downlinkCapacity'] / 1000000) upload = int(device['overview']['uplinkCapacity'] / 1000000) + dlRatio = None + if device['identification']['type'] == 'airMax': + download, upload = airMaxCapacityCorrection(device, download, upload) 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 @@ -147,6 +154,29 @@ def findApCapacities(devices, siteBandwidth): siteBandwidth[device['identification']['name']] = { "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): foundAirFibersBySite = {} for device in devices: @@ -157,6 +187,9 @@ def findAirfibers(devices, generatedPNDownloadMbps, generatedPNUploadMbps): if device['overview']['downlinkCapacity'] is not None and device['overview']['uplinkCapacity'] is not None: download = int(device['overview']['downlinkCapacity']/ 1000000) upload = int(device['overview']['uplinkCapacity']/ 1000000) + # Correct AirMax Capacities + if device['identification']['type'] == 'airMax': + download, upload = airMaxCapacityCorrection(device, download, upload) # Make sure to factor in gigabit port for AF60/AF60-LRs if (device['identification']['model'] == "AF60-LR") or (device['identification']['model'] == "AF60"): download = min(download,950) From b6fd808a59130342ebd649cadd86ea81e23f29f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 11:07:21 -0600 Subject: [PATCH 2/6] Update ispConfig.example.py --- src/ispConfig.example.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ispConfig.example.py b/src/ispConfig.example.py index 5f1ae008..eff5aa4f 100644 --- a/src/ispConfig.example.py +++ b/src/ispConfig.example.py @@ -97,6 +97,9 @@ uispSite = '' # or site options. # * "full" - build a complete network map uispStrategy = "full" +# Assumed capacity of airMax radios vs reported capacity by UISP. For example, 65% would be 0.65 +# Applies to flexible frame only. Fixed frame will have capacity based on its ratio. +airMax_capacity = 0.65 # List any sites that should not be included, with each site name surrounded by '' and separated by commas excludeSites = [] # If you use IPv6, this can be used to find associated IPv6 prefixes for your clients' IPv4 addresses, and match them From bd4c14f31be75151f9ef0fb961d25c0b161096a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 11:24:20 -0600 Subject: [PATCH 3/6] Update integrationUISP.py --- src/integrationUISP.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/integrationUISP.py b/src/integrationUISP.py index d88270ef..2db049dd 100644 --- a/src/integrationUISP.py +++ b/src/integrationUISP.py @@ -14,6 +14,10 @@ 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): # Sends an HTTP request to UISP and returns the @@ -143,13 +147,16 @@ def findApCapacities(devices, siteBandwidth): dlRatio = None if device['identification']['type'] == 'airMax': download, upload = airMaxCapacityCorrection(device, download, upload) - 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 + elif device['identification']['model'] == 'LTU-Rocket': + download = download * ltu_capacity + upload = upload * ltu_capacity if device['identification']['model'] == 'WaveAP': if (download < 500) or (upload < 500): download = 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: siteBandwidth[device['identification']['name']] = { "download": download, "upload": upload} From 7f2a772e1cdc4d5caa58c119da3f08824829921e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 11:25:08 -0600 Subject: [PATCH 4/6] Update ispConfig.example.py --- src/ispConfig.example.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ispConfig.example.py b/src/ispConfig.example.py index eff5aa4f..fb96b101 100644 --- a/src/ispConfig.example.py +++ b/src/ispConfig.example.py @@ -97,9 +97,10 @@ uispSite = '' # or site options. # * "full" - build a complete network map uispStrategy = "full" -# Assumed capacity of airMax radios vs reported capacity by UISP. For example, 65% would be 0.65 -# Applies to flexible frame only. Fixed frame will have capacity based on its ratio. +# 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 excludeSites = [] # If you use IPv6, this can be used to find associated IPv6 prefixes for your clients' IPv4 addresses, and match them From 933a4b66ff7e1f888a1d632b71aad7a012f11062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 12:01:33 -0600 Subject: [PATCH 5/6] Update integrationUISP.py --- src/integrationUISP.py | 84 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/src/integrationUISP.py b/src/integrationUISP.py index 2db049dd..d36e2ac2 100644 --- a/src/integrationUISP.py +++ b/src/integrationUISP.py @@ -192,22 +192,25 @@ def findAirfibers(devices, generatedPNDownloadMbps, generatedPNUploadMbps): if device['identification']['type'] == "airFiber" or device['identification']['type'] == "airMax": if device['overview']['status'] == 'active': if device['overview']['downlinkCapacity'] is not None and device['overview']['uplinkCapacity'] is not None: - download = int(device['overview']['downlinkCapacity']/ 1000000) - upload = int(device['overview']['uplinkCapacity']/ 1000000) - # Correct AirMax Capacities - if device['identification']['type'] == 'airMax': - download, upload = airMaxCapacityCorrection(device, download, upload) - # Make sure to factor in gigabit port for AF60/AF60-LRs - if (device['identification']['model'] == "AF60-LR") or (device['identification']['model'] == "AF60"): - download = min(download,950) - upload = min(upload,950) - 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} + # Exclude PtMP LTU clients + excludedAsPtMP = ['LTU-LR', 'LTU-PRO', 'LTU-LITE'] + if (device['identification']['model'] not in excludedAsPtMP): + download = int(device['overview']['downlinkCapacity']/ 1000000) + upload = int(device['overview']['uplinkCapacity']/ 1000000) + # Correct AirMax Capacities + if device['identification']['type'] == 'airMax': + download, upload = airMaxCapacityCorrection(device, download, upload) + # Make sure to factor in gigabit port for AF60/AF60-LRs + if (device['identification']['model'] == "AF60-LR") or (device['identification']['model'] == "AF60"): + download = min(download,950) + upload = min(upload,950) + 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 def buildSiteList(sites, dataLinks): @@ -297,27 +300,34 @@ def findNodesBranchedOffPtMP(siteList, dataLinks, sites, rootSite, foundAirFiber if id not in foundAirFibersBySite: trueParent = findInSiteListById(siteList, id)['parent'] #parent = findInSiteListById(siteList, id)['parent'] - if site['parent'] is not None: - parent = site['parent'] - for link in dataLinks: - if (link['to']['site'] is not None) and (link['to']['site']['identification'] is not None): - if ('identification' in link['to']['site']) and (link['to']['site']['identification'] is not None): - if ('identification' in link['from']['site']) and (link['from']['site']['identification'] is not None): - # Respect parent defined by topology and overrides - if link['from']['site']['identification']['id'] == trueParent: - if link['to']['site']['identification']['id'] == id: - if link['from']['device']['overview']['wirelessMode'] == 'ap-ptmp': - if 'overview' in link['to']['device']: - 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): - # Capacity of the PtMP client radio feeding the PoP will be used as the site bandwidth limit - download = int(round(link['to']['device']['overview']['downlinkCapacity']/1000000)) - upload = int(round(link['to']['device']['overview']['uplinkCapacity']/1000000)) - nodeOffPtMP[id] = {'download': download, - 'upload': upload - } - site['parent'] = parent - if site['type'] == 'site': + isTrueSite = False + for siteItem in sites: + if siteItem['identification']['id'] == id: + if siteItem['identification']['type'] == 'site': + isTrueSite = True + if isTrueSite: + if site['parent'] is not None: + parent = site['parent'] + for link in dataLinks: + if (link['to']['site'] is not None) and (link['to']['site']['identification'] is not None): + if ('identification' in link['to']['site']) and (link['to']['site']['identification'] is not None): + if ('identification' in link['from']['site']) and (link['from']['site']['identification'] is not None): + # Respect parent defined by topology and overrides + if link['from']['site']['identification']['id'] == trueParent: + if link['to']['site']['identification']['id'] == id: + if link['from']['device']['overview']['wirelessMode'] == 'ap-ptmp': + if 'overview' in link['to']['device']: + 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): + + # Capacity of the PtMP client radio feeding the PoP will be used as the site bandwidth limit + download = int(round(link['to']['device']['overview']['downlinkCapacity']/1000000)) + upload = int(round(link['to']['device']['overview']['uplinkCapacity']/1000000)) + nodeOffPtMP[id] = {'download': download, + 'upload': upload + } + site['parent'] = parent + print('Site ' + name + ' will use PtMP AP as parent.') return siteList, nodeOffPtMP From 4aaa0ce90afda8185adab7c07b2abe2a448b11b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Chac=C3=B3n?= Date: Fri, 2 Jun 2023 12:18:22 -0600 Subject: [PATCH 6/6] Update integrationUISP.py --- src/integrationUISP.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/integrationUISP.py b/src/integrationUISP.py index d36e2ac2..5206f8ee 100644 --- a/src/integrationUISP.py +++ b/src/integrationUISP.py @@ -319,16 +319,16 @@ def findNodesBranchedOffPtMP(siteList, dataLinks, sites, rootSite, foundAirFiber if 'overview' in link['to']['device']: 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): - + apID = link['from']['device']['identification']['id'] # Capacity of the PtMP client radio feeding the PoP will be used as the site bandwidth limit download = int(round(link['to']['device']['overview']['downlinkCapacity']/1000000)) upload = int(round(link['to']['device']['overview']['uplinkCapacity']/1000000)) nodeOffPtMP[id] = {'download': download, - 'upload': upload + 'upload': upload, + parent: apID } - site['parent'] = parent - - print('Site ' + name + ' will use PtMP AP as parent.') + site['parent'] = apID + #print('Site ' + name + ' will use PtMP AP as parent.') return siteList, nodeOffPtMP def handleMultipleInternetNodes(sites, dataLinks, uispSite): @@ -434,6 +434,7 @@ def buildFullGraph(): if (nodeOffPtMP[id]['download'] >= download) or (nodeOffPtMP[id]['upload'] >= upload): download = nodeOffPtMP[id]['download'] upload = nodeOffPtMP[id]['upload'] + #parent = nodeOffPtMP[id]['parent'] siteBandwidth[name] = { "download": download, "upload": upload}