commit 2022-02-16]13:26:08

This commit is contained in:
None 2022-02-15 20:26:18 -08:00
parent fac7b51d4c
commit 951cbd51e8
19 changed files with 507 additions and 166 deletions

View File

@ -2,4 +2,6 @@ leftSubnet:10.0.
rightSubnet:10.1. rightSubnet:10.1.
path_c2r_0:10,10,4 path_c2r_0:10,10,4
path_c2r_1:40,30,4 path_c2r_1:40,30,4
path_c2r_3:10,10,4
path_c2r_4:10,10,4
topoType:MultiIf topoType:MultiIf

5
config/topo/topo_1_1 Normal file
View File

@ -0,0 +1,5 @@
clients:5
leftSubnet:10.0.
rightSubnet:10.1.
path_c2r_0:10,10,4,10
topoType:IoTMultiClient

View File

@ -2,4 +2,7 @@ leftSubnet:10.0.
rightSubnet:10.1. rightSubnet:10.1.
path_c2r_0:10,10,4 path_c2r_0:10,10,4
path_c2r_1:40,30,4 path_c2r_1:40,30,4
path_c2r_3:40,30,4
path_c2r_4:40,30,4
topoType:MultiIfMultiClient topoType:MultiIfMultiClient

5
config/xp/basicquic Normal file
View File

@ -0,0 +1,5 @@
xpType:basicquic
serverPcap:yes
kpms:fullmesh
kpmc:fullmesh
rmem:300000 300000 300000

View File

@ -1,4 +1,4 @@
xpType:https xpType:pquic
clientPcap:yes clientPcap:yes
kpms:fullmesh kpms:fullmesh
kpmc:fullmesh kpmc:fullmesh

View File

