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:
bharnden 2020-06-11 16:26:58 -07:00 committed by GitHub
commit f626564200
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 232 additions and 355 deletions

View file

@ -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)

View file

@ -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}). "

View file

@ -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:
""" """

View file

@ -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):

View file

@ -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:
""" """

View file

@ -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):