Skip to content

Commit

Permalink
feat: latency simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
BastienFaivre committed Jan 24, 2025
1 parent f30d2c9 commit 038e2ba
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
26 changes: 26 additions & 0 deletions benchmark/playbooks/tc_apply.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
- name: Apply all TC rules
hosts: all
become: true

vars:
ansible_ssh_user: root

tasks:
- name: Upload latencies csv file
copy:
src: "{{ playbook_dir }}/../config/latencies.csv"
dest: /home/bob/latencies.csv

- name: Upload machines IPs list
copy:
src: "{{ playbook_dir }}/../machines.txt"
dest: /home/bob/machines.txt

- name: Upload tc script
copy:
src: "{{ playbook_dir }}/../scripts/apply-tc-rules.py"
dest: /home/bob/apply-tc-rules.py
mode: 0744

- name: Apply tc rules
command: "/home/bob/apply-tc-rules.py /home/bob/latencies.csv /home/bob/machines.txt {{ ansible_host }}"
10 changes: 10 additions & 0 deletions benchmark/playbooks/tc_reset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- name: Reset all TC rules
hosts: all

vars:
ansible_ssh_user: root

tasks:
- name: Reset all TC rules
shell: tc qdisc del dev eth0 root
ignore_errors: yes
76 changes: 76 additions & 0 deletions benchmark/scripts/apply-tc-rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/python3
# INTENDED TO BE EXECUTED ON BENCHMARK MACHINES
import sys
import csv
import subprocess

def read_matrix(csv_file):
with open(csv_file) as f:
reader = csv.reader(f)
header = next(reader)[1:]
matrix = {}
for row in reader:
row_zone = row[0]
matrix[row_zone] = {}
for i, col_zone in enumerate(header):
matrix[row_zone][col_zone] = int(row[i+1])
return header, matrix

def read_ips(ip_file):
with open(ip_file) as f:
return [line.strip() for line in f if line.strip()]

def execute_command(cmd):
subprocess.run(cmd, shell=True, check=True)

def build_tc_commands(header, matrix, ips, local_ip):
commands = []
num_zones = len(header)
local_index = ips.index(local_ip)
local_zone = header[local_index % num_zones]

commands.append("tc qdisc del dev eth0 root 2> /dev/null || true")
commands.append("tc qdisc add dev eth0 root handle 1: htb default 10")
commands.append("tc class add dev eth0 parent 1: classid 1:1 htb rate 1gbit")
commands.append("tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1gbit")
commands.append("tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10")

handle = 11
for zone in header:
zone_machines = []
for ip in ips:
if ip != local_ip:
idx = ips.index(ip)
z = header[idx % num_zones]
if z == zone:
zone_machines.append(ip)

if not zone_machines:
continue

latency = matrix[local_zone][zone]
if latency > 0:
delta = latency // 20
if delta == 0:
delta = 1
commands.append(f"tc class add dev eth0 parent 1:1 classid 1:{handle} htb rate 1gbit")
commands.append(f"tc qdisc add dev eth0 parent 1:{handle} handle {handle}: netem delay {latency}ms {delta}ms distribution normal")
for ip in zone_machines:
commands.append(f"tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst {ip}/32 flowid 1:{handle}")
handle += 1
return commands

def main():
csv_file = sys.argv[1]
ip_file = sys.argv[2]
local_ip = sys.argv[3]

header, matrix = read_matrix(csv_file)
ips = read_ips(ip_file)
commands = build_tc_commands(header, matrix, ips, local_ip)

for cmd in commands:
execute_command(cmd)

if __name__ == "__main__":
main()

0 comments on commit 038e2ba

Please sign in to comment.