Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add netem limit #185

Merged
merged 3 commits into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/pages/introduction/feature.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The following parameters can be set to network interfaces:
- Packet corruption rate ``[%]``
- Packet duplicate rate ``[%]``
- Packet reordering rate ``[%]``
- Packet limit count ``[COUNT]``

Targets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 3 additions & 1 deletion docs/pages/usage/tcset/tcset_help_output.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
::

usage: tcset [-h] [-V] [--tc-command | --tc-script] [--debug | --quiet] [--debug-query] [--stacktrace] [--import-setting] [--overwrite | --change | --add] [--rate BANDWIDTH_RATE] [--delay LATENCY_TIME] [--delay-distro LATENCY_DISTRO_TIME] [--delay-distribution {normal,pareto,paretonormal}] [--loss PACKET_LOSS_RATE] [--duplicate PACKET_DUPLICATE_RATE]
[--corrupt CORRUPTION_RATE] [--reordering REORDERING_RATE] [--shaping-algo {htb,tbf}] [--iptables] [--direction {outgoing,incoming}] [--network DST_NETWORK] [--src-network SRC_NETWORK] [--port DST_PORT] [--src-port SRC_PORT] [--ipv6] [--exclude-dst-network EXCLUDE_DST_NETWORK] [--exclude-src-network EXCLUDE_SRC_NETWORK]
[--corrupt CORRUPTION_RATE] [--reordering REORDERING_RATE] [--limit PACKET_LIMIT_COUNT] [--shaping-algo {htb,tbf}] [--iptables] [--direction {outgoing,incoming}] [--network DST_NETWORK] [--src-network SRC_NETWORK] [--port DST_PORT] [--src-port SRC_PORT] [--ipv6] [--exclude-dst-network EXCLUDE_DST_NETWORK] [--exclude-src-network EXCLUDE_SRC_NETWORK]
[--exclude-dst-port EXCLUDE_DST_PORT] [--exclude-src-port EXCLUDE_SRC_PORT] [--docker] [--src-container SRC_CONTAINER] [--dst-container DST_CONTAINER]
device

Expand Down Expand Up @@ -42,6 +42,8 @@
packet corruption rate [%]. the valid range is from 0 to 100. packet corruption means a single-bit error at a random offset in the packet. (default=0)
--reordering REORDERING_RATE
packet reordering rate [%]. the valid range is from 0 to 100. (default=0)
--limit PACKET_LIMIT_COUNT
limits the maximum number of packets the qdisc may hold when doing delay. the minimum value is 1. (default=0)
--shaping-algo {htb,tbf}
shaping algorithm. defaults to htb (recommended).
--iptables use iptables for traffic control.
Expand Down
14 changes: 13 additions & 1 deletion tcconfig/_netem_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(
packet_duplicate_rate=None,
corruption_rate=None,
reordering_rate=None,
packet_limit_count=None,
):
self.__device = device

