Add monitorOnlyMode. Note: only latency is tracked in monitorOnlyMode

This commit is contained in:
Robert Chacón 2022-11-11 08:27:02 -07:00 committed by GitHub
parent c9e07e33a8
commit afcf7c8b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,5 +1,4 @@
#!/usr/bin/python3 #!/usr/bin/python3
#!/usr/bin/python3
# v1.3 # v1.3
import csv import csv
@ -20,7 +19,7 @@ import shutil
import binpacking import binpacking
from ispConfig import fqOrCAKE, upstreamBandwidthCapacityDownloadMbps, upstreamBandwidthCapacityUploadMbps, \ from ispConfig import fqOrCAKE, upstreamBandwidthCapacityDownloadMbps, upstreamBandwidthCapacityUploadMbps, \
interfaceA, interfaceB, enableActualShellCommands, useBinPackingToBalanceCPU, \ interfaceA, interfaceB, enableActualShellCommands, useBinPackingToBalanceCPU, monitorOnlyMode, \
runShellCommandsAsSudo, generatedPNDownloadMbps, generatedPNUploadMbps, queuesAvailableOverride runShellCommandsAsSudo, generatedPNDownloadMbps, generatedPNUploadMbps, queuesAvailableOverride
# Automatically account for TCP overhead of plans. For example a 100Mbps plan needs to be set to 109Mbps for the user to ever see that result on a speed test # Automatically account for TCP overhead of plans. For example a 100Mbps plan needs to be set to 109Mbps for the user to ever see that result on a speed test
@ -265,6 +264,12 @@ def loadSubscriberCircuits(shapedDevicesFile):
commentsRemoved.pop(0) commentsRemoved.pop(0)
for row in commentsRemoved: for row in commentsRemoved:
circuitID, circuitName, deviceID, deviceName, ParentNode, mac, ipv4_input, ipv6_input, downloadMin, uploadMin, downloadMax, uploadMax, comment = row circuitID, circuitName, deviceID, deviceName, ParentNode, mac, ipv4_input, ipv6_input, downloadMin, uploadMin, downloadMax, uploadMax, comment = row
# If in monitorOnlyMode, override bandwidth rates to where no shaping will actually occur
if monitorOnlyMode == True:
downloadMin = 10000
uploadMin = 10000
downloadMax = 10000
uploadMax = 10000
ipv4_subnets_and_hosts = [] ipv4_subnets_and_hosts = []
# Each entry in ShapedDevices.csv can have multiple IPv4s or IPv6s seperated by commas. Split them up and parse each # Each entry in ShapedDevices.csv can have multiple IPv4s or IPv6s seperated by commas. Split them up and parse each
if ipv4_input != "": if ipv4_input != "":
@ -294,6 +299,8 @@ def loadSubscriberCircuits(shapedDevicesFile):
if circuit['ParentNode'] != ParentNode: if circuit['ParentNode'] != ParentNode:
errorMessageString = "Device " + deviceName + " with deviceID " + deviceID + " had different Parent Node from other devices of circuit ID #" + circuitID errorMessageString = "Device " + deviceName + " with deviceID " + deviceID + " had different Parent Node from other devices of circuit ID #" + circuitID
raise ValueError(errorMessageString) raise ValueError(errorMessageString)
# Check if bandwidth parameters match other cdevices of this same circuit ID, but only check if monitorOnlyMode is Off
if monitorOnlyMode == False:
if ((circuit['minDownload'] != round(int(downloadMin)*tcpOverheadFactor)) if ((circuit['minDownload'] != round(int(downloadMin)*tcpOverheadFactor))
or (circuit['minUpload'] != round(int(uploadMin)*tcpOverheadFactor)) or (circuit['minUpload'] != round(int(uploadMin)*tcpOverheadFactor))
or (circuit['maxDownload'] != round(int(downloadMax)*tcpOverheadFactor)) or (circuit['maxDownload'] != round(int(downloadMax)*tcpOverheadFactor))
@ -388,6 +395,9 @@ def refreshShapers():
# Warn user if enableActualShellCommands is False, because that would mean no actual commands are executing # Warn user if enableActualShellCommands is False, because that would mean no actual commands are executing
if enableActualShellCommands == False: if enableActualShellCommands == False:
warnings.warn("enableActualShellCommands is set to False. None of the commands below will actually be executed. Simulated run.", stacklevel=2) warnings.warn("enableActualShellCommands is set to False. None of the commands below will actually be executed. Simulated run.", stacklevel=2)
# Warn user if monitorOnlyMode is True, because that would mean no actual shaping is happening
if monitorOnlyMode == True:
warnings.warn("monitorOnlyMode is set to True. Shaping will not occur.", stacklevel=2)
# Check if first run since boot # Check if first run since boot
@ -431,6 +441,17 @@ def refreshShapers():
# Pull rx/tx queues / CPU cores available # Pull rx/tx queues / CPU cores available
queuesAvailable = findQueuesAvailable() queuesAvailable = findQueuesAvailable()
# If in monitorOnlyMode, override network.json bandwidth rates to where no shaping will actually occur
if monitorOnlyMode == True:
def overrideNetworkBandwidths(data):
for elem in data:
if 'children' in data[elem]:
overrideNetworkBandwidths(data[elem]['children'])
data[elem]['downloadBandwidthMbpsMin'] = 10000
data[elem]['uploadBandwidthMbpsMin'] = 10000
overrideNetworkBandwidths(network)
# Generate Parent Nodes. Spread ShapedDevices.csv which lack defined ParentNode across these (balance across CPUs) # Generate Parent Nodes. Spread ShapedDevices.csv which lack defined ParentNode across these (balance across CPUs)
print("Generating parent nodes") print("Generating parent nodes")
existingPNs = 0 existingPNs = 0
@ -438,11 +459,18 @@ def refreshShapers():
existingPNs += 1 existingPNs += 1
generatedPNs = [] generatedPNs = []
numberOfGeneratedPNs = queuesAvailable-existingPNs numberOfGeneratedPNs = queuesAvailable-existingPNs
# If in monitorOnlyMode, override bandwidth rates to where no shaping will actually occur
if monitorOnlyMode == True:
chosenDownloadMbps = 10000
chosenUploadMbps = 10000
else:
chosenDownloadMbps = generatedPNDownloadMbps
chosenUploadMbps = generatedPNDownloadMbps
for x in range(numberOfGeneratedPNs): for x in range(numberOfGeneratedPNs):
genPNname = "Generated_PN_" + str(x+1) genPNname = "Generated_PN_" + str(x+1)
network[genPNname] = { network[genPNname] = {
"downloadBandwidthMbps":generatedPNDownloadMbps, "downloadBandwidthMbps": chosenDownloadMbps,
"uploadBandwidthMbps":generatedPNUploadMbps "uploadBandwidthMbps": chosenUploadMbps
} }
generatedPNs.append(genPNname) generatedPNs.append(genPNname)
if useBinPackingToBalanceCPU: if useBinPackingToBalanceCPU:
@ -507,6 +535,12 @@ def refreshShapers():
if depth == 0: if depth == 0:
parentClassID = hex(major) + ':' parentClassID = hex(major) + ':'
data[node]['parentClassID'] = parentClassID data[node]['parentClassID'] = parentClassID
# If in monitorOnlyMode, override bandwidth rates to where no shaping will actually occur
if monitorOnlyMode == True:
data[node]['downloadBandwidthMbps'] = 10000
data[node]['uploadBandwidthMbps'] = 10000
# If not in monitorOnlyMode
else:
# Cap based on this node's max bandwidth, or parent node's max bandwidth, whichever is lower # Cap based on this node's max bandwidth, or parent node's max bandwidth, whichever is lower
data[node]['downloadBandwidthMbps'] = min(data[node]['downloadBandwidthMbps'],parentMaxDL) data[node]['downloadBandwidthMbps'] = min(data[node]['downloadBandwidthMbps'],parentMaxDL)
data[node]['uploadBandwidthMbps'] = min(data[node]['uploadBandwidthMbps'],parentMaxUL) data[node]['uploadBandwidthMbps'] = min(data[node]['uploadBandwidthMbps'],parentMaxUL)
@ -515,6 +549,7 @@ def refreshShapers():
# Here we override the rate as 95% of ceil. # Here we override the rate as 95% of ceil.
data[node]['downloadBandwidthMbpsMin'] = round(data[node]['downloadBandwidthMbps']*.95) data[node]['downloadBandwidthMbpsMin'] = round(data[node]['downloadBandwidthMbps']*.95)
data[node]['uploadBandwidthMbpsMin'] = round(data[node]['uploadBandwidthMbps']*.95) data[node]['uploadBandwidthMbpsMin'] = round(data[node]['uploadBandwidthMbps']*.95)
data[node]['classMajor'] = hex(major) data[node]['classMajor'] = hex(major)
data[node]['classMinor'] = hex(minorByCPU[queue]) data[node]['classMinor'] = hex(minorByCPU[queue])
data[node]['cpuNum'] = hex(queue-1) data[node]['cpuNum'] = hex(queue-1)
@ -529,6 +564,7 @@ def refreshShapers():
for circuit in subscriberCircuits: for circuit in subscriberCircuits:
#If a device from ShapedDevices.csv lists this node as its Parent Node, attach it as a leaf to this node HTB #If a device from ShapedDevices.csv lists this node as its Parent Node, attach it as a leaf to this node HTB
if node == circuit['ParentNode']: if node == circuit['ParentNode']:
if monitorOnlyMode == False:
if circuit['maxDownload'] > data[node]['downloadBandwidthMbps']: if circuit['maxDownload'] > data[node]['downloadBandwidthMbps']:
warnings.warn("downloadMax of Circuit ID [" + circuit['circuitID'] + "] exceeded that of its parent node. Reducing to that of its parent node now.", stacklevel=2) warnings.warn("downloadMax of Circuit ID [" + circuit['circuitID'] + "] exceeded that of its parent node. Reducing to that of its parent node now.", stacklevel=2)
if circuit['maxUpload'] > data[node]['uploadBandwidthMbps']: if circuit['maxUpload'] > data[node]['uploadBandwidthMbps']:
@ -642,10 +678,14 @@ def refreshShapers():
comment = comment + '| Comment: ' + circuit['devices'][0]['comment'] comment = comment + '| Comment: ' + circuit['devices'][0]['comment']
command = 'class add dev ' + interfaceA + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minDownload']) + 'mbit ceil '+ str(circuit['maxDownload']) + 'mbit prio 3' command = 'class add dev ' + interfaceA + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minDownload']) + 'mbit ceil '+ str(circuit['maxDownload']) + 'mbit prio 3'
linuxTCcommands.append(command) linuxTCcommands.append(command)
# Only add CAKE / fq_codel qdisc if monitorOnlyMode is Off
if monitorOnlyMode == False:
command = 'qdisc add dev ' + interfaceA + ' parent ' + circuit['classMajor'] + ':' + circuit['classMinor'] + ' ' + fqOrCAKE command = 'qdisc add dev ' + interfaceA + ' parent ' + circuit['classMajor'] + ':' + circuit['classMinor'] + ' ' + fqOrCAKE
linuxTCcommands.append(command) linuxTCcommands.append(command)
command = 'class add dev ' + interfaceB + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minUpload']) + 'mbit ceil '+ str(circuit['maxUpload']) + 'mbit prio 3' command = 'class add dev ' + interfaceB + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minUpload']) + 'mbit ceil '+ str(circuit['maxUpload']) + 'mbit prio 3'
linuxTCcommands.append(command) linuxTCcommands.append(command)
# Only add CAKE / fq_codel qdisc if monitorOnlyMode is Off
if monitorOnlyMode == False:
command = 'qdisc add dev ' + interfaceB + ' parent ' + circuit['classMajor'] + ':' + circuit['classMinor'] + ' ' + fqOrCAKE command = 'qdisc add dev ' + interfaceB + ' parent ' + circuit['classMajor'] + ':' + circuit['classMinor'] + ' ' + fqOrCAKE
linuxTCcommands.append(command) linuxTCcommands.append(command)
for device in circuit['devices']: for device in circuit['devices']:
@ -959,6 +999,8 @@ def refreshShapersUpdateOnly():
command = 'tc class add dev ' + interface + ' parent ' + parentNodeClassID + ' classid ' + minor + ' htb rate ' + rate + 'Mbit ceil ' + ceil + 'Mbit' command = 'tc class add dev ' + interface + ' parent ' + parentNodeClassID + ' classid ' + minor + ' htb rate ' + rate + 'Mbit ceil ' + ceil + 'Mbit'
print(command) print(command)
shell(command) shell(command)
# Only add CAKE / fq_codel qdisc if monitorOnlyMode is Off
if monitorOnlyMode == False:
command = 'tc qdisc add dev ' + interface + ' parent ' + classID + ' ' + fqOrCAKE command = 'tc qdisc add dev ' + interface + ' parent ' + classID + ' ' + fqOrCAKE
print(command) print(command)
shell(command) shell(command)