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 # wireless link
node_one, node_two, net_one, net_two = self._link_nodes( if options.type == LinkTypes.WIRELESS:
node_one_id, node_two_id if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
) self._link_wireless(node1, node2, connect=True)
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
if options.type == LinkTypes.WIRELESS:
objects = [node_one, node_two, net_one, net_two]
self._link_wireless(objects, connect=True)
# wired link
else: else:
# 2 nodes being linked, ptp network raise CoreError(
if all([node_one, node_two]) and not net_one: f"cannot wireless link node1({type(node1)}) node2({type(node2)})"
logging.info( )
"adding link for peer to peer nodes: %s - %s", # wired link
node_one.name, else:
node_two.name, # peer to peer link
) if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
start = self.state.should_start() logging.info("linking ptp: %s - %s", node1.name, node2.name)
net_one = self.create_node(PtpNet, start=start) start = self.state.should_start()
ptp = self.create_node(PtpNet, start=start)
# node to network node1_interface = node1.newnetif(ptp, interface_one)
if node_one and net_one: node2_interface = node2.newnetif(ptp, interface_two)
logging.info( ptp.linkconfig(node1_interface, options)
"adding link from node to network: %s - %s", if not options.unidirectional:
node_one.name, ptp.linkconfig(node2_interface, options)
net_one.name, # link node to net
) elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
ifindex = node_one.newnetif(net_one, interface_one) node1_interface = node1.newnetif(node2, interface_one)
node_one_interface = node_one.netif(ifindex) if not isinstance(node2, (EmaneNet, WlanNode)):
wireless_net = isinstance(net_one, (EmaneNet, WlanNode)) node2.linkconfig(node1_interface, options)
if not wireless_net: # link net to node
net_one.linkconfig(node_one_interface, options) elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
node2_interface = node2.newnetif(node1, interface_two)
# network to node wireless_net = isinstance(node1, (EmaneNet, WlanNode))
if node_two and net_one: if not options.unidirectional and not wireless_net:
logging.info( node1.linkconfig(node2_interface, options)
"adding link from network to node: %s - %s", # network to network
node_two.name, elif isinstance(node1, CoreNetworkBase) and isinstance(
net_one.name, node2, CoreNetworkBase
) ):
ifindex = node_two.newnetif(net_one, interface_two) logging.info(
node_two_interface = node_two.netif(ifindex) "linking network to network: %s - %s", node1.name, node2.name
wireless_net = isinstance(net_one, (EmaneNet, WlanNode)) )
if not options.unidirectional and not wireless_net: node1_interface = node1.linknet(node2)
net_one.linkconfig(node_two_interface, options) node1.linkconfig(node1_interface, options)
if not options.unidirectional:
# network to network node1_interface.swapparams("_params_up")
if net_one and net_two: node2.linkconfig(node1_interface, options)
logging.info( node1_interface.swapparams("_params_up")
"adding link from network to network: %s - %s", else:
net_one.name, raise CoreError(
net_two.name, f"cannot link node1({type(node1)}) node2({type(node2)})"
) )
interface = net_one.linknet(net_two)
node_one_interface = interface
net_one.linkconfig(interface, options)
if not options.unidirectional:
interface.swapparams("_params_up")
net_two.linkconfig(interface, options)
interface.swapparams("_params_up")
# a tunnel node was found for the 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
if key and isinstance(net_one, TunnelNode):
logging.info("setting tunnel key for: %s", net_one.name)
net_one.setkey(key)
if addresses:
net_one.addrconfig(addresses)
if key and isinstance(net_two, TunnelNode):
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()
# configure tunnel nodes
key = options.key
if isinstance(node1, TunnelNode):
logging.info("setting tunnel key for: %s", node1.name)
node1.setkey(key, interface_one)
if isinstance(node2, TunnelNode):
logging.info("setting tunnel key for: %s", node2.name)
node2.setkey(key, interface_two)
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: # wireless link
node_one.lock.acquire() if link_type == LinkTypes.WIRELESS:
if node_two: if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
node_two.lock.acquire() self._link_wireless(node1, node2, connect=False)
try:
# wireless link
if link_type == LinkTypes.WIRELESS:
objects = [node_one, node_two, net_one, net_two]
self._link_wireless(objects, connect=False)
# wired link
else: else:
if all([node_one, node_two]): raise CoreError(
# TODO: fix this for the case where ifindex[1,2] are not specified "cannot delete wireless link "
# a wired unlink event, delete the connecting bridge f"node1({type(node1)}) node2({type(node2)})"
interface_one = node_one.netif(interface_one_id) )
interface_two = node_two.netif(interface_two_id) # wired link
else:
# get interfaces from common network, if no network node if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
# otherwise get interfaces between a node and network interface1 = node1.netif(interface_one_id)
if not interface_one and not interface_two: interface2 = node2.netif(interface_two_id)
common_networks = node_one.commonnets(node_two) if not interface1:
for ( raise CoreError(
network, f"node({node1.name}) missing interface({interface_one_id})"
common_interface_one, )
common_interface_two, if not interface2:
) in common_networks: raise CoreError(
if (net_one and network == net_one) or not net_one: f"node({node2.name}) missing interface({interface_two_id})"
interface_one = common_interface_one )
interface_two = common_interface_two if interface1.net != interface2.net:
break raise CoreError(
f"node1({node1.name}) node2({node2.name}) "
if all([interface_one, interface_two]) and any( "not connected to same net"
[interface_one.net, interface_two.net] )
): ptp = interface1.net
if interface_one.net != interface_two.net and all( node1.delnetif(interface_one_id)
[interface_one.up, interface_two.up] node2.delnetif(interface_two_id)
): self.delete_node(ptp.id)
raise CoreError("no common network found") elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
node1.delnetif(interface_one_id)
logging.info( elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
"deleting link node(%s):interface(%s) node(%s):interface(%s)", node2.delnetif(interface_two_id)
node_one.name,
interface_one.name,
node_two.name,
interface_two.name,
)
net_one = interface_one.net
interface_one.detachnet()
interface_two.detachnet()
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()
node_one.delnetif(interface.netindex)
elif node_two and net_one:
interface = node_two.netif(interface_two_id)
if interface:
logging.info(
"deleting link node(%s):interface(%s) node(%s)",
node_two.name,
interface.name,
net_one.name,
)
interface.detachnet()
node_two.delnetif(interface.netindex)
finally:
if node_one:
node_one.lock.release()
if node_two:
node_two.lock.release()
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: # wireless link
node_one.lock.acquire() if options.type == LinkTypes.WIRELESS:
if node_two: raise CoreError("cannot update wireless link")
node_two.lock.acquire() else:
if isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNodeBase):
try: interface1 = node1.netif(interface_one_id)
# wireless link interface2 = node2.netif(interface_two_id)
if options.type == LinkTypes.WIRELESS: if not interface1:
raise CoreError("cannot update wireless link") raise CoreError(
else: f"node({node1.name}) missing interface({interface_one_id})"
if not node_one and not node_two: )
if net_one and net_two: if not interface2:
# modify link between nets raise CoreError(
interface = net_one.getlinknetif(net_two) f"node({node2.name}) missing interface({interface_two_id})"
upstream = False )
if interface1.net != interface2.net:
if not interface: raise CoreError(
upstream = True f"node1({node1.name}) node2({node2.name}) "
interface = net_two.getlinknetif(net_one) "not connected to same net"
)
if not interface: ptp = interface1.net
raise CoreError("modify unknown link between nets") ptp.linkconfig(interface1, options, interface2)
if not options.unidirectional:
if upstream: ptp.linkconfig(interface2, options, interface1)
interface.swapparams("_params_up") elif isinstance(node1, CoreNodeBase) and isinstance(node2, CoreNetworkBase):
net_one.linkconfig(interface, options) interface = node1.netif(interface_one_id)
interface.swapparams("_params_up") node2.linkconfig(interface, options)
else: elif isinstance(node2, CoreNodeBase) and isinstance(node1, CoreNetworkBase):
net_one.linkconfig(interface, options) interface = node2.netif(interface_two_id)
node1.linkconfig(interface, options)
if not options.unidirectional: elif isinstance(node1, CoreNetworkBase) and isinstance(
if upstream: node2, CoreNetworkBase
net_two.linkconfig(interface, options) ):
else: interface = node1.getlinknetif(node2)
interface.swapparams("_params_up") upstream = False
net_two.linkconfig(interface, options) if not interface:
interface.swapparams("_params_up") upstream = True
else: interface = node2.getlinknetif(node1)
raise CoreError("modify link for unknown nodes") if not interface:
elif not node_one: raise CoreError("modify unknown link between nets")
# node1 = layer 2node, node2 = layer3 node if upstream:
interface = node_two.netif(interface_two_id) interface.swapparams("_params_up")
net_one.linkconfig(interface, options) node1.linkconfig(interface, options)
elif not node_two: interface.swapparams("_params_up")
# node2 = layer 2node, node1 = layer3 node
interface = node_one.netif(interface_one_id)
net_one.linkconfig(interface, options)
else: else:
common_networks = node_one.commonnets(node_two) node1.linkconfig(interface, options)
if not common_networks: if not options.unidirectional:
raise CoreError("no common network found") if upstream:
node2.linkconfig(interface, options)
for net_one, interface_one, interface_two in common_networks: else:
if ( interface.swapparams("_params_up")
interface_one_id is not None node2.linkconfig(interface, options)
and interface_one_id != node_one.getifindex(interface_one) interface.swapparams("_params_up")
): else:
continue raise CoreError(
f"cannot update link node1({type(node1)}) node2({type(node2)})"
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,16 +883,16 @@ 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)
if interface.mac: if interface.mac:
self.sethwaddr(ifindex, interface.mac) self.sethwaddr(ifindex, interface.mac)
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):