Skip to content

Commit

Permalink
Merge pull request #2 from n-hop/1-define-interfaces-of-network-host-…
Browse files Browse the repository at this point in the history
…route

chore: IHost,IRouting,INetwork
  • Loading branch information
penglei0 authored Aug 4, 2024
2 parents 6ae1ee1 + 871aca4 commit 0a3edb1
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 95 deletions.
33 changes: 33 additions & 0 deletions src/containernet/containernet_host.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# adapter pattern
from interfaces.host import IHost

class ContainernetHostAdapter(IHost):
def __init__(self, containernet_host):
self.containernet_host = containernet_host

def cmd(self, command):
return self.containernet_host.cmd(command)

def name(self) -> str:
"""Get the name of the host.
"""
return self.containernet_host.name

def IP(self) -> str:
"""Get the IP address of the host.
"""
return self.containernet_host.IP()

def deleteIntfs(self):
"""Delete all interfaces.
"""
return self.containernet_host.deleteIntfs()

def cleanup(self):
"""Cleanup the host.
"""
return self.containernet_host.cleanup()

def get_host(self):
return self.containernet_host

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from mininet.util import ipStr, netParse
from mininet.link import TCLink
from containernet.topology import (ITopology, MatrixType)
from containernet.containernet_host import ContainernetHostAdapter
from interfaces.network import INetwork
from interfaces.routing import IRoutingStrategy
from .config import NodeConfig


