diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index a07173184..dc5778f94 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -331,12 +331,12 @@ def primeActivated(activated): @dispatcher.add_method -def setUploadLimit(speed_kbps): +def setBandwithLimit(upload_speed_kbps, download_speed_kbps): if not TICI: return {"success": 0, "error": "only supported on comma three"} try: - HARDWARE.set_upload_limit(speed_kbps) + HARDWARE.set_bandwidth_limit(upload_speed_kbps, download_speed_kbps) return {"success": 1} except subprocess.CalledProcessError as e: return {"success": 0, "error": "failed to set limit", "stdout": e.stdout, "stderr": e.stderr} diff --git a/selfdrive/hardware/base.py b/selfdrive/hardware/base.py index eec09f075..b551138ce 100644 --- a/selfdrive/hardware/base.py +++ b/selfdrive/hardware/base.py @@ -68,7 +68,7 @@ class HardwareBase(ABC): pass @staticmethod - def set_upload_limit(speed_kbps: int) -> None: + def set_bandwidth_limit(upload_speed_kbps: int, download_speed_kbps: int) -> None: pass @abstractmethod diff --git a/selfdrive/hardware/tici/hardware.py b/selfdrive/hardware/tici/hardware.py index 6e0e56247..41ae316d3 100644 --- a/selfdrive/hardware/tici/hardware.py +++ b/selfdrive/hardware/tici/hardware.py @@ -219,30 +219,60 @@ class Tici(HardwareBase): return network_strength @staticmethod - def set_upload_limit(speed_kbps: int) -> None: - speed_kbps = int(speed_kbps) # Ensure integer value + def set_bandwidth_limit(upload_speed_kbps: int, download_speed_kbps: int) -> None: + upload_speed_kbps = int(upload_speed_kbps) # Ensure integer value + download_speed_kbps = int(download_speed_kbps) # Ensure integer value adapter = "wwan0" - tc = ["sudo", "tc"] + ifb = "ifb0" + + sudo = ["sudo"] + tc = sudo + ["tc"] # check, cmd - commands = [ + cleanup = [ # Clean up old rules (False, tc + ["qdisc", "del", "dev", adapter, "root"]), + (False, tc + ["qdisc", "del", "dev", ifb, "root"]), + (False, tc + ["qdisc", "del", "dev", adapter, "ingress"]), + (False, tc + ["qdisc", "del", "dev", ifb, "ingress"]), + # Bring ifb0 down + (False, sudo + ["ip", "link", "set", "dev", ifb, "down"]), + ] + + upload = [ # Create root Hierarchy Token Bucket that sends all trafic to 1:20 (True, tc + ["qdisc", "add", "dev", adapter, "root", "handle", "1:", "htb", "default", "20"]), # Create class 1:20 with specified rate limit - (True, tc + ["class", "add", "dev", adapter, "parent", "1:", "classid", "1:20", "htb", "rate", f"{speed_kbps}kbit"]), + (True, tc + ["class", "add", "dev", adapter, "parent", "1:", "classid", "1:20", "htb", "rate", f"{upload_speed_kbps}kbit"]), # Create universal 32 bit filter on adapter that sends all outbound ip traffic through the class (True, tc + ["filter", "add", "dev", adapter, "parent", "1:", "protocol", "ip", "prio", "10", "u32", "match", "ip", "dst", "0.0.0.0/0", "flowid", "1:20"]), ] - # Disable limits - if speed_kbps == -1: - commands = commands[:1] + download = [ + # Bring ifb0 up + (True, sudo + ["ip", "link", "set", "dev", ifb, "up"]), + + # Redirect ingress (incoming) to egress ifb0 + (True, tc + ["qdisc", "add", "dev", adapter, "handle", "ffff:", "ingress"]), + (True, tc + ["filter", "add", "dev", adapter, "parent", "ffff:", "protocol", "ip", "u32", "match", "u32", "0", "0", "action", "mirred", "egress", "redirect", "dev", ifb]), + + # Add class and rules for virtual interface + (True, tc + ["qdisc", "add", "dev", ifb, "root", "handle", "2:", "htb"]), + (True, tc + ["class", "add", "dev", ifb, "parent", "2:", "classid", "2:1", "htb", "rate", f"{download_speed_kbps}kbit"]), + + # Add filter to rule for IP address + (True, tc + ["filter", "add", "dev", ifb, "protocol", "ip", "parent", "2:", "prio", "1", "u32", "match", "ip", "src", "0.0.0.0/0", "flowid", "2:1"]), + ] + + commands = cleanup + if upload_speed_kbps != -1: + commands += upload + if download_speed_kbps != -1: + commands += download for check, cmd in commands: subprocess.run(cmd, check=check)