Skip to content

Commit

Permalink
rf: refined interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
penglei0 committed Aug 1, 2024
1 parent 47d5f7d commit ec5ef79
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from mininet.util import ipStr, netParse
from mininet.link import TCLink
from containernet.topology import (ITopology, MatrixType)
from containernet.test_suites.test import ITestSuite
from interfaces.network import INetwork
from .config import NodeConfig


Expand All @@ -21,7 +21,7 @@ def subnets(base_ip, parent_ip):
yield from range(base, max_ip, step)


class Network (Containernet):
class ContainerizedNetwork (INetwork):
"""
Create a network from an adjacency matrix.
"""
Expand All @@ -31,6 +31,7 @@ def __init__(self,
net_topology: ITopology = None,
** params) -> None:
super().__init__(**params)
self.containernet = Containernet()
# NodeConfig: Docker node related
self.node_img = node_config.node_img
self.node_vols = node_config.node_vols
Expand Down Expand Up @@ -71,21 +72,17 @@ def __init__(self,
self._init_containernet()

def get_hosts(self):
return self.hosts
return self.containernet.hosts

def reset_test_suites(self):
self.test_suites = []

def add_test_suite(self, test_suite: ITestSuite):
self.test_suites.append(test_suite)
def start(self):
logging.info("Oasis starts the ContainerizedNetwork.")
self.containernet.build()
self.containernet.start()

def perform_test(self):
if self.test_suites is None:
logging.error("No test suite set")
for test in self.test_suites:
test.run(self)
def stop(self):
self.containernet.stop()

def reload(self, node_config: NodeConfig, top: ITopology):
def reload(self, top: ITopology):
"""
Reload the network with new configurations.
"""
Expand All @@ -102,9 +99,9 @@ def reload(self, node_config: NodeConfig, top: ITopology):
self.net_jitter_mat = top.get_matrix(MatrixType.JITTER_MATRIX)
diff = self.num_of_hosts - len(self.net_mat)
if diff < 0:
self._expand_network(-diff, node_config)
self._expand_network(-diff)
else:
self._shrink_network(diff, node_config)
self._shrink_network(diff)

def _init_containernet(self):
self._setup_docker_nodes()
Expand All @@ -123,7 +120,7 @@ def _setup_docker_nodes(self):
else:
port_bindings = {}
ports = []
self.addDocker(
self.containernet.addDocker(
f'{self.node_name_prefix}{i}',
ip=None,
volumes=self.node_vols,
Expand Down Expand Up @@ -153,20 +150,22 @@ def _setup_topology(self):
right_ip = ipStr(link_ip + 2) + f'/{link_prefix}'
logging.info(
"addLink: %s(%s) <--> %s(%s)",
self.hosts[i].name,
self.containernet.hosts[i].name,
left_ip,
self.hosts[j].name,
self.containernet.hosts[j].name,
right_ip
)
self.__addLink(i, j,
params1={'ip': left_ip},
params2={'ip': right_ip}
)
self.pair_to_link_ip[(
self.hosts[i], self.hosts[j])] = ipStr(link_ip + 2)
self.containernet.hosts[i],
self.containernet.hosts[j])] = ipStr(link_ip + 2)
self.pair_to_link_ip[(
self.hosts[j], self.hosts[i])] = ipStr(link_ip + 1)
for host in self.hosts:
self.containernet.hosts[j],
self.containernet.hosts[i])] = ipStr(link_ip + 1)
for host in self.containernet.hosts:
host.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
host.cmd('sysctl -p')
logging.info(
Expand Down Expand Up @@ -195,8 +194,8 @@ class 50001 is big. Consider r2q change.
params['delay'] = str(self.net_latency_mat[id1][id2]) + 'ms'
if self.net_jitter_mat is not None:
params['jitter'] = self.net_jitter_mat[id1][id2]
link = super().addLink(
self.hosts[id1], self.hosts[id2],
link = self.containernet.addLink(
self.containernet.hosts[id1], self.containernet.hosts[id2],
port1, port2, cls=TCLink, **params)
return link

Expand All @@ -219,7 +218,7 @@ def _setup_ip_routes(self):
Setup the routing by ip route.
'''
for route in self.net_routes:
route = [self.nameToNode[f'h{i}'] for i in route]
route = [self.containernet.nameToNode[f'h{i}'] for i in route]
self._add_route(route)

def _setup_olsr_routes(self):
Expand Down Expand Up @@ -279,22 +278,22 @@ def _check_node_vols(self):
self.node_vols = [
vol for vol in self.node_vols if '/usr/bin/perf' not in vol]

def _expand_network(self, diff, node_config):
def _expand_network(self, diff):
"""
Expand the network by adding more nodes.
"""
logging.info(
"Reload the network. number of "
"nodes increased by %s, node %s",
diff, node_config)
"nodes increased by %s",
diff)
self._reset_network(self.num_of_hosts, diff)
for i in range(diff):
self.addDocker(
self.containernet.addDocker(
f'{self.node_name_prefix}{self.num_of_hosts + i}',
ip=None,
volumes=node_config.node_vols,
volumes=self.node_vols,
cap_add=["NET_ADMIN", "SYS_ADMIN"],
dimage=node_config.node_img,
dimage=self.node_img,
ports=[self.num_of_hosts + i + 10000],
port_bindings={self.num_of_hosts + i +
10000: self.num_of_hosts + i + 10000},
Expand All @@ -304,19 +303,19 @@ def _expand_network(self, diff, node_config):
self._setup_topology()
self._setup_routes()
logging.info(
"Expand the network. number of nodes increased by %s, node %s",
diff, node_config)
"Expand the network. number of nodes increased by %s",
diff)
return True

def _shrink_network(self, diff, node_config):
def _shrink_network(self, diff):
logging.info(
"Reload the network. number of "
"nodes decreased by %s, node %s",
diff, node_config)
"nodes decreased by %s",
diff)
self._reset_network(self.num_of_hosts, -diff)
for i in range(self.num_of_hosts - diff, self.num_of_hosts):
logging.info("removeDocker: %s", f'{self.node_name_prefix}{i}')
self.removeDocker(f'{self.node_name_prefix}{i}')
self.containernet.removeDocker(f'{self.node_name_prefix}{i}')
self.num_of_hosts -= diff
self._setup_topology()
self._setup_routes()
Expand All @@ -327,11 +326,13 @@ def _reset_network(self, num, diff):
# remove all links
for i in range(num - 1):
logging.info("removeLink: %s-%s",
self.hosts[i].name, self.hosts[i+1].name)
self.removeLink(
node1=self.hosts[i].name, node2=self.hosts[i+1].name)
self.containernet.hosts[i].name,
self.containernet.hosts[i+1].name)
self.containernet.removeLink(
node1=self.containernet.hosts[i].name,
node2=self.containernet.hosts[i+1].name)
# remove all routes.
for host in self.hosts:
for host in self.containernet.hosts:
host.cmd('ip route flush table main')
host.deleteIntfs()
host.cleanup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@


def load_nested_config(nested_config_file: str,
nested_containernet: str) -> NestedConfig:
containernet: str) -> NestedConfig:
"""
Load the nested configuration from a yaml file.
"""
if nested_config_file == "" or nested_containernet == "":
if nested_config_file == "" or containernet == "":
return None
containernet_list = []
logging.info(
Expand All @@ -28,7 +28,7 @@ def load_nested_config(nested_config_file: str,
logging.info(
f"loaded containernet: %s", containernet_list)
for containernet in containernet_names:
if containernet == nested_containernet:
if containernet == containernet:
logging.info(
f"loaded containernet: %s", containernet_list[containernet])
return NestedConfig(**containernet_list[containernet])
Expand Down Expand Up @@ -57,9 +57,9 @@ def setUp(self) -> None:
def tearDown(self) -> None:
logging.info(
"NestedContainernet tearDown the Containernet.")
# stop all the running containers with the name "nested_containernet**"
# stop all the running containers with the name "containernet**"
os.system(
"docker stop $(docker ps -a -q -fname=nested_containernet) || true")
"docker stop $(docker ps -a -q -fname=containernet) || true")
os.system("docker container prune --force || true")
logging.info(
"########################## Oasis teardown"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions src/interfaces/host.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from abc import ABC, abstractmethod


class IHost(ABC):
def __init__(self):
pass

@abstractmethod
def cmd(self, input: str) -> str:
"""Execute a command on the host.
"""
37 changes: 37 additions & 0 deletions src/interfaces/network.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import logging
from abc import ABC, abstractmethod
from containernet.topology import (ITopology)
from test_suites.test import ITestSuite


class INetwork(ABC):
def __init__(self):
self.test_suites = []

@abstractmethod
def start(self):
pass

@abstractmethod
def stop(self):
pass

@abstractmethod
def get_hosts(self):
pass

@abstractmethod
def reload(self, top: ITopology):
pass

def add_test_suite(self, test_suite: ITestSuite):
self.test_suites.append(test_suite)

def perform_test(self):
if self.test_suites is None:
logging.error("No test suite set")
for test in self.test_suites:
test.run(self)

def reset_test_suites(self):
self.test_suites = []
15 changes: 7 additions & 8 deletions src/run_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
# from mininet.cli import CLI
from mininet.log import setLogLevel
from containernet.linear_topology import LinearTopology
from containernet.network import Network
from containernet.containerized_network import ContainerizedNetwork
from containernet.config import (
IConfig, NodeConfig, TopologyConfig, supported_config_keys)
from containernet.test_suites.test import (TestType, TestConfig)
from containernet.test_suites.test_iperf import IperfTest
from containernet.test_suites.test_ping import PingTest
from test_suites.test import (TestType, TestConfig)
from test_suites.test_iperf import IperfTest
from test_suites.test_ping import PingTest


def load_test(test_yaml_file: str):
Expand Down Expand Up @@ -92,10 +92,10 @@ def build_network(node_config: NodeConfig, top_config: TopologyConfig):
yaml_file_path (str): the path of the yaml configuration file
Returns:
Network: the container network object
ContainerizedNetwork: the container network object
"""
net_top = build_topology(top_config)
return Network(node_config, net_top)
return ContainerizedNetwork(node_config, net_top)


if __name__ == '__main__':
Expand All @@ -114,13 +114,12 @@ def build_network(node_config: NodeConfig, top_config: TopologyConfig):
cur_node_config, cur_top_config = load_config(test)
if linear_network is None:
linear_network = build_network(cur_node_config, cur_top_config)
linear_network.build()
linear_network.start()
else:
local_net_top = build_topology(cur_top_config)
if local_net_top is None:
continue
linear_network.reload(cur_node_config, local_net_top)
linear_network.reload(local_net_top)

# add test suites
iperf_test_conf = TestConfig(
Expand Down
12 changes: 9 additions & 3 deletions src/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
import logging

from mininet.log import setLogLevel
from containernet.nested_containernet import (
from containernet.containernet import (
NestedContainernet, load_nested_config)

""" ################# USAGE OF THE SCRIPT ##########################
start.py is used to initialize the nested containernet environment,
and inside the nested containernet, it will execute the test cases
through the run_test.py script.
"""


def parse_args():
"""
Expand All @@ -20,7 +26,7 @@ def parse_args():
default="")
parser.add_argument('--containernet',
help='nested containernet name in the YAML file',
dest='nested_containernet',
dest='containernet',
type=str,
default="nuc_sz")
parser.add_argument('-t',
Expand Down Expand Up @@ -58,7 +64,7 @@ def build_nested_env(config_file, containernet, workspace):
ns, args = local_parser.parse_known_args()
cur_config_yaml_file_path = ns.tests_config_file
nested_config_file = ns.nested_config_file
nested_containernet = ns.nested_containernet
nested_containernet = ns.containernet
cur_workspace = ns.workspace

if not os.path.exists(cur_config_yaml_file_path):
Expand Down
Empty file added src/test_suites/__init__.py
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ def pre_process(self):
pass

@abstractmethod
def _run_test(self, network: 'Network'): # type: ignore
def _run_test(self, network: 'INetwork'): # type: ignore
pass

def run(self, network: 'Network'): # type: ignore
def run(self, network: 'INetwork'): # type: ignore
self.is_success = self.pre_process()
if not self.is_success:
return
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logging

from containernet.network import Network
from containernet.data_analyzer.analyzer import AnalyzerConfig
from containernet.data_analyzer.analyzer_factory import AnalyzerFactory
from interfaces.network import INetwork
from data_analyzer.analyzer import AnalyzerConfig
from data_analyzer.analyzer_factory import AnalyzerFactory
from .test import (ITestSuite)


Expand All @@ -22,6 +22,6 @@ def pre_process(self):
self.config.log_file = "iperf3_log.txt"
return True

def _run_test(self, network: Network):
def _run_test(self, network: INetwork):
logging.info(
"############### Oasis IperfTest ###########")
Loading

0 comments on commit ec5ef79

Please sign in to comment.