Merge pull request #468 from coreemu/cleanup/session-add-link
daemon: refactored add_link,update_link,delete_link to have more spec…
This commit is contained in:
commit
f626564200
6 changed files with 232 additions and 355 deletions
|
@ -767,7 +767,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
|
||||||
ip6_mask=message.get_tlv(LinkTlvs.INTERFACE2_IP6_MASK.value),
|
ip6_mask=message.get_tlv(LinkTlvs.INTERFACE2_IP6_MASK.value),
|
||||||
)
|
)
|
||||||
|
|
||||||
link_type = None
|
link_type = LinkTypes.WIRED
|
||||||
link_type_value = message.get_tlv(LinkTlvs.TYPE.value)
|
link_type_value = message.get_tlv(LinkTlvs.TYPE.value)
|
||||||
if link_type_value is not None:
|
if link_type_value is not None:
|
||||||
link_type = LinkTypes(link_type_value)
|
link_type = LinkTypes(link_type_value)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, TypeVar
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar
|
||||||
|
|
||||||
from core import constants, utils
|
from core import constants, utils
|
||||||
from core.configservice.manager import ConfigServiceManager
|
from core.configservice.manager import ConfigServiceManager
|
||||||
|
@ -193,76 +193,28 @@ class Session:
|
||||||
raise CoreError(f"invalid node class: {_class}")
|
raise CoreError(f"invalid node class: {_class}")
|
||||||
return node_type
|
return node_type
|
||||||
|
|
||||||
def _link_nodes(
|
def _link_wireless(
|
||||||
self, node_one_id: int, node_two_id: int
|
self, node_one: CoreNodeBase, node_two: CoreNodeBase, connect: bool
|
||||||
) -> Tuple[
|
) -> None:
|
||||||
Optional[CoreNode],
|
|
||||||
Optional[CoreNode],
|
|
||||||
Optional[CoreNetworkBase],
|
|
||||||
Optional[CoreNetworkBase],
|
|
||||||
]:
|
|
||||||
"""
|
|
||||||
Convenience method for retrieving nodes within link data.
|
|
||||||
|
|
||||||
:param node_one_id: node one id
|
|
||||||
:param node_two_id: node two id
|
|
||||||
:return: nodes, network nodes if present, and tunnel if present
|
|
||||||
"""
|
|
||||||
logging.debug(
|
|
||||||
"link message between node1(%s) and node2(%s)", node_one_id, node_two_id
|
|
||||||
)
|
|
||||||
|
|
||||||
# values to fill
|
|
||||||
net_one = None
|
|
||||||
net_two = None
|
|
||||||
|
|
||||||
# retrieve node one
|
|
||||||
node_one = self.get_node(node_one_id, NodeBase)
|
|
||||||
node_two = self.get_node(node_two_id, NodeBase)
|
|
||||||
|
|
||||||
if isinstance(node_one, CoreNetworkBase):
|
|
||||||
if not net_one:
|
|
||||||
net_one = node_one
|
|
||||||
else:
|
|
||||||
net_two = node_one
|
|
||||||
node_one = None
|
|
||||||
|
|
||||||
if isinstance(node_two, CoreNetworkBase):
|
|
||||||
if not net_one:
|
|
||||||
net_one = node_two
|
|
||||||
else:
|
|
||||||
net_two = node_two
|
|
||||||
node_two = None
|
|
||||||
|
|
||||||
logging.debug(
|
|
||||||
"link node types n1(%s) n2(%s) net1(%s) net2(%s)",
|
|
||||||
node_one,
|
|
||||||
node_two,
|
|
||||||
net_one,
|
|
||||||
net_two,
|
|
||||||
)
|
|
||||||
return node_one, node_two, net_one, net_two
|
|
||||||
|
|
||||||
def _link_wireless(self, objects: Iterable[CoreNodeBase], connect: bool) -> None:
|
|
||||||
"""
|
"""
|
||||||
Objects to deal with when connecting/disconnecting wireless links.
|
Objects to deal with when connecting/disconnecting wireless links.
|
||||||
|
|
||||||
:param objects: possible objects to deal with
|
:param node_one: node one for wireless link
|
||||||
|
:param node_two: node two for wireless link
|
||||||
:param connect: link interfaces if True, unlink otherwise
|
:param connect: link interfaces if True, unlink otherwise
|
||||||
:return: nothing
|
:return: nothing
|
||||||
:raises core.CoreError: when objects to link is less than 2, or no common
|
:raises core.CoreError: when objects to link is less than 2, or no common
|
||||||
networks are found
|
networks are found
|
||||||
"""
|
"""
|
||||||
objects = [x for x in objects if x]
|
logging.info(
|
||||||
if len(objects) < 2:
|
"handling wireless linking node1(%s) node2(%s): %s",
|
||||||
raise CoreError(f"wireless link failure: {objects}")
|
node_one.name,
|
||||||
logging.debug(
|
node_two.name,
|
||||||
"handling wireless linking objects(%s) connect(%s)", objects, connect
|
connect,
|
||||||
)
|
)
|
||||||
common_networks = objects[0].commonnets(objects[1])
|
common_networks = node_one.commonnets(node_one)
|
||||||
if not common_networks:
|
if not common_networks:
|
||||||
raise CoreError("no common network found for wireless link/unlink")
|
raise CoreError("no common network found for wireless link/unlink")
|
||||||
|
|
||||||
for common_network, interface_one, interface_two in common_networks:
|
for common_network, interface_one, interface_two in common_networks:
|
||||||
if not isinstance(common_network, (WlanNode, EmaneNet)):
|
if not isinstance(common_network, (WlanNode, EmaneNet)):
|
||||||
logging.info(
|
logging.info(
|
||||||
|
@ -270,13 +222,6 @@ class Session:
|
||||||
common_network,
|
common_network,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logging.info(
|
|
||||||
"wireless linking connect(%s): %s - %s",
|
|
||||||
connect,
|
|
||||||
interface_one,
|
|
||||||
interface_two,
|
|
||||||
)
|
|
||||||
if connect:
|
if connect:
|
||||||
common_network.link(interface_one, interface_two)
|
common_network.link(interface_one, interface_two)
|
||||||
else:
|
else:
|
||||||
|
@ -305,105 +250,70 @@ class Session:
|
||||||
"""
|
"""
|
||||||
if not options:
|
if not options:
|
||||||
options = LinkOptions()
|
options = LinkOptions()
|
||||||
|
node1 = self.get_node(node_one_id, NodeBase)
|
||||||
|
node2 = self.get_node(node_two_id, NodeBase)
|
||||||
|
node1_interface = None
|
||||||
|
node2_interface = None
|
||||||
|
|
||||||
# get node objects identified by link data
|
|
||||||
node_one, node_two, net_one, net_two = self._link_nodes(
|
|
||||||
node_one_id, node_two_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if node_one:
|
|
||||||
node_one.lock.acquire()
|
|
||||||
if node_two:
|
|
||||||
node_two.lock.acquire()
|
|
||||||
|
|
||||||
node_one_interface = None
|
|
||||||
node_two_interface = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# wireless link
|
# wireless link
|
||||||
if options.type == LinkTypes.WIRELESS:
|
if options.type == LinkTypes.WIRELESS:
|
||||||
objects = [node_one, node_two, net_one, net_two]
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
self._link_wireless(objects, connect=True)
|
self._link_wireless(node1, node2, connect=True)
|
||||||
|
else:
|
||||||
|
raise CoreError(
|
||||||
|
f"cannot wireless link node1({type(node1)}) node2({type(node2)})"
|
||||||
|
)
|
||||||
# wired link
|
# wired link
|
||||||
else:
|
else:
|
||||||
# 2 nodes being linked, ptp network
|
# peer to peer link
|
||||||
if all([node_one, node_two]) and not net_one:
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
logging.info(
|
logging.info("linking ptp: %s - %s", node1.name, node2.name)
|
||||||
"adding link for peer to peer nodes: %s - %s",
|
|
||||||
node_one.name,
|
|
||||||
node_two.name,
|
|
||||||
)
|
|
||||||
start = self.state.should_start()
|
start = self.state.should_start()
|
||||||
net_one = self.create_node(PtpNet, start=start)
|
ptp = self.create_node(PtpNet, start=start)
|
||||||
|
node1_interface = node1.newnetif(ptp, interface_one)
|
||||||
# node to network
|
node2_interface = node2.newnetif(ptp, interface_two)
|
||||||
if node_one and net_one:
|
ptp.linkconfig(node1_interface, options)
|
||||||
logging.info(
|
|
||||||
"adding link from node to network: %s - %s",
|
|
||||||
node_one.name,
|
|
||||||
net_one.name,
|
|
||||||
)
|
|
||||||
ifindex = node_one.newnetif(net_one, interface_one)
|
|
||||||
node_one_interface = node_one.netif(ifindex)
|
|
||||||
wireless_net = isinstance(net_one, (EmaneNet, WlanNode))
|
|
||||||
if not wireless_net:
|
|
||||||
net_one.linkconfig(node_one_interface, options)
|
|
||||||
|
|
||||||
# network to node
|
|
||||||
if node_two and net_one:
|
|
||||||
logging.info(
|
|
||||||
"adding link from network to node: %s - %s",
|
|
||||||
node_two.name,
|
|
||||||
net_one.name,
|
|
||||||
)
|
|
||||||
ifindex = node_two.newnetif(net_one, interface_two)
|
|
||||||
node_two_interface = node_two.netif(ifindex)
|
|
||||||
wireless_net = isinstance(net_one, (EmaneNet, WlanNode))
|
|
||||||
if not options.unidirectional and not wireless_net:
|
|
||||||
net_one.linkconfig(node_two_interface, options)
|
|
||||||
|
|
||||||
# network to network
|
|
||||||
if net_one and net_two:
|
|
||||||
logging.info(
|
|
||||||
"adding link from network to network: %s - %s",
|
|
||||||
net_one.name,
|
|
||||||
net_two.name,
|
|
||||||
)
|
|
||||||
interface = net_one.linknet(net_two)
|
|
||||||
node_one_interface = interface
|
|
||||||
net_one.linkconfig(interface, options)
|
|
||||||
if not options.unidirectional:
|
if not options.unidirectional:
|
||||||
interface.swapparams("_params_up")
|
ptp.linkconfig(node2_interface, options)
|
||||||
net_two.linkconfig(interface, options)
|
# link node to net
|
||||||
interface.swapparams("_params_up")
|
elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
|
||||||
|
node1_interface = node1.newnetif(node2, interface_one)
|
||||||
|
if not isinstance(node2, (EmaneNet, WlanNode)):
|
||||||
|
node2.linkconfig(node1_interface, options)
|
||||||
|
# link net to node
|
||||||
|
elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
|
||||||
|
node2_interface = node2.newnetif(node1, interface_two)
|
||||||
|
wireless_net = isinstance(node1, (EmaneNet, WlanNode))
|
||||||
|
if not options.unidirectional and not wireless_net:
|
||||||
|
node1.linkconfig(node2_interface, options)
|
||||||
|
# network to network
|
||||||
|
elif isinstance(node1, CoreNetworkBase) and isinstance(
|
||||||
|
node2, CoreNetworkBase
|
||||||
|
):
|
||||||
|
logging.info(
|
||||||
|
"linking network to network: %s - %s", node1.name, node2.name
|
||||||
|
)
|
||||||
|
node1_interface = node1.linknet(node2)
|
||||||
|
node1.linkconfig(node1_interface, options)
|
||||||
|
if not options.unidirectional:
|
||||||
|
node1_interface.swapparams("_params_up")
|
||||||
|
node2.linkconfig(node1_interface, options)
|
||||||
|
node1_interface.swapparams("_params_up")
|
||||||
|
else:
|
||||||
|
raise CoreError(
|
||||||
|
f"cannot link node1({type(node1)}) node2({type(node2)})"
|
||||||
|
)
|
||||||
|
|
||||||
# a tunnel node was found for the nodes
|
# configure tunnel nodes
|
||||||
addresses = []
|
|
||||||
if not node_one and all([net_one, interface_one]):
|
|
||||||
addresses.extend(interface_one.get_addresses())
|
|
||||||
if not node_two and all([net_two, interface_two]):
|
|
||||||
addresses.extend(interface_two.get_addresses())
|
|
||||||
|
|
||||||
# tunnel node logic
|
|
||||||
key = options.key
|
key = options.key
|
||||||
if key and isinstance(net_one, TunnelNode):
|
if isinstance(node1, TunnelNode):
|
||||||
logging.info("setting tunnel key for: %s", net_one.name)
|
logging.info("setting tunnel key for: %s", node1.name)
|
||||||
net_one.setkey(key)
|
node1.setkey(key, interface_one)
|
||||||
if addresses:
|
if isinstance(node2, TunnelNode):
|
||||||
net_one.addrconfig(addresses)
|
logging.info("setting tunnel key for: %s", node2.name)
|
||||||
if key and isinstance(net_two, TunnelNode):
|
node2.setkey(key, interface_two)
|
||||||
logging.info("setting tunnel key for: %s", net_two.name)
|
|
||||||
net_two.setkey(key)
|
|
||||||
if addresses:
|
|
||||||
net_two.addrconfig(addresses)
|
|
||||||
finally:
|
|
||||||
if node_one:
|
|
||||||
node_one.lock.release()
|
|
||||||
if node_two:
|
|
||||||
node_two.lock.release()
|
|
||||||
|
|
||||||
self.sdt.add_link(node_one_id, node_two_id)
|
self.sdt.add_link(node_one_id, node_two_id)
|
||||||
return node_one_interface, node_two_interface
|
return node1_interface, node2_interface
|
||||||
|
|
||||||
def delete_link(
|
def delete_link(
|
||||||
self,
|
self,
|
||||||
|
@ -424,93 +334,52 @@ class Session:
|
||||||
:return: nothing
|
:return: nothing
|
||||||
:raises core.CoreError: when no common network is found for link being deleted
|
:raises core.CoreError: when no common network is found for link being deleted
|
||||||
"""
|
"""
|
||||||
# get node objects identified by link data
|
node1 = self.get_node(node_one_id, NodeBase)
|
||||||
node_one, node_two, net_one, net_two = self._link_nodes(
|
node2 = self.get_node(node_two_id, NodeBase)
|
||||||
node_one_id, node_two_id
|
logging.info(
|
||||||
|
"deleting link(%s) node(%s):interface(%s) node(%s):interface(%s)",
|
||||||
|
link_type.name,
|
||||||
|
node1.name,
|
||||||
|
interface_one_id,
|
||||||
|
node2.name,
|
||||||
|
interface_two_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if node_one:
|
|
||||||
node_one.lock.acquire()
|
|
||||||
if node_two:
|
|
||||||
node_two.lock.acquire()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# wireless link
|
# wireless link
|
||||||
if link_type == LinkTypes.WIRELESS:
|
if link_type == LinkTypes.WIRELESS:
|
||||||
objects = [node_one, node_two, net_one, net_two]
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
self._link_wireless(objects, connect=False)
|
self._link_wireless(node1, node2, connect=False)
|
||||||
|
else:
|
||||||
|
raise CoreError(
|
||||||
|
"cannot delete wireless link "
|
||||||
|
f"node1({type(node1)}) node2({type(node2)})"
|
||||||
|
)
|
||||||
# wired link
|
# wired link
|
||||||
else:
|
else:
|
||||||
if all([node_one, node_two]):
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
# TODO: fix this for the case where ifindex[1,2] are not specified
|
interface1 = node1.netif(interface_one_id)
|
||||||
# a wired unlink event, delete the connecting bridge
|
interface2 = node2.netif(interface_two_id)
|
||||||
interface_one = node_one.netif(interface_one_id)
|
if not interface1:
|
||||||
interface_two = node_two.netif(interface_two_id)
|
raise CoreError(
|
||||||
|
f"node({node1.name}) missing interface({interface_one_id})"
|
||||||
# get interfaces from common network, if no network node
|
|
||||||
# otherwise get interfaces between a node and network
|
|
||||||
if not interface_one and not interface_two:
|
|
||||||
common_networks = node_one.commonnets(node_two)
|
|
||||||
for (
|
|
||||||
network,
|
|
||||||
common_interface_one,
|
|
||||||
common_interface_two,
|
|
||||||
) in common_networks:
|
|
||||||
if (net_one and network == net_one) or not net_one:
|
|
||||||
interface_one = common_interface_one
|
|
||||||
interface_two = common_interface_two
|
|
||||||
break
|
|
||||||
|
|
||||||
if all([interface_one, interface_two]) and any(
|
|
||||||
[interface_one.net, interface_two.net]
|
|
||||||
):
|
|
||||||
if interface_one.net != interface_two.net and all(
|
|
||||||
[interface_one.up, interface_two.up]
|
|
||||||
):
|
|
||||||
raise CoreError("no common network found")
|
|
||||||
|
|
||||||
logging.info(
|
|
||||||
"deleting link node(%s):interface(%s) node(%s):interface(%s)",
|
|
||||||
node_one.name,
|
|
||||||
interface_one.name,
|
|
||||||
node_two.name,
|
|
||||||
interface_two.name,
|
|
||||||
)
|
)
|
||||||
net_one = interface_one.net
|
if not interface2:
|
||||||
interface_one.detachnet()
|
raise CoreError(
|
||||||
interface_two.detachnet()
|
f"node({node2.name}) missing interface({interface_two_id})"
|
||||||
if net_one.numnetif() == 0:
|
|
||||||
self.delete_node(net_one.id)
|
|
||||||
node_one.delnetif(interface_one.netindex)
|
|
||||||
node_two.delnetif(interface_two.netindex)
|
|
||||||
elif node_one and net_one:
|
|
||||||
interface = node_one.netif(interface_one_id)
|
|
||||||
if interface:
|
|
||||||
logging.info(
|
|
||||||
"deleting link node(%s):interface(%s) node(%s)",
|
|
||||||
node_one.name,
|
|
||||||
interface.name,
|
|
||||||
net_one.name,
|
|
||||||
)
|
)
|
||||||
interface.detachnet()
|
if interface1.net != interface2.net:
|
||||||
node_one.delnetif(interface.netindex)
|
raise CoreError(
|
||||||
elif node_two and net_one:
|
f"node1({node1.name}) node2({node2.name}) "
|
||||||
interface = node_two.netif(interface_two_id)
|
"not connected to same net"
|
||||||
if interface:
|
|
||||||
logging.info(
|
|
||||||
"deleting link node(%s):interface(%s) node(%s)",
|
|
||||||
node_two.name,
|
|
||||||
interface.name,
|
|
||||||
net_one.name,
|
|
||||||
)
|
)
|
||||||
interface.detachnet()
|
ptp = interface1.net
|
||||||
node_two.delnetif(interface.netindex)
|
node1.delnetif(interface_one_id)
|
||||||
finally:
|
node2.delnetif(interface_two_id)
|
||||||
if node_one:
|
self.delete_node(ptp.id)
|
||||||
node_one.lock.release()
|
elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
|
||||||
if node_two:
|
node1.delnetif(interface_one_id)
|
||||||
node_two.lock.release()
|
elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
|
||||||
|
node2.delnetif(interface_two_id)
|
||||||
self.sdt.delete_link(node_one_id, node_two_id)
|
self.sdt.delete_link(node_one_id, node_two_id)
|
||||||
|
|
||||||
def update_link(
|
def update_link(
|
||||||
|
@ -530,84 +399,79 @@ class Session:
|
||||||
:param interface_two_id: interface id for node two
|
:param interface_two_id: interface id for node two
|
||||||
:param options: data to update link with
|
:param options: data to update link with
|
||||||
:return: nothing
|
:return: nothing
|
||||||
:raises core.CoreError: when updating a wireless type link, when there is a unknown
|
:raises core.CoreError: when updating a wireless type link, when there is a
|
||||||
link between networks
|
unknown link between networks
|
||||||
"""
|
"""
|
||||||
if not options:
|
if not options:
|
||||||
options = LinkOptions()
|
options = LinkOptions()
|
||||||
|
node1 = self.get_node(node_one_id, NodeBase)
|
||||||
# get node objects identified by link data
|
node2 = self.get_node(node_two_id, NodeBase)
|
||||||
node_one, node_two, net_one, net_two = self._link_nodes(
|
logging.info(
|
||||||
node_one_id, node_two_id
|
"update link(%s) node(%s):interface(%s) node(%s):interface(%s)",
|
||||||
|
options.type.name,
|
||||||
|
node1.name,
|
||||||
|
interface_one_id,
|
||||||
|
node2.name,
|
||||||
|
interface_two_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if node_one:
|
|
||||||
node_one.lock.acquire()
|
|
||||||
if node_two:
|
|
||||||
node_two.lock.acquire()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# wireless link
|
# wireless link
|
||||||
if options.type == LinkTypes.WIRELESS:
|
if options.type == LinkTypes.WIRELESS:
|
||||||
raise CoreError("cannot update wireless link")
|
raise CoreError("cannot update wireless link")
|
||||||
else:
|
else:
|
||||||
if not node_one and not node_two:
|
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
|
||||||
if net_one and net_two:
|
interface1 = node1.netif(interface_one_id)
|
||||||
# modify link between nets
|
interface2 = node2.netif(interface_two_id)
|
||||||
interface = net_one.getlinknetif(net_two)
|
if not interface1:
|
||||||
|
raise CoreError(
|
||||||
|
f"node({node1.name}) missing interface({interface_one_id})"
|
||||||
|
)
|
||||||
|
if not interface2:
|
||||||
|
raise CoreError(
|
||||||
|
f"node({node2.name}) missing interface({interface_two_id})"
|
||||||
|
)
|
||||||
|
if interface1.net != interface2.net:
|
||||||
|
raise CoreError(
|
||||||
|
f"node1({node1.name}) node2({node2.name}) "
|
||||||
|
"not connected to same net"
|
||||||
|
)
|
||||||
|
ptp = interface1.net
|
||||||
|
ptp.linkconfig(interface1, options, interface2)
|
||||||
|
if not options.unidirectional:
|
||||||
|
ptp.linkconfig(interface2, options, interface1)
|
||||||
|
elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
|
||||||
|
interface = node1.netif(interface_one_id)
|
||||||
|
node2.linkconfig(interface, options)
|
||||||
|
elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
|
||||||
|
interface = node2.netif(interface_two_id)
|
||||||
|
node1.linkconfig(interface, options)
|
||||||
|
elif isinstance(node1, CoreNetworkBase) and isinstance(
|
||||||
|
node2, CoreNetworkBase
|
||||||
|
):
|
||||||
|
interface = node1.getlinknetif(node2)
|
||||||
upstream = False
|
upstream = False
|
||||||
|
|
||||||
if not interface:
|
if not interface:
|
||||||
upstream = True
|
upstream = True
|
||||||
interface = net_two.getlinknetif(net_one)
|
interface = node2.getlinknetif(node1)
|
||||||
|
|
||||||
if not interface:
|
if not interface:
|
||||||
raise CoreError("modify unknown link between nets")
|
raise CoreError("modify unknown link between nets")
|
||||||
|
|
||||||
if upstream:
|
if upstream:
|
||||||
interface.swapparams("_params_up")
|
interface.swapparams("_params_up")
|
||||||
net_one.linkconfig(interface, options)
|
node1.linkconfig(interface, options)
|
||||||
interface.swapparams("_params_up")
|
interface.swapparams("_params_up")
|
||||||
else:
|
else:
|
||||||
net_one.linkconfig(interface, options)
|
node1.linkconfig(interface, options)
|
||||||
|
|
||||||
if not options.unidirectional:
|
if not options.unidirectional:
|
||||||
if upstream:
|
if upstream:
|
||||||
net_two.linkconfig(interface, options)
|
node2.linkconfig(interface, options)
|
||||||
else:
|
else:
|
||||||
interface.swapparams("_params_up")
|
interface.swapparams("_params_up")
|
||||||
net_two.linkconfig(interface, options)
|
node2.linkconfig(interface, options)
|
||||||
interface.swapparams("_params_up")
|
interface.swapparams("_params_up")
|
||||||
else:
|
else:
|
||||||
raise CoreError("modify link for unknown nodes")
|
raise CoreError(
|
||||||
elif not node_one:
|
f"cannot update link node1({type(node1)}) node2({type(node2)})"
|
||||||
# node1 = layer 2node, node2 = layer3 node
|
)
|
||||||
interface = node_two.netif(interface_two_id)
|
|
||||||
net_one.linkconfig(interface, options)
|
|
||||||
elif not node_two:
|
|
||||||
# node2 = layer 2node, node1 = layer3 node
|
|
||||||
interface = node_one.netif(interface_one_id)
|
|
||||||
net_one.linkconfig(interface, options)
|
|
||||||
else:
|
|
||||||
common_networks = node_one.commonnets(node_two)
|
|
||||||
if not common_networks:
|
|
||||||
raise CoreError("no common network found")
|
|
||||||
|
|
||||||
for net_one, interface_one, interface_two in common_networks:
|
|
||||||
if (
|
|
||||||
interface_one_id is not None
|
|
||||||
and interface_one_id != node_one.getifindex(interface_one)
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
net_one.linkconfig(interface_one, options, interface_two)
|
|
||||||
if not options.unidirectional:
|
|
||||||
net_one.linkconfig(interface_two, options, interface_one)
|
|
||||||
finally:
|
|
||||||
if node_one:
|
|
||||||
node_one.lock.release()
|
|
||||||
if node_two:
|
|
||||||
node_two.lock.release()
|
|
||||||
|
|
||||||
def _next_node_id(self) -> int:
|
def _next_node_id(self) -> int:
|
||||||
"""
|
"""
|
||||||
|
@ -1345,17 +1209,15 @@ class Session:
|
||||||
:return: True if node deleted, False otherwise
|
:return: True if node deleted, False otherwise
|
||||||
"""
|
"""
|
||||||
# delete node and check for session shutdown if a node was removed
|
# delete node and check for session shutdown if a node was removed
|
||||||
logging.info("deleting node(%s)", _id)
|
|
||||||
node = None
|
node = None
|
||||||
with self._nodes_lock:
|
with self._nodes_lock:
|
||||||
if _id in self.nodes:
|
if _id in self.nodes:
|
||||||
node = self.nodes.pop(_id)
|
node = self.nodes.pop(_id)
|
||||||
|
logging.info("deleted node(%s)", node.name)
|
||||||
if node:
|
if node:
|
||||||
node.shutdown()
|
node.shutdown()
|
||||||
self.sdt.delete_node(_id)
|
self.sdt.delete_node(_id)
|
||||||
self.check_shutdown()
|
self.check_shutdown()
|
||||||
|
|
||||||
return node is not None
|
return node is not None
|
||||||
|
|
||||||
def delete_nodes(self) -> None:
|
def delete_nodes(self) -> None:
|
||||||
|
@ -1767,15 +1629,15 @@ class Session:
|
||||||
try:
|
try:
|
||||||
ip4 = control_net.prefix[node.id]
|
ip4 = control_net.prefix[node.id]
|
||||||
ip4_mask = control_net.prefix.prefixlen
|
ip4_mask = control_net.prefix.prefixlen
|
||||||
interface = InterfaceData(
|
interface_data = InterfaceData(
|
||||||
id=control_net.CTRLIF_IDX_BASE + net_index,
|
id=control_net.CTRLIF_IDX_BASE + net_index,
|
||||||
name=f"ctrl{net_index}",
|
name=f"ctrl{net_index}",
|
||||||
mac=utils.random_mac(),
|
mac=utils.random_mac(),
|
||||||
ip4=ip4,
|
ip4=ip4,
|
||||||
ip4_mask=ip4_mask,
|
ip4_mask=ip4_mask,
|
||||||
)
|
)
|
||||||
ifindex = node.newnetif(control_net, interface)
|
interface = node.newnetif(control_net, interface_data)
|
||||||
node.netif(ifindex).control = True
|
interface.control = True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = f"Control interface not added to node {node.id}. "
|
msg = f"Control interface not added to node {node.id}. "
|
||||||
msg += f"Invalid control network prefix ({control_net.prefix}). "
|
msg += f"Invalid control network prefix ({control_net.prefix}). "
|
||||||
|
|
|
@ -355,10 +355,11 @@ class CoreNodeBase(NodeBase):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if ifindex not in self._netif:
|
if ifindex not in self._netif:
|
||||||
raise ValueError(f"ifindex {ifindex} does not exist")
|
raise CoreError(f"node({self.name}) ifindex({ifindex}) does not exist")
|
||||||
netif = self._netif.pop(ifindex)
|
netif = self._netif.pop(ifindex)
|
||||||
|
logging.info("node(%s) removing interface(%s)", self.name, netif.name)
|
||||||
|
netif.detachnet()
|
||||||
netif.shutdown()
|
netif.shutdown()
|
||||||
del netif
|
|
||||||
|
|
||||||
def netif(self, ifindex: int) -> Optional[CoreInterface]:
|
def netif(self, ifindex: int) -> Optional[CoreInterface]:
|
||||||
"""
|
"""
|
||||||
|
@ -473,6 +474,18 @@ class CoreNodeBase(NodeBase):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def newnetif(
|
||||||
|
self, net: "CoreNetworkBase", interface: InterfaceData
|
||||||
|
) -> CoreInterface:
|
||||||
|
"""
|
||||||
|
Create a new network interface.
|
||||||
|
|
||||||
|
:param net: network to associate with
|
||||||
|
:param interface: interface data for new interface
|
||||||
|
:return: interface index
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class CoreNode(CoreNodeBase):
|
class CoreNode(CoreNodeBase):
|
||||||
"""
|
"""
|
||||||
|
@ -846,7 +859,9 @@ class CoreNode(CoreNodeBase):
|
||||||
interface_name = self.ifname(ifindex)
|
interface_name = self.ifname(ifindex)
|
||||||
self.node_net_client.device_up(interface_name)
|
self.node_net_client.device_up(interface_name)
|
||||||
|
|
||||||
def newnetif(self, net: "CoreNetworkBase", interface: InterfaceData) -> int:
|
def newnetif(
|
||||||
|
self, net: "CoreNetworkBase", interface: InterfaceData
|
||||||
|
) -> CoreInterface:
|
||||||
"""
|
"""
|
||||||
Create a new network interface.
|
Create a new network interface.
|
||||||
|
|
||||||
|
@ -868,7 +883,6 @@ class CoreNode(CoreNodeBase):
|
||||||
netif.sethwaddr(interface.mac)
|
netif.sethwaddr(interface.mac)
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
netif.addaddr(address)
|
netif.addaddr(address)
|
||||||
return ifindex
|
|
||||||
else:
|
else:
|
||||||
ifindex = self.newveth(interface.id, interface.name)
|
ifindex = self.newveth(interface.id, interface.name)
|
||||||
self.attachnet(ifindex, net)
|
self.attachnet(ifindex, net)
|
||||||
|
@ -877,7 +891,8 @@ class CoreNode(CoreNodeBase):
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
self.addaddr(ifindex, address)
|
self.addaddr(ifindex, address)
|
||||||
self.ifup(ifindex)
|
self.ifup(ifindex)
|
||||||
return ifindex
|
netif = self.netif(ifindex)
|
||||||
|
return netif
|
||||||
|
|
||||||
def addfile(self, srcname: str, filename: str) -> None:
|
def addfile(self, srcname: str, filename: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -12,7 +12,7 @@ import netaddr
|
||||||
from core import utils
|
from core import utils
|
||||||
from core.constants import EBTABLES_BIN, TC_BIN
|
from core.constants import EBTABLES_BIN, TC_BIN
|
||||||
from core.emulator.data import LinkData, NodeData
|
from core.emulator.data import LinkData, NodeData
|
||||||
from core.emulator.emudata import LinkOptions
|
from core.emulator.emudata import InterfaceData, LinkOptions
|
||||||
from core.emulator.enumerations import (
|
from core.emulator.enumerations import (
|
||||||
LinkTypes,
|
LinkTypes,
|
||||||
MessageFlags,
|
MessageFlags,
|
||||||
|
@ -697,15 +697,19 @@ class GreTapBridge(CoreNetwork):
|
||||||
)
|
)
|
||||||
self.attach(self.gretap)
|
self.attach(self.gretap)
|
||||||
|
|
||||||
def setkey(self, key: int) -> None:
|
def setkey(self, key: int, interface_data: InterfaceData) -> None:
|
||||||
"""
|
"""
|
||||||
Set the GRE key used for the GreTap device. This needs to be set
|
Set the GRE key used for the GreTap device. This needs to be set
|
||||||
prior to instantiating the GreTap device (before addrconfig).
|
prior to instantiating the GreTap device (before addrconfig).
|
||||||
|
|
||||||
:param key: gre key
|
:param key: gre key
|
||||||
|
:param interface_data: interface data for setting up tunnel key
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
self.grekey = key
|
self.grekey = key
|
||||||
|
addresses = interface_data.get_addresses()
|
||||||
|
if addresses:
|
||||||
|
self.addrconfig(addresses)
|
||||||
|
|
||||||
|
|
||||||
class CtrlNet(CoreNetwork):
|
class CtrlNet(CoreNetwork):
|
||||||
|
|
|
@ -157,7 +157,7 @@ class PhysicalNode(CoreNodeBase):
|
||||||
self.ifindex += 1
|
self.ifindex += 1
|
||||||
return ifindex
|
return ifindex
|
||||||
|
|
||||||
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> int:
|
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> CoreInterface:
|
||||||
logging.info("creating interface")
|
logging.info("creating interface")
|
||||||
addresses = interface.get_addresses()
|
addresses = interface.get_addresses()
|
||||||
ifindex = interface.id
|
ifindex = interface.id
|
||||||
|
@ -171,12 +171,12 @@ class PhysicalNode(CoreNodeBase):
|
||||||
# tunnel to net not built yet, so build it now and adopt it
|
# tunnel to net not built yet, so build it now and adopt it
|
||||||
_, remote_tap = self.session.distributed.create_gre_tunnel(net, self.server)
|
_, remote_tap = self.session.distributed.create_gre_tunnel(net, self.server)
|
||||||
self.adoptnetif(remote_tap, ifindex, interface.mac, addresses)
|
self.adoptnetif(remote_tap, ifindex, interface.mac, addresses)
|
||||||
return ifindex
|
return remote_tap
|
||||||
else:
|
else:
|
||||||
# this is reached when configuring services (self.up=False)
|
# this is reached when configuring services (self.up=False)
|
||||||
netif = GreTap(node=self, name=name, session=self.session, start=False)
|
netif = GreTap(node=self, name=name, session=self.session, start=False)
|
||||||
self.adoptnetif(netif, ifindex, interface.mac, addresses)
|
self.adoptnetif(netif, ifindex, interface.mac, addresses)
|
||||||
return ifindex
|
return netif
|
||||||
|
|
||||||
def privatedir(self, path: str) -> None:
|
def privatedir(self, path: str) -> None:
|
||||||
if path[0] != "/":
|
if path[0] != "/":
|
||||||
|
@ -297,7 +297,7 @@ class Rj45Node(CoreNodeBase):
|
||||||
self.up = False
|
self.up = False
|
||||||
self.restorestate()
|
self.restorestate()
|
||||||
|
|
||||||
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> int:
|
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> CoreInterface:
|
||||||
"""
|
"""
|
||||||
This is called when linking with another node. Since this node
|
This is called when linking with another node. Since this node
|
||||||
represents an interface, we do not create another object here,
|
represents an interface, we do not create another object here,
|
||||||
|
@ -320,7 +320,7 @@ class Rj45Node(CoreNodeBase):
|
||||||
self.interface.attachnet(net)
|
self.interface.attachnet(net)
|
||||||
for addr in interface.get_addresses():
|
for addr in interface.get_addresses():
|
||||||
self.addaddr(addr)
|
self.addaddr(addr)
|
||||||
return ifindex
|
return self.interface
|
||||||
|
|
||||||
def delnetif(self, ifindex: int) -> None:
|
def delnetif(self, ifindex: int) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -54,12 +54,11 @@ class TestNodes:
|
||||||
node = session.add_node(CoreNode)
|
node = session.add_node(CoreNode)
|
||||||
switch = session.add_node(SwitchNode)
|
switch = session.add_node(SwitchNode)
|
||||||
interface_data = InterfaceData()
|
interface_data = InterfaceData()
|
||||||
index = node.newnetif(switch, interface_data)
|
interface = node.newnetif(switch, interface_data)
|
||||||
interface = node.netif(index)
|
|
||||||
mac = "aa:aa:aa:ff:ff:ff"
|
mac = "aa:aa:aa:ff:ff:ff"
|
||||||
|
|
||||||
# when
|
# when
|
||||||
node.sethwaddr(index, mac)
|
node.sethwaddr(interface.netindex, mac)
|
||||||
|
|
||||||
# then
|
# then
|
||||||
assert interface.hwaddr == mac
|
assert interface.hwaddr == mac
|
||||||
|
@ -69,25 +68,23 @@ class TestNodes:
|
||||||
node = session.add_node(CoreNode)
|
node = session.add_node(CoreNode)
|
||||||
switch = session.add_node(SwitchNode)
|
switch = session.add_node(SwitchNode)
|
||||||
interface_data = InterfaceData()
|
interface_data = InterfaceData()
|
||||||
index = node.newnetif(switch, interface_data)
|
interface = node.newnetif(switch, interface_data)
|
||||||
node.netif(index)
|
|
||||||
mac = "aa:aa:aa:ff:ff:fff"
|
mac = "aa:aa:aa:ff:ff:fff"
|
||||||
|
|
||||||
# when
|
# when
|
||||||
with pytest.raises(CoreError):
|
with pytest.raises(CoreError):
|
||||||
node.sethwaddr(index, mac)
|
node.sethwaddr(interface.netindex, mac)
|
||||||
|
|
||||||
def test_node_addaddr(self, session: Session):
|
def test_node_addaddr(self, session: Session):
|
||||||
# given
|
# given
|
||||||
node = session.add_node(CoreNode)
|
node = session.add_node(CoreNode)
|
||||||
switch = session.add_node(SwitchNode)
|
switch = session.add_node(SwitchNode)
|
||||||
interface_data = InterfaceData()
|
interface_data = InterfaceData()
|
||||||
index = node.newnetif(switch, interface_data)
|
interface = node.newnetif(switch, interface_data)
|
||||||
interface = node.netif(index)
|
|
||||||
addr = "192.168.0.1/24"
|
addr = "192.168.0.1/24"
|
||||||
|
|
||||||
# when
|
# when
|
||||||
node.addaddr(index, addr)
|
node.addaddr(interface.netindex, addr)
|
||||||
|
|
||||||
# then
|
# then
|
||||||
assert interface.addrlist[0] == addr
|
assert interface.addrlist[0] == addr
|
||||||
|
@ -97,13 +94,12 @@ class TestNodes:
|
||||||
node = session.add_node(CoreNode)
|
node = session.add_node(CoreNode)
|
||||||
switch = session.add_node(SwitchNode)
|
switch = session.add_node(SwitchNode)
|
||||||
interface_data = InterfaceData()
|
interface_data = InterfaceData()
|
||||||
index = node.newnetif(switch, interface_data)
|
interface = node.newnetif(switch, interface_data)
|
||||||
node.netif(index)
|
|
||||||
addr = "256.168.0.1/24"
|
addr = "256.168.0.1/24"
|
||||||
|
|
||||||
# when
|
# when
|
||||||
with pytest.raises(CoreError):
|
with pytest.raises(CoreError):
|
||||||
node.addaddr(index, addr)
|
node.addaddr(interface.netindex, addr)
|
||||||
|
|
||||||
@pytest.mark.parametrize("net_type", NET_TYPES)
|
@pytest.mark.parametrize("net_type", NET_TYPES)
|
||||||
def test_net(self, session, net_type):
|
def test_net(self, session, net_type):
|
||||||
|
|
Loading…
Reference in a new issue