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.
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
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.
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
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
kpms:fullmesh
kpmc:fullmesh

View File

@ -2,6 +2,7 @@ from .parameter import Parameter
import logging
class ExperimentParameter(Parameter):
"""
Handler for experiment parameters stored in configuration files.
@ -20,10 +21,10 @@ class ExperimentParameter(Parameter):
AUTOCORK = "autocork"
EARLY_RETRANS = "earlyRetrans"
KERNELPM = "kpm"
KERNELPMC = "kpmc" #kernel path manager client / server
KERNELPMC = "kpmc" # kernel path manager client / server
KERNELPMS = "kpms"
USERPMC = "upmc"
USERPMS = "upms" #userspace path manager client / server
USERPMS = "upms" # userspace path manager client / server
USERPMC_ARGS = "upmc_args"
USERPMS_ARGS = "upms_args"
CLIENT_PCAP = "clientPcap"
@ -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
@ -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,13 +174,15 @@ 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.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)
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)))
@ -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,7 +254,8 @@ 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)
@ -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)
self._write_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore,
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)
self._restore_sysctl(ExperimentParameter.SYSCTL_KEY_SERVER, self.server_sysctl_to_restore,
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,9 +339,14 @@ 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))
@ -337,7 +355,7 @@ class Experiment(object):
"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,
@ -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,14 +397,16 @@ 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()

View File

@ -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
@ -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)
@ -297,12 +315,14 @@ 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)
@ -311,7 +331,8 @@ class BottleneckLink(object):
"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)
@ -320,7 +341,8 @@ class BottleneckLink(object):
"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
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"
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")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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))
@ -113,11 +121,13 @@ if __name__ == '__main__':
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
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,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"]
@ -106,10 +107,10 @@ class MultiInterfaceConfig(TopoConfig):
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,20 +120,25 @@ 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.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))
@ -141,13 +147,16 @@ class MultiInterfaceConfig(TopoConfig):
cmd = self.interface_up_command(self.get_router_interface_to_server_switch(0),
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))
@ -155,19 +164,22 @@ class MultiInterfaceConfig(TopoConfig):
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()
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)

View File

@ -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
@ -50,24 +56,32 @@ class MultiInterfaceMultiClientConfig(MultiInterfaceConfig):
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))
@ -76,12 +90,15 @@ class MultiInterfaceMultiClientConfig(MultiInterfaceConfig):
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()
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

Binary file not shown.

BIN
utils/server Executable file

Binary file not shown.