@ -2,6 +2,7 @@ from .parameter import Parameter
import logging import logging
class ExperimentParameter(Parameter): class ExperimentParameter(Parameter):
""" """
Handler for experiment parameters stored in configuration files. Handler for experiment parameters stored in configuration files.
@ -12,25 +13,25 @@ class ExperimentParameter(Parameter):
Attribute: Attribute:
default_parameters Default values for the parameters default_parameters Default values for the parameters
""" """
RMEM = "rmem" RMEM = "rmem"
WMEM = "wmem" WMEM = "wmem"
MPTCP_ENABLED = "mptcpEnabled" MPTCP_ENABLED = "mptcpEnabled"
SCHED = "sched" SCHED = "sched"
CC = "congctrl" CC = "congctrl"
AUTOCORK = "autocork" AUTOCORK = "autocork"
EARLY_RETRANS = "earlyRetrans" EARLY_RETRANS = "earlyRetrans"
KERNELPM = "kpm" KERNELPM = "kpm"
KERNELPMC = "kpmc" #kernel path manager client / server KERNELPMC = "kpmc" # kernel path manager client / server
KERNELPMS = "kpms" KERNELPMS = "kpms"
USERPMC = "upmc" USERPMC = "upmc"
USERPMS = "upms" #userspace path manager client / server USERPMS = "upms" # userspace path manager client / server
USERPMC_ARGS = "upmc_args" USERPMC_ARGS = "upmc_args"
USERPMS_ARGS = "upms_args" USERPMS_ARGS = "upms_args"
CLIENT_PCAP = "clientPcap" CLIENT_PCAP = "clientPcap"
SERVER_PCAP = "serverPcap" SERVER_PCAP = "serverPcap"
SNAPLEN_PCAP = "snaplen_pcap" SNAPLEN_PCAP = "snaplen_pcap"
XP_TYPE = "xpType" XP_TYPE = "xpType"
PING_COUNT = "pingCount" PING_COUNT = "pingCount"
PRIO_PATH_0 = "priority_path_0" PRIO_PATH_0 = "priority_path_0"
PRIO_PATH_1 = "priority_path_1" PRIO_PATH_1 = "priority_path_1"
BACKUP_PATH_0 = "backup_path_0" BACKUP_PATH_0 = "backup_path_0"
@ -41,13 +42,13 @@ class ExperimentParameter(Parameter):
SYSCTL_KEY = { SYSCTL_KEY = {
RMEM: "net.ipv4.tcp_rmem", RMEM: "net.ipv4.tcp_rmem",
WMEM: "net.ipv4.tcp_wmem", WMEM: "net.ipv4.tcp_wmem",
MPTCP_ENABLED: "net.mptcp.mptcp_enabled", # MPTCP_ENABLED: "net.mptcp.mptcp_enabled",
KERNELPM: "net.mptcp.mptcp_path_manager", # KERNELPM: "net.mptcp.mptcp_path_manager",
SCHED: "net.mptcp.mptcp_scheduler", # SCHED: "net.mptcp.mptcp_scheduler",
CC: "net.ipv4.tcp_congestion_control", # CC: "net.ipv4.tcp_congestion_control",
AUTOCORK: "net.ipv4.tcp_autocorking", # AUTOCORK: "net.ipv4.tcp_autocorking",
EARLY_RETRANS: "net.ipv4.tcp_early_retrans", # EARLY_RETRANS: "net.ipv4.tcp_early_retrans",
BUFFER_AUTOTUNING: "net.ipv4.tcp_moderate_rcvbuf", # BUFFER_AUTOTUNING: "net.ipv4.tcp_moderate_rcvbuf",
} }
# sysctl keys specific to client and server, independently # sysctl keys specific to client and server, independently
@ -93,10 +94,10 @@ class ExperimentParameter(Parameter):
class Experiment(object): class Experiment(object):
""" """
Base class to instantiate an experiment to perform. Base class to instantiate an experiment to perform.
This class is not instantiable as it. You must define a child class with the This class is not instantiable as it. You must define a child class with the
`NAME` attribute. `NAME` attribute.
By default, an Experiment relies on an instance of ExperimentParameter to By default, an Experiment relies on an instance of ExperimentParameter to
collect the parameters from the experiment configuration file. However, an collect the parameters from the experiment configuration file. However, an
@ -108,7 +109,7 @@ class Experiment(object):
experiment_parameter Instance of ExperimentParameter experiment_parameter Instance of ExperimentParameter
topo Instance of Topo topo Instance of Topo
topo_config Instance of TopoConfig topo_config Instance of TopoConfig
""" """
PARAMETER_CLASS = ExperimentParameter PARAMETER_CLASS = ExperimentParameter
IP_BIN = "ip" IP_BIN = "ip"
@ -118,7 +119,8 @@ class Experiment(object):
""" """
Instantiation of this base class only load the experiment parameter Instantiation of this base class only load the experiment parameter
""" """
self.experiment_parameter = self.__class__.PARAMETER_CLASS(experiment_parameter_filename) self.experiment_parameter = self.__class__.PARAMETER_CLASS(
experiment_parameter_filename)
self.topo = topo self.topo = topo
self.topo_config = topo_config self.topo_config = topo_config
@ -158,8 +160,10 @@ class Experiment(object):
""" """
Function only meaningful for MPTCP Function only meaningful for MPTCP
""" """
priority_path_0 = self.experiment_parameter.get(ExperimentParameter.PRIO_PATH_0) priority_path_0 = self.experiment_parameter.get(
priority_path_1 = self.experiment_parameter.get(ExperimentParameter.PRIO_PATH_1) ExperimentParameter.PRIO_PATH_0)
priority_path_1 = self.experiment_parameter.get(
ExperimentParameter.PRIO_PATH_1)
if not priority_path_0 == priority_path_1: if not priority_path_0 == priority_path_1:
self.topo.command_to(self.topo_config.client, "{} link set dev {} priority {}".format( self.topo.command_to(self.topo_config.client, "{} link set dev {} priority {}".format(
Experiment.IP_BIN, self.topo_config.get_client_interface(0), priority_path_0)) Experiment.IP_BIN, self.topo_config.get_client_interface(0), priority_path_0))
@ -170,18 +174,20 @@ class Experiment(object):
self.topo.command_to(self.topo_config.router, "{} link set dev {} priority {}".format( self.topo.command_to(self.topo_config.router, "{} link set dev {} priority {}".format(
Experiment.IP_BIN, self.topo_config.get_router_interface_to_client_switch(1), priority_path_1)) Experiment.IP_BIN, self.topo_config.get_router_interface_to_client_switch(1), priority_path_1))
backup_path_0 = self.experiment_parameter.get(ExperimentParameter.BACKUP_PATH_0) backup_path_0 = self.experiment_parameter.get(
ExperimentParameter.BACKUP_PATH_0)
if int(backup_path_0) > 0: if int(backup_path_0) > 0:
self.topo.command_to(self.topo_config.client, self.topo.command_to(self.topo_config.client,
self.topo_config.interface_backup_command(self.topo_config.get_client_interface(0))) self.topo_config.interface_backup_command(self.topo_config.get_client_interface(0)))
self.topo.command_to(self.topo_config.router, self.topo.command_to(self.topo_config.router,
self.topo_config.interface_backup_command(self.topo_config.get_router_interface_to_client_switch(0))) self.topo_config.interface_backup_command(self.topo_config.get_router_interface_to_client_switch(0)))
backup_path_1 = self.experiment_parameter.get(ExperimentParameter.BACKUP_PATH_1) backup_path_1 = self.experiment_parameter.get(
ExperimentParameter.BACKUP_PATH_1)
if int(backup_path_1) > 0: if int(backup_path_1) > 0:
self.topo.command_to(self.topo_config.client, self.topo.command_to(self.topo_config.client,
self.topo_config.interface_backup_command(self.topo_config.get_client_interface(1))) self.topo_config.interface_backup_command(self.topo_config.get_client_interface(1)))
self.topo.command_to(self.topo_config.router, self.topo.command_to(self.topo_config.router,
self.topo_config.interface_backup_command(self.topo_config.get_router_interface_to_client_switch(1))) self.topo_config.interface_backup_command(self.topo_config.get_router_interface_to_client_switch(1)))
def run_userspace_path_manager(self): def run_userspace_path_manager(self):
""" """
@ -190,13 +196,15 @@ class Experiment(object):
if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink": if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink":
logging.info("Running user-space path manager on client") logging.info("Running user-space path manager on client")
upmc = self.experiment_parameter.get(ExperimentParameter.USERPMC) upmc = self.experiment_parameter.get(ExperimentParameter.USERPMC)
upmca = self.experiment_parameter.get(ExperimentParameter.USERPMC_ARGS) upmca = self.experiment_parameter.get(
ExperimentParameter.USERPMC_ARGS)
self.topo.command_to(self.topo_config.client, "{} {} &>{} &".format( self.topo.command_to(self.topo_config.client, "{} {} &>{} &".format(
upmc, upmca, "upmc.log")) upmc, upmca, "upmc.log"))
if self.experiment_parameter.get(ExperimentParameter.KERNELPMS) == "netlink": if self.experiment_parameter.get(ExperimentParameter.KERNELPMS) == "netlink":
logging.info("Running user-space path manager on server") logging.info("Running user-space path manager on server")
upms = self.experiment_parameter.get(ExperimentParameter.USERPMS) upms = self.experiment_parameter.get(ExperimentParameter.USERPMS)
upmsa = self.experiment_parameter.get(ExperimentParameter.USERPMS_ARGS) upmsa = self.experiment_parameter.get(
ExperimentParameter.USERPMS_ARGS)
self.topo.command_to(self.topo_config.server, "{} {} &>{} &".format( self.topo.command_to(self.topo_config.server, "{} {} &>{} &".format(
upms, upmsa, "upms.log")) upms, upmsa, "upms.log"))
@ -204,11 +212,13 @@ class Experiment(object):
if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink": if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink":
logging.info("Cleaning user-space path manager on client") logging.info("Cleaning user-space path manager on client")
upmc = self.experiment_parameter.get(ExperimentParameter.USERPMC) upmc = self.experiment_parameter.get(ExperimentParameter.USERPMC)
self.topo.command_to(self.topo_config.client, "killall {}".format(upmc)) self.topo.command_to(self.topo_config.client,
"killall {}".format(upmc))
if self.experiment_parameter.get(ExperimentParameter.KERNELPMS) == "netlink": if self.experiment_parameter.get(ExperimentParameter.KERNELPMS) == "netlink":
logging.info("Cleaning user-space path manager on server") logging.info("Cleaning user-space path manager on server")
upms = self.experiment_parameter.get(ExperimentParameter.USERPMS) upms = self.experiment_parameter.get(ExperimentParameter.USERPMS)
self.topo.command_to(self.topo_config.client, "killall {}".format(upms)) self.topo.command_to(self.topo_config.client,
"killall {}".format(upms))
def run_netem_at(self): def run_netem_at(self):
self.topo_config.run_netem_at() self.topo_config.run_netem_at()
@ -244,13 +254,14 @@ class Experiment(object):
Record the current sysctls Record the current sysctls
""" """
self.sysctl_to_restore = {} self.sysctl_to_restore = {}
self._save_sysctl(ExperimentParameter.SYSCTL_KEY, self.sysctl_to_restore) self._save_sysctl(ExperimentParameter.SYSCTL_KEY,
self.sysctl_to_restore)
self.client_sysctl_to_restore = {} self.client_sysctl_to_restore = {}
self._save_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore, self._save_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore,
ns=True, who=self.topo_config.client) ns=True, who=self.topo_config.client)
self.server_sysctl_to_restore = {} self.server_sysctl_to_restore = {}
self._save_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore, self._save_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore,
ns=True, who=self.topo_config.server) ns=True, who=self.topo_config.server)
def _save_sysctl(self, sysctl_dict, sysctl_to_restore, ns=False, who=None): def _save_sysctl(self, sysctl_dict, sysctl_to_restore, ns=False, who=None):
for k in sysctl_dict: for k in sysctl_dict:
@ -284,13 +295,14 @@ class Experiment(object):
""" """
Write the experiment sysctls Write the experiment sysctls
""" """
self._write_sysctl(ExperimentParameter.SYSCTL_KEY, self.sysctl_to_restore) self._write_sysctl(ExperimentParameter.SYSCTL_KEY,
self.sysctl_to_restore)
self._write_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore, self._write_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore,
ns=True, who=self.topo_config.client) ns=True, who=self.topo_config.client)
self._write_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore, self._write_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore,
ns=True, who=self.topo_config.server) ns=True, who=self.topo_config.server)
def _write_sysctl(self, sysctl_dict, sysctl_to_restore, ns = False, who = None): def _write_sysctl(self, sysctl_dict, sysctl_to_restore, ns=False, who=None):
for k in sysctl_to_restore: for k in sysctl_to_restore:
sysctl_key = sysctl_dict[k] sysctl_key = sysctl_dict[k]
sysctl_value = self.experiment_parameter.get(k) sysctl_value = self.experiment_parameter.get(k)
@ -306,13 +318,14 @@ class Experiment(object):
""" """
Restore back the sysctls that were present before running the experiment Restore back the sysctls that were present before running the experiment
""" """
self._restore_sysctl(ExperimentParameter.SYSCTL_KEY, self.sysctl_to_restore) self._restore_sysctl(ExperimentParameter.SYSCTL_KEY,
self.sysctl_to_restore)
self._restore_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore, self._restore_sysctl(ExperimentParameter.SYSCTL_KEY_CLIENT, self.client_sysctl_to_restore,
ns=True, who=self.topo_config.client) ns=True, who=self.topo_config.client)
self._restore_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore, self._restore_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore,
ns=True, who=self.topo_config.server) ns=True, who=self.topo_config.server)
def _restore_sysctl(self, sysctl_dict, sysctl_to_restore, ns = False, who = None): def _restore_sysctl(self, sysctl_dict, sysctl_to_restore, ns=False, who=None):
for k in sysctl_to_restore: for k in sysctl_to_restore:
sysctl_key = sysctl_dict[k] sysctl_key = sysctl_dict[k]
sysctl_value = sysctl_to_restore[k] sysctl_value = sysctl_to_restore[k]
@ -326,27 +339,32 @@ class Experiment(object):
logging.error("unable to set sysctl {}".format(sysctl_key)) logging.error("unable to set sysctl {}".format(sysctl_key))
def run_tcpdump(self): def run_tcpdump(self):
client_pcap = self.experiment_parameter.get(ExperimentParameter.CLIENT_PCAP) client_pcap = self.experiment_parameter.get(
server_pcap = self.experiment_parameter.get(ExperimentParameter.SERVER_PCAP) ExperimentParameter.CLIENT_PCAP)
snaplen_pcap = self.experiment_parameter.get(ExperimentParameter.SNAPLEN_PCAP) server_pcap = self.experiment_parameter.get(
ExperimentParameter.SERVER_PCAP)
snaplen_pcap = self.experiment_parameter.get(
ExperimentParameter.SNAPLEN_PCAP)
self.topo.command_to(self.topo_config.router,
"tcpdump -i any -s {} -w router.pcap &".format(snaplen_pcap))
if client_pcap == "yes": if client_pcap == "yes":
self.topo.command_to(self.topo_config.client, self.topo.command_to(self.topo_config.client,
"tcpdump -i any -s {} -w client.pcap &".format(snaplen_pcap)) "tcpdump -i any -s {} -w client.pcap &".format(snaplen_pcap))
if server_pcap == "yes": if server_pcap == "yes":
self.topo.command_to(self.topo_config.server, self.topo.command_to(self.topo_config.server,
"tcpdump -i any -s {} -w server.pcap &".format(snaplen_pcap)) "tcpdump -i any -s {} -w server.pcap &".format(snaplen_pcap))
if server_pcap == "yes" or client_pcap == "yes": if server_pcap == "yes" or client_pcap == "yes":
logging.info("Activating tcpdump, waiting for it to run") logging.info("Activating tcpdump, waiting for it to run")
self.topo.command_to(self.topo_config.client,"sleep 5") self.topo.command_to(self.topo_config.client, "sleep 5")
def ping(self): def ping(self):
self.topo.command_to(self.topo_config.client, self.topo.command_to(self.topo_config.client,
"rm {}".format(Experiment.PING_OUTPUT)) "rm {}".format(Experiment.PING_OUTPUT))
count = self.experiment_parameter.get(ExperimentParameter.PING_COUNT) count = self.experiment_parameter.get(ExperimentParameter.PING_COUNT)
for j in range(0, self.topo_config.server_interface_count()): for j in range(0, self.topo_config.server_interface_count()):
for i in range(0, self.topo_config.client_interface_count()): for i in range(0, self.topo_config.client_interface_count()):
cmd = self.ping_command(self.topo_config.get_client_ip(i), cmd = self.ping_command(self.topo_config.get_client_ip(i),
self.topo_config.get_server_ip(interface_index=j), n=count) self.topo_config.get_server_ip(interface_index=j), n=count)
logging.info(cmd) logging.info(cmd)
self.topo.command_to(self.topo_config.client, cmd) self.topo.command_to(self.topo_config.client, cmd)
@ -362,7 +380,8 @@ class RandomFileParameter(ExperimentParameter):
RANDOM_SIZE = "file_size" # in KB RANDOM_SIZE = "file_size" # in KB
def __init__(self, experiment_parameter_filename): def __init__(self, experiment_parameter_filename):
super(RandomFileParameter, self).__init__(experiment_parameter_filename) super(RandomFileParameter, self).__init__(
experiment_parameter_filename)
self.default_parameters.update({ self.default_parameters.update({
RandomFileParameter.FILE: "random", RandomFileParameter.FILE: "random",
RandomFileParameter.RANDOM_SIZE: "1024", RandomFileParameter.RANDOM_SIZE: "1024",
@ -378,22 +397,24 @@ class RandomFileExperiment(Experiment):
PARAMETER_CLASS = RandomFileParameter PARAMETER_CLASS = RandomFileParameter
def __init__(self, experiment_parameter_filename, topo, topo_config): def __init__(self, experiment_parameter_filename, topo, topo_config):
super(RandomFileExperiment, self).__init__(experiment_parameter_filename, topo, topo_config) super(RandomFileExperiment, self).__init__(
experiment_parameter_filename, topo, topo_config)
self.load_parameters() self.load_parameters()
self.ping() self.ping()
def load_parameters(self): def load_parameters(self):
super(RandomFileExperiment, self).load_parameters() super(RandomFileExperiment, self).load_parameters()
self.file = self.experiment_parameter.get(RandomFileParameter.FILE) self.file = self.experiment_parameter.get(RandomFileParameter.FILE)
self.random_size = self.experiment_parameter.get(RandomFileParameter.RANDOM_SIZE) self.random_size = self.experiment_parameter.get(
RandomFileParameter.RANDOM_SIZE)
def prepare(self): def prepare(self):
super(RandomFileExperiment, self).prepare() super(RandomFileExperiment, self).prepare()
if self.file == "random": if self.file == "random":
self.topo.command_to(self.topo_config.client, self.topo.command_to(self.topo_config.client,
"dd if=/dev/urandom of=random bs=1K count={}".format(self.random_size)) "dd if=/dev/urandom of=random bs=1K count={}".format(self.random_size))
def clean(self): def clean(self):
super(RandomFileExperiment, self).clean() super(RandomFileExperiment, self).clean()
if self.file == "random": if self.file == "random":
self.topo.command_to(self.topo_config.client, "rm random*") self.topo.command_to(self.topo_config.client, "rm random*")

View File

@ -8,6 +8,7 @@ class NetemAt(object):
""" """
Class representing a netem command to be run after some time Class representing a netem command to be run after some time
""" """
def __init__(self, at, cmd): def __init__(self, at, cmd):
self.at = at self.at = at
self.cmd = cmd self.cmd = cmd
@ -41,6 +42,7 @@ class LinkCharacteristics(object):
netem_at list of NetemAt instances applicable to the link netem_at list of NetemAt instances applicable to the link
backup integer indicating if this link is a backup one or not (useful for MPTCP) backup integer indicating if this link is a backup one or not (useful for MPTCP)
""" """
def __init__(self, id, link_type, delay, queue_size, bandwidth, loss, backup=0): def __init__(self, id, link_type, delay, queue_size, bandwidth, loss, backup=0):
self.id = id self.id = id
self.link_type = link_type self.link_type = link_type
@ -48,7 +50,8 @@ class LinkCharacteristics(object):
self.queue_size = queue_size self.queue_size = queue_size
self.bandwidth = bandwidth self.bandwidth = bandwidth
self.loss = loss self.loss = loss
self.queuing_delay = str(self.extract_queuing_delay(queue_size, bandwidth, delay)) self.queuing_delay = str(
self.extract_queuing_delay(queue_size, bandwidth, delay))
self.netem_at = [] self.netem_at = []
self.backup = backup self.backup = backup
@ -63,11 +66,11 @@ class LinkCharacteristics(object):
Return the buffer size in bytes Return the buffer size in bytes
""" """
return (1500.0 * self.bandwidth_delay_product_divided_by_mtu()) + \ return (1500.0 * self.bandwidth_delay_product_divided_by_mtu()) + \
(float(self.bandwidth) * 1000.0 * float(self.queuing_delay) / 8) (float(self.bandwidth) * 1000.0 * float(self.queuing_delay) / 8)
def extract_queuing_delay(self, queue_size, bandwidth, delay, mtu=1500): def extract_queuing_delay(self, queue_size, bandwidth, delay, mtu=1500):
queuing_delay = (int(queue_size) * int(mtu) * 8.0 * 1000.0) / \ queuing_delay = (int(queue_size) * int(mtu) * 8.0 * 1000.0) / \
(float(bandwidth) * 1024 * 1024) (float(bandwidth) * 1024 * 1024)
return max(int(queuing_delay), 1) return max(int(queuing_delay), 1)
def add_netem_at(self, n): def add_netem_at(self, n):
@ -79,7 +82,8 @@ class LinkCharacteristics(object):
n.delta = n.at - self.netem_at[-1].at n.delta = n.at - self.netem_at[-1].at
self.netem_at.append(n) self.netem_at.append(n)
else: else:
logging.error("{}: not taken into account because not specified in order in the topo param file".format(n)) logging.error(
"{}: not taken into account because not specified in order in the topo param file".format(n))
def build_delete_tc_cmd(self, ifname): def build_delete_tc_cmd(self, ifname):
return "tc qdisc del dev {} root; tc qdisc del dev {} ingress ".format(ifname, ifname) return "tc qdisc del dev {} root; tc qdisc del dev {} ingress ".format(ifname, ifname)
@ -137,11 +141,13 @@ class TopoParameter(Parameter):
RIGHT_SUBNET = "rightSubnet" RIGHT_SUBNET = "rightSubnet"
NETEM_AT = "netemAt_" NETEM_AT = "netemAt_"
CHANGE_NETEM = "changeNetem" CHANGE_NETEM = "changeNetem"
CLIENTS = "clients"
DEFAULT_PARAMETERS = { DEFAULT_PARAMETERS = {
LEFT_SUBNET: "10.1.", LEFT_SUBNET: "10.1.",
RIGHT_SUBNET: "10.2.", RIGHT_SUBNET: "10.2.",
CHANGE_NETEM: "false", CHANGE_NETEM: "false",
CLIENTS: "1",
} }
def __init__(self, parameter_filename): def __init__(self, parameter_filename):
@ -150,6 +156,7 @@ class TopoParameter(Parameter):
self.link_characteristics = [] self.link_characteristics = []
self.load_link_characteristics() self.load_link_characteristics()
self.load_netem_at() self.load_netem_at()
self.load_clients()
logging.info(self) logging.info(self)
def parse_netem_at(self, key): def parse_netem_at(self, key):
@ -161,13 +168,23 @@ class TopoParameter(Parameter):
_, link_type, link_id = key.split("_") _, link_type, link_id = key.split("_")
return link_type, int(link_id) return link_type, int(link_id)
def load_clients(self):
for k in sorted(self.parameters):
if k == 'clients':
self._clients = int(self.parameters[k])
@property
def clients(self):
return self._clients
def load_netem_at(self): def load_netem_at(self):
if not self.get(TopoParameter.CHANGE_NETEM) == "yes": if not self.get(TopoParameter.CHANGE_NETEM) == "yes":
return return
for k in sorted(self.parameters): for k in sorted(self.parameters):
if k.startswith(TopoParameter.NETEM_AT): if k.startswith(TopoParameter.NETEM_AT):
link_type, link_id = self.parse_netem_at(k) link_type, link_id = self.parse_netem_at(k)
self.load_netem_at_value(link_type, link_id, self.parameters[k]) self.load_netem_at_value(
link_type, link_id, self.parameters[k])
def find_link_characteristic(self, link_type, link_id): def find_link_characteristic(self, link_type, link_id):
for l in self.link_characteristics: for l in self.link_characteristics:
@ -184,7 +201,8 @@ class TopoParameter(Parameter):
l.add_netem_at(na) l.add_netem_at(na)
except ValueError as e: except ValueError as e:
logging.error("Unable to set netem for link {} with command {}: {}".format(link_id, n, e)) logging.error(
"Unable to set netem for link {} with command {}: {}".format(link_id, n, e))
logging.info(self.link_characteristics[link_id].netem_at) logging.info(self.link_characteristics[link_id].netem_at)
@ -243,7 +261,7 @@ class TopoParameter(Parameter):
logging.error("Ignored path {}: {}".format(k, e)) logging.error("Ignored path {}: {}".format(k, e))
else: else:
path = LinkCharacteristics(link_id, link_type, delay, queue_size, path = LinkCharacteristics(link_id, link_type, delay, queue_size,
bw, loss_perc, backup=is_backup) bw, loss_perc, backup=is_backup)
self.link_characteristics.append(path) self.link_characteristics.append(path)
def __str__(self): def __str__(self):
@ -281,8 +299,8 @@ class BottleneckLink(object):
topo_builder.add_link(self.bs2, self.bs3) topo_builder.add_link(self.bs2, self.bs3)
def get_bs_name(self, index): def get_bs_name(self, index):
return "{}_{}_{}_{}".format(BottleneckLink.BOTTLENECK_SWITCH_NAME_PREFIX, return "{}_{}_{}_{}".format(BottleneckLink.BOTTLENECK_SWITCH_NAME_PREFIX,
self.link_characteristics.link_type, self.link_characteristics.id, index) self.link_characteristics.link_type, self.link_characteristics.id, index)
def reinit_variables(self): def reinit_variables(self):
# Required to retrieve actual nodes # Required to retrieve actual nodes
@ -297,30 +315,34 @@ class BottleneckLink(object):
# Cleanup tc commands # Cleanup tc commands
for bs1_ifname in bs1_interface_names: for bs1_ifname in bs1_interface_names:
clean_cmd = self.link_characteristics.build_delete_tc_cmd(bs1_ifname) clean_cmd = self.link_characteristics.build_delete_tc_cmd(
bs1_ifname)
logging.info(clean_cmd) logging.info(clean_cmd)
self.topo.command_to(self.bs1, clean_cmd) self.topo.command_to(self.bs1, clean_cmd)
for bs2_ifname in bs2_interface_names: for bs2_ifname in bs2_interface_names:
clean_cmd = self.link_characteristics.build_delete_tc_cmd(bs2_ifname) clean_cmd = self.link_characteristics.build_delete_tc_cmd(
bs2_ifname)
logging.info(clean_cmd) logging.info(clean_cmd)
self.topo.command_to(self.bs2, clean_cmd) self.topo.command_to(self.bs2, clean_cmd)
# Flow bs0 -> bs3 # Flow bs0 -> bs3
netem_cmd = self.link_characteristics.build_netem_cmd(bs1_interface_names[-1], netem_cmd = self.link_characteristics.build_netem_cmd(bs1_interface_names[-1],
"loss {}".format(self.link_characteristics.loss) if float(self.link_characteristics.loss) > 0 else "") "loss {}".format(self.link_characteristics.loss) if float(self.link_characteristics.loss) > 0 else "")
logging.info(netem_cmd) logging.info(netem_cmd)
self.topo.command_to(self.bs1, netem_cmd) self.topo.command_to(self.bs1, netem_cmd)
shaping_cmd = self.link_characteristics.build_bandwidth_cmd(bs2_interface_names[-1]) shaping_cmd = self.link_characteristics.build_bandwidth_cmd(
bs2_interface_names[-1])
logging.info(shaping_cmd) logging.info(shaping_cmd)
self.topo.command_to(self.bs2, shaping_cmd) self.topo.command_to(self.bs2, shaping_cmd)
# Flow bs3 -> bs0 # Flow bs3 -> bs0
netem_cmd = self.link_characteristics.build_netem_cmd(bs2_interface_names[0], netem_cmd = self.link_characteristics.build_netem_cmd(bs2_interface_names[0],
"loss {}".format(self.link_characteristics.loss) if float(self.link_characteristics.loss) > 0 else "") "loss {}".format(self.link_characteristics.loss) if float(self.link_characteristics.loss) > 0 else "")
logging.info(netem_cmd) logging.info(netem_cmd)
self.topo.command_to(self.bs2, netem_cmd) self.topo.command_to(self.bs2, netem_cmd)
shaping_cmd = self.link_characteristics.build_bandwidth_cmd(bs1_interface_names[0]) shaping_cmd = self.link_characteristics.build_bandwidth_cmd(
bs1_interface_names[0])
logging.info(shaping_cmd) logging.info(shaping_cmd)
self.topo.command_to(self.bs1, shaping_cmd) self.topo.command_to(self.bs1, shaping_cmd)
@ -328,18 +350,22 @@ class BottleneckLink(object):
bs1_interface_names = self.topo.get_interface_names(self.bs1) bs1_interface_names = self.topo.get_interface_names(self.bs1)
bs2_interface_names = self.topo.get_interface_names(self.bs2) bs2_interface_names = self.topo.get_interface_names(self.bs2)
# Flow bs0 -> bs3 # Flow bs0 -> bs3
shaping_cmd = self.link_characteristics.build_changing_bandwidth_cmd(bs1_interface_names[-1]) shaping_cmd = self.link_characteristics.build_changing_bandwidth_cmd(
bs1_interface_names[-1])
logging.info(shaping_cmd) logging.info(shaping_cmd)
self.topo.command_to(self.bs1, shaping_cmd) self.topo.command_to(self.bs1, shaping_cmd)
netem_cmd = self.link_characteristics.build_changing_netem_cmd(bs2_interface_names[-1]) netem_cmd = self.link_characteristics.build_changing_netem_cmd(
bs2_interface_names[-1])
logging.info(netem_cmd) logging.info(netem_cmd)
self.topo.command_to(self.bs2, netem_cmd) self.topo.command_to(self.bs2, netem_cmd)
# Flow bs3 -> bs0 # Flow bs3 -> bs0
shaping_cmd = self.link_characteristics.build_changing_bandwidth_cmd(bs2_interface_names[0]) shaping_cmd = self.link_characteristics.build_changing_bandwidth_cmd(
bs2_interface_names[0])
logging.info(shaping_cmd) logging.info(shaping_cmd)
self.topo.command_to(self.bs2, shaping_cmd) self.topo.command_to(self.bs2, shaping_cmd)
netem_cmd = self.link_characteristics.build_changing_netem_cmd(bs1_interface_names[0]) netem_cmd = self.link_characteristics.build_changing_netem_cmd(
bs1_interface_names[0])
logging.info(netem_cmd) logging.info(netem_cmd)
self.topo.command_to(self.bs1, netem_cmd) self.topo.command_to(self.bs1, netem_cmd)
@ -380,7 +406,8 @@ class Topo(object):
def __init__(self, topo_builder, topo_parameter): def __init__(self, topo_builder, topo_parameter):
self.topo_builder = topo_builder self.topo_builder = topo_builder
self.topo_parameter = topo_parameter self.topo_parameter = topo_parameter
self.change_netem = topo_parameter.get(TopoParameter.CHANGE_NETEM).lower() == "yes" self.change_netem = topo_parameter.get(
TopoParameter.CHANGE_NETEM).lower() == "yes"
self.log_file = open(Topo.CMD_LOG_FILENAME, 'w') self.log_file = open(Topo.CMD_LOG_FILENAME, 'w')
self.clients = [] self.clients = []
self.routers = [] self.routers = []
@ -467,7 +494,8 @@ class Topo(object):
otherwise just connect it to from_a and to_b and returns the bottleneck_link otherwise just connect it to from_a and to_b and returns the bottleneck_link
""" """
if bottleneck_link is None: if bottleneck_link is None:
bottleneck_link = BottleneckLink(self.topo_builder, self, link_characteristics) bottleneck_link = BottleneckLink(
self.topo_builder, self, link_characteristics)
self.bottleneck_links.append(bottleneck_link) self.bottleneck_links.append(bottleneck_link)
self.topo_builder.add_link(from_a, bottleneck_link.get_left()) self.topo_builder.add_link(from_a, bottleneck_link.get_left())
@ -476,9 +504,12 @@ class Topo(object):
def reinit_variables(self): def reinit_variables(self):
# Because we create nodes before starting mininet # Because we create nodes before starting mininet
self.clients = [self.get_host(self.get_client_name(i)) for i in range(len(self.clients))] self.clients = [self.get_host(self.get_client_name(i))
self.routers = [self.get_host(self.get_router_name(i)) for i in range(len(self.routers))] for i in range(len(self.clients))]
self.servers = [self.get_host(self.get_server_name(i)) for i in range(len(self.servers))] self.routers = [self.get_host(self.get_router_name(i))
for i in range(len(self.routers))]
self.servers = [self.get_host(self.get_server_name(i))
for i in range(len(self.servers))]
for b in self.bottleneck_links: for b in self.bottleneck_links:
b.reinit_variables() b.reinit_variables()
@ -502,6 +533,7 @@ class TopoConfig(object):
This class is not instantiable as it. You must define a child class with the This class is not instantiable as it. You must define a child class with the
`NAME` attribute. `NAME` attribute.
""" """
def __init__(self, topo, param): def __init__(self, topo, param):
self.topo = topo self.topo = topo
self.param = param self.param = param
@ -520,8 +552,10 @@ class TopoConfig(object):
logging.info("Disable TSO, GSO and GRO on all interfaces of all nodes") logging.info("Disable TSO, GSO and GRO on all interfaces of all nodes")
for node in [self.topo.get_host(n) for n in self.topo.topo_builder.net]: for node in [self.topo.get_host(n) for n in self.topo.topo_builder.net]:
for intf in self.topo.get_interface_names(node): for intf in self.topo.get_interface_names(node):
logging.debug("Disable TSO, GSO and GRO on interface {}".format(intf)) logging.debug(
cmd = "ethtool -K {} tso off; ethtool -K {} gso off; ethtool -K {} gro off".format(intf, intf, intf) "Disable TSO, GSO and GRO on interface {}".format(intf))
cmd = "ethtool -K {} tso off; ethtool -K {} gso off; ethtool -K {} gro off".format(
intf, intf, intf)
logging.debug(cmd) logging.debug(cmd)
self.topo.command_to(node, cmd) self.topo.command_to(node, cmd)

88
experiments/basicquic.py Normal file
View File

@ -0,0 +1,88 @@
from core.experiment import ExperimentParameter, RandomFileExperiment, RandomFileParameter
import os
import threading
class BASICQUIC(RandomFileExperiment):
NAME = "basicquic"
SERVER_LOG = "echo-quic_server.log"
CLIENT_LOG = "echo-quic_client.log"
WGET_BIN = "wget"
PING_OUTPUT = "ping.log"
def __init__(self, experiment_parameter_filename, topo, topo_config):
# Just rely on RandomFileExperiment
super(BASICQUIC, self).__init__(
experiment_parameter_filename, topo, topo_config)
def load_parameters(self):
# Just rely on RandomFileExperiment
super(BASICQUIC, self).load_parameters()
def prepare(self):
super(BASICQUIC, self).prepare()
self.topo.command_to(self.topo_config.client, "rm " +
BASICQUIC.CLIENT_LOG)
self.topo.command_to(self.topo_config.server, "rm " +
BASICQUIC.SERVER_LOG)
def getHTTPSServerCmd(self):
# s = "{}/../utils/server".format(
# os.path.dirname(os.path.abspath(__file__)))
s = "/home/mininet/pugit/sample/minitopo/utils/server & > {}".format(
BASICQUIC.SERVER_LOG)
print(s)
return s
def getHTTPSClientCmd(self):
# s = "ping -c 3 -I {} {} > ping-result".format(
# "10.0.0.", self.topo_config.get_client_ip(1))
# s = "{}/../utils/echo-client {} > {}".format(os.path.dirname(os.path.abspath(__file__)),
# self.topo.get_server_ip(
# 0),
# os.path.dirname(os.path.abspath(__file__)), BASICQUIC.CLIENT_LOG)
s = "/home/mininet/pugit/sample/minitopo/utils/echo-client {} & > {}".format(
self.topo_config.get_server_ip(0),
BASICQUIC.CLIENT_LOG,
)
print(s)
return s
def clean(self):
super(BASICQUIC, self).clean()
def startServer(self):
self.topo.command_to(self.topo_config.server, cmd)
def run(self):
cmd = self.getHTTPSServerCmd()
self.topo.command_to(self.topo_config.server,
"netstat -sn > netstat_server_before")
self.topo.command_to(self.topo_config.router,
"netstat -sn > netstat_router_before")
self.topo.command_to(self.topo_config.server, cmd)
print("Waiting for the server to run")
self.topo.command_to(self.topo_config.client, "sleep 2")
# for i in range(1, self.topo.client_count()):
# self.topo.command_to(self.topo_config.clients[i], "sleep 2")
cmd = self.getHTTPSClientCmd()
# for c in self.topo_config.clients:
# self.topo.command_to(c, cmd)
for i in range(1, self.topo.client_count()):
self.topo.command_to(self.topo_config.clients[i], cmd)
# self.topo_config.configure_client(i)
self.topo.command_to(self.topo_config.server,
"netstat -sn > netstat_server_after")
self.topo.command_to(self.topo_config.router,
"netstat -sn > netstat_router_after")
self.topo.command_to(self.topo_config.server,
"pkill -f server")
self.topo.command_to(self.topo_config.client, "sleep 2")

View File

@ -8,7 +8,8 @@ class IPerfScenarioParameter(ExperimentParameter):
FM_SUBFLOWS = "iperfScenarioFMSublows" FM_SUBFLOWS = "iperfScenarioFMSublows"
def __init__(self, experiment_parameter_filename): def __init__(self, experiment_parameter_filename):
super(IPerfScenarioParameter, self).__init__(experiment_parameter_filename) super(IPerfScenarioParameter, self).__init__(
experiment_parameter_filename)
self.default_parameters.update({ self.default_parameters.update({
IPerfScenarioParameter.FM_SUBFLOWS: "1", IPerfScenarioParameter.FM_SUBFLOWS: "1",
}) })
@ -24,29 +25,37 @@ class IPerfScenario(Experiment):
PING_OUTPUT = "ping.log" PING_OUTPUT = "ping.log"
def __init__(self, experiment_parameter_filename, topo, topo_config): def __init__(self, experiment_parameter_filename, topo, topo_config):
super(IPerfScenario, self).__init__(experiment_parameter_filename, topo, topo_config) super(IPerfScenario, self).__init__(
experiment_parameter_filename, topo, topo_config)
self.load_parameters() self.load_parameters()
self.ping() self.ping()
def load_parameters(self): def load_parameters(self):
super(IPerfScenario, self).load_parameters() super(IPerfScenario, self).load_parameters()
self.fm_subflows = self.experiment_parameter.get(IPerfScenarioParameter.FM_SUBFLOWS) self.fm_subflows = self.experiment_parameter.get(
IPerfScenarioParameter.FM_SUBFLOWS)
def prepare(self): def prepare(self):
super(IPerfScenario, self).prepare() super(IPerfScenario, self).prepare()
self.topo.command_to(self.topo_config.client, "rm {}".format(IPerfScenario.IPERF_LOG)) self.topo.command_to(self.topo_config.client,
self.topo.command_to(self.topo_config.server, "rm {}".format(IPerfScenario.SERVER_LOG)) "rm {}".format(IPerfScenario.IPERF_LOG))
self.topo.command_to(self.topo_config.server,
"rm {}".format(IPerfScenario.SERVER_LOG))
if not isinstance(self.topo, MultiInterfaceMultiClientTopo): if not isinstance(self.topo, MultiInterfaceMultiClientTopo):
raise Exception("IPerfScenario only runs with MultiInterfaceMultiClientTopo") raise Exception(
"IPerfScenario only runs with MultiInterfaceMultiClientTopo")
def get_client_iperf_cmd(self, server_ip, time, client_id): def get_client_iperf_cmd(self, server_ip, time, client_id):
s = "{} -c {} -t {} -P 1 -i 5 &>{}{}".format(IPerfScenario.IPERF_BIN, server_ip, time, IPerfScenario.IPERF_LOG, client_id) s = "{} -c {} -t {} -P 1 -i 5 &>{}{}".format(
IPerfScenario.IPERF_BIN, server_ip, time, IPerfScenario.IPERF_LOG, client_id)
logging.info(s) logging.info(s)
return s return s
def get_server_cmd(self, server_id=0): def get_server_cmd(self, server_id=0):
s = "{} -s &> {}{} &".format(IPerfScenario.IPERF_BIN, IPerfScenario.SERVER_LOG, server_id) s = "{} -s &> {}{} &".format(IPerfScenario.IPERF_BIN,
IPerfScenario.SERVER_LOG, server_id)
logging.info(s) logging.info(s)
return s return s
@ -54,32 +63,39 @@ class IPerfScenario(Experiment):
super(IPerfScenario, self).clean() super(IPerfScenario, self).clean()
def run(self): def run(self):
print('IPerfScenario!!!!!!')
self.topo.command_to(self.topo_config.router, "tcpdump -i any -w router.pcap &") self.topo.command_to(self.topo_config.router,
"tcpdump -i any -w router.pcap &")
# First run servers # First run servers
for l, s in enumerate(self.topo_config.servers): for l, s in enumerate(self.topo_config.servers):
self.topo.command_to(s, self.get_server_cmd(server_id=l)) self.topo.command_to(s, self.get_server_cmd(server_id=l))
# And set nb of subflows for fullmesh # And set nb of subflows for fullmesh
self.topo.command_to(self.topo_config.client, "echo {} > /sys/module/mptcp_fullmesh/parameters/num_subflows".format(self.fm_subflows)) self.topo.command_to(
self.topo_config.client, "echo {} > /sys/module/mptcp_fullmesh/parameters/num_subflows".format(self.fm_subflows))
self.topo.command_to(self.topo_config.client, "sleep 2") self.topo.command_to(self.topo_config.client, "sleep 2")
# We run as follow. # We run as follow.
logging.info("This experiment last about 1 minute. Please wait...") logging.info("This experiment last about 1 minute. Please wait...")
cmd = "sleep 10 && {} &".format(self.get_client_iperf_cmd(self.topo_config.get_server_ip(interface_index=1), 20, 1)) cmd = "sleep 10 && {} &".format(self.get_client_iperf_cmd(
self.topo_config.get_server_ip(interface_index=1), 20, 1))
self.topo.command_to(self.topo_config.clients[1], cmd) self.topo.command_to(self.topo_config.clients[1], cmd)
cmd = "sleep 20 && {} &".format(self.get_client_iperf_cmd(self.topo_config.get_server_ip(interface_index=2), 20, 2)) cmd = "sleep 20 && {} &".format(self.get_client_iperf_cmd(
self.topo_config.get_server_ip(interface_index=2), 20, 2))
self.topo.command_to(self.topo_config.clients[2], cmd) self.topo.command_to(self.topo_config.clients[2], cmd)
cmd = "{} &".format(self.get_client_iperf_cmd(self.topo_config.get_server_ip(), 50, 0)) cmd = "{} &".format(self.get_client_iperf_cmd(
self.topo_config.get_server_ip(), 50, 0))
self.topo.command_to(self.topo_config.client, cmd) self.topo.command_to(self.topo_config.client, cmd)
self.topo.command_to(self.topo_config.client, "sleep 2") self.topo.command_to(self.topo_config.client, "sleep 2")
# This is hacky # This is hacky
self.topo.command_global("sysctl -w net.mptcp.mptcp_enabled=0") self.topo.command_global("sysctl -w net.mptcp.mptcp_enabled=0")
self.topo.command_global("sysctl -w net.ipv4.tcp_congestion_control=reno") self.topo.command_global(
"sysctl -w net.ipv4.tcp_congestion_control=reno")
self.topo.command_to(self.topo_config.client, "sleep 50") self.topo.command_to(self.topo_config.client, "sleep 50")
self.topo.command_to(self.topo_config.client, "echo 1 > /sys/module/mptcp_fullmesh/parameters/num_subflows") self.topo.command_to(
self.topo_config.client, "echo 1 > /sys/module/mptcp_fullmesh/parameters/num_subflows")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -14,15 +14,18 @@ import os
import subprocess import subprocess
import traceback import traceback
def get_git_revision_short_hash(): def get_git_revision_short_hash():
# Because we might run Minitopo from elsewhere. # Because we might run Minitopo from elsewhere.
curr_dir = os.getcwd() curr_dir = os.getcwd()
ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
os.chdir(ROOT_DIR) os.chdir(ROOT_DIR)
ret = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode("unicode_escape").strip() ret = subprocess.check_output(
['git', 'rev-parse', '--short', 'HEAD']).decode("unicode_escape").strip()
os.chdir(curr_dir) os.chdir(curr_dir)
return ret return ret
class Runner(object): class Runner(object):
""" """
Run an experiment described by `experiment_parameter_file` in the topology Run an experiment described by `experiment_parameter_file` in the topology
@ -31,8 +34,10 @@ class Runner(object):
All the operations are done when calling the constructor. All the operations are done when calling the constructor.
""" """
def __init__(self, builder_type, topo_parameter_file, experiment_parameter_file): def __init__(self, builder_type, topo_parameter_file, experiment_parameter_file):
logging.info("Minitopo version {}".format(get_git_revision_short_hash())) logging.info("Minitopo version {}".format(
get_git_revision_short_hash()))
self.topo_parameter = TopoParameter(topo_parameter_file) self.topo_parameter = TopoParameter(topo_parameter_file)
self.set_builder(builder_type) self.set_builder(builder_type)
self.apply_topo() self.apply_topo()
@ -48,7 +53,8 @@ class Runner(object):
if builder_type == Topo.MININET_BUILDER: if builder_type == Topo.MININET_BUILDER:
self.topo_builder = MininetBuilder() self.topo_builder = MininetBuilder()
else: else:
raise Exception("I can not find the builder {}".format(builder_type)) raise Exception(
"I can not find the builder {}".format(builder_type))
def apply_topo(self): def apply_topo(self):
""" """
@ -86,9 +92,11 @@ class Runner(object):
Match the name of the experiement and launch it Match the name of the experiement and launch it
""" """
# Well, we need to load twice the experiment parameters, is it really annoying? # Well, we need to load twice the experiment parameters, is it really annoying?
xp = ExperimentParameter(experiment_parameter_file).get(ExperimentParameter.XP_TYPE) xp = ExperimentParameter(experiment_parameter_file).get(
ExperimentParameter.XP_TYPE)
if xp in EXPERIMENTS: if xp in EXPERIMENTS:
exp = EXPERIMENTS[xp](experiment_parameter_file, self.topo, self.topo_config) exp = EXPERIMENTS[xp](experiment_parameter_file,
self.topo, self.topo_config)
exp.classic_run() exp.classic_run()
else: else:
raise Exception("Unknown experiment {}".format(xp)) raise Exception("Unknown experiment {}".format(xp))
@ -107,21 +115,23 @@ if __name__ == '__main__':
description="Minitopo, a wrapper of Mininet to run multipath experiments") description="Minitopo, a wrapper of Mininet to run multipath experiments")
parser.add_argument("--topo_param_file", "-t", required=True, parser.add_argument("--topo_param_file", "-t", required=True,
help="path to the topo parameter file") help="path to the topo parameter file")
parser.add_argument("--experiment_param_file", "-x", parser.add_argument("--experiment_param_file", "-x",
help="path to the experiment parameter file") help="path to the experiment parameter file")
args = parser.parse_args() args = parser.parse_args()
logging.basicConfig(format="%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s", level=logging.INFO) logging.basicConfig(
format="%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s", level=logging.INFO)
# XXX Currently, there is no alternate topo builder... # XXX Currently, there is no alternate topo builder...
try: try:
Runner(Topo.MININET_BUILDER, args.topo_param_file, args.experiment_param_file) Runner(Topo.MININET_BUILDER, args.topo_param_file,
args.experiment_param_file)
except Exception as e: except Exception as e:
logging.fatal("A fatal error occurred: {}".format(e)) logging.fatal("A fatal error occurred: {}".format(e))
traceback.print_exc() traceback.print_exc()
finally: finally:
# Always cleanup Mininet # Always cleanup Mininet
logging.info("cleanup mininet") logging.info("cleanup mininet")
cleanup() cleanup()

128
topos/iot_multi_client.py Normal file
View File

@ -0,0 +1,128 @@
from core.topo import TopoParameter
from .multi_interface import MultiInterfaceTopo, MultiInterfaceConfig
import logging
class IoTMultiClientTopo(MultiInterfaceTopo):
NAME = "IoTMultiClient"
def __init__(self, topo_builder, parameterFile):
logging.info("Initializing IoTMultiClientTopo...")
super(IoTMultiClientTopo, self).__init__(
topo_builder, parameterFile)
for i in range(self.topo_parameter.clients):
# For each client-router, add a client, a bottleneck link, and a server
self.add_client_with_link()
# And connect the router to all servers
# for s in self.servers[1:]:
# self.add_link(self.router, s)
def add_client_with_link(self):
client = self.add_client()
for bl in self.c2r_links:
self.add_link(client, bl.get_left())
def __str__(self):
s = "IoT Multiple interface topology with several clients and servers\n"
# i = 0
# nc = len(self.get_client_to_router_links())
# for i in range(0, nc):
# if i == nc // 2:
# s = s + "c- r--s\n"
# s = s + "c-\sw---bl---sw-/ \-s\n"
# else:
# s = s + "c-/sw---bl---sw-\ /-s\n"
print(self.client_count)
return s
class IoTMultiClientConfig(MultiInterfaceConfig):
NAME = "IoTMultiClient"
def __init__(self, topo, param):
super(IoTMultiClientConfig, self).__init__(topo, param)
def configure_routing(self):
super(IoTMultiClientConfig, self).configure_routing()
for ci in range(len(self.clients)):
for i, _ in enumerate(self.topo.c2r_links):
# Routing for the congestion client
cmd = self.add_global_default_route_command(self.get_router_ip_to_client_switch(i),
self.get_client_interface(ci, i))
self.topo.command_to(self.clients[ci], cmd)
for i, s in enumerate(self.topo.servers):
# Routing for the congestion server
cmd = self.add_simple_default_route_command(
self.get_router_ip_to_server_switch(i))
self.topo.command_to(s, cmd)
def configure_interfaces(self):
logging.info(
"Configure interfaces using IoTMultiClientConfig...")
super(IoTMultiClientConfig, self).configure_interfaces()
self.clients = [self.topo.get_client(
i) for i in range(0, self.topo.client_count())]
self.servers = [self.topo.get_server(
i) for i in range(0, self.topo.server_count())]
netmask = "255.255.255.0"
for ci in range(len(self.clients)):
self.configure_client(ci)
# for i, _ in enumerate(self.topo.c2r_links):
# # Congestion client
# cmd = self.interface_up_command(self.get_client_interface(
# ci, i), self.get_client_ip(i, ci), netmask)
# self.topo.command_to(self.clients[ci], cmd)
# client_interface_mac = self.clients[ci].intf(
# self.get_client_interface(ci, i)).MAC()
# self.topo.command_to(self.router, "arp -s {} {}".format(
# self.get_client_ip(i, ci), client_interface_mac))
# router_interface_mac = self.router.intf(
# self.get_router_interface_to_client_switch(i)).MAC()
# # Congestion client
# self.topo.command_to(self.clients[ci], "arp -s {} {}".format(
# self.get_router_ip_to_client_switch(i), router_interface_mac))
for i, s in enumerate(self.servers):
cmd = self.interface_up_command(self.get_router_interface_to_server_switch(i),
self.get_router_ip_to_server_switch(i), netmask)
self.topo.command_to(self.router, cmd)
router_interface_mac = self.router.intf(
self.get_router_interface_to_server_switch(i)).MAC()
self.topo.command_to(s, "arp -s {} {}".format(
self.get_router_ip_to_server_switch(i), router_interface_mac))
cmd = self.interface_up_command(self.get_server_interface(
i, 0), self.get_server_ip(interface_index=i), netmask)
self.topo.command_to(s, cmd)
server_interface_mac = s.intf(
self.get_server_interface(i, 0)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_server_ip(interface_index=i), server_interface_mac))
def configure_client(self, ci):
netmask = "255.255.255.0"
for i, _ in enumerate(self.topo.c2r_links):
# Congestion client
cmd = self.interface_up_command(self.get_client_interface(
ci, i), self.get_client_ip(i, ci), netmask)
self.topo.command_to(self.clients[ci], cmd)
client_interface_mac = self.clients[ci].intf(
self.get_client_interface(ci, i)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_client_ip(i, ci), client_interface_mac))
router_interface_mac = self.router.intf(
self.get_router_interface_to_client_switch(i)).MAC()
# Congestion client
self.topo.command_to(self.clients[ci], "arp -s {} {}".format(
self.get_router_ip_to_client_switch(i), router_interface_mac))
def get_client_ip(self, interface_index, client_index=100):
return "{}{}.{}".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index, 5+client_index)
def server_interface_count(self):
return max(len(self.servers), 1)

