commit 2022-02-16]13:26:08
This commit is contained in:
parent
fac7b51d4c
commit
951cbd51e8
@ -2,4 +2,6 @@ leftSubnet:10.0.
|
||||
rightSubnet:10.1.
|
||||
path_c2r_0:10,10,4
|
||||
path_c2r_1:40,30,4
|
||||
path_c2r_3:10,10,4
|
||||
path_c2r_4:10,10,4
|
||||
topoType:MultiIf
|
||||
|
5
config/topo/topo_1_1
Normal file
5
config/topo/topo_1_1
Normal file
@ -0,0 +1,5 @@
|
||||
clients:5
|
||||
leftSubnet:10.0.
|
||||
rightSubnet:10.1.
|
||||
path_c2r_0:10,10,4,10
|
||||
topoType:IoTMultiClient
|
@ -2,4 +2,7 @@ leftSubnet:10.0.
|
||||
rightSubnet:10.1.
|
||||
path_c2r_0:10,10,4
|
||||
path_c2r_1:40,30,4
|
||||
path_c2r_3:40,30,4
|
||||
path_c2r_4:40,30,4
|
||||
topoType:MultiIfMultiClient
|
||||
|
||||
|
5
config/xp/basicquic
Normal file
5
config/xp/basicquic
Normal file
@ -0,0 +1,5 @@
|
||||
xpType:basicquic
|
||||
serverPcap:yes
|
||||
kpms:fullmesh
|
||||
kpmc:fullmesh
|
||||
rmem:300000 300000 300000
|
@ -1,4 +1,4 @@
|
||||
xpType:https
|
||||
xpType:pquic
|
||||
clientPcap:yes
|
||||
kpms:fullmesh
|
||||
kpmc:fullmesh
|
||||
|
@ -2,6 +2,7 @@ from .parameter import Parameter
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class ExperimentParameter(Parameter):
|
||||
"""
|
||||
Handler for experiment parameters stored in configuration files.
|
||||
@ -12,25 +13,25 @@ class ExperimentParameter(Parameter):
|
||||
Attribute:
|
||||
default_parameters Default values for the parameters
|
||||
"""
|
||||
RMEM = "rmem"
|
||||
WMEM = "wmem"
|
||||
RMEM = "rmem"
|
||||
WMEM = "wmem"
|
||||
MPTCP_ENABLED = "mptcpEnabled"
|
||||
SCHED = "sched"
|
||||
CC = "congctrl"
|
||||
AUTOCORK = "autocork"
|
||||
SCHED = "sched"
|
||||
CC = "congctrl"
|
||||
AUTOCORK = "autocork"
|
||||
EARLY_RETRANS = "earlyRetrans"
|
||||
KERNELPM = "kpm"
|
||||
KERNELPMC = "kpmc" #kernel path manager client / server
|
||||
KERNELPMS = "kpms"
|
||||
USERPMC = "upmc"
|
||||
USERPMS = "upms" #userspace path manager client / server
|
||||
USERPMC_ARGS = "upmc_args"
|
||||
USERPMS_ARGS = "upms_args"
|
||||
KERNELPM = "kpm"
|
||||
KERNELPMC = "kpmc" # kernel path manager client / server
|
||||
KERNELPMS = "kpms"
|
||||
USERPMC = "upmc"
|
||||
USERPMS = "upms" # userspace path manager client / server
|
||||
USERPMC_ARGS = "upmc_args"
|
||||
USERPMS_ARGS = "upms_args"
|
||||
CLIENT_PCAP = "clientPcap"
|
||||
SERVER_PCAP = "serverPcap"
|
||||
SNAPLEN_PCAP = "snaplen_pcap"
|
||||
XP_TYPE = "xpType"
|
||||
PING_COUNT = "pingCount"
|
||||
XP_TYPE = "xpType"
|
||||
PING_COUNT = "pingCount"
|
||||
PRIO_PATH_0 = "priority_path_0"
|
||||
PRIO_PATH_1 = "priority_path_1"
|
||||
BACKUP_PATH_0 = "backup_path_0"
|
||||
@ -41,13 +42,13 @@ class ExperimentParameter(Parameter):
|
||||
SYSCTL_KEY = {
|
||||
RMEM: "net.ipv4.tcp_rmem",
|
||||
WMEM: "net.ipv4.tcp_wmem",
|
||||
MPTCP_ENABLED: "net.mptcp.mptcp_enabled",
|
||||
KERNELPM: "net.mptcp.mptcp_path_manager",
|
||||
SCHED: "net.mptcp.mptcp_scheduler",
|
||||
CC: "net.ipv4.tcp_congestion_control",
|
||||
AUTOCORK: "net.ipv4.tcp_autocorking",
|
||||
EARLY_RETRANS: "net.ipv4.tcp_early_retrans",
|
||||
BUFFER_AUTOTUNING: "net.ipv4.tcp_moderate_rcvbuf",
|
||||
# MPTCP_ENABLED: "net.mptcp.mptcp_enabled",
|
||||
# KERNELPM: "net.mptcp.mptcp_path_manager",
|
||||
# SCHED: "net.mptcp.mptcp_scheduler",
|
||||
# CC: "net.ipv4.tcp_congestion_control",
|
||||
# AUTOCORK: "net.ipv4.tcp_autocorking",
|
||||
# EARLY_RETRANS: "net.ipv4.tcp_early_retrans",
|
||||
# BUFFER_AUTOTUNING: "net.ipv4.tcp_moderate_rcvbuf",
|
||||
}
|
||||
|
||||
# sysctl keys specific to client and server, independently
|
||||
@ -93,10 +94,10 @@ class ExperimentParameter(Parameter):
|
||||
|
||||
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
|
||||
`NAME` attribute.
|
||||
This class is not instantiable as it. You must define a child class with the
|
||||
`NAME` attribute.
|
||||
|
||||
By default, an Experiment relies on an instance of ExperimentParameter to
|
||||
collect the parameters from the experiment configuration file. However, an
|
||||
@ -108,7 +109,7 @@ class Experiment(object):
|
||||
experiment_parameter Instance of ExperimentParameter
|
||||
topo Instance of Topo
|
||||
topo_config Instance of TopoConfig
|
||||
"""
|
||||
"""
|
||||
PARAMETER_CLASS = ExperimentParameter
|
||||
|
||||
IP_BIN = "ip"
|
||||
@ -118,7 +119,8 @@ class Experiment(object):
|
||||
"""
|
||||
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_config = topo_config
|
||||
|
||||
@ -158,8 +160,10 @@ class Experiment(object):
|
||||
"""
|
||||
Function only meaningful for MPTCP
|
||||
"""
|
||||
priority_path_0 = self.experiment_parameter.get(ExperimentParameter.PRIO_PATH_0)
|
||||
priority_path_1 = self.experiment_parameter.get(ExperimentParameter.PRIO_PATH_1)
|
||||
priority_path_0 = self.experiment_parameter.get(
|
||||
ExperimentParameter.PRIO_PATH_0)
|
||||
priority_path_1 = self.experiment_parameter.get(
|
||||
ExperimentParameter.PRIO_PATH_1)
|
||||
if not priority_path_0 == priority_path_1:
|
||||
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))
|
||||
@ -170,18 +174,20 @@ class Experiment(object):
|
||||
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))
|
||||
|
||||
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:
|
||||
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_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)
|
||||
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)
|
||||
if int(backup_path_1) > 0:
|
||||
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_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):
|
||||
"""
|
||||
@ -190,13 +196,15 @@ class Experiment(object):
|
||||
if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink":
|
||||
logging.info("Running user-space path manager on client")
|
||||
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(
|
||||
upmc, upmca, "upmc.log"))
|
||||
if self.experiment_parameter.get(ExperimentParameter.KERNELPMS) == "netlink":
|
||||
logging.info("Running user-space path manager on server")
|
||||
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(
|
||||
upms, upmsa, "upms.log"))
|
||||
|
||||
@ -204,11 +212,13 @@ class Experiment(object):
|
||||
if self.experiment_parameter.get(ExperimentParameter.KERNELPMC) == "netlink":
|
||||
logging.info("Cleaning user-space path manager on client")
|
||||
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":
|
||||
logging.info("Cleaning user-space path manager on server")
|
||||
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):
|
||||
self.topo_config.run_netem_at()
|
||||
@ -244,13 +254,14 @@ class Experiment(object):
|
||||
Record the current sysctls
|
||||
"""
|
||||
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._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._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):
|
||||
for k in sysctl_dict:
|
||||
@ -284,13 +295,14 @@ class Experiment(object):
|
||||
"""
|
||||
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,
|
||||
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,
|
||||
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:
|
||||
sysctl_key = sysctl_dict[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
|
||||
"""
|
||||
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,
|
||||
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,
|
||||
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:
|
||||
sysctl_key = sysctl_dict[k]
|
||||
sysctl_value = sysctl_to_restore[k]
|
||||
@ -326,27 +339,32 @@ class Experiment(object):
|
||||
logging.error("unable to set sysctl {}".format(sysctl_key))
|
||||
|
||||
def run_tcpdump(self):
|
||||
client_pcap = self.experiment_parameter.get(ExperimentParameter.CLIENT_PCAP)
|
||||
server_pcap = self.experiment_parameter.get(ExperimentParameter.SERVER_PCAP)
|
||||
snaplen_pcap = self.experiment_parameter.get(ExperimentParameter.SNAPLEN_PCAP)
|
||||
client_pcap = self.experiment_parameter.get(
|
||||
ExperimentParameter.CLIENT_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":
|
||||
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":
|
||||
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":
|
||||
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):
|
||||
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)
|
||||
for j in range(0, self.topo_config.server_interface_count()):
|
||||
for i in range(0, self.topo_config.client_interface_count()):
|
||||
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)
|
||||
self.topo.command_to(self.topo_config.client, cmd)
|
||||
|
||||
@ -362,7 +380,8 @@ class RandomFileParameter(ExperimentParameter):
|
||||
RANDOM_SIZE = "file_size" # in KB
|
||||
|
||||
def __init__(self, experiment_parameter_filename):
|
||||
super(RandomFileParameter, self).__init__(experiment_parameter_filename)
|
||||
super(RandomFileParameter, self).__init__(
|
||||
experiment_parameter_filename)
|
||||
self.default_parameters.update({
|
||||
RandomFileParameter.FILE: "random",
|
||||
RandomFileParameter.RANDOM_SIZE: "1024",
|
||||
@ -378,22 +397,24 @@ class RandomFileExperiment(Experiment):
|
||||
PARAMETER_CLASS = RandomFileParameter
|
||||
|
||||
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.ping()
|
||||
|
||||
def load_parameters(self):
|
||||
super(RandomFileExperiment, self).load_parameters()
|
||||
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):
|
||||
super(RandomFileExperiment, self).prepare()
|
||||
if self.file == "random":
|
||||
if self.file == "random":
|
||||
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):
|
||||
super(RandomFileExperiment, self).clean()
|
||||
if self.file == "random":
|
||||
if self.file == "random":
|
||||
self.topo.command_to(self.topo_config.client, "rm random*")
|
||||
|
84
core/topo.py
84
core/topo.py
@ -8,6 +8,7 @@ class NetemAt(object):
|
||||
"""
|
||||
Class representing a netem command to be run after some time
|
||||
"""
|
||||
|
||||
def __init__(self, at, cmd):
|
||||
self.at = at
|
||||
self.cmd = cmd
|
||||
@ -41,6 +42,7 @@ class LinkCharacteristics(object):
|
||||
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)
|
||||
"""
|
||||
|
||||
def __init__(self, id, link_type, delay, queue_size, bandwidth, loss, backup=0):
|
||||
self.id = id
|
||||
self.link_type = link_type
|
||||
@ -48,7 +50,8 @@ class LinkCharacteristics(object):
|
||||
self.queue_size = queue_size
|
||||
self.bandwidth = bandwidth
|
||||
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.backup = backup
|
||||
|
||||
@ -63,11 +66,11 @@ class LinkCharacteristics(object):
|
||||
Return the buffer size in bytes
|
||||
"""
|
||||
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):
|
||||
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)
|
||||
|
||||
def add_netem_at(self, n):
|
||||
@ -79,7 +82,8 @@ class LinkCharacteristics(object):
|
||||
n.delta = n.at - self.netem_at[-1].at
|
||||
self.netem_at.append(n)
|
||||
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):
|
||||
return "tc qdisc del dev {} root; tc qdisc del dev {} ingress ".format(ifname, ifname)
|
||||
@ -137,11 +141,13 @@ class TopoParameter(Parameter):
|
||||
RIGHT_SUBNET = "rightSubnet"
|
||||
NETEM_AT = "netemAt_"
|
||||
CHANGE_NETEM = "changeNetem"
|
||||
CLIENTS = "clients"
|
||||
|
||||
DEFAULT_PARAMETERS = {
|
||||
LEFT_SUBNET: "10.1.",
|
||||
RIGHT_SUBNET: "10.2.",
|
||||
CHANGE_NETEM: "false",
|
||||
CLIENTS: "1",
|
||||
}
|
||||
|
||||
def __init__(self, parameter_filename):
|
||||
@ -150,6 +156,7 @@ class TopoParameter(Parameter):
|
||||
self.link_characteristics = []
|
||||
self.load_link_characteristics()
|
||||
self.load_netem_at()
|
||||
self.load_clients()
|
||||
logging.info(self)
|
||||
|
||||
def parse_netem_at(self, key):
|
||||
@ -161,13 +168,23 @@ class TopoParameter(Parameter):
|
||||
_, link_type, link_id = key.split("_")
|
||||
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):
|
||||
if not self.get(TopoParameter.CHANGE_NETEM) == "yes":
|
||||
return
|
||||
for k in sorted(self.parameters):
|
||||
if k.startswith(TopoParameter.NETEM_AT):
|
||||
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):
|
||||
for l in self.link_characteristics:
|
||||
@ -184,7 +201,8 @@ class TopoParameter(Parameter):
|
||||
l.add_netem_at(na)
|
||||
|
||||
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)
|
||||
|
||||
@ -243,7 +261,7 @@ class TopoParameter(Parameter):
|
||||
logging.error("Ignored path {}: {}".format(k, e))
|
||||
else:
|
||||
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)
|
||||
|
||||
def __str__(self):
|
||||
@ -282,7 +300,7 @@ class BottleneckLink(object):
|
||||
|
||||
def get_bs_name(self, index):
|
||||
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):
|
||||
# Required to retrieve actual nodes
|
||||
@ -297,30 +315,34 @@ class BottleneckLink(object):
|
||||
|
||||
# Cleanup tc commands
|
||||
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)
|
||||
self.topo.command_to(self.bs1, clean_cmd)
|
||||
|
||||
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)
|
||||
self.topo.command_to(self.bs2, clean_cmd)
|
||||
|
||||
# Flow bs0 -> bs3
|
||||
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)
|
||||
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)
|
||||
self.topo.command_to(self.bs2, shaping_cmd)
|
||||
|
||||
# Flow bs3 -> bs0
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
bs2_interface_names = self.topo.get_interface_names(self.bs2)
|
||||
# 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)
|
||||
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)
|
||||
self.topo.command_to(self.bs2, netem_cmd)
|
||||
|
||||
# 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)
|
||||
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)
|
||||
self.topo.command_to(self.bs1, netem_cmd)
|
||||
|
||||
@ -380,7 +406,8 @@ class Topo(object):
|
||||
def __init__(self, topo_builder, topo_parameter):
|
||||
self.topo_builder = topo_builder
|
||||
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.clients = []
|
||||
self.routers = []
|
||||
@ -467,7 +494,8 @@ class Topo(object):
|
||||
otherwise just connect it to from_a and to_b and returns the bottleneck_link
|
||||
"""
|
||||
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.topo_builder.add_link(from_a, bottleneck_link.get_left())
|
||||
@ -476,9 +504,12 @@ class Topo(object):
|
||||
|
||||
def reinit_variables(self):
|
||||
# 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.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))]
|
||||
self.clients = [self.get_host(self.get_client_name(i))
|
||||
for i in range(len(self.clients))]
|
||||
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:
|
||||
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
|
||||
`NAME` attribute.
|
||||
"""
|
||||
|
||||
def __init__(self, topo, param):
|
||||
self.topo = topo
|
||||
self.param = param
|
||||
@ -520,8 +552,10 @@ class TopoConfig(object):
|
||||
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 intf in self.topo.get_interface_names(node):
|
||||
logging.debug("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(
|
||||
"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)
|
||||
self.topo.command_to(node, cmd)
|
||||
|
||||
|
88
experiments/basicquic.py
Normal file
88
experiments/basicquic.py
Normal 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")
|
@ -8,7 +8,8 @@ class IPerfScenarioParameter(ExperimentParameter):
|
||||
FM_SUBFLOWS = "iperfScenarioFMSublows"
|
||||
|
||||
def __init__(self, experiment_parameter_filename):
|
||||
super(IPerfScenarioParameter, self).__init__(experiment_parameter_filename)
|
||||
super(IPerfScenarioParameter, self).__init__(
|
||||
experiment_parameter_filename)
|
||||
self.default_parameters.update({
|
||||
IPerfScenarioParameter.FM_SUBFLOWS: "1",
|
||||
})
|
||||
@ -24,29 +25,37 @@ class IPerfScenario(Experiment):
|
||||
PING_OUTPUT = "ping.log"
|
||||
|
||||
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.ping()
|
||||
|
||||
def load_parameters(self):
|
||||
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):
|
||||
super(IPerfScenario, self).prepare()
|
||||
self.topo.command_to(self.topo_config.client, "rm {}".format(IPerfScenario.IPERF_LOG))
|
||||
self.topo.command_to(self.topo_config.server, "rm {}".format(IPerfScenario.SERVER_LOG))
|
||||
self.topo.command_to(self.topo_config.client,
|
||||
"rm {}".format(IPerfScenario.IPERF_LOG))
|
||||
self.topo.command_to(self.topo_config.server,
|
||||
"rm {}".format(IPerfScenario.SERVER_LOG))
|
||||
|
||||
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):
|
||||
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)
|
||||
return s
|
||||
|
||||
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)
|
||||
return s
|
||||
|
||||
@ -54,32 +63,39 @@ class IPerfScenario(Experiment):
|
||||
super(IPerfScenario, self).clean()
|
||||
|
||||
def run(self):
|
||||
|
||||
self.topo.command_to(self.topo_config.router, "tcpdump -i any -w router.pcap &")
|
||||
print('IPerfScenario!!!!!!')
|
||||
self.topo.command_to(self.topo_config.router,
|
||||
"tcpdump -i any -w router.pcap &")
|
||||
# First run servers
|
||||
for l, s in enumerate(self.topo_config.servers):
|
||||
self.topo.command_to(s, self.get_server_cmd(server_id=l))
|
||||
|
||||
# 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")
|
||||
|
||||
# We run as follow.
|
||||
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)
|
||||
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)
|
||||
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, "sleep 2")
|
||||
|
||||
# This is hacky
|
||||
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, "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")
|
||||
|
BIN
mptcp_debs/linux-headers-4.1.39+_4.1.39+-81_amd64.deb
Normal file
BIN
mptcp_debs/linux-headers-4.1.39+_4.1.39+-81_amd64.deb
Normal file
Binary file not shown.
BIN
mptcp_debs/linux-image-4.1.39+-dbg_4.1.39+-81_amd64.deb
Normal file
BIN
mptcp_debs/linux-image-4.1.39+-dbg_4.1.39+-81_amd64.deb
Normal file
Binary file not shown.
BIN
mptcp_debs/linux-image-4.1.39+_4.1.39+-81_amd64.deb
Normal file
BIN
mptcp_debs/linux-image-4.1.39+_4.1.39+-81_amd64.deb
Normal file
Binary file not shown.
BIN
mptcp_debs/linux-libc-dev_4.1.39+-81_amd64.deb
Normal file
BIN
mptcp_debs/linux-libc-dev_4.1.39+-81_amd64.deb
Normal file
Binary file not shown.
28
runner.py
28
runner.py
@ -14,15 +14,18 @@ import os
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
|
||||
def get_git_revision_short_hash():
|
||||
# Because we might run Minitopo from elsewhere.
|
||||
curr_dir = os.getcwd()
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
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)
|
||||
return ret
|
||||
|
||||
|
||||
class Runner(object):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
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.set_builder(builder_type)
|
||||
self.apply_topo()
|
||||
@ -48,7 +53,8 @@ class Runner(object):
|
||||
if builder_type == Topo.MININET_BUILDER:
|
||||
self.topo_builder = MininetBuilder()
|
||||
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):
|
||||
"""
|
||||
@ -86,9 +92,11 @@ class Runner(object):
|
||||
Match the name of the experiement and launch it
|
||||
"""
|
||||
# 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:
|
||||
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()
|
||||
else:
|
||||
raise Exception("Unknown experiment {}".format(xp))
|
||||
@ -107,17 +115,19 @@ if __name__ == '__main__':
|
||||
description="Minitopo, a wrapper of Mininet to run multipath experiments")
|
||||
|
||||
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",
|
||||
help="path to the experiment parameter file")
|
||||
help="path to the experiment parameter file")
|
||||
|
||||
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...
|
||||
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:
|
||||
logging.fatal("A fatal error occurred: {}".format(e))
|
||||
traceback.print_exc()
|
||||
|
128
topos/iot_multi_client.py
Normal file
128
topos/iot_multi_client.py
Normal 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)
|
@ -16,16 +16,17 @@ class MultiInterfaceTopo(Topo):
|
||||
|
||||
# Add client - 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!
|
||||
if len(self.get_router_to_server_links()) > 0:
|
||||
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:
|
||||
self.add_link(self.router, self.server)
|
||||
|
||||
|
||||
def get_client_to_router_links(self):
|
||||
return [l for l in self.topo_parameter.link_characteristics if l.link_type == "c2r"]
|
||||
|
||||
@ -81,12 +82,12 @@ class MultiInterfaceConfig(TopoConfig):
|
||||
self.topo.command_to(self.client, cmd)
|
||||
|
||||
cmd = self.add_link_scope_route_command(
|
||||
self.get_client_subnet(i),
|
||||
self.get_client_interface(0, i), i)
|
||||
self.get_client_subnet(i),
|
||||
self.get_client_interface(0, i), i)
|
||||
self.topo.command_to(self.client, cmd)
|
||||
|
||||
cmd = self.add_table_default_route_command(self.get_router_ip_to_client_switch(i),
|
||||
i)
|
||||
i)
|
||||
self.topo.command_to(self.client, cmd)
|
||||
|
||||
for i, _ in enumerate(self.topo.r2s_links):
|
||||
@ -94,22 +95,22 @@ class MultiInterfaceConfig(TopoConfig):
|
||||
self.topo.command_to(self.server, cmd)
|
||||
|
||||
cmd = self.add_link_scope_route_command(
|
||||
self.get_server_subnet(i),
|
||||
self.get_server_interface(0, i), i)
|
||||
self.get_server_subnet(i),
|
||||
self.get_server_interface(0, i), i)
|
||||
self.topo.command_to(self.server, cmd)
|
||||
|
||||
cmd = self.add_table_default_route_command(self.get_router_ip_to_server_switch(i),
|
||||
i)
|
||||
i)
|
||||
self.topo.command_to(self.server, cmd)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def configure_interfaces(self):
|
||||
logging.info("Configure interfaces using MultiInterfaceConfig...")
|
||||
super(MultiInterfaceConfig, self).configure_interfaces()
|
||||
@ -119,55 +120,66 @@ class MultiInterfaceConfig(TopoConfig):
|
||||
netmask = "255.255.255.0"
|
||||
|
||||
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)
|
||||
client_interface_mac = self.client.intf(self.get_client_interface(0, i)).MAC()
|
||||
self.topo.command_to(self.router, "arp -s {} {}".format(self.get_client_ip(i), client_interface_mac))
|
||||
client_interface_mac = self.client.intf(
|
||||
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:
|
||||
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)
|
||||
|
||||
for i, _ in enumerate(self.topo.c2r_links):
|
||||
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)
|
||||
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.get_router_ip_to_client_switch(i), router_interface_mac))
|
||||
|
||||
if len(self.topo.r2s_links) == 0:
|
||||
# Case no server param is specified
|
||||
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)
|
||||
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.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)
|
||||
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.get_server_ip(0), server_interface_mac))
|
||||
|
||||
for i, _ in enumerate(self.topo.r2s_links):
|
||||
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)
|
||||
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.get_router_ip_to_server_switch(i), router_interface_mac))
|
||||
|
||||
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)
|
||||
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.get_server_ip(i), server_interface_mac))
|
||||
|
||||
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):
|
||||
return "{}{}.0/24".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index)
|
||||
|
@ -8,14 +8,17 @@ class MultiInterfaceMultiClientTopo(MultiInterfaceTopo):
|
||||
|
||||
def __init__(self, topo_builder, parameterFile):
|
||||
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 bl in self.c2r_links:
|
||||
client = self.add_client()
|
||||
self.add_server()
|
||||
self.add_link(client, bl.get_left())
|
||||
|
||||
self.add_server()
|
||||
|
||||
# And connect the router to all servers
|
||||
for s in self.servers[1:]:
|
||||
self.add_link(self.router, s)
|
||||
@ -24,12 +27,15 @@ class MultiInterfaceMultiClientTopo(MultiInterfaceTopo):
|
||||
s = "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 + " r--s\n"
|
||||
s = s + "c-\sw---bl---sw-/ \-s\n"
|
||||
else:
|
||||
elif i < nc // 2:
|
||||
s = s + "c-/sw---bl---sw-\ /-s\n"
|
||||
else:
|
||||
s = s + "c-\sw---bl---sw-/ \-s\n"
|
||||
|
||||
return s
|
||||
|
||||
@ -45,43 +51,54 @@ class MultiInterfaceMultiClientConfig(MultiInterfaceConfig):
|
||||
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(i+1, 0))
|
||||
self.get_client_interface(i+1, 0))
|
||||
self.topo.command_to(self.clients[i+1], 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))
|
||||
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 MultiInterfaceMultiClientConfig...")
|
||||
logging.info(
|
||||
"Configure interfaces using MultiInterfaceMultiClientConfig...")
|
||||
super(MultiInterfaceMultiClientConfig, 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())]
|
||||
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 i, _ in enumerate(self.topo.c2r_links):
|
||||
# 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)
|
||||
client_interface_mac = self.clients[i+1].intf(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))
|
||||
client_interface_mac = self.clients[i+1].intf(
|
||||
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
|
||||
self.topo.command_to(self.clients[i+1], "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.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()
|
||||
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)
|
||||
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()
|
||||
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))
|
||||
|
||||
|
BIN
utils/echo-client
Executable file
BIN
utils/echo-client
Executable file
Binary file not shown.
BIN
utils/server
Executable file
BIN
utils/server
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user