Expand All @@ -29,9 +31,12 @@ class ContainerizedNetwork (INetwork):
def __init__(self,
node_config: NodeConfig = None,
net_topology: ITopology = None,
routing_strategy: IRoutingStrategy = None,
** params) -> None:
super().__init__(**params)
self.containernet = Containernet()
self.routing_strategy = routing_strategy
self.hosts = []
# NodeConfig: Docker node related
self.node_img = node_config.node_img
self.node_vols = node_config.node_vols
Expand Down Expand Up @@ -72,7 +77,10 @@ def __init__(self,
self._init_containernet()

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

def get_num_of_host(self):
return self.num_of_hosts

def start(self):
logging.info("Oasis starts the ContainerizedNetwork.")
Expand Down Expand Up @@ -103,10 +111,13 @@ def reload(self, top: ITopology):
else:
self._shrink_network(diff)

def get_link_table(self):
return self.pair_to_link_ip

def _init_containernet(self):
self._setup_docker_nodes()
self._setup_topology()
self._setup_routes()
self.routing_strategy.setup_routes(self)

def _setup_docker_nodes(self):
"""
Expand All @@ -130,6 +141,8 @@ def _setup_docker_nodes(self):
port_bindings=port_bindings,
publish_all_ports=True
)
self.hosts = [ContainernetHostAdapter(host) \
for host in self.containernet.hosts]
logging.info(
"setup_docker_nodes, num. of nodes is %s.", self.num_of_hosts)
return True
Expand All @@ -150,22 +163,22 @@ def _setup_topology(self):
right_ip = ipStr(link_ip + 2) + f'/{link_prefix}'
logging.info(
"addLink: %s(%s) <--> %s(%s)",
self.containernet.hosts[i].name,
self.hosts[i].name,
left_ip,
self.containernet.hosts[j].name,
self.hosts[j].name,
right_ip
)
self.__addLink(i, j,
params1={'ip': left_ip},
params2={'ip': right_ip}
)
self.pair_to_link_ip[(
self.containernet.hosts[i],
self.containernet.hosts[j])] = ipStr(link_ip + 2)
self.hosts[i],
self.hosts[j])] = ipStr(link_ip + 2)
self.pair_to_link_ip[(
self.containernet.hosts[j],
self.containernet.hosts[i])] = ipStr(link_ip + 1)
for host in self.containernet.hosts:
self.hosts[j],
self.hosts[i])] = ipStr(link_ip + 1)
for host in self.hosts:
host.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
host.cmd('sysctl -p')
logging.info(
Expand Down Expand Up @@ -195,82 +208,11 @@ class 50001 is big. Consider r2q change.
if self.net_jitter_mat is not None:
params['jitter'] = self.net_jitter_mat[id1][id2]
link = self.containernet.addLink(
self.containernet.hosts[id1], self.containernet.hosts[id2],
self.hosts[id1].get_host(),
self.hosts[id2].get_host(),
port1, port2, cls=TCLink, **params)
return link

def _setup_routes(self):
if self.node_route == 'ip' and self.topology_type != 'linear':
logging.error(
"The ip routing config %s is not supported for %s.",
self.node_route, self.topology_type)
# setup routes
if self.node_route == 'ip':
self._setup_ip_routes()
elif self.node_route == 'olsr':
self._setup_olsr_routes()
else:
logging.error(
"The routing config %s is not supported.", self.node_route)

def _setup_ip_routes(self):
'''
Setup the routing by ip route.
'''
for route in self.net_routes:
route = [self.containernet.nameToNode[f'h{i}'] for i in route]
self._add_route(route)

def _setup_olsr_routes(self):
'''
setup the OLSR routing
'''

@ staticmethod
def _add_ip_gateway(host, gateway_ip, dst_ip):
host.cmd(f'ip r a {dst_ip} via {gateway_ip}')

def _add_route(self, route):
for i in range(len(route) - 1):
for j in range(i + 1, len(route)):
host = route[i]
gateway = route[i + 1]
dst_prev = route[j - 1]
dst = route[j]
if j < len(route) - 1:
dst_next = route[j + 1]

# gateway ip is the ip of the second (right) interface
# of the link (route_i, route_{i+1})
gateway_ip = self.pair_to_link_ip[(host, gateway)]

# dst ip is the ip of the second (right) interface in the link
# (route_{j-1}, route_j)
dst_ip = self.pair_to_link_ip[(dst_prev, dst)]
if j < len(route) - 1:
dst_ip_right = self.pair_to_link_ip[(dst_next, dst)]
self._add_ip_gateway(host, gateway_ip, dst_ip)
if j < len(route) - 1:
self._add_ip_gateway(host, gateway_ip, dst_ip_right)

for i in range(1, len(route)):
for j in range(0, i):
host = route[i]
gateway = route[i - 1]
dst_prev = route[j + 1]
dst = route[j]

if j >= 1:
dst_next = route[j - 1]

gateway_ip = self.pair_to_link_ip[(host, gateway)]
dst_ip = self.pair_to_link_ip[(dst_prev, dst)]
if j >= 1:
dst_ip_left = self.pair_to_link_ip[(dst_next, dst)]
self._add_ip_gateway(host, gateway_ip, dst_ip)
if j >= 1:
self._add_ip_gateway(host, gateway_ip, dst_ip_left)

def _check_node_vols(self):
if not os.path.exists('/usr/bin/perf') or \
not os.path.isfile('/usr/bin/perf'):
Expand Down Expand Up @@ -301,7 +243,7 @@ def _expand_network(self, diff):
)
self.num_of_hosts += diff
self._setup_topology()
self._setup_routes()
self.routing_strategy.setup_routes(self)
logging.info(
"Expand the network. number of nodes increased by %s",
diff)
Expand All @@ -318,21 +260,21 @@ def _shrink_network(self, diff):
self.containernet.removeDocker(f'{self.node_name_prefix}{i}')
self.num_of_hosts -= diff
self._setup_topology()
self._setup_routes()
self.routing_strategy.setup_routes(self)
return True

def _reset_network(self, num, diff):
logging.info("Reset the network.")
# remove all links
for i in range(num - 1):
logging.info("removeLink: %s-%s",
self.containernet.hosts[i].name,
self.containernet.hosts[i+1].name)
self.hosts[i].name,
self.hosts[i+1].name)
self.containernet.removeLink(
node1=self.containernet.hosts[i].name,
node2=self.containernet.hosts[i+1].name)
node1=self.hosts[i].name,
node2=self.hosts[i+1].name)
# remove all routes.
for host in self.containernet.hosts:
for host in self.hosts:
host.cmd('ip route flush table main')
host.deleteIntfs()
host.cleanup()
Expand Down
3 changes: 3 additions & 0 deletions src/containernet/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# python3.6
pyyaml
dataclasses
16 changes: 15 additions & 1 deletion src/interfaces/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ def __init__(self):
pass

@abstractmethod
def cmd(self, input: str) -> str:
def cmd(self, command: str) -> str:
"""Execute a command on the host.
"""
def name(self) -> str:
"""Get the name of the host.
"""
def IP(self) -> str:
"""Get the IP address of the host.
"""
def deleteIntfs(self):
"""Delete all interfaces.
"""
def cleanup(self):
"""Cleanup the host.
"""
def get_host(self):
pass
8 changes: 8 additions & 0 deletions src/interfaces/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ def stop(self):
def get_hosts(self):
pass

@abstractmethod
def get_num_of_host(self):
pass

@abstractmethod
def get_link_table(self):
pass

@abstractmethod
def reload(self, top: ITopology):
pass
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from abc import ABC, abstractmethod

class IRoutingStrategy(ABC):
@abstractmethod
def setup_routes(self, network):
pass
9 changes: 9 additions & 0 deletions src/routing/olsr_routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from interfaces.routing import IRoutingStrategy

class OLSRRouting(IRoutingStrategy):
"""Summary:
Configure routing for the network with OLSR.
"""
def setup_routes(self, network: 'INetwork'): # type: ignore
pass

9 changes: 9 additions & 0 deletions src/routing/openr_routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from interfaces.routing import IRoutingStrategy

class OpenrRouting(IRoutingStrategy):
"""Summary:
Configure routing for the network with open-r.
"""
def setup_routes(self, network: 'INetwork'): # type: ignore
pass

65 changes: 65 additions & 0 deletions src/routing/static_routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from interfaces.routing import IRoutingStrategy

class StaticRouting(IRoutingStrategy):
"""Summary:
Configure static routing for the network.
"""
def __init__(self):
self.pair_to_link_ip = {}
self.net_routes = []

def setup_routes(self, network: 'INetwork'):
'''
Setup the routing by ip route.
'''
hosts = network.get_hosts()
self.pair_to_link_ip = network.get_link_table()
self.net_routes = [range(network.get_num_of_host())]
for route in self.net_routes:
route = [hosts[i] for i in route]
self._add_route(route)

@ staticmethod
def _add_ip_gateway(host, gateway_ip, dst_ip):
host.cmd(f'ip r a {dst_ip} via {gateway_ip}')

def _add_route(self, route):
for i in range(len(route) - 1):
for j in range(i + 1, len(route)):
host = route[i]
gateway = route[i + 1]
dst_prev = route[j - 1]
dst = route[j]
if j < len(route) - 1:
dst_next = route[j + 1]

# gateway ip is the ip of the second (right) interface
# of the link (route_i, route_{i+1})
gateway_ip = self.pair_to_link_ip[(host, gateway)]

# dst ip is the ip of the second (right) interface in the link
# (route_{j-1}, route_j)
dst_ip = self.pair_to_link_ip[(dst_prev, dst)]
if j < len(route) - 1:
dst_ip_right = self.pair_to_link_ip[(dst_next, dst)]
self._add_ip_gateway(host, gateway_ip, dst_ip)
if j < len(route) - 1:
self._add_ip_gateway(host, gateway_ip, dst_ip_right)

for i in range(1, len(route)):
for j in range(0, i):
host = route[i]
gateway = route[i - 1]
dst_prev = route[j + 1]
dst = route[j]

if j >= 1:
dst_next = route[j - 1]

gateway_ip = self.pair_to_link_ip[(host, gateway)]
dst_ip = self.pair_to_link_ip[(dst_prev, dst)]
if j >= 1:
dst_ip_left = self.pair_to_link_ip[(dst_next, dst)]
self._add_ip_gateway(host, gateway_ip, dst_ip)
if j >= 1:
self._add_ip_gateway(host, gateway_ip, dst_ip_left)
Loading

0 comments on commit 0a3edb1

Please sign in to comment.