Expand All @@ -59,6 +60,7 @@ def __init__(
self.__packet_duplicate_rate = convert_rate_to_f(packet_duplicate_rate) # [%]
self.__corruption_rate = convert_rate_to_f(corruption_rate) # [%]
self.__reordering_rate = convert_rate_to_f(reordering_rate) # [%]
self.__packet_limit_count = convert_rate_to_f(packet_limit_count) # [COUNT]

self.__latency_time = None
if latency_time:
Expand Down Expand Up @@ -106,12 +108,14 @@ def validate_netem_parameter(self):
self.__validate_corruption_rate()
self.__validate_reordering_rate()
self.__validate_reordering_and_delay()
self.__validate_packet_limit_count()

netem_param_values = [
self.__packet_loss_rate,
self.__packet_duplicate_rate,
self.__corruption_rate,
self.__reordering_rate,
self.__packet_limit_count,
]
if self.__bandwidth_rate:
netem_param_values.append(self.__bandwidth_rate.kilo_bps)
Expand All @@ -128,7 +132,7 @@ def validate_netem_parameter(self):
raise hr.ParameterError(
"there are no valid net emulation parameters found. "
"at least one or more following parameters are required: "
"--rate, --delay, --loss, --duplicate, --corrupt, --reordering"
"--rate, --delay, --loss, --duplicate, --corrupt, --reordering, --limit"
)

def validate_bandwidth_rate(self):
Expand Down Expand Up @@ -175,6 +179,8 @@ def make_param_name(self):
if self.__reordering_rate:
item_list.append(f"reordering{self.__reordering_rate}")

if self.__packet_limit_count:
item_list.append(f"limit{self.__packet_limit_count}")
return "_".join(item_list)

def make_netem_command_parts(self):
Expand Down Expand Up @@ -205,6 +211,8 @@ def make_netem_command_parts(self):
if self.__reordering_rate > 0:
item_list.append(f"reorder {self.__reordering_rate:f}%")

if self.__packet_limit_count > 0:
item_list.append(f"limit {self.__packet_limit_count:f}")
return " ".join(item_list)

def calc_hash(self, extra=""):
Expand Down Expand Up @@ -274,3 +282,7 @@ def __validate_reordering_rate(self):
def __validate_reordering_and_delay(self):
if self.__reordering_rate and self.__latency_time and self.__latency_time.milliseconds <= 0:
raise hr.ParameterError("reordering needs latency to be specified: set latency > 0")

def __validate_packet_limit_count(self):
if self.__packet_limit_count and self.__packet_limit_count <= 0:
raise hr.ParameterError("packets limit count can't be less than 1: set limit > 0")
1 change: 1 addition & 0 deletions tcconfig/parser/_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ class Qdisc(Model):
corrupt = Text()
reorder = Text()
rate = Text()
limit = Integer()
1 change: 1 addition & 0 deletions tcconfig/parser/_qdisc.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def parse(self, device, text):
self.__parse_netem_param(line, "duplicate", pp.nums + ".%")
self.__parse_netem_param(line, "corrupt", pp.nums + ".%")
self.__parse_netem_param(line, "reorder", pp.nums + ".%")
self.__parse_netem_param(line, "limit", pp.nums)
self.__parse_bandwidth_rate(line)

logger.debug(f"parse a qdisc entry: {self.__parsed_param}")
Expand Down
9 changes: 9 additions & 0 deletions tcconfig/tcset.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ def get_arg_parser():
to {:d}. (default=%(default)s)
""".format(MIN_REORDERING_RATE, MAX_REORDERING_RATE),
)
group.add_argument(
"--limit",
dest="packet_limit_count",
default=0,
help="""limits the maximum number of packets the qdisc may hold when doing delay.
the minimum value is {:d}. (default=%(default)s)
""".format(1),
)
group.add_argument(
"--shaping-algo",
dest="shaping_algorithm",
Expand Down Expand Up @@ -309,6 +317,7 @@ def __create_tc(self, device):
packet_duplicate_rate=options.packet_duplicate_rate,
corruption_rate=options.corruption_rate,
reordering_rate=options.reordering_rate,
packet_limit_count=options.packet_limit_count,
),
dst_network=self._extract_dst_network(),
exclude_dst_network=options.exclude_dst_network,
Expand Down
1 change: 1 addition & 0 deletions tcconfig/tcshow.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ShapingRuleModel(Model):
corrupt = Text()
reorder = Text()
rate = Text()
limit = Text()


def parse_option():
Expand Down
4 changes: 2 additions & 2 deletions test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def print_test_result(expected, actual, error=None):
print(error, file=sys.stderr)


def is_invalid_param(rate, delay, packet_loss, packet_duplicate, corrupt, reordering):
param_values = [packet_loss, packet_duplicate, corrupt, reordering]
def is_invalid_param(rate, delay, packet_loss, packet_duplicate, corrupt, reordering, packet_limit):
param_values = [packet_loss, packet_duplicate, corrupt, reordering, packet_limit]

print(f"rate={rate}, params={param_values}")

Expand Down
2 changes: 2 additions & 0 deletions test/parser/test_shaping_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def test_normal(self, device_value):
packet_duplicate_rate=0,
corruption_rate=0,
reordering_rate=0,
packet_limit_count=0,
),
src_network="192.168.3.188",
dst_port=5201,
Expand All @@ -51,6 +52,7 @@ def test_normal(self, device_value):
packet_duplicate_rate=0,
corruption_rate=0,
reordering_rate=0,
packet_limit_count=0,
),
dst_network="192.168.3.188",
)
Expand Down
6 changes: 6 additions & 0 deletions test/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ class Test_TcQdiscParser_parse:
Tc.Param.HANDLE: "2007:",
Tc.Param.PARENT: "1f87:2",
"direct_qlen": 1000,
"limit": 1000,
}
)
],
Expand All @@ -518,6 +519,7 @@ class Test_TcQdiscParser_parse:
Tc.Param.HANDLE: "1a9a:",
Tc.Param.PARENT: "1a1a:2",
"direct_qlen": 1000,
"limit": 1000,
}
)
],
Expand All @@ -538,6 +540,7 @@ class Test_TcQdiscParser_parse:
Tc.Param.HANDLE: "2007:",
Tc.Param.PARENT: "1f87:2",
"direct_qlen": 1000,
"limit": 1000,
}
),
Qdisc(
Expand All @@ -548,6 +551,7 @@ class Test_TcQdiscParser_parse:
"delay-distro": "1.0ms",
Tc.Param.HANDLE: "2008:",
Tc.Param.PARENT: "1f87:3",
"limit": 1000,
}
),
],
Expand All @@ -568,6 +572,7 @@ class Test_TcQdiscParser_parse:
Tc.Param.HANDLE: "2007:",
Tc.Param.PARENT: "1f87:2",
"direct_qlen": 1000,
"limit": 1000,
}
),
Qdisc(
Expand All @@ -578,6 +583,7 @@ class Test_TcQdiscParser_parse:
"delay-distro": "1.0ms",
Tc.Param.HANDLE: "2008:",
Tc.Param.PARENT: "1f87:3",
"limit": 1000,
}
),
],
Expand Down
2 changes: 1 addition & 1 deletion test/test_traffic_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def test_normal(
shaping_algorithm=shaping_algorithm,
)

if is_invalid_param(rate, delay, loss, duplicate, corrupt, reordering=None):
if is_invalid_param(rate, delay, loss, duplicate, corrupt, reordering=None, limit=None):
with pytest.raises(ParameterError):
tc_obj.validate()
else:
Expand Down
Loading