diff --git a/src/LibreQoS.py b/src/LibreQoS.py index 22fe0f407..8f492cb92 100755 --- a/src/LibreQoS.py +++ b/src/LibreQoS.py @@ -27,6 +27,18 @@ run_shell_commands_as_sudo, generated_pn_download_mbps, generated_pn_upload_mbps, queues_available_override, \ on_a_stick, get_tree_weights, get_weights +def quantum(rateInMbps): + # Attempt to calculate an appropriate quantum for an HTB queue, given + # that `mq` does not appear to carry a valid `r2q` value to individual + # root nodes. + R2Q = 10 + rateInBytesPerSecond = rateInMbps * 125000 + quantum = int(rateInBytesPerSecond / R2Q) + quantrumString = " quantum " + str(quantum) + #print("Calculated quantum for " + str(rateInMbps) + " Mbps: " + str(quantum)) + return quantrumString + #return " quantum 1522" + # 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 # Does not apply to nodes of any sort, just endpoint devices tcpOverheadFactor = 1.09 @@ -784,14 +796,14 @@ def traverseNetwork(data, depth, major, minorByCPU, queue, parentClassID, upPare for queue in range(queuesAvailable): command = 'qdisc add dev ' + thisInterface + ' parent 7FFF:' + hex(queue+1) + ' handle ' + hex(queue+1) + ': htb default 2' linuxTCcommands.append(command) - command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+1) + ': classid ' + hex(queue+1) + ':1 htb rate '+ str(upstream_bandwidth_capacity_download_mbps()) + 'mbit ceil ' + str(upstream_bandwidth_capacity_download_mbps()) + 'mbit' + command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+1) + ': classid ' + hex(queue+1) + ':1 htb rate '+ str(upstream_bandwidth_capacity_download_mbps()) + 'mbit ceil ' + str(upstream_bandwidth_capacity_download_mbps()) + 'mbit' + quantum(upstream_bandwidth_capacity_download_mbps()) linuxTCcommands.append(command) command = 'qdisc add dev ' + thisInterface + ' parent ' + hex(queue+1) + ':1 ' + sqm() linuxTCcommands.append(command) # Default class - traffic gets passed through this limiter with lower priority if it enters the top HTB without a specific class. # Technically, that should not even happen. So don't expect much if any traffic in this default class. # Only 1/4 of defaultClassCapacity is guaranteed (to prevent hitting ceiling of upstream), for the most part it serves as an "up to" ceiling. - command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+1) + ':1 classid ' + hex(queue+1) + ':2 htb rate ' + str(round((upstream_bandwidth_capacity_download_mbps()-1)/4)) + 'mbit ceil ' + str(upstream_bandwidth_capacity_download_mbps()-1) + 'mbit prio 5' + command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+1) + ':1 classid ' + hex(queue+1) + ':2 htb rate ' + str(round((upstream_bandwidth_capacity_download_mbps()-1)/4)) + 'mbit ceil ' + str(upstream_bandwidth_capacity_download_mbps()-1) + 'mbit prio 5' + quantum(upstream_bandwidth_capacity_download_mbps()) linuxTCcommands.append(command) command = 'qdisc add dev ' + thisInterface + ' parent ' + hex(queue+1) + ':2 ' + sqm() linuxTCcommands.append(command) @@ -805,14 +817,14 @@ def traverseNetwork(data, depth, major, minorByCPU, queue, parentClassID, upPare for queue in range(queuesAvailable): command = 'qdisc add dev ' + thisInterface + ' parent 7FFF:' + hex(queue+stickOffset+1) + ' handle ' + hex(queue+stickOffset+1) + ': htb default 2' linuxTCcommands.append(command) - command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ': classid ' + hex(queue+stickOffset+1) + ':1 htb rate '+ str(upstream_bandwidth_capacity_upload_mbps()) + 'mbit ceil ' + str(upstream_bandwidth_capacity_upload_mbps()) + 'mbit' + command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ': classid ' + hex(queue+stickOffset+1) + ':1 htb rate '+ str(upstream_bandwidth_capacity_upload_mbps()) + 'mbit ceil ' + str(upstream_bandwidth_capacity_upload_mbps()) + 'mbit' + quantum(upstream_bandwidth_capacity_upload_mbps()) linuxTCcommands.append(command) command = 'qdisc add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ':1 ' + sqm() linuxTCcommands.append(command) # Default class - traffic gets passed through this limiter with lower priority if it enters the top HTB without a specific class. # Technically, that should not even happen. So don't expect much if any traffic in this default class. # Only 1/4 of defaultClassCapacity is guarenteed (to prevent hitting ceiling of upstream), for the most part it serves as an "up to" ceiling. - command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ':1 classid ' + hex(queue+stickOffset+1) + ':2 htb rate ' + str(round((upstream_bandwidth_capacity_upload_mbps()-1)/4)) + 'mbit ceil ' + str(upstream_bandwidth_capacity_upload_mbps()-1) + 'mbit prio 5' + command = 'class add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ':1 classid ' + hex(queue+stickOffset+1) + ':2 htb rate ' + str(round((upstream_bandwidth_capacity_upload_mbps()-1)/4)) + 'mbit ceil ' + str(upstream_bandwidth_capacity_upload_mbps()-1) + 'mbit prio 5' + quantum(upstream_bandwidth_capacity_upload_mbps()) linuxTCcommands.append(command) command = 'qdisc add dev ' + thisInterface + ' parent ' + hex(queue+stickOffset+1) + ':2 ' + sqm() linuxTCcommands.append(command) @@ -827,6 +839,7 @@ def sqmFixupRate(rate:int, sqm:str) -> str: # If we aren't using cake, just return the sqm string if not sqm.startswith("cake") or "rtt" in sqm: return sqm() + # If we are using cake, we need to fixup the rate # Based on: 1 MTU is 1500 bytes, or 12,000 bits. # At 1 Mbps, (1,000 bits per ms) transmitting an MTU takes 12ms. Add 3ms for overhead, and we get 15ms. @@ -842,11 +855,11 @@ def sqmFixupRate(rate:int, sqm:str) -> str: case _: return sqm for node in data: - command = 'class add dev ' + interface_a() + ' parent ' + data[node]['parentClassID'] + ' classid ' + data[node]['classMinor'] + ' htb rate '+ str(data[node]['downloadBandwidthMbpsMin']) + 'mbit ceil '+ str(data[node]['downloadBandwidthMbps']) + 'mbit prio 3' + command = 'class add dev ' + interface_a() + ' parent ' + data[node]['parentClassID'] + ' classid ' + data[node]['classMinor'] + ' htb rate '+ str(data[node]['downloadBandwidthMbpsMin']) + 'mbit ceil '+ str(data[node]['downloadBandwidthMbps']) + 'mbit prio 3' + quantum(data[node]['downloadBandwidthMbps']) linuxTCcommands.append(command) logging.info("Up ParentClassID: " + data[node]['up_parentClassID']) logging.info("ClassMinor: " + data[node]['classMinor']) - command = 'class add dev ' + interface_b() + ' parent ' + data[node]['up_parentClassID'] + ' classid ' + data[node]['classMinor'] + ' htb rate '+ str(data[node]['uploadBandwidthMbpsMin']) + 'mbit ceil '+ str(data[node]['uploadBandwidthMbps']) + 'mbit prio 3' + command = 'class add dev ' + interface_b() + ' parent ' + data[node]['up_parentClassID'] + ' classid ' + data[node]['classMinor'] + ' htb rate '+ str(data[node]['uploadBandwidthMbpsMin']) + 'mbit ceil '+ str(data[node]['uploadBandwidthMbps']) + 'mbit prio 3' + quantum(data[node]['uploadBandwidthMbps']) linuxTCcommands.append(command) if 'circuits' in data[node]: for circuit in data[node]['circuits']: @@ -858,7 +871,7 @@ def sqmFixupRate(rate:int, sqm:str) -> str: if 'comment' in circuit['devices'][0]: tcComment = tcComment + '| Comment: ' + circuit['devices'][0]['comment'] tcComment = tcComment.replace("\n", "") - command = 'class add dev ' + interface_a() + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minDownload']) + 'mbit ceil '+ str(circuit['maxDownload']) + 'mbit prio 3' + tcComment + command = 'class add dev ' + interface_a() + ' parent ' + data[node]['classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minDownload']) + 'mbit ceil '+ str(circuit['maxDownload']) + 'mbit prio 3' + quantum(circuit['maxDownload']) + tcComment linuxTCcommands.append(command) # Only add CAKE / fq_codel qdisc if monitorOnlyMode is Off if monitor_mode_only() == False: @@ -866,7 +879,7 @@ def sqmFixupRate(rate:int, sqm:str) -> str: useSqm = sqmFixupRate(circuit['maxDownload'], sqm()) command = 'qdisc add dev ' + interface_a() + ' parent ' + circuit['classMajor'] + ':' + circuit['classMinor'] + ' ' + useSqm linuxTCcommands.append(command) - command = 'class add dev ' + interface_b() + ' parent ' + data[node]['up_classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minUpload']) + 'mbit ceil '+ str(circuit['maxUpload']) + 'mbit prio 3' + command = 'class add dev ' + interface_b() + ' parent ' + data[node]['up_classid'] + ' classid ' + circuit['classMinor'] + ' htb rate '+ str(circuit['minUpload']) + 'mbit ceil '+ str(circuit['maxUpload']) + 'mbit prio 3' + quantum(circuit['maxUpload']) linuxTCcommands.append(command) # Only add CAKE / fq_codel qdisc if monitorOnlyMode is Off if monitor_mode_only() == False: