diff --git a/MFLib.pdf b/MFLib.pdf index 4542d86..7255eaf 100644 Binary files a/MFLib.pdf and b/MFLib.pdf differ diff --git a/mflib/__init__.py b/mflib/__init__.py index 00eb1fb..413c957 100644 --- a/mflib/__init__.py +++ b/mflib/__init__.py @@ -3,7 +3,7 @@ """ # release level is a alpha, b beta, rc candidate, dev development, post post, or f final # (major, minor, micro, release level, release build) -__version_info__ = [1, 0, 5, "rc", 2] +__version_info__ = [1, 0, 6, "f", 0] __version__ = f"{__version_info__[0]}.{__version_info__[1]}.{__version_info__[2]}" diff --git a/mflib/owl.py b/mflib/owl.py index 5fa2573..70e71e1 100644 --- a/mflib/owl.py +++ b/mflib/owl.py @@ -72,9 +72,11 @@ def get_node_ip_addr(slice, node_name): for interface in interfaces: network = interface.toDict()['network'] + if 'l3_meas_net' not in network: - node_ip = str(interface.get_ip_addr()) - return node_ip + return str(interface.get_ip_addr()) + + return None def nodes_ip_addrs(slice): diff --git a/mflib/owl_data.py b/mflib/owl_data.py index f60ea07..da9ede9 100644 --- a/mflib/owl_data.py +++ b/mflib/owl_data.py @@ -23,18 +23,33 @@ import csv +import os from decimal import Decimal from pathlib import Path -from glob import glob -#from configparser import ConfigParser -from scapy.all import * +import scapy.all as scp +import pandas as pd -import numpy as np -import pandas as pd -import plotly.graph_objects as go +def list_experiment_ip_addrs(node): + """ + Get experimenter IPv4 addresses for each node. + + :param node: Node on which IPv4 address is queried. + :type node: fablib.Node + :return: a list of of IPv4 addresses assigned to node interfaces + :rtype: [ipaddress.IPv4Address,] + """ + + # The following line excludes management net interface + interfaces = node.get_interfaces() + exp_network_ips = [] + for interface in interfaces: + network = interface.toDict()['network'] + if 'l3_meas_net' not in network: + exp_network_ips.append(interface.get_ip_addr()) + + return exp_network_ips -from fabrictestbed_extensions.fablib.fablib import FablibManager as fablib_manager def list_pcap_files(root_dir): @@ -87,7 +102,7 @@ def convert_pcap_to_csv(pcap_files, outfile="out.csv", append_csv=False, verbose # Extract data for pcapfile in pcapfiles_with_data: print("file name:", pcapfile) - pkts = rdpcap(pcapfile) + pkts = scp.rdpcap(pcapfile) for pkt in pkts: # Fields are {dst_ip} ({dst_node.get_site()})") - print(f"Number of samples {len(f_data.index)}") - print(f"Median Latency (ns): {f_data['latency'].median()}") - print(f"Median Latency (micros): {(f_data['latency'].median())/1000}") - print(f"Median Latency (ms): {(f_data['latency'].median())/1000000}") - print(f"Median Latency (s): {(f_data['latency'].median())/1000000000}") - print(f"max latency (ns): {f_data['latency'].max()}") - print(f"min latency (ns): {f_data['latency'].min()}") - print("\n***Compare the result to ping") - stdout, stderr = src_node.execute(f"ping -c 2 {dst_ip}") - - - def filter_data(self, src_ip, dst_ip): - """ - Filter data by source and destination IPs - - :param src[dst]_ip: Source and destination IPv4 addresses - :type src[dst]_ip: str - """ - - return self.owl_df.loc[(self.owl_df['src_ip']==src_ip) & - (self.owl_df['dst_ip']==dst_ip)] + :param df: latency data + :type df: Panda Dataframe + :param src[dst]_node: source/destination nodes + :type src[dst]_node:fablib.Node + :param src[dst]_ip: needed only if there are multiple experimenter IP interfaces + :type src[dst]_ip: str + """ + + # If IP addresses not given, assume there is only 1 + if not src_ip: + src_ip = list_experiment_ip_addrs(src_node)[0] + if not dst_ip: + dst_ip = list_experiment_ip_addrs(dst_node)[0] + + f_data = filter_data(df, str(src_ip), str(dst_ip)) + + print(f"\n*****{src_ip} ({src_node.get_site()}) --> {dst_ip} ({dst_node.get_site()})") + print(f"Number of samples {len(f_data.index)}") + print(f"Median Latency (ns): {f_data['latency'].median()}") + print(f"Median Latency (micros): {(f_data['latency'].median())/1000}") + print(f"Median Latency (ms): {(f_data['latency'].median())/1000000}") + print(f"Median Latency (s): {(f_data['latency'].median())/1000000000}") + print(f"max latency (ns): {f_data['latency'].max()}") + print(f"min latency (ns): {f_data['latency'].min()}") + print("\n***Compare the result to ping") - def graph_latency_data(self, src_node, dst_node, src_ip=None, dst_ip=None): - """ - Graph latency data collected between source and destination nodes - - :param src[dst]_node: source/destination nodes - :type src[dst]_node:fablib.Node - :param src[dst]_ip: needed only if there are multiple experimenter IP interfaces - :type src[dst]_ip: str - """ - - if not src_ip: - src_ip = self.list_experiment_ip_addrs(src_node)[0] - if not dst_ip: - dst_ip = self.list_experiment_ip_addrs(dst_node)[0] - - filtered = self.filter_data(src_ip, dst_ip) - # import plotly.io as pio - # pio.renderers.default = 'iframe' - - - fig = go.Figure([go.Scatter(x=filtered['sent_t_datetime'], - y=filtered['latency'])]) - fig.update_layout( - title = f'{src_ip} ({src_node.get_site()}) -> {dst_ip} ({dst_node.get_site()})', - xaxis_title = "Sent time", - yaxis_title = "latency in nano-sec", - yaxis = dict( - tickformat='d')) - - fig.show() - - - - def find_node_locations(self, nodes): - """ - Print site information for nodes - - :param nodes: nodes whose data to be printed - :type nodes: fablib.Node - :return: node name, site name, location and experimenter IPv4 (only the first if multiple) - :rtype: pandas.DataFrame - """ - - fablib = fablib_manager() - r = fablib.get_resources() - - df = pd.DataFrame(columns = ['node_name', 'site_name', 'lon', 'lat', 'exp_ip']) - for node in nodes: - node_name = node.get_name() - - if node_name == "meas-node": - pass - else: - site_name = node.get_site() - lat, lon = r.get_location_lat_long(site_name) - node_ip = self.list_experiment_ip_addrs(node)[0] - - new_row = pd.DataFrame([{ - 'node_name': node_name, - 'site_name': site_name, - 'lon': lon, - 'lat': lat, - 'exp_ip': node_ip}]) - df = pd.concat([df, new_row]) - - return df - - - @staticmethod - def print_map(df): - """ - Print a map with nodes/sites data for fun. - - :param df: Pandas.DataFrame with columns 'node_name', 'site_name', 'lon', 'lat', 'exp_ip' - :type df: Pandas.DataFrame - """ - - - - fig = go.Figure(data=go.Scattergeo( - lon = df['lon'], - lat = df['lat'], - text = df['site_name'] + '; ' + df['exp_ip'], - marker=dict(size=8, color="blue") - )) - - fig.update_layout( - title = 'Slice nodes', - geo_scope='world', - ) - fig.show() + src_node.execute(f"ping -c 2 {dst_ip}") + + +def graph_latency_data(df, src_node, dst_node, src_ip=None, dst_ip=None): + """ + Graph latency data collected between source and destination nodes + + :param df: latency data + :type df: Panda Dataframe + :param src[dst]_node: source/destination nodes + :type src[dst]_node:fablib.Node + :param src[dst]_ip: needed only if there are multiple experimenter IP interfaces + :type src[dst]_ip: str + """ + + import plotly.graph_objects as go - @staticmethod - def list_experiment_ip_addrs(node): - """ - Get experimenter IPv4 addresses for each node. - - :param node: Node on which IPv4 address is queried. - :type node: fablib.Node - :return: a list of of IPv4 addresses assigned to node interfaces - :rtype: [str] - """ - - # The following line excludes management net interface - interfaces = node.get_interfaces() - exp_network_ips = [] - for interface in interfaces: - network = interface.toDict()['network'] - if 'l3_meas_net' not in network: - exp_network_ips.append(interface.get_ip_addr()) - - return exp_network_ips + if not src_ip: + src_ip = list_experiment_ip_addrs(src_node)[0] + if not dst_ip: + dst_ip = list_experiment_ip_addrs(dst_node)[0] + + filtered = filter_data(df, str(src_ip), str(dst_ip)) + + import plotly.io as pio + pio.renderers.default = 'iframe' + + + fig = go.Figure([go.Scatter(x=filtered['sent_t_datetime'], + y=filtered['latency'])]) + fig.update_layout( + title = f'{src_ip} ({src_node.get_site()}) -> {dst_ip} ({dst_node.get_site()})', + xaxis_title = "Sent time", + yaxis_title = "latency in nano-sec", + yaxis = dict( + tickformat='d')) + + fig.show() + \ No newline at end of file