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.
-
+
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
-
+- 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.
+
- 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
+
+
+
+- Network latency and latency variation (Jitter) simulation
+- Jitter simulation with and without reordering allowed
+
+
+
+
+- Packet loss with random and burst support
+
+
+
- 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 @@