View File

@ -16,15 +16,16 @@ class MultiInterfaceTopo(Topo):
# Add client - router links # Add client - router links
for l in self.get_client_to_router_links(): for l in self.get_client_to_router_links():
self.c2r_links.append(self.add_bottleneck_link(self.client, self.router, link_characteristics=l)) self.c2r_links.append(self.add_bottleneck_link(
self.client, self.router, link_characteristics=l))
# Special case: if there is no specified link between router and server, directly connect them! # Special case: if there is no specified link between router and server, directly connect them!
if len(self.get_router_to_server_links()) > 0: if len(self.get_router_to_server_links()) > 0:
for l in self.get_router_to_server_links(): for l in self.get_router_to_server_links():
self.r2s_links.append(self.add_bottleneck_link(self.router, self.server, link_characteristics=l)) self.r2s_links.append(self.add_bottleneck_link(
self.router, self.server, link_characteristics=l))
else: else:
self.add_link(self.router, self.server) self.add_link(self.router, self.server)
def get_client_to_router_links(self): def get_client_to_router_links(self):
return [l for l in self.topo_parameter.link_characteristics if l.link_type == "c2r"] return [l for l in self.topo_parameter.link_characteristics if l.link_type == "c2r"]
@ -65,7 +66,7 @@ class MultiInterfaceTopo(Topo):
else: else:
s = s + " \-sw---bl---sw-/ \n" s = s + " \-sw---bl---sw-/ \n"
skipped += 1 skipped += 1
return s return s
@ -81,12 +82,12 @@ class MultiInterfaceConfig(TopoConfig):
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
cmd = self.add_link_scope_route_command( cmd = self.add_link_scope_route_command(
self.get_client_subnet(i), self.get_client_subnet(i),
self.get_client_interface(0, i), i) self.get_client_interface(0, i), i)
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
cmd = self.add_table_default_route_command(self.get_router_ip_to_client_switch(i), cmd = self.add_table_default_route_command(self.get_router_ip_to_client_switch(i),
i) i)
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
for i, _ in enumerate(self.topo.r2s_links): for i, _ in enumerate(self.topo.r2s_links):
@ -94,22 +95,22 @@ class MultiInterfaceConfig(TopoConfig):
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
cmd = self.add_link_scope_route_command( cmd = self.add_link_scope_route_command(
self.get_server_subnet(i), self.get_server_subnet(i),
self.get_server_interface(0, i), i) self.get_server_interface(0, i), i)
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
cmd = self.add_table_default_route_command(self.get_router_ip_to_server_switch(i), cmd = self.add_table_default_route_command(self.get_router_ip_to_server_switch(i),
i) i)
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
cmd = self.add_global_default_route_command(self.get_router_ip_to_client_switch(0), cmd = self.add_global_default_route_command(self.get_router_ip_to_client_switch(0),
self.get_client_interface(0, 0)) self.get_client_interface(0, 0))
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
cmd = self.add_simple_default_route_command(self.get_router_ip_to_server_switch(0)) cmd = self.add_simple_default_route_command(
self.get_router_ip_to_server_switch(0))
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
def configure_interfaces(self): def configure_interfaces(self):
logging.info("Configure interfaces using MultiInterfaceConfig...") logging.info("Configure interfaces using MultiInterfaceConfig...")
super(MultiInterfaceConfig, self).configure_interfaces() super(MultiInterfaceConfig, self).configure_interfaces()
@ -119,55 +120,66 @@ class MultiInterfaceConfig(TopoConfig):
netmask = "255.255.255.0" netmask = "255.255.255.0"
for i, _ in enumerate(self.topo.c2r_links): for i, _ in enumerate(self.topo.c2r_links):
cmd = self.interface_up_command(self.get_client_interface(0, i), self.get_client_ip(i), netmask) cmd = self.interface_up_command(
self.get_client_interface(0, i), self.get_client_ip(i), netmask)
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
client_interface_mac = self.client.intf(self.get_client_interface(0, i)).MAC() client_interface_mac = self.client.intf(
self.topo.command_to(self.router, "arp -s {} {}".format(self.get_client_ip(i), client_interface_mac)) self.get_client_interface(0, i)).MAC()
self.topo.command_to(
self.router, "arp -s {} {}".format(self.get_client_ip(i), client_interface_mac))
if self.topo.get_client_to_router_links()[i].backup: if self.topo.get_client_to_router_links()[i].backup:
cmd = self.interface_backup_command(self.get_client_interface(0, i)) cmd = self.interface_backup_command(
self.get_client_interface(0, i))
self.topo.command_to(self.client, cmd) self.topo.command_to(self.client, cmd)
for i, _ in enumerate(self.topo.c2r_links): for i, _ in enumerate(self.topo.c2r_links):
cmd = self.interface_up_command(self.get_router_interface_to_client_switch(i), cmd = self.interface_up_command(self.get_router_interface_to_client_switch(i),
self.get_router_ip_to_client_switch(i), netmask) self.get_router_ip_to_client_switch(i), netmask)
self.topo.command_to(self.router, cmd) self.topo.command_to(self.router, cmd)
router_interface_mac = self.router.intf(self.get_router_interface_to_client_switch(i)).MAC() router_interface_mac = self.router.intf(
self.get_router_interface_to_client_switch(i)).MAC()
self.topo.command_to(self.client, "arp -s {} {}".format( self.topo.command_to(self.client, "arp -s {} {}".format(
self.get_router_ip_to_client_switch(i), router_interface_mac)) self.get_router_ip_to_client_switch(i), router_interface_mac))
if len(self.topo.r2s_links) == 0: if len(self.topo.r2s_links) == 0:
# Case no server param is specified # Case no server param is specified
cmd = self.interface_up_command(self.get_router_interface_to_server_switch(0), cmd = self.interface_up_command(self.get_router_interface_to_server_switch(0),
self.get_router_ip_to_server_switch(0), netmask) self.get_router_ip_to_server_switch(0), netmask)
self.topo.command_to(self.router, cmd) self.topo.command_to(self.router, cmd)
router_interface_mac = self.router.intf(self.get_router_interface_to_server_switch(0)).MAC() router_interface_mac = self.router.intf(
self.get_router_interface_to_server_switch(0)).MAC()
self.topo.command_to(self.server, "arp -s {} {}".format( self.topo.command_to(self.server, "arp -s {} {}".format(
self.get_router_ip_to_server_switch(0), router_interface_mac)) self.get_router_ip_to_server_switch(0), router_interface_mac))
cmd = self.interface_up_command(self.get_server_interface(0, 0), self.get_server_ip(0), netmask) cmd = self.interface_up_command(
self.get_server_interface(0, 0), self.get_server_ip(0), netmask)
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
server_interface_mac = self.server.intf(self.get_server_interface(0, 0)).MAC() server_interface_mac = self.server.intf(
self.get_server_interface(0, 0)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format( self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_server_ip(0), server_interface_mac)) self.get_server_ip(0), server_interface_mac))
for i, _ in enumerate(self.topo.r2s_links): for i, _ in enumerate(self.topo.r2s_links):
cmd = self.interface_up_command(self.get_router_interface_to_server_switch(i), cmd = self.interface_up_command(self.get_router_interface_to_server_switch(i),
self.get_router_ip_to_server_switch(i), netmask) self.get_router_ip_to_server_switch(i), netmask)
self.topo.command_to(self.router, cmd) self.topo.command_to(self.router, cmd)
router_interface_mac = self.router.intf(self.get_router_interface_to_server_switch(i)).MAC() router_interface_mac = self.router.intf(
self.get_router_interface_to_server_switch(i)).MAC()
self.topo.command_to(self.server, "arp -s {} {}".format( self.topo.command_to(self.server, "arp -s {} {}".format(
self.get_router_ip_to_server_switch(i), router_interface_mac)) self.get_router_ip_to_server_switch(i), router_interface_mac))
for i, _ in enumerate(self.topo.r2s_links): for i, _ in enumerate(self.topo.r2s_links):
cmd = self.interface_up_command(self.get_server_interface(0, i), self.get_server_ip(i), netmask) cmd = self.interface_up_command(
self.get_server_interface(0, i), self.get_server_ip(i), netmask)
self.topo.command_to(self.server, cmd) self.topo.command_to(self.server, cmd)
server_interface_mac = self.server.intf(self.get_server_interface(0, i)).MAC() server_interface_mac = self.server.intf(
self.get_server_interface(0, i)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format( self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_server_ip(i), server_interface_mac)) self.get_server_ip(i), server_interface_mac))
def get_client_ip(self, interface_index): def get_client_ip(self, interface_index):
return "{}{}.1".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index) return "{}{}.5".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index)
def get_client_subnet(self, interface_index): def get_client_subnet(self, interface_index):
return "{}{}.0/24".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index) return "{}{}.0/24".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index)
@ -200,4 +212,4 @@ class MultiInterfaceConfig(TopoConfig):
return "{}-eth{}".format(self.topo.get_router_name(0), interface_index) return "{}-eth{}".format(self.topo.get_router_name(0), interface_index)
def get_server_interface(self, server_index, interface_index): def get_server_interface(self, server_index, interface_index):
return "{}-eth{}".format(self.topo.get_server_name(server_index), interface_index) return "{}-eth{}".format(self.topo.get_server_name(server_index), interface_index)

