diff --git a/config/topo/topo_1 b/config/topo/topo_1 index 4d87e30..9196599 100644 --- a/config/topo/topo_1 +++ b/config/topo/topo_1 @@ -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 diff --git a/config/topo/topo_1_1 b/config/topo/topo_1_1 new file mode 100644 index 0000000..0fb8774 --- /dev/null +++ b/config/topo/topo_1_1 @@ -0,0 +1,5 @@ +clients:5 +leftSubnet:10.0. +rightSubnet:10.1. +path_c2r_0:10,10,4,10 +topoType:IoTMultiClient diff --git a/config/topo/topo_cong b/config/topo/topo_cong index 068b51c..f61f13e 100644 --- a/config/topo/topo_cong +++ b/config/topo/topo_cong @@ -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 + diff --git a/config/xp/basicquic b/config/xp/basicquic new file mode 100644 index 0000000..6f895bb --- /dev/null +++ b/config/xp/basicquic @@ -0,0 +1,5 @@ +xpType:basicquic +serverPcap:yes +kpms:fullmesh +kpmc:fullmesh +rmem:300000 300000 300000 diff --git a/config/xp/https b/config/xp/https index c09aff7..1beb405 100644 --- a/config/xp/https +++ b/config/xp/https @@ -1,4 +1,4 @@ -xpType:https +xpType:pquic clientPcap:yes kpms:fullmesh kpmc:fullmesh diff --git a/core/experiment.py b/core/experiment.py index 64c1ee9..926f21c 100644 --- a/core/experiment.py +++ b/core/experiment.py @@ -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*") diff --git a/core/topo.py b/core/topo.py index 96c87fc..db3e463 100644 --- a/core/topo.py +++ b/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): @@ -281,8 +299,8 @@ class BottleneckLink(object): topo_builder.add_link(self.bs2, self.bs3) def get_bs_name(self, index): - return "{}_{}_{}_{}".format(BottleneckLink.BOTTLENECK_SWITCH_NAME_PREFIX, - self.link_characteristics.link_type, self.link_characteristics.id, index) + return "{}_{}_{}_{}".format(BottleneckLink.BOTTLENECK_SWITCH_NAME_PREFIX, + 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) diff --git a/experiments/basicquic.py b/experiments/basicquic.py new file mode 100644 index 0000000..693467a --- /dev/null +++ b/experiments/basicquic.py @@ -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") diff --git a/experiments/iperf_scenario.py b/experiments/iperf_scenario.py index 30a6622..ef04b98 100644 --- a/experiments/iperf_scenario.py +++ b/experiments/iperf_scenario.py @@ -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") diff --git a/mptcp_debs/linux-headers-4.1.39+_4.1.39+-81_amd64.deb b/mptcp_debs/linux-headers-4.1.39+_4.1.39+-81_amd64.deb new file mode 100644 index 0000000..e35a1d9 Binary files /dev/null and b/mptcp_debs/linux-headers-4.1.39+_4.1.39+-81_amd64.deb differ diff --git a/mptcp_debs/linux-image-4.1.39+-dbg_4.1.39+-81_amd64.deb b/mptcp_debs/linux-image-4.1.39+-dbg_4.1.39+-81_amd64.deb new file mode 100644 index 0000000..4e7d8f9 Binary files /dev/null and b/mptcp_debs/linux-image-4.1.39+-dbg_4.1.39+-81_amd64.deb differ diff --git a/mptcp_debs/linux-image-4.1.39+_4.1.39+-81_amd64.deb b/mptcp_debs/linux-image-4.1.39+_4.1.39+-81_amd64.deb new file mode 100644 index 0000000..efdf98d Binary files /dev/null and b/mptcp_debs/linux-image-4.1.39+_4.1.39+-81_amd64.deb differ diff --git a/mptcp_debs/linux-libc-dev_4.1.39+-81_amd64.deb b/mptcp_debs/linux-libc-dev_4.1.39+-81_amd64.deb new file mode 100644 index 0000000..8cf6b63 Binary files /dev/null and b/mptcp_debs/linux-libc-dev_4.1.39+-81_amd64.deb differ diff --git a/runner.py b/runner.py index 4721558..8547499 100644 --- a/runner.py +++ b/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,21 +115,23 @@ 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() finally: # Always cleanup Mininet logging.info("cleanup mininet") - cleanup() \ No newline at end of file + cleanup() diff --git a/topos/iot_multi_client.py b/topos/iot_multi_client.py new file mode 100644 index 0000000..b213f76 --- /dev/null +++ b/topos/iot_multi_client.py @@ -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) diff --git a/topos/multi_interface.py b/topos/multi_interface.py index 925292b..a0a642b 100644 --- a/topos/multi_interface.py +++ b/topos/multi_interface.py @@ -16,15 +16,16 @@ 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"] @@ -65,7 +66,7 @@ class MultiInterfaceTopo(Topo): else: s = s + " \-sw---bl---sw-/ \n" skipped += 1 - + return s @@ -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) @@ -200,4 +212,4 @@ class MultiInterfaceConfig(TopoConfig): return "{}-eth{}".format(self.topo.get_router_name(0), interface_index) def get_server_interface(self, server_index, interface_index): - return "{}-eth{}".format(self.topo.get_server_name(server_index), interface_index) \ No newline at end of file + return "{}-eth{}".format(self.topo.get_server_name(server_index), interface_index) diff --git a/topos/multi_interface_multi_client.py b/topos/multi_interface_multi_client.py index f8a9d98..0034471 100644 --- a/topos/multi_interface_multi_client.py +++ b/topos/multi_interface_multi_client.py @@ -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,13 +27,16 @@ 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,48 +51,59 @@ 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)) def get_client_ip(self, interface_index, congestion_client=False): return "{}{}.{}".format(self.param.get(TopoParameter.LEFT_SUBNET), interface_index, "10" if congestion_client else "1") - def server_interface_count(self): - return max(len(self.servers), 1) \ No newline at end of file + def server_interface_count(self): + return max(len(self.servers), 1) diff --git a/utils/echo-client b/utils/echo-client new file mode 100755 index 0000000..be26881 Binary files /dev/null and b/utils/echo-client differ diff --git a/utils/server b/utils/server new file mode 100755 index 0000000..400062f Binary files /dev/null and b/utils/server differ