This is my bachelor thesis.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 

722 lines
30 KiB

import argparse
from mininet.net import Mininet
from mininet.log import setLogLevel, info
from mininet.cli import CLI
import topologies
import inspect
import importlib
import pkgutil
from time import sleep
from mininet.link import TCLink
from mininet.node import CPULimitedHost
from datetime import datetime
import threading, time, traceback
from nftables import Nftables
from nftables import json
import os
topos = {
"Minimal": {
"class": "Minimal",
"module": "minimum",
"description": "2 hosts connected to a switch"
},
"4R4H": {
"class": "FourRoutersFourHosts",
"module": "4r4h_topo",
"description": "A topology using 4 routers and 3 hosts"
},
"6R4H": {
"class": "SixRoutersFourHosts",
"module": "6r4h_topo",
"description": "A topology using 6 routers and 3 hosts"
},
"8R4H": {
"class": "EightRoutersFourHosts",
"module": "8r4h_topo",
"description": "A topology using 8 routers and 3 hosts"
}
}
functions = {
"connection_shutdown": {
"callable": lambda net, triple: connection_shutdown(net, triple[0], triple[1], triple[2])
},
"measure_bandwidth": {
"callable": lambda net, nonet: measure_bandwidth(net, nonet[0], nonet[1], nonet[2], nonet[3], nonet[4],
nonet[5], nonet[6], nonet[7], nonet[8])
},
"measure_latency": {
"callable": lambda net, septet: measure_latency(net, septet[0], septet[1], septet[2], septet[3], septet[4],
septet[5], septet[6])
},
"measure_packet_flow": {
"callable": lambda net, elevenet: measure_packet_flow(net, elevenet[0], elevenet[1], elevenet[2], elevenet[3],
elevenet[4], elevenet[5], elevenet[6], elevenet[7],
elevenet[8], elevenet[9], elevenet[10])
},
"measure_link_usage_bandwidth": {
"callable": lambda net, nonet: measure_link_usage_bandwidth(net, nonet[0], nonet[1], nonet[2], nonet[3], nonet[4],
nonet[5], nonet[6], nonet[7], nonet[8])
}
}
use_shortcut = False
# Stores information about already created chains and tables on each router. If a router is in this list, it means the chain and table for nftables were already created
shortcut_nftables_memory = []
packet_counter_memory = []
packet_counter_initialized = False
def get_tests(topo):
available_tests = []
topology = get_topo_by_name(topo)
if topology is None:
print(f"Unknown topology {topo}, exiting...")
exit()
for test, test_data in topology.get_tests().items():
available_tests.append(test)
print('Currently available tests are: ' + str(available_tests))
def implement_shortcut(net, router, interface, dest_ip, gateway, queue_id):
# implement hook
info(f"Deploying ShortCut for {interface} to {dest_ip} in Queue {queue_id}\n")
shortcut_log_file = "/tmp/shortcut.log"
if router not in shortcut_nftables_memory:
# creating nftables table and chains as these are not supplied by default
net[router].cmd(f"nft add table ip filter >> {shortcut_log_file}")
net[router].cmd(
f"nft 'add chain ip filter INPUT {{ type filter hook input priority 0; policy accept; }}' >> {shortcut_log_file}")
net[router].cmd(
f"nft 'add chain ip filter FORWARD {{ type filter hook forward priority 0; policy accept; }}' >> {shortcut_log_file}")
net[router].cmd(
f"nft 'add chain ip filter OUTPUT {{ type filter hook output priority 0; policy accept; }}' >> {shortcut_log_file}")
shortcut_nftables_memory.append(router)
net[router].cmd(
f"nft add rule ip filter FORWARD iifname '{interface}' ip daddr {dest_ip} counter queue num {queue_id} >> {shortcut_log_file}")
# execute listener
net[router].cmd(f"sudo python3 shortcut_listener.py -g {gateway} -id {queue_id} -s 24 &> listener.log &")
def implement_packet_counter(net, device, protocol):
available_protocols = ["tcp", "udp"]
if protocol.lower() not in available_protocols:
info(
f"The protocol {protocol} is not an available protocol. Available protocols for packet counters are: {str(available_protocols)}")
return
table_name = f"counter_{protocol.lower()}"
counter_name = f"{protocol.lower()}_{device}_counter"
net[device].cmd(f"nft add table ip {table_name}")
net[device].cmd(
f"nft 'add chain ip {table_name} FORWARD {{ type filter hook forward priority filter; policy accept; }}'")
net[device].cmd(f"nft add counter {table_name} {counter_name}")
net[device].cmd(f"nft 'add rule {table_name} FORWARD {protocol.lower()} dport 0-65535 counter name {counter_name}'")
memory_entry = {
"device": device,
"protocol": protocol.lower(),
"counter": counter_name,
"table": table_name
}
packet_counter_memory.append(memory_entry)
def reset_packet_counters(net):
for memory_entry in packet_counter_memory:
net[memory_entry["device"]].cmd(f"nft reset counter ip {memory_entry['table']} {memory_entry['counter']}")
def start_packet_counter_timers(net, interval, length, flag, test_prefix, test_type, timestamp):
for memory_entry in packet_counter_memory:
threading.Thread(
target=lambda: read_packet_counter(interval, length, net, memory_entry["device"], memory_entry["table"],
memory_entry["counter"], flag, test_prefix, test_type,
timestamp)).start()
def get_packet_counter_log_file_name(device, table, flag):
return f"{device}_packet_{table}_{flag}.out"
def read_packet_counter(delay, length, net, device, table, counter, flag, test_prefix, test_type, timestamp):
info(f"\nStarted packet counter thread for {device}")
executions = int(length / delay)
execution_counter = 0
current_time = 0
running = True
initial_run = True
next_time = int(time.time())
last_value = 0
log_file_folder = get_test_folder_path(test_prefix, test_type, timestamp)
log_file = f"{log_file_folder}/{get_packet_counter_log_file_name(device, table, flag)}"
if os.path.exists(log_file):
os.remove(log_file)
log_file_object = open(log_file, "a")
while running:
if initial_run:
initial_run = False
else:
time.sleep(max(0, next_time - int(time.time())))
try:
# nft works in network namespaces, therefore each device holds its own nftables configuration
packet_counter_output = net[device].cmd(f"nft list counter ip {table} {counter}")
if packet_counter_output is not None:
packet_counter_output_lines = packet_counter_output.split("\n")
# parsing the received output from nftables
relevant_output = packet_counter_output_lines[2][
packet_counter_output_lines[2].find("packets") + 7:packet_counter_output_lines[
2].find("bytes")].strip()
current_time = round(current_time + delay, 1)
log_output = int(relevant_output) - last_value
last_value = int(relevant_output)
log_file_object.write(f"{current_time - delay} {str(log_output)}\n")
if execution_counter >= executions:
running = False
else:
execution_counter += 1
except Exception:
traceback.print_exc()
# in production code you might want to have this instead of course:
# logger.exception("Problem while executing repetitive task.")
# skip tasks if we are behind schedule:
next_time = next_time + delay
log_file_object.close()
info(f"\nPacket counter thread for {device} finished executing after {execution_counter}/{executions} executions")
def connection_shutdown(net, connection, names, interfaces):
counter = 0
info(f"\nCutting connection between {names[0]} and {names[1]}\n")
for component in connection:
name = names[counter]
interface = interfaces[counter]
interface_shutdown(net[component], name, interface)
counter += 1
def number_check(pseudo_number):
return type(pseudo_number) == float or type(pseudo_number) == int
def create_plot_command(graph_title, file_name, yrange, xlabel="", ylabel=""):
title_string = ""
if graph_title != "":
title_string = f"title \'{graph_title}\' "
graph_file_name = f"{file_name}_graph.eps"
info(f"\nCreating plot graphic {graph_file_name}...")
if yrange[1] < 0:
calc_yrange = get_graph_yrange(file_name + "_parsed.out", 0)
yrange[1] = calc_yrange[1]
return f'gnuplot -e "set term eps;set yrange [{yrange[0]}:{yrange[1]}]; set ylabel \'{ylabel}\' ; set xlabel \'{xlabel}\' ; set output \'{graph_file_name}\'; plot \'{file_name}_parsed.out\' {title_string}w linespoints lc rgb \'black\'"'
def map_color(number_of_colors):
distinguishable_greys = [0, 37, 82, 115, 150]
if number_of_colors == 1:
return [0]
elif number_of_colors == 2:
return [0, 150]
elif number_of_colors == 3:
return [0, 82, 150]
elif number_of_colors == 4:
return [0, 37, 115, 150]
elif number_of_colors == 5:
return distinguishable_greys
def grey_to_hex(grey_value_list):
hex_value_list = []
for grey_value in grey_value_list:
hex_value = '{:02x}'.format(int(grey_value))
hex_value_list.append("#" + hex_value * 3)
return hex_value_list
def get_test_folder_path(prefix, test_type, timestamp):
return f"/tmp/{prefix}_{test_type}_{timestamp}"
def create_multi_plot_command(graph_title, file_name, yrange, data_file_names, xlabel="", ylabel=""):
title_string = ""
if graph_title != "":
title_string = f"title \'{graph_title}\' "
if len(data_file_names) > 5:
info("\nThis function can only create up to 5 plots in one graph, you provided " + str(
len(data_file_names)) + " file sources")
return ""
graph_file_name = f"{file_name}_graph.eps"
info(f"\nCreating plot graphic {graph_file_name}...")
if yrange[1] < 0:
calc_yrange = get_graph_yrange(file_name + "_parsed.out", 0)
yrange[1] = calc_yrange[1]
plot_command = "plot "
plot_counter = 0
graph_colors = grey_to_hex(map_color(len(data_file_names)))
for label, data_file_name in data_file_names.items():
plot_command += f"'{data_file_name}' using 1:2 title '{label}' lc rgb '{graph_colors[plot_counter]}' dt {plot_counter + 1} w linespoints,"
plot_counter += 1
plot_command = plot_command[:-1]
gnuplot_command = f'gnuplot -e "set term eps;set yrange [{yrange[0]}:{yrange[1]}]; set ylabel \'{ylabel}\' ; set xlabel \'{xlabel}\' ; set output \'{graph_file_name}\'; show style line; {plot_command}"'
info("\nGnuplot command: " + gnuplot_command)
return gnuplot_command
def measure_packet_flow(net, client, server, server_ip, flow_measurement_targets, length, interval, unique_test_name,
y_range, graph_title, flag="tcp", bandwidth=100):
global packet_counter_initialized
if not packet_counter_initialized:
info("\nImplementing nftables packet counters")
for target in flow_measurement_targets:
implement_packet_counter(net, target, flag)
packet_counter_initialized = True
else:
info("\nPacket counters already initialized, resetting counters")
reset_packet_counters(net)
# make sure everything is initialized
sleep(1)
client_type_string = ""
if flag == "udp":
client_type_string = f"-u"
shortcut_flag = "wo_sc"
if use_shortcut:
shortcut_flag = "sc"
test_prefix = f"{client}_to_{server}"
test_type = "packet_flow"
timestamp = datetime.now().strftime("%d%m%Y_%H%M%S")
tmp_file_folder = get_test_folder_path(test_prefix, test_type, timestamp)
if not os.path.exists(tmp_file_folder):
info(f"\nCreated folder for new test under {tmp_file_folder}")
os.mkdir(tmp_file_folder)
tmp_file_name = f"{tmp_file_folder}/{unique_test_name}_{shortcut_flag}"
iperf_server_command = get_iperf_server_command(interval, tmp_file_name)
net[server].cmd(iperf_server_command)
sleep(1)
net[client].cmd(
f"iperf3 -c {server_ip} -b 0 -f m -i {interval} -t {length+5} {client_type_string} > {tmp_file_name}_client.out &")
sleep(2)
reset_packet_counters(net)
start_packet_counter_timers(net, interval, length, unique_test_name, test_prefix, test_type, timestamp)
sleep(length + 4)
# make sure packet counters ran out
info("\nStopping iPerf server...")
net[server].cmd("pkill iperf3")
info("\nCollecting information...")
number_of_lines = int(length / interval)
file_names = {}
for memory_entry in packet_counter_memory:
file_names[memory_entry[
"device"]] = f"{tmp_file_folder}/{get_packet_counter_log_file_name(memory_entry['device'], memory_entry['table'], unique_test_name)}"
multiplot_command = create_multi_plot_command(graph_title, tmp_file_name, y_range, file_names, "Time in seconds",
"Packets received")
if multiplot_command is not None:
net[server].cmd(multiplot_command)
def get_graph_yrange(parsed_file_name, y_offset):
parsed_file = open(parsed_file_name)
parsed_file_lines = parsed_file.readlines()
y_max = None
y_min = None
for line in parsed_file_lines:
values = line.split()
if len(values) != 2:
pass
else:
if y_max is None or int(values[1]) > y_max:
y_max = int(values[1])
if y_min is None or int(values[1]) < y_min:
y_min = int(values[1])
y_min -= y_offset
y_max += y_offset
return [y_min, y_max]
def measure_latency(net, sender, dest_ip, length, interval, unique_test_name, y_range, graph_title=""):
shortcut_flag = "wo_sc"
if use_shortcut:
shortcut_flag = "sc"
tmp_file_name = f"/tmp/{sender}_to_{dest_ip}_ping_{unique_test_name}_{shortcut_flag}"
packet_count = int(length / interval)
ping_command = f"ping -c {packet_count} -i {interval} {dest_ip} > {tmp_file_name}.out &"
net[sender].cmd(ping_command)
info(f"\nUsing ping command: {ping_command}")
sleep(length + 5)
parsed_file_name = f"{tmp_file_name}_pre_parsed.out"
extended_file_name = f"{tmp_file_name}_parsed.out"
extended_command = f'printf "0.0 0\n$(cat {parsed_file_name})" > {extended_file_name}'
parsing_command = f"more {tmp_file_name}.out | grep ms | head -{packet_count} | tr = ' ' | awk '{{print $6*{interval},$10}}' > {parsed_file_name}"
info(f"\nLatency measurement finished. Output under: {tmp_file_name}.out")
net[sender].cmd(parsing_command)
info(f"\nParsed output. Data source for Gnuplot under: {extended_file_name}")
net[sender].cmd(extended_command)
sleep(1)
net[sender].cmd(create_plot_command(graph_title, tmp_file_name, y_range, "Time in seconds", "Latency in milliseconds"))
def measure_bandwidth(net, components, iperf_server_ip, length, interval, unique_test_name, graph_title="", flag="tcp",
bandwidth=100, yrange=[0, 0]):
if len(components) != 2:
info("\nCan't measure bandwidth between more than 2 hosts")
return
if not number_check(length) or not number_check(interval):
info("\nlength and interval need to be either floats or ints")
return
iperf_client = components[0]
iperf_server = components[1]
shortcut_flag = "wo_sc"
if use_shortcut:
shortcut_flag = "sc"
tmp_file_name = f"/tmp/{iperf_client}_to_{iperf_server}_iperf_{unique_test_name}_{shortcut_flag}"
client_type_string = ""
if flag == "udp":
client_type_string = f"-u"
iperf_server_command = get_iperf_server_command(interval, tmp_file_name)
net[iperf_server].cmd(iperf_server_command)
info("\niPerf3 server command: " + iperf_server_command)
# wait for server to finish starting
sleep(1)
# setting bandwidth to a value of bits/s, default for bandwidth argument is Megabit/s
iperf_client_command = f"iperf3 -c {iperf_server_ip} -b {int(bandwidth) * 1000000} -f m -i {interval} -t {length} {client_type_string} > {tmp_file_name}_client.out &"
info("\niPerf3 client command: " + iperf_client_command)
net[iperf_client].cmd(iperf_client_command)
sleep(length + 5)
info("\nStopping iPerf server...")
net[iperf_server].cmd("pkill iperf3")
info("\nCollecting information...")
number_of_lines = int(length / interval)
parsed_file_name = f"{tmp_file_name}_pre_parsed.out"
parsing_command = f'cat {tmp_file_name}_server.out | grep sec | head -{number_of_lines} | tr - " " | awk \'{{print $4,$8}}\' > {parsed_file_name}'
net[iperf_server].cmd(parsing_command)
extended_file_name = f"{tmp_file_name}_parsed.out"
extended_command = f'printf "0.0 0\n$(cat {parsed_file_name})" > {extended_file_name}'
net[iperf_server].cmd(extended_command)
sleep(1)
xlabel = "Time in seconds"
ylabel = "Mbit(s)"
plot_command = create_plot_command(graph_title, tmp_file_name, yrange, xlabel, ylabel)
net[iperf_server].cmd(plot_command)
def get_iperf_server_command(interval, file_name, port=5201):
return f"iperf3 -s -p {port} -f m -i {interval} > {file_name}_server.out &"
def get_iperf_client_command(server_ip, bandwidth, interval, length, flag, file_name, port=5201):
client_type_string = f"-b {int(bandwidth) * 1000000}"
if flag == "udp":
client_type_string = "-u -b 0"
return f"iperf3 -c {server_ip} -p {port} -f m -i {interval} -t {length} {client_type_string} > {file_name}_client.out &"
def execute_command(net, device, command):
net[device].cmd(command)
def measure_link_usage_bandwidth(net, test_iperf_config, additional_iperf_config, length, interval, unique_test_name,
graph_title="", flag="tcp",
bandwidth=100, yrange=[0, 0]):
shortcut_flag = "wo_sc"
if use_shortcut:
shortcut_flag = "sc"
sleep(2) # little delay in case of previous executions
tmp_file_name = f"/tmp/{test_iperf_config['client']}_to_{test_iperf_config['server']}_iperf_{unique_test_name}_{shortcut_flag}"
iperf_additional_server_command = get_iperf_server_command(interval, tmp_file_name + "_additional", 5202)
info(f"\nStarting additional transfer to measure influence on bandwidth between {additional_iperf_config['client']} and {additional_iperf_config['server']}")
net[additional_iperf_config['server']].cmd(iperf_additional_server_command)
sleep(1) # wait to be sure server started
iperf_additional_client_command = get_iperf_client_command(additional_iperf_config['server_ip'], bandwidth, interval, length+4, flag, tmp_file_name+"_additional", 5202)
info(f"\nExecuting command on {additional_iperf_config['client']}: {iperf_additional_client_command}")
# Start concurrent traffic at the same time as actual traffic
#threading.Timer(1, execute_command, [net, additional_iperf_config['client'], iperf_additional_client_command])
net[additional_iperf_config['client']].cmd(iperf_additional_client_command)
measure_bandwidth(net, [test_iperf_config['client'], test_iperf_config['server']], test_iperf_config['server_ip'], length, interval, unique_test_name, graph_title, flag, bandwidth, yrange)
sleep(5)
net[additional_iperf_config['server']].cmd("pkill iperf3")
number_of_lines = int(length / interval)
parsed_file_name = f"{tmp_file_name}_pre_parsed.out"
parsing_command = f'cat {tmp_file_name}_additional_server.out | grep sec | head -{number_of_lines+1} | tail -{number_of_lines} | tr - " " | awk \'{{print $3,$8}}\' > {parsed_file_name}'
net[additional_iperf_config['server']].cmd(parsing_command)
extended_file_name = f"{tmp_file_name}_additional_parsed.out"
extended_command = f'printf "0.0 0\n$(cat {parsed_file_name})" > {extended_file_name}'
net[additional_iperf_config['server']].cmd(extended_command)
xlabel = "Time in seconds"
ylabel = "Mbit(s)"
plot_command = create_multi_plot_command(graph_title, tmp_file_name+"_combined", yrange, {"main data flow": f"{tmp_file_name}_parsed.out", "additional data flow": f"{tmp_file_name}_additional_parsed.out"}, xlabel, ylabel)
net[additional_iperf_config['server']].cmd(plot_command)
def interface_shutdown(component, component_name, interface):
info(f"\nShutting down intf {interface} on {component_name}\n")
component.cmd(f"ifconfig {interface} down")
def get_available_topos():
available_topos = {}
for topo_id, topo_info in topos.items():
available_topos[topo_id] = topo_info["description"]
return available_topos
def configure_mininet(net, topo, shortcut=False):
table_interface_map = topo.get_policy_table_interface_map()
interface_gateway_map = topo.get_interface_gateway_map()
for router, configuration in topo.get_routings().items():
tables = []
shortcut_memory = []
shortcut_queue_id = 1
table_id = 200
for table, routes in configuration.items():
if table not in tables and table != "default":
# Creating tables that do not exist for this router yet
net[router].cmd(f"echo {table_id} {table} >> /etc/iproute2/rt_tables")
tables.append(table)
table_id += 1
for route in routes:
address = route[0]
gateway = route[1]
interface = route[2]
priority = route[3]
table_string = ""
if table != "default":
table_string = f"table {table} "
incoming_interface = table_interface_map[router][table]
cut_gateway = interface_gateway_map[incoming_interface]
shortcut_identification = f"{incoming_interface}-{address}-{cut_gateway}"
if shortcut_identification not in shortcut_memory and shortcut:
implement_shortcut(net, router, incoming_interface, address, cut_gateway, shortcut_queue_id)
shortcut_memory.append(shortcut_identification)
shortcut_queue_id += 1
net[router].cmd(f"ip route add {table_string}{address} via {gateway} dev {interface} metric {priority}")
def get_topo_by_name(name, limit=None, delay=None):
if name not in topos:
info(f"Unknown topology {name}...")
module = importlib.import_module(f"topologies.{topos[name]['module']}")
topo_class = getattr(module, topos[name]['class'])
return topo_class(custom_limit=limit, custom_delay=delay)
def handle_config_execute(net, execute_config, execution_flag=None):
if execution_flag is None or "separate_definitions" not in execute_config or not execute_config[
"separate_definitions"]:
if execute_config['use_pre_defined_function']:
return execute_function(net, execute_config["command"])
else:
return execute_config['command'](net)
else:
if execution_flag == "pre":
if execute_config['use_pre_defined_function']:
return execute_function(net, execute_config["command_pre"])
else:
return execute_config['command_pre'](net)
elif execution_flag == "post":
if execute_config['use_pre_defined_function']:
return execute_function(net, execute_config["command_post"])
else:
return execute_config['command_post'](net)
else:
print("Unknown execution flag, valid flags are 'pre' and 'post'")
return None
def handle_timer_execute(net, execute_config, timing):
if execute_config['use_pre_defined_function']:
timer = threading.Timer(timing, execute_function, [net, execute_config["command"]])
else:
timer = threading.Timer(timing, execute_config['command'], [net])
timer.start()
def execute_function(net, function_tuple):
function_call = functions[function_tuple[0]]
if function_call is not None:
return function_call["callable"](net, function_tuple[1])
return None
def run(topology, test=None, limit=None, delay=None, shortcut=False):
if topology is None:
info("No topology was provided, aborting...")
exit()
topo_obj = get_topo_by_name(topology, limit, delay)
if topo_obj is None:
exit()
net = Mininet(topo=topo_obj, host=CPULimitedHost, link=TCLink)
configure_mininet(net, topo_obj, shortcut)
# adding additional routing tables, we use 200 as custom table number
for router, policies in topo_obj.get_policies().items():
for rule in policies['rules']:
for to in rule['to']:
net[router].cmd(f"ip rule add iif {rule['inport']} to {to} table {rule['table']}")
# if we want to create a timed failure (maybe while pinging), we can use a timer
# router2_failure = Timer(15, introduce_failure(net["r2"], "r2-eth3"))
global packet_counter_initialized
global packet_counter_memory
global shortcut_nftables_memory
# reset values in case of second execution in runtime
packet_counter_initialized = False
packet_counter_memory = []
shortcut_nftables_memory = []
net.start()
# CLI(net)
n = 1
tests = topo_obj.get_tests()
intermediates = []
timers = []
if test is not None:
if test in tests:
test_data = tests[test]
# print(test_data)
repeat_test = False
info(f"---- Performing test on route {test_data['source']} -> {test_data['destination']} ----\n")
if 'pre_execution' in test_data.keys():
handle_config_execute(net, test_data['pre_execution'])
if test_data['failures']:
for failure in test_data['failures']:
if failure['type'] == "intermediate":
intermediates.append(failure)
if failure['type'] == "timer":
timers.append(failure)
if timers:
for timer in timers:
handle_timer_execute(net, timer['execute'], timer['timing'])
info(f"Performing test {n}\n")
results = handle_config_execute(net, test_data['execute'], 'pre')
if type(results) is str:
info(results + '\n')
if intermediates:
repeat_test = True
for failure in intermediates:
handle_config_execute(net, failure['execute'])
if repeat_test:
info(f"Performing test {n} after failure\n")
# Make sure failure has taken effect
sleep(1)
if 'pre_execution' in test_data.keys():
handle_config_execute(net, test_data['pre_execution'])
results = handle_config_execute(net, test_data['execute'], 'post')
if type(results) is str:
info(results + '\n')
n += 1
else:
CLI(net)
# introduce_failure(net["r2"], "r2-eth3")
net.stop()
if __name__ == '__main__':
setLogLevel('info')
parser = argparse.ArgumentParser()
parser.add_argument('--tests', help='list all available tests for a topology', action='store_true')
parser.add_argument('--test', help='perform defined test on execution')
parser.add_argument('--topo', help='use defined topo')
parser.add_argument('--topos', help='list all available topologies', action='store_true')
parser.add_argument('--shortcut', help='use shortcut', action='store_true')
parser.add_argument('--limit_bw', help='limit bandwith of links in MBits')
parser.add_argument('--delay', help='add delay in ms to each link')
parser.add_argument('--produce_set', help='will execute the test with and without ShortCut', action='store_true')
parser.add_argument('--full_suite', help='will execute the test with and without ShortCut on all defined topologies', action='store_true')
args = parser.parse_args()
bw_limit = None
delay = None
if args.tests:
if args.topo is None:
info("Please specify a topology to print out tests for! (--topo)")
exit()
topo = get_topo_by_name(args.topo)
if topo is None:
exit()
get_tests(args.topo)
exit()
if args.topos:
print(get_available_topos())
exit()
if args.limit_bw is not None:
if not args.limit_bw.isnumeric():
info("Please only specify a numeric value as bandwith limit, exiting...")
exit()
bw_limit = int(args.limit_bw)
if args.delay is not None:
if not args.delay.isnumeric():
info("Please only specify a numeric value as delay, exiting...")
exit()
delay = f"{args.delay}ms"
if args.shortcut:
use_shortcut = True
if args.produce_set:
# we need to set global value because some functions depend on it
use_shortcut = False
run(args.topo, args.test, bw_limit, delay, use_shortcut)
sleep(1)
use_shortcut = True
run(args.topo, args.test, bw_limit, delay, use_shortcut)
elif args.full_suite:
topologies_to_test = ['4R4H', '6R4H', '8R4H']
for test_topo in topologies_to_test:
use_shortcut = False
run(test_topo, args.test, bw_limit, delay, use_shortcut)
sleep(1)
use_shortcut = True
run(test_topo, args.test, bw_limit, delay, use_shortcut)
else:
run(args.topo, args.test, bw_limit, delay, use_shortcut)