View File

@ -8,14 +8,17 @@ class MultiInterfaceMultiClientTopo(MultiInterfaceTopo):
def __init__(self, topo_builder, parameterFile): def __init__(self, topo_builder, parameterFile):
logging.info("Initializing MultiInterfaceMultiClientTopo...") logging.info("Initializing MultiInterfaceMultiClientTopo...")
super(MultiInterfaceMultiClientTopo, self).__init__(topo_builder, parameterFile)
super(MultiInterfaceMultiClientTopo, self).__init__(
topo_builder, parameterFile)
# For each client-router, add a client, a bottleneck link, and a server # For each client-router, add a client, a bottleneck link, and a server
for bl in self.c2r_links: for bl in self.c2r_links:
client = self.add_client() client = self.add_client()
self.add_server()
self.add_link(client, bl.get_left()) self.add_link(client, bl.get_left())
self.add_server()
# And connect the router to all servers # And connect the router to all servers
for s in self.servers[1:]: for s in self.servers[1:]:
self.add_link(self.router, s) self.add_link(self.router, s)
@ -24,13 +27,16 @@ class MultiInterfaceMultiClientTopo(MultiInterfaceTopo):
s = "Multiple interface topology with several clients and servers\n" s = "Multiple interface topology with several clients and servers\n"
i = 0 i = 0
nc = len(self.get_client_to_router_links()) nc = len(self.get_client_to_router_links())
for i in range(0, nc): for i in range(0, nc):
if i == nc // 2: if i == nc // 2:
s = s + "c- r--s\n" s = s + " r--s\n"
s = s + "c-\sw---bl---sw-/ \-s\n" s = s + "c-\sw---bl---sw-/ \-s\n"
else: elif i < nc // 2:
s = s + "c-/sw---bl---sw-\ /-s\n" s = s + "c-/sw---bl---sw-\ /-s\n"
else:
s = s + "c-\sw---bl---sw-/ \-s\n"
return s return s
@ -45,48 +51,59 @@ class MultiInterfaceMultiClientConfig(MultiInterfaceConfig):
for i, _ in enumerate(self.topo.c2r_links): for i, _ in enumerate(self.topo.c2r_links):
# Routing for the congestion client # Routing for the congestion client
cmd = self.add_global_default_route_command(self.get_router_ip_to_client_switch(i), cmd = self.add_global_default_route_command(self.get_router_ip_to_client_switch(i),
self.get_client_interface(i+1, 0)) self.get_client_interface(i+1, 0))
self.topo.command_to(self.clients[i+1], cmd) self.topo.command_to(self.clients[i+1], cmd)
for i, s in enumerate(self.topo.servers): for i, s in enumerate(self.topo.servers):
# Routing for the congestion server # Routing for the congestion server
cmd = self.add_simple_default_route_command(self.get_router_ip_to_server_switch(i)) cmd = self.add_simple_default_route_command(
self.get_router_ip_to_server_switch(i))
self.topo.command_to(s, cmd) self.topo.command_to(s, cmd)
def configure_interfaces(self): def configure_interfaces(self):
logging.info("Configure interfaces using MultiInterfaceMultiClientConfig...") logging.info(
"Configure interfaces using MultiInterfaceMultiClientConfig...")
super(MultiInterfaceMultiClientConfig, self).configure_interfaces() super(MultiInterfaceMultiClientConfig, self).configure_interfaces()
self.clients = [self.topo.get_client(i) for i in range(0, self.topo.client_count())] self.clients = [self.topo.get_client(
self.servers = [self.topo.get_server(i) for i in range(0, self.topo.server_count())] i) for i in range(0, self.topo.client_count())]
self.servers = [self.topo.get_server(
i) for i in range(0, self.topo.server_count())]
netmask = "255.255.255.0" netmask = "255.255.255.0"
for i, _ in enumerate(self.topo.c2r_links): for i, _ in enumerate(self.topo.c2r_links):
# Congestion client # Congestion client
cmd = self.interface_up_command(self.get_client_interface(i + 1, 0), self.get_client_ip(i, congestion_client=True), netmask) cmd = self.interface_up_command(self.get_client_interface(
i + 1, 0), self.get_client_ip(i, congestion_client=True), netmask)
self.topo.command_to(self.clients[i+1], cmd) self.topo.command_to(self.clients[i+1], cmd)
client_interface_mac = self.clients[i+1].intf(self.get_client_interface(i + 1, 0)).MAC() client_interface_mac = self.clients[i+1].intf(
self.topo.command_to(self.router, "arp -s {} {}".format(self.get_client_ip(i, congestion_client=True), client_interface_mac)) self.get_client_interface(i + 1, 0)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_client_ip(i, congestion_client=True), client_interface_mac))
router_interface_mac = self.router.intf(self.get_router_interface_to_client_switch(i)).MAC() router_interface_mac = self.router.intf(
self.get_router_interface_to_client_switch(i)).MAC()
# Congestion client # Congestion client
self.topo.command_to(self.clients[i+1], "arp -s {} {}".format( self.topo.command_to(self.clients[i+1], "arp -s {} {}".format(
self.get_router_ip_to_client_switch(i), router_interface_mac)) self.get_router_ip_to_client_switch(i), router_interface_mac))
for i, s in enumerate(self.servers): for i, s in enumerate(self.servers):
cmd = self.interface_up_command(self.get_router_interface_to_server_switch(i), cmd = self.interface_up_command(self.get_router_interface_to_server_switch(i),
self.get_router_ip_to_server_switch(i), netmask) self.get_router_ip_to_server_switch(i), netmask)
self.topo.command_to(self.router, cmd) self.topo.command_to(self.router, cmd)
router_interface_mac = self.router.intf(self.get_router_interface_to_server_switch(i)).MAC() router_interface_mac = self.router.intf(
self.get_router_interface_to_server_switch(i)).MAC()
self.topo.command_to(s, "arp -s {} {}".format( self.topo.command_to(s, "arp -s {} {}".format(
self.get_router_ip_to_server_switch(i), router_interface_mac)) self.get_router_ip_to_server_switch(i), router_interface_mac))
cmd = self.interface_up_command(self.get_server_interface(i, 0), self.get_server_ip(interface_index=i), netmask) cmd = self.interface_up_command(self.get_server_interface(
i, 0), self.get_server_ip(interface_index=i), netmask)
self.topo.command_to(s, cmd) self.topo.command_to(s, cmd)
server_interface_mac = s.intf(self.get_server_interface(i, 0)).MAC() server_interface_mac = s.intf(
self.get_server_interface(i, 0)).MAC()
self.topo.command_to(self.router, "arp -s {} {}".format( self.topo.command_to(self.router, "arp -s {} {}".format(
self.get_server_ip(interface_index=i), server_interface_mac)) self.get_server_ip(interface_index=i), server_interface_mac))
def get_client_ip(self, interface_index, congestion_client=False): def get_client_ip(self, interface_index, congestion_client=False):
return "{}{}.{}".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index, "10" if congestion_client else "1") return "{}{}.{}".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index, "10" if congestion_client else "1")
def server_interface_count(self): def server_interface_count(self):
return max(len(self.servers), 1) return max(len(self.servers), 1)

BIN
utils/echo-client Executable file

Binary file not shown.

BIN
utils/server Executable file

Binary file not shown.