daemon: update CoreNode.newnetif to require parameters, CoreNode.newnetif now depends on being provided InterfaceData

This commit is contained in:
Blake Harnden 2020-06-09 12:42:15 -07:00
parent 3691c6029f
commit 3be15a1316
5 changed files with 71 additions and 130 deletions

View file

@ -1,18 +1,22 @@
from dataclasses import dataclass, field
from typing import List, Optional, Union
from typing import TYPE_CHECKING, List, Optional, Union
import netaddr
from core import utils
from core.api.grpc.core_pb2 import LinkOptions
from core.emulator.enumerations import LinkTypes
from core.nodes.base import CoreNetworkBase, CoreNode
from core.nodes.interface import CoreInterface
from core.nodes.physical import PhysicalNode
if TYPE_CHECKING:
from core.nodes.base import CoreNetworkBase, CoreNode
from core.nodes.physical import PhysicalNode
LinkConfigNode = Union[CoreNetworkBase, PhysicalNode]
def link_config(
node: Union[CoreNetworkBase, PhysicalNode],
node: "LinkConfigNode",
interface: CoreInterface,
link_options: LinkOptions,
interface_two: CoreInterface = None,
@ -160,7 +164,7 @@ class IpPrefixes:
if ip6_prefix:
self.ip6 = netaddr.IPNetwork(ip6_prefix)
def ip4_address(self, node: CoreNode) -> str:
def ip4_address(self, node: "CoreNode") -> str:
"""
Convenience method to return the IP4 address for a node.
@ -171,7 +175,7 @@ class IpPrefixes:
raise ValueError("ip4 prefixes have not been set")
return str(self.ip4[node.id])
def ip6_address(self, node: CoreNode) -> str:
def ip6_address(self, node: "CoreNode") -> str:
"""
Convenience method to return the IP6 address for a node.
@ -183,7 +187,7 @@ class IpPrefixes:
return str(self.ip6[node.id])
def create_interface(
self, node: CoreNode, name: str = None, mac: str = None
self, node: "CoreNode", name: str = None, mac: str = None
) -> InterfaceData:
"""
Creates interface data for linking nodes, using the nodes unique id for
@ -225,24 +229,3 @@ class IpPrefixes:
ip6_mask=ip6_mask,
mac=mac,
)
def create_interface(
node: CoreNode, network: CoreNetworkBase, interface_data: InterfaceData
):
"""
Create an interface for a node on a network using provided interface data.
:param node: node to create interface for
:param network: network to associate interface with
:param interface_data: interface data
:return: created interface
"""
node.newnetif(
network,
addrlist=interface_data.get_addresses(),
hwaddr=interface_data.mac,
ifindex=interface_data.id,
ifname=interface_data.name,
)
return node.netif(interface_data.id)

View file

@ -19,13 +19,7 @@ from core.emane.emanemanager import EmaneManager
from core.emane.nodes import EmaneNet
from core.emulator.data import ConfigData, EventData, ExceptionData, FileData, LinkData
from core.emulator.distributed import DistributedController
from core.emulator.emudata import (
InterfaceData,
LinkOptions,
NodeOptions,
create_interface,
link_config,
)
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions, link_config
from core.emulator.enumerations import (
EventTypes,
ExceptionLevels,
@ -360,11 +354,11 @@ class Session:
node_one.name,
net_one.name,
)
interface = create_interface(node_one, net_one, interface_one)
node_one_interface = interface
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:
link_config(net_one, interface, link_options)
link_config(net_one, node_one_interface, link_options)
# network to node
if node_two and net_one:
@ -373,11 +367,11 @@ class Session:
node_two.name,
net_one.name,
)
interface = create_interface(node_two, net_one, interface_two)
node_two_interface = interface
ifindex = node_two.newnetif(net_one, interface_two)
node_two_interface = node_two.netif(ifindex)
wireless_net = isinstance(net_one, (EmaneNet, WlanNode))
if not link_options.unidirectional and not wireless_net:
link_config(net_one, interface, link_options)
link_config(net_one, node_two_interface, link_options)
# network to network
if net_one and net_two:
@ -1797,35 +1791,28 @@ class Session:
control_net = self.add_remove_control_net(net_index, remove, conf_required)
if not control_net:
return
if not node:
return
# ctrl# already exists
if node.netif(control_net.CTRLIF_IDX_BASE + net_index):
return
control_ip = node.id
try:
address = control_net.prefix[control_ip]
prefix = control_net.prefix.prefixlen
addrlist = [f"{address}/{prefix}"]
ip4 = control_net.prefix[node.id]
ip4_mask = control_net.prefix.prefixlen
interface = InterfaceData(
id=control_net.CTRLIF_IDX_BASE + net_index,
name=f"ctrl{net_index}",
mac=utils.random_mac(),
ip4=ip4,
ip4_mask=ip4_mask,
)
ifindex = node.newnetif(control_net, interface)
node.netif(ifindex).control = True
except ValueError:
msg = f"Control interface not added to node {node.id}. "
msg += f"Invalid control network prefix ({control_net.prefix}). "
msg += "A longer prefix length may be required for this many nodes."
logging.exception(msg)
return
interface1 = node.newnetif(
net=control_net,
ifindex=control_net.CTRLIF_IDX_BASE + net_index,
ifname=f"ctrl{net_index}",
hwaddr=utils.random_mac(),
addrlist=addrlist,
)
node.netif(interface1).control = True
def update_control_interface_hosts(
self, net_index: int = 0, remove: bool = False

View file

@ -15,6 +15,7 @@ from core import utils
from core.configservice.dependencies import ConfigServiceDependencies
from core.constants import MOUNT_BIN, VNODED_BIN
from core.emulator.data import LinkData, NodeData
from core.emulator.emudata import InterfaceData
from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes
from core.errors import CoreCommandError, CoreError
from core.nodes.client import VnodeClient
@ -845,53 +846,36 @@ class CoreNode(CoreNodeBase):
interface_name = self.ifname(ifindex)
self.node_net_client.device_up(interface_name)
def newnetif(
self,
net: "CoreNetworkBase" = None,
addrlist: List[str] = None,
hwaddr: str = None,
ifindex: int = None,
ifname: str = None,
) -> int:
def newnetif(self, net: "CoreNetworkBase", interface: InterfaceData) -> int:
"""
Create a new network interface.
:param net: network to associate with
:param addrlist: addresses to add on the interface
:param hwaddr: hardware address to set for interface
:param ifindex: index of interface to create
:param ifname: name for interface
:param interface: interface data for new interface
:return: interface index
"""
if not addrlist:
addrlist = []
addresses = interface.get_addresses()
with self.lock:
# TODO: emane specific code
if net is not None and net.is_emane is True:
ifindex = self.newtuntap(ifindex, ifname)
if net.is_emane is True:
ifindex = self.newtuntap(interface.id, interface.name)
# TUN/TAP is not ready for addressing yet; the device may
# take some time to appear, and installing it into a
# namespace after it has been bound removes addressing;
# save addresses with the interface now
self.attachnet(ifindex, net)
netif = self.netif(ifindex)
netif.sethwaddr(hwaddr)
for address in utils.make_tuple(addrlist):
netif.sethwaddr(interface.mac)
for address in addresses:
netif.addaddr(address)
return ifindex
else:
ifindex = self.newveth(ifindex, ifname)
if net is not None:
self.attachnet(ifindex, net)
if hwaddr:
self.sethwaddr(ifindex, hwaddr)
for address in utils.make_tuple(addrlist):
ifindex = self.newveth(interface.id, interface.name)
self.attachnet(ifindex, net)
if interface.mac:
self.sethwaddr(ifindex, interface.mac)
for address in addresses:
self.addaddr(ifindex, address)
self.ifup(ifindex)
return ifindex

View file

@ -10,10 +10,11 @@ from typing import IO, TYPE_CHECKING, List, Optional, Tuple
from core import utils
from core.constants import MOUNT_BIN, UMOUNT_BIN
from core.emulator.distributed import DistributedServer
from core.emulator.emudata import InterfaceData
from core.emulator.enumerations import NodeTypes, TransportType
from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNetworkBase, CoreNodeBase
from core.nodes.interface import CoreInterface, Veth
from core.nodes.interface import CoreInterface
from core.nodes.network import CoreNetwork, GreTap
if TYPE_CHECKING:
@ -168,37 +169,25 @@ class PhysicalNode(CoreNodeBase):
self.ifindex += 1
return ifindex
def newnetif(
self,
net: Veth = None,
addrlist: List[str] = None,
hwaddr: str = None,
ifindex: int = None,
ifname: str = None,
) -> int:
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> int:
logging.info("creating interface")
if not addrlist:
addrlist = []
if self.up and net is None:
raise NotImplementedError
addresses = interface.get_addresses()
ifindex = interface.id
if ifindex is None:
ifindex = self.newifindex()
if ifname is None:
ifname = f"gt{ifindex}"
name = interface.name
if name is None:
name = f"gt{ifindex}"
if self.up:
# this is reached when this node is linked to a network node
# tunnel to net not built yet, so build it now and adopt it
_, remote_tap = self.session.distributed.create_gre_tunnel(net, self.server)
self.adoptnetif(remote_tap, ifindex, hwaddr, addrlist)
self.adoptnetif(remote_tap, ifindex, interface.mac, addresses)
return ifindex
else:
# this is reached when configuring services (self.up=False)
netif = GreTap(node=self, name=ifname, session=self.session, start=False)
self.adoptnetif(netif, ifindex, hwaddr, addrlist)
netif = GreTap(node=self, name=name, session=self.session, start=False)
self.adoptnetif(netif, ifindex, interface.mac, addresses)
return ifindex
def privatedir(self, path: str) -> None:
@ -320,28 +309,19 @@ class Rj45Node(CoreNodeBase):
self.up = False
self.restorestate()
def newnetif(
self,
net: CoreNetworkBase = None,
addrlist: List[str] = None,
hwaddr: str = None,
ifindex: int = None,
ifname: str = None,
) -> int:
def newnetif(self, net: CoreNetworkBase, interface: InterfaceData) -> int:
"""
This is called when linking with another node. Since this node
represents an interface, we do not create another object here,
but attach ourselves to the given network.
:param net: new network instance
:param addrlist: address list
:param hwaddr: hardware address
:param ifindex: interface index
:param ifname: interface name
:param interface: interface data for new interface
:return: interface index
:raises ValueError: when an interface has already been created, one max
"""
with self.lock:
ifindex = interface.id
if ifindex is None:
ifindex = 0
if self.interface.net is not None:
@ -350,9 +330,8 @@ class Rj45Node(CoreNodeBase):
self.ifindex = ifindex
if net is not None:
self.interface.attachnet(net)
if addrlist:
for addr in utils.make_tuple(addrlist):
self.addaddr(addr)
for addr in interface.get_addresses():
self.addaddr(addr)
return ifindex
def delnetif(self, ifindex: int) -> None:

View file

@ -1,6 +1,6 @@
import pytest
from core.emulator.emudata import NodeOptions
from core.emulator.emudata import InterfaceData, NodeOptions
from core.emulator.session import Session
from core.errors import CoreError
from core.nodes.base import CoreNode
@ -52,7 +52,9 @@ class TestNodes:
def test_node_sethwaddr(self, session: Session):
# given
node = session.add_node(CoreNode)
index = node.newnetif()
switch = session.add_node(SwitchNode)
interface_data = InterfaceData()
index = node.newnetif(switch, interface_data)
interface = node.netif(index)
mac = "aa:aa:aa:ff:ff:ff"
@ -65,7 +67,9 @@ class TestNodes:
def test_node_sethwaddr_exception(self, session: Session):
# given
node = session.add_node(CoreNode)
index = node.newnetif()
switch = session.add_node(SwitchNode)
interface_data = InterfaceData()
index = node.newnetif(switch, interface_data)
node.netif(index)
mac = "aa:aa:aa:ff:ff:fff"
@ -76,7 +80,9 @@ class TestNodes:
def test_node_addaddr(self, session: Session):
# given
node = session.add_node(CoreNode)
index = node.newnetif()
switch = session.add_node(SwitchNode)
interface_data = InterfaceData()
index = node.newnetif(switch, interface_data)
interface = node.netif(index)
addr = "192.168.0.1/24"
@ -89,7 +95,9 @@ class TestNodes:
def test_node_addaddr_exception(self, session):
# given
node = session.add_node(CoreNode)
index = node.newnetif()
switch = session.add_node(SwitchNode)
interface_data = InterfaceData()
index = node.newnetif(switch, interface_data)
node.netif(index)
addr = "256.168.0.1/24"