diff --git a/README.md b/README.md index dabe2b5..8579ec9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ NetHang is a web-based tool designed to simulate network quality, focusing on the diversity of last-mile network conditions. For modern internet applications and services with high real-time requirements, NetHang offers a stable, reentrant, customizable, and easily extensible network quality simulation system, helping to achieve low-latency and high-quality internet services. -Add Path +Add Path Unlike traditional network impairment tools that target backbone network quality between servers and switches, NetHang is optimized for: @@ -15,9 +15,9 @@ Unlike traditional network impairment tools that target backbone network quality - UE <--> Cellular <--> ISP edge nodes <--> APP servers - UE <--> Air interface <--> Satellite <--> APP servers -Start Simulation +- The current network model is built and simplified based on existing network quality data modeling, while also supporting users to easily customize the network models they need for testing in YAML format. The following image shows the StarLink network simulation ( Queuing changes every 20s - 30s caused by Satellite handover ): -- The current network model is built and simplified based on existing network quality data modeling, while also supporting users to easily customize the network models they need for testing in YAML format. +StarLink Simulation - NetHang clearly displays the differences in data traffic before and after simulation, as well as the state of the simulation conditions. @@ -25,11 +25,23 @@ Unlike traditional network impairment tools that target backbone network quality ## Features +- Configurable traffic rules and models - Traffic rate limiting and shaping -- Network latency and latency variation simulation -- Packet loss simulation +- Throttle queue depth control + +Throttle Settings + +- Network latency and latency variation (Jitter) simulation +- Jitter simulation with and without reordering allowed + +Latency Settings +Latency Settings + +- Packet loss with random and burst support + +Loss Settings + - Support for both uplink and downlink traffic control -- Configurable traffic rules and models - Real-time traffic statistics display ## Requirements diff --git a/assets/latency-settings-0.png b/assets/latency-settings-0.png new file mode 100644 index 0000000..3ee0e1d Binary files /dev/null and b/assets/latency-settings-0.png differ diff --git a/assets/latency-settings-1.png b/assets/latency-settings-1.png new file mode 100644 index 0000000..bb556c3 Binary files /dev/null and b/assets/latency-settings-1.png differ diff --git a/assets/loss-settings-0.png b/assets/loss-settings-0.png new file mode 100644 index 0000000..07f8226 Binary files /dev/null and b/assets/loss-settings-0.png differ diff --git a/assets/model-starlink.gif b/assets/model-starlink.gif new file mode 100644 index 0000000..bef7a1d Binary files /dev/null and b/assets/model-starlink.gif differ diff --git a/assets/models-settings.png b/assets/models-settings.png new file mode 100644 index 0000000..d060f1a Binary files /dev/null and b/assets/models-settings.png differ diff --git a/assets/nh-10.gif b/assets/nh-10.gif index 6cbebf9..f80039d 100644 Binary files a/assets/nh-10.gif and b/assets/nh-10.gif differ diff --git a/assets/throttle-settings-0.png b/assets/throttle-settings-0.png new file mode 100644 index 0000000..9482669 Binary files /dev/null and b/assets/throttle-settings-0.png differ diff --git a/config_files/models_v0.2.0.yaml b/config_files/models_v0.2.0.yaml new file mode 100644 index 0000000..0db2a23 --- /dev/null +++ b/config_files/models_v0.2.0.yaml @@ -0,0 +1,446 @@ +version: v0.2.0 + +components: + delay_components: + delay_lan: &delay_lan + delay: 2 + latency_type: "constant" + delay_intercity: &delay_intercity + delay: 15 + latency_type: "constant" + delay_intercontinental: &delay_intercontinental + delay: 150 + latency_type: "constant" + delay_DSL: &delay_DSL + delay: 5 + latency_type: "constant" + delay_cellular_LTE_uplink: &delay_cellular_LTE_uplink + delay: 65 + latency_type: "constant" + delay_cellular_LTE_downlink: &delay_cellular_LTE_downlink + delay: 50 + latency_type: "constant" + delay_cellular_3G: &delay_cellular_3G + delay: 100 + latency_type: "constant" + delay_cellular_EDGE_uplink: &delay_cellular_EDGE_uplink + delay: 440 + latency_type: "constant" + delay_cellular_EDGE_downlink: &delay_cellular_EDGE_downlink + delay: 400 + latency_type: "constant" + delay_very_bad_network: &delay_very_bad_network + delay: 500 + latency_type: "constant" + delay_starlink_low_latency: &delay_starlink_low_latency + delay: 60 + latency_type: "constant" + delay_starlink_moderate_latency: &delay_starlink_moderate_latency + delay: 100 + latency_type: "constant" + delay_starlink_high_latency: &delay_starlink_high_latency + delay: 180 + latency_type: "constant" + + jitter_components: + jitter_moderate_wireless: &jitter_moderate_wireless + jitter: 100 + latency_type: "jitter-reorder-off" + jitter_bad_wireless: &jitter_bad_wireless + jitter: 250 + latency_type: "jitter-reorder-off" + jitter_moderate_congestion: &jitter_moderate_congestion + jitter: 1000 + latency_type: "jitter-reorder-off" + jitter_severe_congestion: &jitter_severe_congestion + jitter: 2000 + latency_type: "jitter-reorder-off" + jitter_starlink_handover: &jitter_starlink_handover + jitter: 200 + latency_type: "jitter-reorder-off" + jitter_wireless_handover: &jitter_wireless_handover + jitter: 100 + latency_type: "jitter-reorder-on" + jitter_wireless_low_snr: &jitter_wireless_low_snr + jitter: 50 + latency_type: "jitter-reorder-off" + + loss_components: + loss_slight: &loss_slight + loss: 1 + loss_type: "burst-low" + loss_low: &loss_low + loss: 5 + loss_type: "burst-low" + loss_moderate: &loss_moderate + loss: 10 + loss_type: "burst-low" + loss_high: &loss_high + loss: 20 + loss_type: "burst-low" + loss_severe: &loss_severe + loss: 30 + loss_type: "burst-medium" + loss_wireless_low_snr: &loss_wireless_low_snr + loss: 10 + loss_type: "burst-medium" + loss_very_bad_network: &loss_very_bad_network + loss: 10 + loss_type: "burst-high" + + rate_components: + rate_1000M: &rate_1000M + rate_limit: 1000000 + qdepth: 1000 + throttle_type: "on" + rate_1M_qdepth_1: &rate_1M_qdepth_1 + rate_limit: 1000 + qdepth: 1 + throttle_type: "on" + rate_1M_nlc: &rate_1M_nlc + rate_limit: 1000 + qdepth: 20 + throttle_type: "on" + rate_1M_qdepth_150: &rate_1M_qdepth_150 + rate_limit: 1000 + qdepth: 150 + throttle_type: "on" + rate_2M_qdepth_150: &rate_2M_qdepth_150 + rate_limit: 2000 + qdepth: 150 + throttle_type: "on" + rate_100M_qdepth_1000: &rate_100M_qdepth_1000 + rate_limit: 100000 + qdepth: 1000 + throttle_type: "on" + rate_DSL_uplink: &rate_DSL_uplink + rate_limit: 256 + qdepth: 20 + throttle_type: "on" + rate_DSL_downlink: &rate_DSL_downlink + rate_limit: 2000 + qdepth: 20 + throttle_type: "on" + rate_cellular_EDGE_uplink: &rate_cellular_EDGE_uplink + rate_limit: 200 + qdepth: 20 + throttle_type: "on" + rate_cellular_EDGE_downlink: &rate_cellular_EDGE_downlink + rate_limit: 240 + qdepth: 20 + throttle_type: "on" + rate_cellular_LTE_uplink: &rate_cellular_LTE_uplink + rate_limit: 10000 + qdepth: 150 + throttle_type: "on" + rate_cellular_LTE_downlink: &rate_cellular_LTE_downlink + rate_limit: 50000 + qdepth: 20 + throttle_type: "on" + rate_cellular_3G_uplink: &rate_cellular_3G_uplink + rate_limit: 330 + qdepth: 20 + throttle_type: "on" + rate_cellular_3G_downlink: &rate_cellular_3G_downlink + rate_limit: 780 + qdepth: 20 + throttle_type: "on" + rate_cellular_3G: &rate_cellular_3G + rate_limit: 2000 + qdepth: 1000 + throttle_type: "on" + rate_wifi_uplink: &rate_wifi_uplink + rate_limit: 33000 + qdepth: 20 + throttle_type: "on" + rate_wifi_downlink: &rate_wifi_downlink + rate_limit: 40000 + qdepth: 20 + throttle_type: "on" + rate_starlink_uplink: &rate_starlink_uplink + rate_limit: 15000 + qdepth: 100 + throttle_type: "on" + rate_starlink_downlink: &rate_starlink_downlink + rate_limit: 50000 + qdepth: 100 + throttle_type: "on" + accu_rate_10_qdepth_10: &accu_rate_10_qdepth_10 + rate_limit: 10 + qdepth: 10 + throttle_type: "on" + accu_rate_10_qdepth_100: &accu_rate_10_qdepth_100 + rate_limit: 10 + qdepth: 100 + throttle_type: "on" + accu_rate_10_qdepth_1000: &accu_rate_10_qdepth_1000 + rate_limit: 10 + qdepth: 1000 + throttle_type: "on" + accu_rate_10_qdepth_10000: &accu_rate_10_qdepth_10000 + rate_limit: 10 + qdepth: 10000 + throttle_type: "on" + +models: + (Scenario) Elevator: + description: "In a running elevator" + global: + uplink: + <<: [*rate_cellular_LTE_uplink, *delay_cellular_LTE_uplink] + downlink: + <<: [*rate_cellular_LTE_downlink, *delay_cellular_LTE_downlink] + timeline: + - duration: 10 + uplink: + downlink: + - duration: 2 + uplink: + <<: [*jitter_moderate_congestion, *loss_severe] + downlink: + <<: [*jitter_moderate_congestion, *loss_severe] + - duration: 5 + uplink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + - duration: 2 + uplink: + <<: [*jitter_moderate_congestion] + downlink: + <<: [*jitter_moderate_congestion] + (Scenario) High_speed_Driving: + description: "In a high speed driving situation" + global: + uplink: + <<: [*rate_cellular_LTE_uplink, *delay_cellular_LTE_uplink] + downlink: + <<: [*rate_cellular_LTE_downlink, *delay_cellular_LTE_downlink] + timeline: + - duration: 30 + uplink: + downlink: + - duration: 2 + uplink: + <<: [*jitter_moderate_congestion, *loss_severe, *delay_cellular_3G] + downlink: + <<: [*jitter_moderate_congestion, *loss_severe, *delay_cellular_3G] + - duration: 30 + uplink: + <<: [*rate_cellular_3G_uplink, *delay_cellular_3G] + downlink: + <<: [*rate_cellular_3G_downlink, *delay_cellular_3G] + - duration: 2 + uplink: + <<: [*jitter_moderate_congestion, *delay_cellular_EDGE_uplink] + downlink: + <<: [*jitter_moderate_congestion, *delay_cellular_EDGE_downlink] + - duration: 30 + uplink: + <<: [*rate_cellular_EDGE_uplink, *delay_cellular_EDGE_uplink] + downlink: + <<: [*rate_cellular_EDGE_downlink, *delay_cellular_EDGE_downlink] + - duration: 2 + uplink: + <<: [*jitter_moderate_congestion, *loss_severe, *delay_cellular_LTE_uplink] + downlink: + <<: [*jitter_moderate_congestion, *loss_severe, *delay_cellular_LTE_downlink] + (Scenario) Underground_parking_lot: + description: "In a underground parking lot" + global: + uplink: + <<: [*rate_cellular_LTE_uplink, *delay_cellular_LTE_uplink, *jitter_bad_wireless] + downlink: + <<: [*rate_cellular_LTE_downlink, *delay_cellular_LTE_downlink, *jitter_wireless_low_snr] + timeline: + - duration: 15 + uplink: + downlink: + - duration: 2 + uplink: + <<: [*accu_rate_10_qdepth_10000] + downlink: + <<: [*accu_rate_10_qdepth_10000] + - duration: 10 + uplink: + <<: [*rate_cellular_3G_uplink, *delay_cellular_3G, *jitter_bad_wireless] + downlink: + <<: [*rate_cellular_3G_downlink, *delay_cellular_3G, *jitter_wireless_low_snr] + - duration: 1 + uplink: + <<: [*accu_rate_10_qdepth_10000] + downlink: + <<: [*accu_rate_10_qdepth_10000] + - duration: 30 + uplink: + <<: [*rate_cellular_3G_uplink, *delay_cellular_3G] + downlink: + <<: [*rate_cellular_3G_downlink, *delay_cellular_3G] + - duration: 2 + uplink: + <<: [*accu_rate_10_qdepth_10] + downlink: + <<: [*accu_rate_10_qdepth_10] + + EDGE_with_handover: + description: "Using cellular EDGE with handover between different cells" + global: + uplink: + <<: [*rate_cellular_EDGE_uplink, *delay_cellular_EDGE_uplink] + downlink: + <<: [*rate_cellular_EDGE_downlink, *delay_cellular_EDGE_downlink] + timeline: + - duration: 60 + uplink: + downlink: + - duration: 2.5 + uplink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + - duration: 60 + uplink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + - duration: 2.5 + uplink: + <<: [*jitter_wireless_handover] + downlink: + <<: [*jitter_wireless_handover] + 3G_with_handover: + description: "Using cellular 3G with handover between different cells" + global: + uplink: + <<: [*rate_cellular_3G_uplink, *delay_cellular_3G] + downlink: + <<: [*rate_cellular_3G_downlink, *delay_cellular_3G] + timeline: + - duration: 60 + uplink: + downlink: + - duration: 2 + uplink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + - duration: 60 + uplink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + - duration: 2 + uplink: + <<: [*jitter_wireless_handover] + downlink: + <<: [*jitter_wireless_handover] + LTE_with_handover: + description: "Using cellular LTE with handover between different cells" + global: + uplink: + <<: [*rate_cellular_LTE_uplink, *delay_cellular_LTE_uplink] + downlink: + <<: [*rate_cellular_LTE_downlink, *delay_cellular_LTE_downlink] + timeline: + - duration: 60 + uplink: + downlink: + - duration: 1 + uplink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_handover, *loss_wireless_low_snr] + - duration: 60 + uplink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + downlink: + <<: [*jitter_wireless_low_snr, *loss_wireless_low_snr] + - duration: 1 + uplink: + <<: [*jitter_wireless_handover] + downlink: + <<: [*jitter_wireless_handover] + Cellular_with_isp_throttle: + description: "Using cellular with ISP throttle" + global: + uplink: + <<: [*rate_1M_qdepth_150, *delay_intercity] + downlink: + <<: [*rate_1M_qdepth_1, *delay_intercity] + timeline: + Starlink: + description: "Using Starlink satellite internet" + global: + uplink: + <<: [*rate_starlink_uplink, *delay_starlink_low_latency] + downlink: + <<: [*rate_starlink_downlink, *delay_starlink_low_latency] + timeline: + - duration: 20 + uplink: + downlink: + - duration: 0.8 + uplink: + <<: [*jitter_starlink_handover, *loss_low] + downlink: + <<: [*jitter_starlink_handover, *loss_low] + - duration: 15 + uplink: + <<: [*delay_starlink_high_latency] + downlink: + <<: [*delay_starlink_high_latency] + - duration: 0.8 + uplink: + <<: [*jitter_starlink_handover, *loss_low] + downlink: + <<: [*jitter_starlink_handover, *loss_low] + - duration: 20 + uplink: + <<: [*delay_starlink_moderate_latency] + downlink: + <<: [*delay_starlink_moderate_latency] + - duration: 0.8 + uplink: + <<: [*jitter_starlink_handover, *loss_low] + downlink: + <<: [*jitter_starlink_handover, *loss_low] + (NLC) Very_bad_network: + description: "From Apple Network Link Conditioner" + global: + uplink: + <<: [*rate_1M_nlc, *delay_very_bad_network, *loss_very_bad_network] + downlink: + <<: [*rate_1M_nlc, *delay_very_bad_network, *loss_very_bad_network] + timeline: + (NLC) Wi-Fi: + description: "From Apple Network Link Conditioner" + global: + uplink: + <<: [*rate_wifi_uplink, *loss_slight] + downlink: + <<: [*rate_wifi_downlink, *loss_slight] + timeline: + (NLC) LTE: + description: "From Apple Network Link Conditioner" + global: + uplink: + <<: [*rate_cellular_LTE_uplink, *delay_cellular_LTE_uplink] + downlink: + <<: [*rate_cellular_LTE_downlink, *delay_cellular_LTE_downlink] + timeline: + (NLC) EDGE: + description: "From Apple Network Link Conditioner" + global: + uplink: + <<: [*rate_cellular_EDGE_uplink, *delay_cellular_EDGE_uplink] + downlink: + <<: [*rate_cellular_EDGE_downlink, *delay_cellular_EDGE_downlink] + timeline: + (NLC) DSL: + description: "From Apple Network Link Conditioner" + global: + uplink: + <<: [*rate_DSL_uplink, *delay_DSL] + downlink: + <<: [*rate_DSL_downlink, *delay_DSL] + timeline: diff --git a/nethang/config_manager.py b/nethang/config_manager.py index efc0794..47d912c 100644 --- a/nethang/config_manager.py +++ b/nethang/config_manager.py @@ -17,157 +17,193 @@ class ConfigManager: def __init__(self): # GitHub config URL - self.github_config_url = "https://raw.githubusercontent.com/stephenyin/nethang/main/config_files/models.yaml" + self.github_config_url = "https://raw.githubusercontent.com/stephenyin/nethang/main/config_files/models_v0.2.0.yaml" # Fallback config (if network fails) self.fallback_models = """# Nethang Fallback models -version: 0.1.0 +version: v0.2.0 components: delay_components: delay_lan: &delay_lan delay: 2 + latency_type: "constant" delay_intercity: &delay_intercity delay: 15 + latency_type: "constant" delay_intercontinental: &delay_intercontinental delay: 150 + latency_type: "constant" delay_DSL: &delay_DSL delay: 5 + latency_type: "constant" delay_cellular_LTE_uplink: &delay_cellular_LTE_uplink delay: 65 + latency_type: "constant" delay_cellular_LTE_downlink: &delay_cellular_LTE_downlink delay: 50 + latency_type: "constant" delay_cellular_3G: &delay_cellular_3G delay: 100 + latency_type: "constant" delay_cellular_EDGE_uplink: &delay_cellular_EDGE_uplink delay: 440 + latency_type: "constant" delay_cellular_EDGE_downlink: &delay_cellular_EDGE_downlink delay: 400 + latency_type: "constant" delay_very_bad_network: &delay_very_bad_network delay: 500 + latency_type: "constant" delay_starlink_low_latency: &delay_starlink_low_latency delay: 60 + latency_type: "constant" delay_starlink_moderate_latency: &delay_starlink_moderate_latency delay: 100 + latency_type: "constant" delay_starlink_high_latency: &delay_starlink_high_latency delay: 180 + latency_type: "constant" jitter_components: jitter_moderate_wireless: &jitter_moderate_wireless - slot: - - 100 - - 100 + jitter: 100 + latency_type: "jitter-reorder-off" jitter_bad_wireless: &jitter_bad_wireless - slot: - - 300 - - 300 + jitter: 250 + latency_type: "jitter-reorder-off" jitter_moderate_congestion: &jitter_moderate_congestion - slot: - - 1500 - - 2000 + jitter: 1000 + latency_type: "jitter-reorder-off" jitter_severe_congestion: &jitter_severe_congestion - slot: - - 3000 - - 4000 + jitter: 2000 + latency_type: "jitter-reorder-off" jitter_starlink_handover: &jitter_starlink_handover - slot: - - 300 - - 300 + jitter: 200 + latency_type: "jitter-reorder-off" jitter_wireless_handover: &jitter_wireless_handover - slot: - - 500 - - 500 + jitter: 100 + latency_type: "jitter-reorder-on" jitter_wireless_low_snr: &jitter_wireless_low_snr - slot: - - 50 - - 50 + jitter: 50 + latency_type: "jitter-reorder-off" loss_components: loss_slight: &loss_slight loss: 1 + loss_type: "burst-low" loss_low: &loss_low loss: 5 + loss_type: "burst-low" loss_moderate: &loss_moderate loss: 10 + loss_type: "burst-low" loss_high: &loss_high loss: 20 + loss_type: "burst-low" loss_severe: &loss_severe loss: 30 + loss_type: "burst-medium" loss_wireless_low_snr: &loss_wireless_low_snr loss: 10 + loss_type: "burst-medium" loss_very_bad_network: &loss_very_bad_network loss: 10 + loss_type: "burst-high" rate_components: rate_1000M: &rate_1000M rate_limit: 1000000 qdepth: 1000 + throttle_type: "on" rate_1M_qdepth_1: &rate_1M_qdepth_1 rate_limit: 1000 qdepth: 1 + throttle_type: "on" rate_1M_nlc: &rate_1M_nlc rate_limit: 1000 qdepth: 20 + throttle_type: "on" rate_1M_qdepth_150: &rate_1M_qdepth_150 rate_limit: 1000 qdepth: 150 + throttle_type: "on" rate_2M_qdepth_150: &rate_2M_qdepth_150 rate_limit: 2000 qdepth: 150 + throttle_type: "on" rate_100M_qdepth_1000: &rate_100M_qdepth_1000 rate_limit: 100000 qdepth: 1000 + throttle_type: "on" rate_DSL_uplink: &rate_DSL_uplink rate_limit: 256 qdepth: 20 + throttle_type: "on" rate_DSL_downlink: &rate_DSL_downlink rate_limit: 2000 qdepth: 20 + throttle_type: "on" rate_cellular_EDGE_uplink: &rate_cellular_EDGE_uplink rate_limit: 200 qdepth: 20 + throttle_type: "on" rate_cellular_EDGE_downlink: &rate_cellular_EDGE_downlink rate_limit: 240 qdepth: 20 + throttle_type: "on" rate_cellular_LTE_uplink: &rate_cellular_LTE_uplink rate_limit: 10000 qdepth: 150 + throttle_type: "on" rate_cellular_LTE_downlink: &rate_cellular_LTE_downlink rate_limit: 50000 qdepth: 20 + throttle_type: "on" rate_cellular_3G_uplink: &rate_cellular_3G_uplink rate_limit: 330 qdepth: 20 + throttle_type: "on" rate_cellular_3G_downlink: &rate_cellular_3G_downlink rate_limit: 780 qdepth: 20 + throttle_type: "on" rate_cellular_3G: &rate_cellular_3G rate_limit: 2000 qdepth: 1000 + throttle_type: "on" rate_wifi_uplink: &rate_wifi_uplink rate_limit: 33000 qdepth: 20 + throttle_type: "on" rate_wifi_downlink: &rate_wifi_downlink rate_limit: 40000 qdepth: 20 + throttle_type: "on" rate_starlink_uplink: &rate_starlink_uplink rate_limit: 15000 qdepth: 100 + throttle_type: "on" rate_starlink_downlink: &rate_starlink_downlink rate_limit: 50000 qdepth: 100 + throttle_type: "on" accu_rate_10_qdepth_10: &accu_rate_10_qdepth_10 rate_limit: 10 qdepth: 10 + throttle_type: "on" accu_rate_10_qdepth_100: &accu_rate_10_qdepth_100 rate_limit: 10 qdepth: 100 + throttle_type: "on" accu_rate_10_qdepth_1000: &accu_rate_10_qdepth_1000 rate_limit: 10 qdepth: 1000 + throttle_type: "on" accu_rate_10_qdepth_10000: &accu_rate_10_qdepth_10000 rate_limit: 10 qdepth: 10000 + throttle_type: "on" models: (Scenario) Elevator: diff --git a/nethang/simu_path.py b/nethang/simu_path.py index b8b2637..ac8475d 100644 --- a/nethang/simu_path.py +++ b/nethang/simu_path.py @@ -12,6 +12,7 @@ import yaml import os import time +import json from . import app, CONFIG_PATH, CONFIG_FILE, MODELS_FILE, PATHS_FILE, IPT_LOCK_FILE from multiprocessing import Process from dataclasses import dataclass @@ -39,7 +40,7 @@ def __init__(self, **kwargs): def get_default_value(self, key): if key == 'rate_limit': - return 32000000 + return 1000000 elif key == 'qdepth': return 1000 elif key == 'loss': @@ -48,6 +49,12 @@ def get_default_value(self, key): return 0 elif key == 'jitter': return 0 + elif key == 'loss_type': + return 'off' + elif key == 'latency_type': + return 'off' + elif key == 'throttle_type': + return 'off' else: app.logger.info(f"Not implemented key: {key}") @@ -59,7 +66,9 @@ def __eq__(self, other): self.restrict_settings['loss'] == other.restrict_settings['loss'] and \ self.restrict_settings['delay'] == other.restrict_settings['delay'] and \ self.restrict_settings['jitter'] == other.restrict_settings['jitter'] and \ - self.restrict_settings['reorder_allowed'] == other.restrict_settings['reorder_allowed'] + self.restrict_settings['loss_type'] == other.restrict_settings['loss_type'] and \ + self.restrict_settings['latency_type'] == other.restrict_settings['latency_type'] and \ + self.restrict_settings['throttle_type'] == other.restrict_settings['throttle_type'] ) def to_dict(self): @@ -133,21 +142,25 @@ def _init_tc(self, direction_ : str): iface = self.__direction[direction_]['to'], handle = SimuPathManager.handle_name, rate = SimuPathManager.MAX_RATE)) def _apply_tc(self, direction_ : str, opt : str = 'add', - rate_limit : int = 32000000, rate_ceil : int = 32000000, + rate_limit : int = 1000000, rate_ceil : int = 1000000, rate_burst : int = 0, rate_cburst : int = 0, qdepth : int = 1000, loss : float = 0.0, delay : int = 0, jitter : int = 0, jitter_dist : str = 'normal', - slot : list = [0, 0], - reorder_allowed : bool = False + loss_type : str = 'off', + latency_type : str = 'off', + throttle_type : str = 'off' ): class_str_ = '' + if throttle_type == 'off': + rate_limit = SimuPathManager.MAX_RATE + # If rate_limit is greater than MAX_RATE, using MAX_RATE as rate # Otherwise, using rate_limit as rate - if rate_limit > SimuPathManager.MAX_RATE: + if rate_limit >= SimuPathManager.MAX_RATE: class_str_ += ' rate {}Gbit'.format(SimuPathManager.MAX_RATE / 1000000) else: class_str_ += ' rate {}Kbit'.format(rate_limit) @@ -174,16 +187,37 @@ def _apply_tc(self, direction_ : str, opt : str = 'add', class_str_ += ' cburst {}KB'.format(rate_cburst) netem_str_ = '' - netem_str_ += f' limit {qdepth}' - delay_, jitter_ = self.__get_delay_jitter_param(delay, jitter) - if delay_ != 0 or jitter_ != 0: - netem_str_ += ' delay' - netem_str_ += f' {delay_}ms' - if jitter_ != 0: - netem_str_ += f' {jitter_}ms distribution {jitter_dist}' - netem_str_ += f' loss {loss}%' - netem_str_ += f' slot {slot[0]}ms {slot[1]}ms' + netem_str_ += f'limit {qdepth}' + + if latency_type != 'off': + # If jitter-reorder-off is selected (jitter > 0 and latency_type == 'jitter-reorder-off'), + # use slot for jitter instead of delay+jitter approach + use_slot_for_jitter = (jitter > 0 and latency_type == 'jitter-reorder-off') + + if use_slot_for_jitter: + min_delay, max_delay = self.__get_slot_jitter_param(jitter) + + # Use slot for jitter + netem_str_ += f' delay {delay}ms slot {min_delay}ms {max_delay}ms' + else: + # Use delay + jitter approach if latency_type is not 'jitter-reorder-off' + delay_, jitter_ = self.__get_delay_jitter_param(delay, jitter) + if delay_ != 0 or jitter_ != 0: + netem_str_ += f' delay {delay_}ms' + if jitter_ != 0: + netem_str_ += f' {jitter_}ms distribution {jitter_dist}' + # Set slot to 0 0 to make sure slot is not used + netem_str_ += f' slot 0 0' + + if loss_type != 'off': + if loss_type == 'random': + netem_str_ += f' loss {loss:.6f}%' + else: + probability_good2bad, probability_bad2good = self.__get_loss_state_param(loss / 100.0, loss_type) + netem_str_ += f' loss gemodel {probability_good2bad*100:.6f}% {probability_bad2good*100:.6f}%' + app.logger.info(f"class_str: {class_str_}") + app.logger.info(f"netem_str: {netem_str_}") SimuPathManager.run_cmd('tc class {opt} dev {iface} parent {handle}: classid {handle}:{host_num} htb {class_str} quantum 60000'.format( opt = opt, iface = self.__direction[direction_]['to'], handle = SimuPathManager.handle_name, host_num = self.filter.mark, class_str = class_str_)) SimuPathManager.run_cmd('tc qdisc {opt} dev {iface} parent {handle}:{host_num} handle {host_num}: netem {netem_str}'.format( @@ -239,6 +273,7 @@ def _run_model(self): for model_timeslot in model_timeline: merged_model = SimuPathManager.merge_dicts(model_global, model_timeslot) + app.logger.info(f"merged_model: {json.dumps(merged_model, indent=2)}") if is_first_timeslot: opt_ = 'add' @@ -271,8 +306,9 @@ def _set_rule(self, direction : str, opt : str, config : dict): delay = config.get('delay', 0), jitter = config.get('jitter', 0), jitter_dist = config.get('jitter_dist', 'normal'), - slot = config.get('slot', [0, 0]), - reorder_allowed = config.get('reorder_allowed', False), + loss_type = config.get('loss_type', 'off'), + latency_type = config.get('latency_type', 'off'), + throttle_type = config.get('throttle_type', 'off') ) def _simu_path_worker(self): @@ -412,6 +448,56 @@ def __get_delay_jitter_param(self, input_delay, input_jitter): # Make the jitter's literal value closer to the observed value in statistics return delay_, int(jitter_ / 2) + def __get_slot_jitter_param( self, input_jitter: float, slot_time: float = 20.0 ): + """ + Generate a tc netem command that simulates jitter WITHOUT packet reordering + using slot-based delay. + + Args: + input_jitter: Target jitter (± range, milliseconds) + slot_time: Slot interval; smaller = finer jitter resolution (default: 20.0ms) + + Returns: + tuple: (slot_time, max_delay) + """ + + # max_delay chosen so that mean deviation ≈ input_jitter + max_delay = (input_jitter + slot_time) * 2 + + return slot_time, max_delay + + def __get_loss_state_param(self, loss_rate: float, loss_type: str = 'random'): + """ + Generate tc netem Markov loss commands with the same overall loss rate + but different burst characteristics. + + Args: + loss_rate: overall packet loss rate (0 < loss_rate < 1) + loss_type: loss type, 'random', 'burst-low', 'burst-medium', 'burst-high' + + Returns: + tuple: (probability_good2bad, probability_bad2good) + """ + + if not (0 < loss_rate < 1): + raise ValueError("loss_rate must be in (0, 1)") + + # Average burst lengths for each profile + profiles = { + "random": 1.0, # almost i.i.d + "burst-low": 3.0, # mild correlation + "burst-medium": 10.0, # typical bad network + "burst-high": 50.0 # severe burst loss + } + + if loss_type not in profiles: + raise ValueError(f"Invalid loss type: {loss_type}") + + probability_bad2good = 1.0 / profiles[loss_type] + probability_good2bad = loss_rate * probability_bad2good / (1.0 - loss_rate) + + return probability_good2bad, probability_bad2good + @classmethod def from_dict(cls, data: Dict) -> 'SimuPath': """Create a SimuPath instance from a dictionary""" @@ -430,11 +516,11 @@ class SimuPathManager: PRIO = 2 OVERHEAD = 0 - MAX_RATE = 32000000 # 32Gbps + MAX_RATE = 1000000 # 32Gbps handle_name = '9527' lan_ifname = None wan_ifname = None - mark_range = (9527, 9559) + mark_range = (9528, 9560) def __new__(cls): if cls._instance is None: diff --git a/nethang/templates/index.html b/nethang/templates/index.html index ce3ff0c..517acb7 100644 --- a/nethang/templates/index.html +++ b/nethang/templates/index.html @@ -167,17 +167,13 @@
Filter Settings
- Delay - + Delay / Jitter + Loss - - Jitter - - @@ -199,17 +195,13 @@
Filter Settings
- Delay - + Delay / Jitter + Loss - - Jitter - - @@ -348,11 +340,11 @@
Uplink Settings
-
Throttle
- - - + +
-
Latency -
-
+
+
Latency
+ +
+
-
Loss
-
+
+
Loss
+ +
+ @@ -483,11 +473,11 @@
Downlink Settings
-
Throttle
- - - + +
-
Latency -
-
+
+
Latency
+ +
+
-
Loss
-
+
+
Loss
+ +
+ @@ -700,11 +687,11 @@
Uplink Settings
-
Throttle
- - - + +
-
Latency -
-
+
+
Latency
+ +
+
-
Loss
-
+
+
Loss
+ +
+ @@ -838,11 +822,11 @@
Downlink Settings
-
Throttle
- - - + +
-
Latency -
-
+
+
Latency
+ +
+
-
Loss
-
+
+
Loss
+ +
+ @@ -994,9 +975,30 @@
Loss
{% endblock %} {% block extra_js %} +