class CPSC558FinalProject: __DEFAULT_RUN_NAME = "main" __DEFAULT_FILE_SERVER_DIRECTORY = "data" __BANDWIDTH_LIMIT_MBPS = 1000 __BANDWIDTH_LIMIT_LATENCY = "1ms" def __init__(self, run_name): self.__run_name = run_name self.__logger = Logger(group=self.__run_name, log_name=__name__, label="558 Project") self.__logger_summary = Logger(group="summary", log_name=__name__, label="558 Project Summary", append=True) self.__net = None # Mininet self.__topo = None self.__controller = None self.__logger.get().info("Instantiated inside Python version: " + str(sys.version)) def run(self): log = self.__logger.get() controller_log_file = os.path.join( self.__logger.make_log_file_directory_path(), "controller.txt") controller_name = "ryu_" + self.__run_name controller_path_relative = "controllers/" if self.__run_name == "demo": controller_source_file_name = "Demo_SimpleSwitch.py" elif self.__run_name == "hub": controller_source_file_name = "DumbHub.py" elif self.__run_name == "switch": controller_source_file_name = "SimpleSwitch.py" elif self.__run_name == "qswitch": controller_source_file_name = "QSwitch.py" else: raise Exception("Invalid run name: " + str(self.__run_name)) controller_path_relative += controller_source_file_name # Instantiate Mininet::Ryu(), which just launches ryu-manager for us controller = Ryu( controller_name, controller_path_relative, # "--verbose", "--log-file", controller_log_file) self.__logger.heading("Running with controller: " + controller_source_file_name) log.info("Instantiating custom Topology class") self.__topo = Topology(self.__logger) log.info("Rendering graph of current topology") self.__topo.render_dotgraph() self.run_with_controller(controller) # log.info("Done") def run_with_controller(self, controller): log = self.__logger.get() log.info("Instantiating Mininet") self.__net = Mininet(topo=self.__topo, controller=controller, waitConnected=False) self.__topo.set_net(self.__net) log.info("Starting Mininet (will wait for controller)") self.__net.start() wait_result = self.__net.waitConnected(timeout=10) if wait_result is False: log.error("Failed to wait for a controller!") log.error("FAIL") return log.info("Mininet found a controller to connect to") # Create qos queues self.__topo.create_qos_queues_on_switch() # Ping tests self.ping_all() # Begin node traffic self.start_tattle_tail(True) self.start_file_traffic(True) self.start_video_traffic(True) # self.wait_for_hosts_to_finish() self.summarize_node_logs() def do_topology_test(self): log = self.__logger.get() log.info("Running topology test") log.info("Instantiating custom Topology class") self.__topo = Topology(self.__logger) log.info("Instantiating Mininet") self.__net = Mininet(topo=self.__topo, controller=mininet.node.RemoteController) self.__topo.set_net(self.__net) self.__topo.consume_instances() log.info("Rendering graph of current topology") self.__topo.render_dotgraph(False) log.info("Done!") def ping_all(self): self.__logger.get().info("Attempting to ping between all nodes") self.__net.pingAll(timeout=1) print() self.__logger.get().info("Done pinging between all nodes") @staticmethod def make_process_stdout_file_path(run_name, file_name, clear=True): output_dir = os.path.join(os.path.dirname(__file__), "log", run_name) try: os.makedirs(output_dir) except FileExistsError: pass file_path = os.path.join(output_dir, file_name + ".txt") if clear and os.path.isfile(file_path): os.unlink(file_path) return file_path def start_tattle_tail(self, use_log: bool = True): log = self.__logger.get() log.info("Starting tattle tail") log_file = self.make_process_stdout_file_path(self.__run_name, "tattle-tail-stdout") log.info(log_file) # Get tattle tail instance tattle = self.__topo.get_tattle_tail_instance() tattle_ip = tattle.IP() log.info("Tattle tail IP is: " + str(tattle_ip)) # Start the tattle tail if use_log: tattle.cmd("ifconfig | grep eth >> \"" + log_file + "\" 2>&1") tattle.sendCmd("./main.py --tattle-tail" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(tattle) + "\"" + " >> \"" + log_file + "\" 2>&1") else: tattle.cmd("ifconfig | grep eth 2>&1") tattle.sendCmd("./main.py --tattle-tail" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(tattle) + "\"" + " 2>&1") log.info("Done starting tattle tail") def start_video_traffic(self, use_log: bool = True): log = self.__logger.get() log.info("Starting video traffic") server_log_file = self.make_process_stdout_file_path( self.__run_name, "video-server-stdout") log.info("Video server stdout: " + server_log_file) client_log_file = self.make_process_stdout_file_path( self.__run_name, "video-clients-stdout") log.info("Video clients stdout: " + client_log_file) # Get video server instance server = self.__topo.get_video_server_instance() server_ip = server.IP() log.info("Video server IP is: " + str(server_ip)) # Start video server if use_log: server.cmd("ifconfig | grep eth >> \"" + server_log_file + "\" 2>&1") server.sendCmd("./main.py --video-server" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(server) + "\"" + " >> \"" + server_log_file + "\" 2>&1") else: server.cmd("ifconfig | grep eth 2>&1") server.sendCmd("./main.py --video-server" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(server) + "\"" + " 2>&1") # Grab client instances clients = list(self.__topo.get_video_client_instances().values()) # Start each client for client in clients: if use_log: client.cmd("ifconfig | grep eth >> \"" + client_log_file + "\" 2>&1") client.sendCmd("./main.py --video-client" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(client) + "\"" + " --host \"" + server_ip + "\"" + " >> \"" + client_log_file + "\" 2>&1") else: client.cmd("ifconfig | grep eth 2>&1") client.sendCmd("./main.py --video-client" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(client) + "\"" + " --host \"" + server_ip + "\"" + " 2>&1") log.info("Done starting video traffic") def start_file_traffic(self, use_log: bool = True): log = self.__logger.get() log.info("Starting file traffic") server_log_file = self.make_process_stdout_file_path( self.__run_name, "file-server-stdout") log.info("File server stdout: " + server_log_file) client_log_file = self.make_process_stdout_file_path( self.__run_name, "file-clients-stdout") log.info("File clients stdout: " + client_log_file) # Get file server instance server = self.__topo.get_file_server_instance() server_ip = server.IP() log.info("File server IP is: " + str(server_ip)) # Start file server if use_log: server.cmd("ifconfig | grep eth >> \"" + server_log_file + "\" 2>&1") server.sendCmd("./main.py --file-server" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(server) + "\"" + " --directory \"" + self.make_file_server_directory() + "\"" + " >> \"" + server_log_file + "\" 2>&1") else: server.cmd("ifconfig | grep eth 2>&1") server.sendCmd("./main.py --file-server" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(server) + "\"" + " --directory \"" + self.make_file_server_directory() + "\"" + " 2>&1") # Grab client instances clients = list(self.__topo.get_file_client_instances().values()) # Start each client for client in clients: if use_log: client.cmd("ifconfig | grep eth >> \"" + client_log_file + "\" 2>&1") client.sendCmd("./main.py --file-client" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(client) + "\"" + " --host \"" + server_ip + "\"" + " >> \"" + client_log_file + "\" 2>&1") else: client.cmd("ifconfig | grep eth 2>&1") client.sendCmd("./main.py --file-client" + " --run-name \"" + str(self.__run_name) + "\"" + " --name \"" + str(client) + "\"" + " --host \"" + server_ip + "\"" + " 2>&1") log.info("Done starting file traffic") def wait_for_hosts_to_finish(self): log = self.__logger.get() log.info("Start waiting for all hosts to finish") # Gather all hosts to wait for hosts_to_wait_for = list() for host_name in self.__topo.get_video_client_instances(): hosts_to_wait_for.append(self.__net.nameToNode[host_name]) for host_name in self.__topo.get_file_client_instances(): hosts_to_wait_for.append(self.__net.nameToNode[host_name]) # Wait for all the hosts for host in hosts_to_wait_for: log.info("Waiting for host " + str(host) + " to finish its command") host.waitOutput(verbose=True) log.info("Host " + str(host) + " has finished its command") log.info("Done waiting for all hosts to finish") def make_file_server_directory(self): d = os.path.join(os.path.dirname(__file__), self.__DEFAULT_FILE_SERVER_DIRECTORY) return d def summarize_node_logs(self): self.summarize_node_benchmark_logs() def summarize_node_benchmark_logs(self): log = self.__logger.get() log_s = self.__logger_summary.get() log.info("Attempting to summarize node benchmark logs") log_s.info("") log_s.info("*** " + self.__run_name + " ***") log_s.info("Attempting to summarize node benchmark logs") logs_dir = self.__logger.make_log_file_directory_path() log.info("Pulling from log directory: " + logs_dir) # Build a list of all nodes we're interested in nodes_file_clients = list( self.__topo.get_file_client_instances().values()) nodes_video_clients = list( self.__topo.get_video_client_instances().values()) nodes_all_clients = nodes_file_clients + nodes_video_clients log.info("Will examine logs from " + str(len(nodes_all_clients)) + " client nodes") pattern_bytes_received = re.compile( """^Bytes received: (?P<bytes>[0-9]+)$""", re.MULTILINE | re.IGNORECASE) pattern_mbps = re.compile( """^Megabits per second: (?P<mbps>[0-9.]+)$""", re.MULTILINE | re.IGNORECASE) # For each client we're interested in, pull the number of bytes transferred from its logs total_bytes = 0 mbps_all_samples = list() mbps_file_samples = list() mbps_video_samples = list() for node in nodes_all_clients: node_log_file_name = str(node) + ".txt" log_path = os.path.join(logs_dir, node_log_file_name) log.info("Examining log for node \"" + str(node) + "\": " + node_log_file_name) # Load the logfile with open(log_path, "rt") as f: s = f.read() # Bytes received match = pattern_bytes_received.search(s) if match is None: raise Exception( "Failed to parse node; Cannot find bytes received in: " + node_log_file_name) node_bytes = int(match.group("bytes")) total_bytes += node_bytes log.info("Node \"" + str(node) + "\" seems to have received " + str(node_bytes) + " bytes" + " (" + str(total_bytes) + " total)") # Megabits per second match = pattern_mbps.search(s) if match is None: raise Exception( "Failed to parse node; Cannot find megabits per second!" ) node_mbps = float(match.group("mbps")) log.info("Node \"" + str(node) + "\" seems to have received data at " + str(node_mbps) + " megabits per second") # Add to sample pools mbps_all_samples.append(node_mbps) if node in nodes_file_clients: mbps_file_samples.append(node_mbps) elif node in nodes_video_clients: mbps_video_samples.append(node_mbps) else: raise Exception( "Don't know where to add this node's bandwidth sample!" ) mbps_average_file = sum(mbps_file_samples) / len(mbps_file_samples) mbps_average_video = sum(mbps_video_samples) / len(mbps_video_samples) mbps_average_all = sum(mbps_all_samples) / len(mbps_all_samples) log.info("We seem to have the following aggregate bandwidths:") log_s.info("We seem to have the following aggregate bandwidths:") log.info("File clients: " + str(mbps_average_file) + " mbps") log_s.info("File clients: " + str(mbps_average_file) + " mbps") log.info("Video clients: " + str(mbps_average_video) + " mbps") log_s.info("Video clients: " + str(mbps_average_video) + " mbps") log.info("All clients: " + str(mbps_average_all) + " mbps") log_s.info("All clients: " + str(mbps_average_all) + " mbps")