Merge pull request #289 from coreemu/cleanup/remove-node-map

Removed node maps and integrated OVS mode
This commit is contained in:
bharnden 2019-09-27 10:54:42 -07:00 committed by GitHub
commit 08ea1dd813
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 420 additions and 1179 deletions

View file

@ -11,6 +11,7 @@ insert_final_newline = true
[*.py] [*.py]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
max_line_length = 88
[*.am] [*.am]
indent_style = tab indent_style = tab

View file

@ -4,8 +4,9 @@ url = "https://pypi.org/simple"
verify_ssl = true verify_ssl = true
[scripts] [scripts]
coredev = "python scripts/core-daemon -f data/core.conf -l data/logging.conf" core = "python scripts/core-daemon -f data/core.conf -l data/logging.conf"
coretest = "python -m pytest -v tests" test = "pytest -v tests"
test_emane = "pytest -v tests/emane"
[dev-packages] [dev-packages]
grpcio-tools = "*" grpcio-tools = "*"

View file

@ -12,6 +12,7 @@ import grpc
from core import CoreError from core import CoreError
from core.api.grpc import core_pb2, core_pb2_grpc from core.api.grpc import core_pb2, core_pb2_grpc
from core.emane.nodes import EmaneNode
from core.emulator.data import ( from core.emulator.data import (
ConfigData, ConfigData,
EventData, EventData,
@ -23,7 +24,6 @@ from core.emulator.data import (
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
from core.emulator.enumerations import EventTypes, LinkTypes, NodeTypes from core.emulator.enumerations import EventTypes, LinkTypes, NodeTypes
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase from core.nodes.base import CoreNetworkBase
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
from core.nodes.ipaddress import MacAddress from core.nodes.ipaddress import MacAddress
@ -444,7 +444,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
if not isinstance(node.id, int): if not isinstance(node.id, int):
continue continue
node_type = nodeutils.get_node_type(node.__class__).value node_type = session.get_node_type(node.__class__)
model = getattr(node, "type", None) model = getattr(node, "type", None)
position = core_pb2.Position( position = core_pb2.Position(
x=node.position.x, y=node.position.y, z=node.position.z x=node.position.x, y=node.position.y, z=node.position.z
@ -456,7 +456,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
services = [x.name for x in services] services = [x.name for x in services]
emane_model = None emane_model = None
if nodeutils.is_node(node, NodeTypes.EMANE): if isinstance(node, EmaneNode):
emane_model = node.model.name emane_model = node.model.name
node_proto = core_pb2.Node( node_proto = core_pb2.Node(
@ -464,7 +464,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
name=node.name, name=node.name,
emane=emane_model, emane=emane_model,
model=model, model=model,
type=node_type, type=node_type.value,
position=position, position=position,
services=services, services=services,
) )
@ -809,18 +809,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
interfaces.append(interface_proto) interfaces.append(interface_proto)
emane_model = None emane_model = None
if nodeutils.is_node(node, NodeTypes.EMANE): if isinstance(node, EmaneNode):
emane_model = node.model.name emane_model = node.model.name
services = [x.name for x in getattr(node, "services", [])] services = [x.name for x in getattr(node, "services", [])]
position = core_pb2.Position( position = core_pb2.Position(
x=node.position.x, y=node.position.y, z=node.position.z x=node.position.x, y=node.position.y, z=node.position.z
) )
node_type = nodeutils.get_node_type(node.__class__).value node_type = session.get_node_type(node.__class__)
node_proto = core_pb2.Node( node_proto = core_pb2.Node(
id=node.id, id=node.id,
name=node.name, name=node.name,
type=node_type, type=node_type.value,
emane=emane_model, emane=emane_model,
model=node.type, model=node.type,
position=position, position=position,

View file

@ -12,6 +12,7 @@ import threading
from core import utils from core import utils
from core.api.tlv import coreapi from core.api.tlv import coreapi
from core.emane.nodes import EmaneNet
from core.emulator.enumerations import ( from core.emulator.enumerations import (
ConfigDataTypes, ConfigDataTypes,
ConfigFlags, ConfigFlags,
@ -27,11 +28,10 @@ from core.emulator.enumerations import (
NodeTypes, NodeTypes,
RegisterTlvs, RegisterTlvs,
) )
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase, CoreNodeBase from core.nodes.base import CoreNetworkBase, CoreNodeBase
from core.nodes.interface import GreTap from core.nodes.interface import GreTap
from core.nodes.ipaddress import IpAddress from core.nodes.ipaddress import IpAddress
from core.nodes.network import GreTapBridge from core.nodes.network import CtrlNet, GreTapBridge
from core.nodes.physical import PhysicalNode from core.nodes.physical import PhysicalNode
@ -495,15 +495,12 @@ class CoreBroker(object):
logging.info("adding net tunnel for: id(%s) %s", node_id, net) logging.info("adding net tunnel for: id(%s) %s", node_id, net)
# add other nets here that do not require tunnels # add other nets here that do not require tunnels
if nodeutils.is_node(net, NodeTypes.EMANE_NET): if isinstance(net, EmaneNet):
logging.warning("emane network does not require a tunnel") logging.warning("emane network does not require a tunnel")
return None return None
server_interface = getattr(net, "serverintf", None) server_interface = getattr(net, "serverintf", None)
if ( if isinstance(net, CtrlNet) and server_interface is not None:
nodeutils.is_node(net, NodeTypes.CONTROL_NET)
and server_interface is not None
):
logging.warning( logging.warning(
"control networks with server interfaces do not need a tunnel" "control networks with server interfaces do not need a tunnel"
) )
@ -824,7 +821,8 @@ class CoreBroker(object):
nodetype = message.get_tlv(NodeTlvs.TYPE.value) nodetype = message.get_tlv(NodeTlvs.TYPE.value)
if nodetype is not None: if nodetype is not None:
try: try:
nodecls = nodeutils.get_node_class(NodeTypes(nodetype)) nodetype = NodeTypes(nodetype)
nodecls = self.session.get_node_class(nodetype)
except KeyError: except KeyError:
logging.warning("broker invalid node type %s", nodetype) logging.warning("broker invalid node type %s", nodetype)
return handle_locally, servers return handle_locally, servers

View file

@ -38,7 +38,7 @@ from core.emulator.enumerations import (
SessionTlvs, SessionTlvs,
) )
from core.location.mobility import BasicRangeModel from core.location.mobility import BasicRangeModel
from core.nodes import nodeutils from core.nodes.network import WlanNode
from core.services.coreservices import ServiceManager, ServiceShim from core.services.coreservices import ServiceManager, ServiceShim
@ -1603,8 +1603,8 @@ class CoreHandler(socketserver.BaseRequestHandler):
node = self.session.get_node(node_id) node = self.session.get_node(node_id)
# configure mobility models for WLAN added during runtime # configure mobility models for WLAN added during runtime
if event_type == EventTypes.INSTANTIATION_STATE and nodeutils.is_node( if event_type == EventTypes.INSTANTIATION_STATE and isinstance(
node, NodeTypes.WIRELESS_LAN node, WlanNode
): ):
self.session.start_mobility(node_ids=(node.id,)) self.session.start_mobility(node_ids=(node.id,))
return () return ()

View file

@ -15,6 +15,7 @@ from core.emane.bypass import EmaneBypassModel
from core.emane.commeffect import EmaneCommEffectModel from core.emane.commeffect import EmaneCommEffectModel
from core.emane.emanemodel import EmaneModel from core.emane.emanemodel import EmaneModel
from core.emane.ieee80211abg import EmaneIeee80211abgModel from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emane.nodes import EmaneNode
from core.emane.rfpipe import EmaneRfPipeModel from core.emane.rfpipe import EmaneRfPipeModel
from core.emane.tdma import EmaneTdmaModel from core.emane.tdma import EmaneTdmaModel
from core.emulator.enumerations import ( from core.emulator.enumerations import (
@ -23,10 +24,8 @@ from core.emulator.enumerations import (
ConfigTlvs, ConfigTlvs,
MessageFlags, MessageFlags,
MessageTypes, MessageTypes,
NodeTypes,
RegisterTlvs, RegisterTlvs,
) )
from core.nodes import nodeutils
from core.xml import emanexml from core.xml import emanexml
try: try:
@ -266,7 +265,7 @@ class EmaneManager(ModelManager):
with self.session._nodes_lock: with self.session._nodes_lock:
for node_id in self.session.nodes: for node_id in self.session.nodes:
node = self.session.nodes[node_id] node = self.session.nodes[node_id]
if nodeutils.is_node(node, NodeTypes.EMANE): if isinstance(node, EmaneNode):
logging.debug( logging.debug(
"adding emane node: id(%s) name(%s)", node.id, node.name "adding emane node: id(%s) name(%s)", node.id, node.name
) )

View file

@ -25,7 +25,6 @@ class EmaneNet(CoreNetworkBase):
apitype = NodeTypes.EMANE.value apitype = NodeTypes.EMANE.value
linktype = LinkTypes.WIRELESS.value linktype = LinkTypes.WIRELESS.value
# icon used
type = "wlan" type = "wlan"
@ -36,6 +35,8 @@ class EmaneNode(EmaneNet):
Emane controller object that exists in a session. Emane controller object that exists in a session.
""" """
is_emane = True
def __init__(self, session, _id=None, name=None, start=True): def __init__(self, session, _id=None, name=None, start=True):
super(EmaneNode, self).__init__(session, _id, name, start) super(EmaneNode, self).__init__(session, _id, name, start)
self.conf = "" self.conf = ""

View file

@ -7,7 +7,6 @@ import sys
import core.services import core.services
from core.emulator.emudata import IdGen from core.emulator.emudata import IdGen
from core.emulator.session import Session from core.emulator.session import Session
from core.nodes import nodemaps, nodeutils
from core.services.coreservices import ServiceManager from core.services.coreservices import ServiceManager
@ -45,7 +44,7 @@ class CoreEmu(object):
os.umask(0) os.umask(0)
# configuration # configuration
if not config: if config is None:
config = {} config = {}
self.config = config self.config = config
@ -53,10 +52,6 @@ class CoreEmu(object):
self.session_id_gen = IdGen(_id=0) self.session_id_gen = IdGen(_id=0)
self.sessions = {} self.sessions = {}
# set default nodes
node_map = nodemaps.NODES
nodeutils.set_node_map(node_map)
# load services # load services
self.service_errors = [] self.service_errors = []
self.load_services() self.load_services()
@ -77,15 +72,6 @@ class CoreEmu(object):
custom_service_errors = ServiceManager.add_services(service_path) custom_service_errors = ServiceManager.add_services(service_path)
self.service_errors.extend(custom_service_errors) self.service_errors.extend(custom_service_errors)
def update_nodes(self, node_map):
"""
Updates node map used by core.
:param dict node_map: node map to update existing node map with
:return: nothing
"""
nodeutils.update_node_map(node_map)
def shutdown(self): def shutdown(self):
""" """
Shutdown all CORE session. Shutdown all CORE session.

View file

@ -1,7 +1,7 @@
from core.emulator.enumerations import LinkTypes, NodeTypes from core.emane.nodes import EmaneNode
from core.nodes import nodeutils from core.emulator.enumerations import LinkTypes
from core.nodes.base import CoreNetworkBase
from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress
from core.nodes.physical import PhysicalNode
class IdGen(object): class IdGen(object):
@ -13,17 +13,6 @@ class IdGen(object):
return self.id return self.id
def is_net_node(node):
"""
Convenience method for testing if a legacy core node is considered a network node.
:param object node: object to test against
:return: True if object is an instance of a network node, False otherwise
:rtype: bool
"""
return isinstance(node, CoreNetworkBase)
def create_interface(node, network, interface_data): def create_interface(node, network, interface_data):
""" """
Create an interface for a node on a network using provided interface data. Create an interface for a node on a network using provided interface data.
@ -65,7 +54,7 @@ def link_config(network, interface, link_options, devname=None, interface_two=No
} }
# hacky check here, because physical and emane nodes do not conform to the same linkconfig interface # hacky check here, because physical and emane nodes do not conform to the same linkconfig interface
if not nodeutils.is_node(network, [NodeTypes.EMANE, NodeTypes.PHYSICAL]): if not isinstance(network, (EmaneNode, PhysicalNode)):
config["devname"] = devname config["devname"] = devname
network.linkconfig(**config) network.linkconfig(**config)

View file

@ -14,18 +14,17 @@ import threading
import time import time
from multiprocessing.pool import ThreadPool from multiprocessing.pool import ThreadPool
import core.nodes.base
from core import CoreError, constants, utils from core import CoreError, constants, utils
from core.api.tlv import coreapi from core.api.tlv import coreapi
from core.api.tlv.broker import CoreBroker from core.api.tlv.broker import CoreBroker
from core.emane.emanemanager import EmaneManager from core.emane.emanemanager import EmaneManager
from core.emane.nodes import EmaneNet, EmaneNode
from core.emulator.data import EventData, ExceptionData, NodeData from core.emulator.data import EventData, ExceptionData, NodeData
from core.emulator.emudata import ( from core.emulator.emudata import (
IdGen, IdGen,
LinkOptions, LinkOptions,
NodeOptions, NodeOptions,
create_interface, create_interface,
is_net_node,
link_config, link_config,
) )
from core.emulator.enumerations import EventTypes, ExceptionLevels, LinkTypes, NodeTypes from core.emulator.enumerations import EventTypes, ExceptionLevels, LinkTypes, NodeTypes
@ -33,14 +32,46 @@ from core.emulator.sessionconfig import SessionConfig, SessionMetaData
from core.location.corelocation import CoreLocation from core.location.corelocation import CoreLocation
from core.location.event import EventLoop from core.location.event import EventLoop
from core.location.mobility import MobilityManager from core.location.mobility import MobilityManager
from core.nodes import nodeutils from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase
from core.nodes.base import CoreNodeBase from core.nodes.docker import DockerNode
from core.nodes.ipaddress import MacAddress from core.nodes.ipaddress import MacAddress
from core.nodes.lxd import LxcNode
from core.nodes.network import (
CtrlNet,
GreTapBridge,
HubNode,
PtpNet,
SwitchNode,
TunnelNode,
WlanNode,
)
from core.nodes.physical import PhysicalNode, Rj45Node
from core.plugins.sdt import Sdt from core.plugins.sdt import Sdt
from core.services.coreservices import CoreServices from core.services.coreservices import CoreServices
from core.xml import corexml, corexmldeployment from core.xml import corexml, corexmldeployment
from core.xml.corexml import CoreXmlReader, CoreXmlWriter from core.xml.corexml import CoreXmlReader, CoreXmlWriter
# maps for converting from API call node type values to classes and vice versa
NODES = {
NodeTypes.DEFAULT: CoreNode,
NodeTypes.PHYSICAL: PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: SwitchNode,
NodeTypes.HUB: HubNode,
NodeTypes.WIRELESS_LAN: WlanNode,
NodeTypes.RJ45: Rj45Node,
NodeTypes.TUNNEL: TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNode,
NodeTypes.EMANE_NET: EmaneNet,
NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: PtpNet,
NodeTypes.CONTROL_NET: CtrlNet,
NodeTypes.DOCKER: DockerNode,
NodeTypes.LXC: LxcNode,
}
NODES_TYPE = {NODES[x]: x for x in NODES}
class Session(object): class Session(object):
""" """
@ -121,6 +152,33 @@ class Session(object):
"host": ("DefaultRoute", "SSH"), "host": ("DefaultRoute", "SSH"),
} }
@classmethod
def get_node_class(cls, _type):
"""
Retrieve the class for a given node type.
:param core.emulator.enumerations.NodeTypes _type: node type to get class for
:return: node class
"""
node_class = NODES.get(_type)
if node_class is None:
raise CoreError("invalid node type: %s" % _type)
return node_class
@classmethod
def get_node_type(cls, _class):
"""
Retrieve node type for a given node class.
:param _class: node class to get a node type for
:return: node type
:rtype: core.emulator.enumerations.NodeTypes
"""
node_type = NODES_TYPE.get(_class)
if node_type is None:
raise CoreError("invalid node class: %s" % _class)
return node_type
def _link_nodes(self, node_one_id, node_two_id): def _link_nodes(self, node_one_id, node_two_id):
""" """
Convenience method for retrieving nodes within link data. Convenience method for retrieving nodes within link data.
@ -145,7 +203,7 @@ class Session(object):
# both node ids are provided # both node ids are provided
tunnel = self.broker.gettunnel(node_one_id, node_two_id) tunnel = self.broker.gettunnel(node_one_id, node_two_id)
logging.debug("tunnel between nodes: %s", tunnel) logging.debug("tunnel between nodes: %s", tunnel)
if nodeutils.is_node(tunnel, NodeTypes.TAP_BRIDGE): if isinstance(tunnel, GreTapBridge):
net_one = tunnel net_one = tunnel
if tunnel.remotenum == node_one_id: if tunnel.remotenum == node_one_id:
node_one = None node_one = None
@ -158,14 +216,14 @@ class Session(object):
else: else:
node_two = None node_two = None
if is_net_node(node_one): if isinstance(node_one, CoreNetworkBase):
if not net_one: if not net_one:
net_one = node_one net_one = node_one
else: else:
net_two = node_one net_two = node_one
node_one = None node_one = None
if is_net_node(node_two): if isinstance(node_two, CoreNetworkBase):
if not net_one: if not net_one:
net_one = node_two net_one = node_two
else: else:
@ -203,9 +261,7 @@ class Session(object):
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 nodeutils.is_node( if not isinstance(common_network, (WlanNode, EmaneNode)):
common_network, [NodeTypes.WIRELESS_LAN, NodeTypes.EMANE]
):
logging.info( logging.info(
"skipping common network that is not wireless/emane: %s", "skipping common network that is not wireless/emane: %s",
common_network, common_network,
@ -268,9 +324,8 @@ class Session(object):
node_one.name, node_one.name,
node_two.name, node_two.name,
) )
ptp_class = nodeutils.get_node_class(NodeTypes.PEER_TO_PEER)
start = self.state > EventTypes.DEFINITION_STATE.value start = self.state > EventTypes.DEFINITION_STATE.value
net_one = self.create_node(cls=ptp_class, start=start) net_one = self.create_node(cls=PtpNet, start=start)
# node to network # node to network
if node_one and net_one: if node_one and net_one:
@ -300,7 +355,7 @@ class Session(object):
net_one.name, net_one.name,
net_two.name, net_two.name,
) )
if nodeutils.is_node(net_two, NodeTypes.RJ45): if isinstance(net_two, Rj45Node):
interface = net_two.linknet(net_one) interface = net_two.linknet(net_one)
else: else:
interface = net_one.linknet(net_two) interface = net_one.linknet(net_two)
@ -324,12 +379,12 @@ class Session(object):
# tunnel node logic # tunnel node logic
key = link_options.key key = link_options.key
if key and nodeutils.is_node(net_one, NodeTypes.TUNNEL): if key and isinstance(net_one, TunnelNode):
logging.info("setting tunnel key for: %s", net_one.name) logging.info("setting tunnel key for: %s", net_one.name)
net_one.setkey(key) net_one.setkey(key)
if addresses: if addresses:
net_one.addrconfig(addresses) net_one.addrconfig(addresses)
if key and nodeutils.is_node(net_two, NodeTypes.TUNNEL): if key and isinstance(net_two, TunnelNode):
logging.info("setting tunnel key for: %s", net_two.name) logging.info("setting tunnel key for: %s", net_two.name)
net_two.setkey(key) net_two.setkey(key)
if addresses: if addresses:
@ -337,14 +392,14 @@ class Session(object):
# physical node connected with tunnel # physical node connected with tunnel
if not net_one and not net_two and (node_one or node_two): if not net_one and not net_two and (node_one or node_two):
if node_one and nodeutils.is_node(node_one, NodeTypes.PHYSICAL): if node_one and isinstance(node_one, PhysicalNode):
logging.info("adding link for physical node: %s", node_one.name) logging.info("adding link for physical node: %s", node_one.name)
addresses = interface_one.get_addresses() addresses = interface_one.get_addresses()
node_one.adoptnetif( node_one.adoptnetif(
tunnel, interface_one.id, interface_one.mac, addresses tunnel, interface_one.id, interface_one.mac, addresses
) )
link_config(node_one, tunnel, link_options) link_config(node_one, tunnel, link_options)
elif node_two and nodeutils.is_node(node_two, NodeTypes.PHYSICAL): elif node_two and isinstance(node_two, PhysicalNode):
logging.info("adding link for physical node: %s", node_two.name) logging.info("adding link for physical node: %s", node_two.name)
addresses = interface_two.get_addresses() addresses = interface_two.get_addresses()
node_two.adoptnetif( node_two.adoptnetif(
@ -584,14 +639,11 @@ class Session(object):
:param int _id: id for node, defaults to None for generated id :param int _id: id for node, defaults to None for generated id
:param core.emulator.emudata.NodeOptions node_options: data to create node with :param core.emulator.emudata.NodeOptions node_options: data to create node with
:return: created node :return: created node
:raises core.CoreError: when an invalid node type is given
""" """
# retrieve node class for given node type # validate node type, get class, or throw error
try: node_class = self.get_node_class(_type)
node_class = nodeutils.get_node_class(_type)
except KeyError:
logging.error("invalid node type to create: %s", _type)
return None
# set node start based on current session state, override and check when rj45 # set node start based on current session state, override and check when rj45
start = self.state > EventTypes.DEFINITION_STATE.value start = self.state > EventTypes.DEFINITION_STATE.value
@ -651,10 +703,8 @@ class Session(object):
logging.debug("set node type: %s", node.type) logging.debug("set node type: %s", node.type)
self.services.add_services(node, node.type, node_options.services) self.services.add_services(node, node.type, node_options.services)
# boot nodes if created after runtime, LcxNodes, Physical, and RJ45 are all PyCoreNodes # boot nodes if created after runtime, CoreNodes, Physical, and RJ45 are all nodes
is_boot_node = isinstance(node, CoreNodeBase) and not nodeutils.is_node( is_boot_node = isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node)
node, NodeTypes.RJ45
)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node: if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
self.write_nodes() self.write_nodes()
self.add_remove_control_interface(node=node, remove=False) self.add_remove_control_interface(node=node, remove=False)
@ -1441,12 +1491,10 @@ class Session(object):
count = 0 count = 0
for node_id in self.nodes: for node_id in self.nodes:
node = self.nodes[node_id] node = self.nodes[node_id]
is_p2p_ctrlnet = nodeutils.is_node( is_p2p_ctrlnet = isinstance(node, (PtpNet, CtrlNet))
node, (NodeTypes.PEER_TO_PEER, NodeTypes.CONTROL_NET) is_tap = isinstance(node, GreTapBridge) and not isinstance(
node, TunnelNode
) )
is_tap = nodeutils.is_node(
node, NodeTypes.TAP_BRIDGE
) and not nodeutils.is_node(node, NodeTypes.TUNNEL)
if is_p2p_ctrlnet or is_tap: if is_p2p_ctrlnet or is_tap:
continue continue
@ -1493,7 +1541,7 @@ class Session(object):
for node_id in self.nodes: for node_id in self.nodes:
node = self.nodes[node_id] node = self.nodes[node_id]
# TODO: determine if checking for CoreNode alone is ok # TODO: determine if checking for CoreNode alone is ok
if isinstance(node, core.nodes.base.CoreNodeBase): if isinstance(node, CoreNodeBase):
self.services.stop_services(node) self.services.stop_services(node)
# shutdown emane # shutdown emane
@ -1546,10 +1594,7 @@ class Session(object):
start = time.time() start = time.time()
for _id in self.nodes: for _id in self.nodes:
node = self.nodes[_id] node = self.nodes[_id]
# TODO: PyCoreNode is not the type to check if isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node):
if isinstance(node, CoreNodeBase) and not nodeutils.is_node(
node, NodeTypes.RJ45
):
# add a control interface if configured # add a control interface if configured
logging.info( logging.info(
"booting node(%s): %s", "booting node(%s): %s",
@ -1648,8 +1693,7 @@ class Session(object):
# no controlnet needed # no controlnet needed
return None return None
else: else:
control_net_class = nodeutils.get_node_class(NodeTypes.CONTROL_NET) prefix_spec = CtrlNet.DEFAULT_PREFIX_LIST[net_index]
prefix_spec = control_net_class.DEFAULT_PREFIX_LIST[net_index]
logging.debug("prefix spec: %s", prefix_spec) logging.debug("prefix spec: %s", prefix_spec)
server_interface = self.get_control_net_server_interfaces()[net_index] server_interface = self.get_control_net_server_interfaces()[net_index]
@ -1725,9 +1769,8 @@ class Session(object):
prefix = prefixes[0] prefix = prefixes[0]
logging.info("controlnet prefix: %s - %s", type(prefix), prefix) logging.info("controlnet prefix: %s - %s", type(prefix), prefix)
control_net_class = nodeutils.get_node_class(NodeTypes.CONTROL_NET)
control_net = self.create_node( control_net = self.create_node(
cls=control_net_class, cls=CtrlNet,
_id=_id, _id=_id,
prefix=prefix, prefix=prefix,
assign_address=assign_address, assign_address=assign_address,

View file

@ -17,8 +17,9 @@ from socket import AF_INET, AF_INET6
from core import CoreCommandError, constants, utils from core import CoreCommandError, constants, utils
from core.emulator.data import LinkData, NodeData from core.emulator.data import LinkData, NodeData
from core.emulator.enumerations import LinkTypes, NodeTypes from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes import client, ipaddress, nodeutils from core.nodes import client, ipaddress
from core.nodes.interface import CoreInterface, TunTap, Veth from core.nodes.interface import CoreInterface, TunTap, Veth
from core.nodes.netclient import LinuxNetClient, OvsNetClient
_DEFAULT_MTU = 1500 _DEFAULT_MTU = 1500
@ -886,8 +887,8 @@ class CoreNode(CoreNodeBase):
addrlist = [] addrlist = []
with self.lock: with self.lock:
# TODO: see if you can move this to emane specific code # TODO: emane specific code
if nodeutils.is_node(net, NodeTypes.EMANE): if net.is_emane is True:
ifindex = self.newtuntap(ifindex=ifindex, ifname=ifname, net=net) ifindex = self.newtuntap(ifindex=ifindex, ifname=ifname, net=net)
# TUN/TAP is not ready for addressing yet; the device may # TUN/TAP is not ready for addressing yet; the device may
# take some time to appear, and installing it into a # take some time to appear, and installing it into a
@ -1050,6 +1051,7 @@ class CoreNetworkBase(NodeBase):
""" """
linktype = LinkTypes.WIRED.value linktype = LinkTypes.WIRED.value
is_emane = False
def __init__(self, session, _id, name, start=True): def __init__(self, session, _id, name, start=True):
""" """
@ -1063,6 +1065,10 @@ class CoreNetworkBase(NodeBase):
super(CoreNetworkBase, self).__init__(session, _id, name, start=start) super(CoreNetworkBase, self).__init__(session, _id, name, start=start)
self._linked = {} self._linked = {}
self._linked_lock = threading.Lock() self._linked_lock = threading.Lock()
if session.options.get_config("ovs") == "True":
self.net_client = OvsNetClient()
else:
self.net_client = LinuxNetClient()
def startup(self): def startup(self):
""" """

View file

@ -7,8 +7,6 @@ import time
from builtins import int, range from builtins import int, range
from core import CoreCommandError, constants, utils from core import CoreCommandError, constants, utils
from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
utils.check_executables([constants.IP_BIN]) utils.check_executables([constants.IP_BIN])
@ -387,13 +385,12 @@ class TunTap(CoreInterface):
if result: if result:
break break
# TODO: emane specific code
# check if this is an EMANE interface; if so, continue # check if this is an EMANE interface; if so, continue
# waiting if EMANE is still running # waiting if EMANE is still running
# TODO: remove emane code
should_retry = count < 5 should_retry = count < 5
is_emane_node = nodeutils.is_node(self.net, NodeTypes.EMANE)
is_emane_running = self.node.session.emane.emanerunning(self.node) is_emane_running = self.node.session.emane.emanerunning(self.node)
if all([should_retry, is_emane_node, is_emane_running]): if all([should_retry, self.net.is_emane, is_emane_running]):
count += 1 count += 1
else: else:
raise RuntimeError("node device failed to exist") raise RuntimeError("node device failed to exist")

View file

@ -0,0 +1,233 @@
"""
Clients for dealing with bridge/interface commands.
"""
import abc
import os
from future.utils import with_metaclass
from core.constants import BRCTL_BIN, IP_BIN, OVS_BIN
from core.utils import check_cmd
class NetClientBase(with_metaclass(abc.ABCMeta)):
"""
Base client for running command line bridge/interface commands.
"""
@abc.abstractmethod
def create_bridge(self, name):
"""
Create a network bridge to connect interfaces to.
:param str name: bridge name
:return: nothing
"""
pass
@abc.abstractmethod
def delete_bridge(self, name):
"""
Delete a network bridge.
:param str name: bridge name
:return: nothing
"""
pass
@abc.abstractmethod
def create_interface(self, bridge_name, interface_name):
"""
Create an interface associated with a network bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
pass
@abc.abstractmethod
def delete_interface(self, bridge_name, interface_name):
"""
Delete an interface associated with a network bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
pass
@abc.abstractmethod
def existing_bridges(self, _id):
"""
Checks if there are any existing bridges for a node.
:param _id: node id to check bridges for
"""
pass
@abc.abstractmethod
def disable_mac_learning(self, name):
"""
Disable mac learning for a bridge.
:param str name: bridge name
:return: nothing
"""
pass
class LinuxNetClient(NetClientBase):
"""
Client for creating Linux bridges and ip interfaces for nodes.
"""
def create_bridge(self, name):
"""
Create a Linux bridge and bring it up.
:param str name: bridge name
:return: nothing
"""
check_cmd([BRCTL_BIN, "addbr", name])
check_cmd([BRCTL_BIN, "stp", name, "off"])
check_cmd([BRCTL_BIN, "setfd", name, "0"])
check_cmd([IP_BIN, "link", "set", name, "up"])
# turn off multicast snooping so forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % name
if os.path.exists(snoop):
with open(snoop, "w") as f:
f.write("0")
def delete_bridge(self, name):
"""
Bring down and delete a Linux bridge.
:param str name: bridge name
:return: nothing
"""
check_cmd([IP_BIN, "link", "set", name, "down"])
check_cmd([BRCTL_BIN, "delbr", name])
def create_interface(self, bridge_name, interface_name):
"""
Create an interface associated with a Linux bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
check_cmd([BRCTL_BIN, "addif", bridge_name, interface_name])
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name):
"""
Delete an interface associated with a Linux bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
check_cmd([BRCTL_BIN, "delif", bridge_name, interface_name])
def existing_bridges(self, _id):
"""
Checks if there are any existing Linux bridges for a node.
:param _id: node id to check bridges for
"""
output = check_cmd([BRCTL_BIN, "show"])
lines = output.split("\n")
for line in lines[1:]:
columns = line.split()
name = columns[0]
fields = name.split(".")
if len(fields) != 3:
continue
if fields[0] == "b" and fields[1] == _id:
return True
return False
def disable_mac_learning(self, name):
"""
Disable mac learning for a Linux bridge.
:param str name: bridge name
:return: nothing
"""
check_cmd([BRCTL_BIN, "setageing", name, "0"])
class OvsNetClient(NetClientBase):
"""
Client for creating OVS bridges and ip interfaces for nodes.
"""
def create_bridge(self, name):
"""
Create a OVS bridge and bring it up.
:param str name: bridge name
:return: nothing
"""
check_cmd([OVS_BIN, "add-br", name])
check_cmd([OVS_BIN, "set", "bridge", name, "stp_enable=false"])
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:stp-max-age=6"])
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:stp-forward-delay=4"])
check_cmd([IP_BIN, "link", "set", name, "up"])
def delete_bridge(self, name):
"""
Bring down and delete a OVS bridge.
:param str name: bridge name
:return: nothing
"""
check_cmd([IP_BIN, "link", "set", name, "down"])
check_cmd([OVS_BIN, "del-br", name])
def create_interface(self, bridge_name, interface_name):
"""
Create an interface associated with a network bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
check_cmd([OVS_BIN, "add-port", bridge_name, interface_name])
check_cmd([IP_BIN, "link", "set", interface_name, "up"])
def delete_interface(self, bridge_name, interface_name):
"""
Delete an interface associated with a OVS bridge.
:param str bridge_name: bridge name
:param str interface_name: interface name
:return: nothing
"""
check_cmd([OVS_BIN, "del-port", bridge_name, interface_name])
def existing_bridges(self, _id):
"""
Checks if there are any existing OVS bridges for a node.
:param _id: node id to check bridges for
"""
output = check_cmd([OVS_BIN, "list-br"])
if output:
for line in output.split("\n"):
fields = line.split(".")
if fields[0] == "b" and fields[1] == _id:
return True
return False
def disable_mac_learning(self, name):
"""
Disable mac learning for a OVS bridge.
:param str name: bridge name
:return: nothing
"""
check_cmd([OVS_BIN, "set", "bridge", name, "other_config:mac-aging-time=0"])

View file

@ -9,7 +9,7 @@ import threading
import time import time
from socket import AF_INET, AF_INET6 from socket import AF_INET, AF_INET6
from core import CoreCommandError, constants, utils from core import CoreCommandError, CoreError, constants, utils
from core.emulator.data import LinkData from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress from core.nodes import ipaddress
@ -314,12 +314,8 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing :return: nothing
:raises CoreCommandError: when there is a command exception :raises CoreCommandError: when there is a command exception
""" """
utils.check_cmd([constants.BRCTL_BIN, "addbr", self.brname]) self.net_client.create_bridge(self.brname)
# turn off spanning tree protocol and forwarding delay
utils.check_cmd([constants.BRCTL_BIN, "stp", self.brname, "off"])
utils.check_cmd([constants.BRCTL_BIN, "setfd", self.brname, "0"])
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "up"])
# create a new ebtables chain for this bridge # create a new ebtables chain for this bridge
ebtablescmds( ebtablescmds(
utils.check_cmd, utils.check_cmd,
@ -336,11 +332,6 @@ class CoreNetwork(CoreNetworkBase):
], ],
], ],
) )
# turn off multicast snooping so mcast forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % self.brname
if os.path.exists(snoop):
with open(snoop, "w") as snoop_file:
snoop_file.write("0")
self.up = True self.up = True
@ -356,8 +347,7 @@ class CoreNetwork(CoreNetworkBase):
ebq.stopupdateloop(self) ebq.stopupdateloop(self)
try: try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "down"]) self.net_client.delete_bridge(self.brname)
utils.check_cmd([constants.BRCTL_BIN, "delbr", self.brname])
ebtablescmds( ebtablescmds(
utils.check_cmd, utils.check_cmd,
[ [
@ -385,7 +375,8 @@ class CoreNetwork(CoreNetworkBase):
del self.session del self.session
self.up = False self.up = False
# TODO: this depends on a subtype with localname defined, seems like the wrong place for this to live # TODO: this depends on a subtype with localname defined, seems like the
# wrong place for this to live
def attach(self, netif): def attach(self, netif):
""" """
Attach a network interface. Attach a network interface.
@ -394,10 +385,7 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing :return: nothing
""" """
if self.up: if self.up:
utils.check_cmd( self.net_client.create_interface(self.brname, netif.localname)
[constants.BRCTL_BIN, "addif", self.brname, netif.localname]
)
utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
CoreNetworkBase.attach(self, netif) CoreNetworkBase.attach(self, netif)
@ -409,9 +397,7 @@ class CoreNetwork(CoreNetworkBase):
:return: nothing :return: nothing
""" """
if self.up: if self.up:
utils.check_cmd( self.net_client.delete_interface(self.brname, netif.localname)
[constants.BRCTL_BIN, "delif", self.brname, netif.localname]
)
CoreNetworkBase.detach(self, netif) CoreNetworkBase.detach(self, netif)
@ -610,10 +596,8 @@ class CoreNetwork(CoreNetworkBase):
) )
self.attach(netif) self.attach(netif)
if net.up: if net.up:
# this is similar to net.attach() but uses netif.name instead # this is similar to net.attach() but uses netif.name instead of localname
# of localname self.net_client.create_interface(net.brname, netif.name)
utils.check_cmd([constants.BRCTL_BIN, "addif", net.brname, netif.name])
utils.check_cmd([constants.IP_BIN, "link", "set", netif.name, "up"])
i = net.newifindex() i = net.newifindex()
net._netif[i] = netif net._netif[i] = netif
with net._linked_lock: with net._linked_lock:
@ -822,8 +806,8 @@ class CtrlNet(CoreNetwork):
:return: nothing :return: nothing
:raises CoreCommandError: when there is a command exception :raises CoreCommandError: when there is a command exception
""" """
if self.detectoldbridge(): if self.net_client.existing_bridges(self.id):
return raise CoreError("old bridges exist for node: %s" % self.id)
CoreNetwork.startup(self) CoreNetwork.startup(self)
@ -848,42 +832,7 @@ class CtrlNet(CoreNetwork):
utils.check_cmd([self.updown_script, self.brname, "startup"]) utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf: if self.serverintf:
# sets the interface as a port of the bridge self.net_client.create_interface(self.brname, self.serverintf)
utils.check_cmd(
[constants.BRCTL_BIN, "addif", self.brname, self.serverintf]
)
# bring interface up
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
"""
Occasionally, control net bridges from previously closed sessions are not cleaned up.
Check if there are old control net bridges and delete them
:return: True if an old bridge was detected, False otherwise
:rtype: bool
"""
status, output = utils.cmd_output([constants.BRCTL_BIN, "show"])
if status != 0:
logging.error("Unable to retrieve list of installed bridges")
else:
lines = output.split("\n")
for line in lines[1:]:
cols = line.split("\t")
oldbr = cols[0]
flds = cols[0].split(".")
if len(flds) == 3:
if flds[0] == "b" and flds[1] == self.id:
logging.error(
"error: An active control net bridge (%s) found. "
"An older session might still be running. "
"Stop all sessions and, if needed, delete %s to continue.",
oldbr,
oldbr,
)
return True
return False
def shutdown(self): def shutdown(self):
""" """
@ -893,9 +842,7 @@ class CtrlNet(CoreNetwork):
""" """
if self.serverintf is not None: if self.serverintf is not None:
try: try:
utils.check_cmd( self.net_client.delete_interface(self.brname, self.serverintf)
[constants.BRCTL_BIN, "delif", self.brname, self.serverintf]
)
except CoreCommandError: except CoreCommandError:
logging.exception( logging.exception(
"error deleting server interface %s from bridge %s", "error deleting server interface %s from bridge %s",
@ -1100,7 +1047,7 @@ class HubNode(CoreNetwork):
# TODO: move to startup method # TODO: move to startup method
if start: if start:
utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"]) self.net_client.disable_mac_learning(self.brname)
class WlanNode(CoreNetwork): class WlanNode(CoreNetwork):
@ -1131,7 +1078,7 @@ class WlanNode(CoreNetwork):
# TODO: move to startup method # TODO: move to startup method
if start: if start:
utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"]) self.net_client.disable_mac_learning(self.brname)
def attach(self, netif): def attach(self, netif):
""" """

View file

@ -1,32 +0,0 @@
"""
Provides default node maps that can be used to run core with.
"""
import core.nodes.base
import core.nodes.docker
import core.nodes.lxd
import core.nodes.network
import core.nodes.physical
from core.emane.nodes import EmaneNet, EmaneNode
from core.emulator.enumerations import NodeTypes
from core.nodes import physical
from core.nodes.network import GreTapBridge
# legacy core nodes, that leverage linux bridges
NODES = {
NodeTypes.DEFAULT: core.nodes.base.CoreNode,
NodeTypes.PHYSICAL: physical.PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: core.nodes.network.SwitchNode,
NodeTypes.HUB: core.nodes.network.HubNode,
NodeTypes.WIRELESS_LAN: core.nodes.network.WlanNode,
NodeTypes.RJ45: core.nodes.physical.Rj45Node,
NodeTypes.TUNNEL: core.nodes.network.TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNode,
NodeTypes.EMANE_NET: EmaneNet,
NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: core.nodes.network.PtpNet,
NodeTypes.CONTROL_NET: core.nodes.network.CtrlNet,
NodeTypes.DOCKER: core.nodes.docker.DockerNode,
NodeTypes.LXC: core.nodes.lxd.LxcNode,
}

View file

@ -1,97 +0,0 @@
"""
Serves as a global point for storing and retrieving node types needed during simulation.
"""
import logging
_NODE_MAP = None
def _log_map():
global _NODE_MAP
for key in _NODE_MAP:
value = _NODE_MAP[key]
name = None
if value:
name = value.__name__
logging.debug("node type (%s) - class (%s)", key.name, name)
def _convert_map(x, y):
"""
Convenience method to create a human readable version of the node map to log.
:param dict x: dictionary to reduce node items into
:param tuple y: current node item
:return: human readable name mapping of the node map
"""
x[y[0].name] = y[1]
return x
def update_node_map(node_map):
"""
Update the current node map with the provided node map values.
:param dict node_map: node map to update with
"""
global _NODE_MAP
_NODE_MAP.update(node_map)
_log_map()
def set_node_map(node_map):
"""
Set the global node map that proides a consistent way to retrieve differently configured nodes.
:param dict node_map: node map to set to
:return: nothing
"""
global _NODE_MAP
_NODE_MAP = node_map
_log_map()
def get_node_class(node_type):
"""
Retrieve the node class for a given node type.
:param int node_type: node type to retrieve class for
:return: node class
"""
global _NODE_MAP
return _NODE_MAP[node_type]
def get_node_type(node_class):
"""
Retrieve the node type given a node class.
:param class node_class: node class to get type for
:return: node type
:rtype: core.emulator.enumerations.NodeTypes
"""
global _NODE_MAP
node_type_map = {_NODE_MAP[x]: x for x in _NODE_MAP}
return node_type_map.get(node_class)
def is_node(obj, node_types):
"""
Validates if an object is one of the provided node types.
:param obj: object to check type for
:param int|tuple|list node_types: node type(s) to check against
:return: True if the object is one of the node types, False otherwise
:rtype: bool
"""
type_classes = []
if isinstance(node_types, (tuple, list)):
for node_type in node_types:
type_class = get_node_class(node_type)
type_classes.append(type_class)
else:
type_class = get_node_class(node_types)
type_classes.append(type_class)
return isinstance(obj, tuple(type_classes))

View file

@ -1,825 +0,0 @@
"""
TODO: probably goes away, or implement the usage of "unshare", or docker formal.
"""
import logging
import socket
import threading
from socket import AF_INET, AF_INET6
from core import CoreCommandError, constants, utils
from core.emulator.data import LinkData
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
from core.nodes import ipaddress
from core.nodes.base import CoreNetworkBase
from core.nodes.interface import GreTap, Veth
from core.nodes.network import EbtablesQueue, GreTapBridge
# a global object because all WLANs share the same queue
# cannot have multiple threads invoking the ebtables commnd
ebtables_queue = EbtablesQueue()
ebtables_lock = threading.Lock()
utils.check_executables([constants.IP_BIN, constants.EBTABLES_BIN, constants.TC_BIN])
def ebtables_commands(call, commands):
with ebtables_lock:
for command in commands:
call(command)
class OvsNet(CoreNetworkBase):
"""
Used to be LxBrNet.
Base class for providing Openvswitch functionality to objects that create bridges.
"""
policy = "DROP"
def __init__(self, session, _id=None, name=None, start=True, policy=None):
"""
Creates an OvsNet instance.
:param core.emulator.session.Session session: session this object is a part of
:param int _id: object id
:param str name: object name
:param bool start: start flag
:param policy: network policy
"""
CoreNetworkBase.__init__(self, session, _id, name, start)
if policy:
self.policy = policy
else:
self.policy = self.__class__.policy
session_id = self.session.short_session_id()
self.bridge_name = "b.%s.%s" % (str(self.id), session_id)
self.up = False
if start:
self.startup()
ebtables_queue.startupdateloop(self)
def startup(self):
"""
:return:
:raises CoreCommandError: when there is a command exception
"""
utils.check_cmd([constants.OVS_BIN, "add-br", self.bridge_name])
# turn off spanning tree protocol and forwarding delay
# TODO: appears stp and rstp are off by default, make sure this always holds true
# TODO: apears ovs only supports rstp forward delay and again it's off by default
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "up"])
# create a new ebtables chain for this bridge
ebtables_commands(
utils.check_cmd,
[
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[
constants.EBTABLES_BIN,
"-A",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
],
)
self.up = True
def shutdown(self):
if not self.up:
logging.info("exiting shutdown, object is not up")
return
ebtables_queue.stopupdateloop(self)
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "down"])
utils.check_cmd([constants.OVS_BIN, "del-br", self.bridge_name])
ebtables_commands(
utils.check_cmd,
[
[
constants.EBTABLES_BIN,
"-D",
"FORWARD",
"--logical-in",
self.bridge_name,
"-j",
self.bridge_name,
],
[constants.EBTABLES_BIN, "-X", self.bridge_name],
],
)
except CoreCommandError:
logging.exception("error bringing bridge down and removing it")
# removes veth pairs used for bridge-to-bridge connections
for interface in self.netifs():
interface.shutdown()
self._netif.clear()
self._linked.clear()
del self.session
self.up = False
def attach(self, interface):
if self.up:
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, interface.localname]
)
utils.check_cmd(
[constants.IP_BIN, "link", "set", interface.localname, "up"]
)
CoreNetworkBase.attach(self, interface)
def detach(self, interface):
if self.up:
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, interface.localname]
)
CoreNetworkBase.detach(self, interface)
def linked(self, interface_one, interface_two):
# check if the network interfaces are attached to this network
if self._netif[interface_one.netifi] != interface_one:
raise ValueError("inconsistency for interface %s" % interface_one.name)
if self._netif[interface_two.netifi] != interface_two:
raise ValueError("inconsistency for interface %s" % interface_two.name)
try:
linked = self._linked[interface_one][interface_two]
except KeyError:
if self.policy == "ACCEPT":
linked = True
elif self.policy == "DROP":
linked = False
else:
raise ValueError("unknown policy: %s" % self.policy)
self._linked[interface_one][interface_two] = linked
return linked
def unlink(self, interface_one, interface_two):
"""
Unlink two PyCoreNetIfs, resulting in adding or removing ebtables
filtering rules.
"""
with self._linked_lock:
if not self.linked(interface_one, interface_two):
return
self._linked[interface_one][interface_two] = False
ebtables_queue.ebchange(self)
def link(self, interface_one, interface_two):
"""
Link two interfaces together, resulting in adding or removing
ebtables filtering rules.
"""
with self._linked_lock:
if self.linked(interface_one, interface_two):
return
self._linked[interface_one][interface_two] = True
ebtables_queue.ebchange(self)
def linkconfig(
self,
netif,
bw=None,
delay=None,
loss=None,
duplicate=None,
jitter=None,
netif2=None,
devname=None,
):
"""
Configure link parameters by applying tc queuing disciplines on the
interface.
"""
if not devname:
devname = netif.localname
tc = [constants.TC_BIN, "qdisc", "replace", "dev", devname]
parent = ["root"]
# attempt to set bandwidth and update as needed if value changed
bandwidth_changed = netif.setparam("bw", bw)
if bandwidth_changed:
# from tc-tbf(8): minimum value for burst is rate / kernel_hz
if bw > 0:
if self.up:
burst = max(2 * netif.mtu, bw / 1000)
limit = 0xFFFF # max IP payload
tbf = [
"tbf",
"rate",
str(bw),
"burst",
str(burst),
"limit",
str(limit),
]
logging.info(
"linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf]
)
utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True)
elif netif.getparam("has_tbf") and bw <= 0:
tcd = [] + tc
tcd[2] = "delete"
if self.up:
utils.check_cmd(tcd + parent)
netif.setparam("has_tbf", False)
# removing the parent removes the child
netif.setparam("has_netem", False)
if netif.getparam("has_tbf"):
parent = ["parent", "1:1"]
netem = ["netem"]
delay_changed = netif.setparam("delay", delay)
if loss is not None:
loss = float(loss)
loss_changed = netif.setparam("loss", loss)
if duplicate is not None:
duplicate = int(duplicate)
duplicate_changed = netif.setparam("duplicate", duplicate)
jitter_changed = netif.setparam("jitter", jitter)
# if nothing changed return
if not any(
[
bandwidth_changed,
delay_changed,
loss_changed,
duplicate_changed,
jitter_changed,
]
):
return
# jitter and delay use the same delay statement
if delay is not None:
netem += ["delay", "%sus" % delay]
else:
netem += ["delay", "0us"]
if jitter is not None:
netem += ["%sus" % jitter, "25%"]
if loss is not None and loss > 0:
netem += ["loss", "%s%%" % min(loss, 100)]
if duplicate is not None and duplicate > 0:
netem += ["duplicate", "%s%%" % min(duplicate, 100)]
if delay <= 0 and jitter <= 0 and loss <= 0 and duplicate <= 0:
# possibly remove netem if it exists and parent queue wasn"t removed
if not netif.getparam("has_netem"):
return
tc[2] = "delete"
if self.up:
logging.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"]],))
utils.check_cmd(tc + parent + ["handle", "10:"])
netif.setparam("has_netem", False)
elif len(netem) > 1:
if self.up:
logging.info(
"linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)
)
utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True)
def linknet(self, network):
"""
Link this bridge with another by creating a veth pair and installing
each device into each bridge.
"""
session_id = self.session.short_session_id()
try:
_id = "%x" % self.id
except TypeError:
_id = "%s" % self.id
try:
network_id = "%x" % network.id
except TypeError:
network_id = "%s" % network.id
localname = "veth%s.%s.%s" % (_id, network_id, session_id)
if len(localname) >= 16:
raise ValueError("interface local name %s too long" % localname)
name = "veth%s.%s.%s" % (network_id, _id, session_id)
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
interface = Veth(
node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up
)
self.attach(interface)
if network.up:
# this is similar to net.attach() but uses netif.name instead of localname
utils.check_cmd(
[constants.OVS_BIN, "add-port", network.bridge_name, interface.name]
)
utils.check_cmd([constants.IP_BIN, "link", "set", interface.name, "up"])
network.attach(interface)
interface.net = self
interface.othernet = network
return interface
def getlinknetif(self, network):
"""
Return the interface of that links this net with another net
(that were linked using linknet()).
"""
for interface in self.netifs():
if hasattr(interface, "othernet") and interface.othernet == network:
return interface
return None
def addrconfig(self, addresses):
"""
Set addresses on the bridge.
"""
if not self.up:
return
for address in addresses:
utils.check_cmd(
[constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name]
)
class OvsCtrlNet(OvsNet):
policy = "ACCEPT"
CTRLIF_IDX_BASE = 99 # base control interface index
DEFAULT_PREFIX_LIST = [
"172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24",
"172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24",
"172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24",
"172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24",
]
def __init__(
self,
session,
_id="ctrlnet",
name=None,
prefix=None,
hostid=None,
start=True,
assign_address=True,
updown_script=None,
serverintf=None,
):
self.prefix = ipaddress.Ipv4Prefix(prefix)
self.hostid = hostid
self.assign_address = assign_address
self.updown_script = updown_script
self.serverintf = serverintf
OvsNet.__init__(self, session, _id=_id, name=name, start=start)
def startup(self):
if self.detectoldbridge():
return
OvsNet.startup(self)
if self.hostid:
addr = self.prefix.addr(self.hostid)
else:
addr = self.prefix.max_addr()
message = "Added control network bridge: %s %s" % (
self.bridge_name,
self.prefix,
)
addresses = ["%s/%s" % (addr, self.prefix.prefixlen)]
if self.assign_address:
self.addrconfig(addresses=addresses)
message += " address %s" % addr
logging.info(message)
if self.updown_script:
logging.info(
"interface %s updown script %s startup called"
% (self.bridge_name, self.updown_script)
)
utils.check_cmd([self.updown_script, self.bridge_name, "startup"])
if self.serverintf:
utils.check_cmd(
[constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf]
)
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
def detectoldbridge(self):
"""
Occasionally, control net bridges from previously closed sessions are not cleaned up.
Check if there are old control net bridges and delete them
"""
output = utils.check_cmd([constants.OVS_BIN, "list-br"])
output = output.strip()
if output:
for line in output.split("\n"):
bride_name = line.split(".")
if bride_name[0] == "b" and bride_name[1] == self.id:
logging.error(
"older session may still be running with conflicting id for bridge: %s",
line,
)
return True
return False
def shutdown(self):
if self.serverintf:
try:
utils.check_cmd(
[constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf]
)
except CoreCommandError:
logging.exception(
"error deleting server interface %s to controlnet bridge %s",
self.serverintf,
self.bridge_name,
)
if self.updown_script:
try:
logging.info(
"interface %s updown script (%s shutdown) called",
self.bridge_name,
self.updown_script,
)
utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"])
except CoreCommandError:
logging.exception("error during updown script shutdown")
OvsNet.shutdown(self)
def all_link_data(self, flags):
"""
Do not include CtrlNet in link messages describing this session.
"""
return []
class OvsPtpNet(OvsNet):
policy = "ACCEPT"
def attach(self, interface):
if len(self._netif) >= 2:
raise ValueError(
"point-to-point links support at most 2 network interfaces"
)
OvsNet.attach(self, interface)
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
"""
return None
def all_link_data(self, flags):
"""
Build CORE API TLVs for a point-to-point link. One Link message describes this network.
"""
all_links = []
if len(self._netif) != 2:
return all_links
if1, if2 = self._netif.values()
unidirectional = 0
if if1.getparams() != if2.getparams():
unidirectional = 1
interface1_ip4 = None
interface1_ip4_mask = None
interface1_ip6 = None
interface1_ip6_mask = None
for address in if1.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface1_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface1_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface1_ip6_mask = mask
interface2_ip4 = None
interface2_ip4_mask = None
interface2_ip6 = None
interface2_ip6_mask = None
for address in if2.addrlist:
ip, _sep, mask = address.partition("/")
mask = int(mask)
if ipaddress.is_ipv4_address(ip):
family = AF_INET
ipl = socket.inet_pton(family, ip)
interface2_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip4_mask = mask
else:
family = AF_INET6
ipl = socket.inet_pton(family, ip)
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip6_mask = mask
# TODO: not currently used
# loss=netif.getparam("loss")
link_data = LinkData(
message_type=flags,
node1_id=if1.node.id,
node2_id=if2.node.id,
link_type=self.linktype,
unidirectional=unidirectional,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
interface1_id=if1.node.getifindex(if1),
interface1_mac=if1.hwaddr,
interface1_ip4=interface1_ip4,
interface1_ip4_mask=interface1_ip4_mask,
interface1_ip6=interface1_ip6,
interface1_ip6_mask=interface1_ip6_mask,
interface2_id=if2.node.getifindex(if2),
interface2_mac=if2.hwaddr,
interface2_ip4=interface2_ip4,
interface2_ip4_mask=interface2_ip4_mask,
interface2_ip6=interface2_ip6,
interface2_ip6_mask=interface2_ip6_mask,
)
all_links.append(link_data)
# build a 2nd link message for the upstream link parameters
# (swap if1 and if2)
if unidirectional:
link_data = LinkData(
message_type=0,
node1_id=if2.node.id,
node2_id=if1.node.id,
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),
interface2_id=if1.node.getifindex(if1),
)
all_links.append(link_data)
return all_links
class OvsSwitchNode(OvsNet):
apitype = NodeTypes.SWITCH.value
policy = "ACCEPT"
type = "lanswitch"
class OvsHubNode(OvsNet):
apitype = NodeTypes.HUB.value
policy = "ACCEPT"
type = "hub"
def __init__(self, session, _id=None, name=None, start=True):
"""
the Hub node forwards packets to all bridge ports by turning off
the MAC address learning
"""
OvsNet.__init__(self, session, _id, name, start)
if start:
# TODO: verify that the below flow accomplishes what is desired for a "HUB"
# TODO: replace "brctl setageing 0"
utils.check_cmd(
[constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"]
)
class OvsWlanNode(OvsNet):
apitype = NodeTypes.WIRELESS_LAN.value
linktype = LinkTypes.WIRELESS.value
policy = "DROP"
type = "wlan"
def __init__(self, session, _id=None, name=None, start=True, policy=None):
OvsNet.__init__(self, session, _id, name, start, policy)
# wireless model such as basic range
self.model = None
# mobility model such as scripted
self.mobility = None
def attach(self, interface):
OvsNet.attach(self, interface)
if self.model:
interface.poshook = self.model.position_callback
if interface.node is None:
return
x, y, z = interface.node.position.get()
# invokes any netif.poshook
interface.setposition(x, y, z)
# self.model.setlinkparams()
def setmodel(self, model, config=None):
"""
Mobility and wireless model.
"""
logging.info("adding model %s", model.name)
if model.type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, _id=self.id, config=config)
if self.model.position_callback:
for interface in self.netifs():
interface.poshook = self.model.position_callback
if interface.node is not None:
x, y, z = interface.node.position.get()
interface.poshook(interface, x, y, z)
self.model.setlinkparams()
elif model.type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, _id=self.id, config=config)
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.id)
logging.info(
"node(%s) updating model(%s): %s", self.id, self.model.name, config
)
self.model.set_configs(config, node_id=self.id)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.updateconfig()
def all_link_data(self, flags):
all_links = OvsNet.all_link_data(self, flags)
if self.model:
all_links.extend(self.model.all_link_data(flags))
return all_links
class OvsTunnelNode(GreTapBridge):
apitype = NodeTypes.TUNNEL.value
policy = "ACCEPT"
type = "tunnel"
class OvsGreTapBridge(OvsNet):
"""
A network consisting of a bridge with a gretap device for tunneling to
another system.
"""
def __init__(
self,
session,
remoteip=None,
_id=None,
name=None,
policy="ACCEPT",
localip=None,
ttl=255,
key=None,
start=True,
):
OvsNet.__init__(
self, session=session, _id=_id, name=name, policy=policy, start=False
)
self.grekey = key
if self.grekey is None:
self.grekey = self.session.id ^ self.id
self.localnum = None
self.remotenum = None
self.remoteip = remoteip
self.localip = localip
self.ttl = ttl
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(
node=self,
session=session,
remoteip=remoteip,
localip=localip,
ttl=ttl,
key=self.grekey,
)
if start:
self.startup()
def startup(self):
"""
Creates a bridge and adds the gretap device to it.
"""
OvsNet.startup(self)
if self.gretap:
self.attach(self.gretap)
def shutdown(self):
"""
Detach the gretap device and remove the bridge.
"""
if self.gretap:
self.detach(self.gretap)
self.gretap.shutdown()
self.gretap = None
OvsNet.shutdown(self)
def addrconfig(self, addresses):
"""
Set the remote tunnel endpoint. This is a one-time method for
creating the GreTap device, which requires the remoteip at startup.
The 1st address in the provided list is remoteip, 2nd optionally
specifies localip.
"""
if self.gretap:
raise ValueError("gretap already exists for %s" % self.name)
remoteip = addresses[0].split("/")[0]
localip = None
if len(addresses) > 1:
localip = addresses[1].split("/")[0]
self.gretap = GreTap(
session=self.session,
remoteip=remoteip,
localip=localip,
ttl=self.ttl,
key=self.grekey,
)
self.attach(self.gretap)
def setkey(self, key):
"""
Set the GRE key used for the GreTap device. This needs to be set
prior to instantiating the GreTap device (before addrconfig).
"""
self.grekey = key
OVS_NODES = {
NodeTypes.SWITCH: OvsSwitchNode,
NodeTypes.HUB: OvsHubNode,
NodeTypes.WIRELESS_LAN: OvsWlanNode,
NodeTypes.TUNNEL: OvsTunnelNode,
NodeTypes.TAP_BRIDGE: OvsGreTapBridge,
NodeTypes.PEER_TO_PEER: OvsPtpNet,
NodeTypes.CONTROL_NET: OvsCtrlNet,
}

View file

@ -8,6 +8,7 @@ import socket
from future.moves.urllib.parse import urlparse from future.moves.urllib.parse import urlparse
from core import CoreError, constants from core import CoreError, constants
from core.emane.nodes import EmaneNode
from core.emulator.enumerations import ( from core.emulator.enumerations import (
EventTypes, EventTypes,
LinkTlvs, LinkTlvs,
@ -17,8 +18,8 @@ from core.emulator.enumerations import (
NodeTlvs, NodeTlvs,
NodeTypes, NodeTypes,
) )
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase, NodeBase from core.nodes.base import CoreNetworkBase, NodeBase
from core.nodes.network import WlanNode
# TODO: A named tuple may be more appropriate, than abusing a class dict like this # TODO: A named tuple may be more appropriate, than abusing a class dict like this
@ -27,14 +28,13 @@ class Bunch(object):
Helper class for recording a collection of attributes. Helper class for recording a collection of attributes.
""" """
def __init__(self, **kwds): def __init__(self, **kwargs):
""" """
Create a Bunch instance. Create a Bunch instance.
:param dict kwds: keyword arguments :param dict kwargs: keyword arguments
:return:
""" """
self.__dict__.update(kwds) self.__dict__.update(kwargs)
class Sdt(object): class Sdt(object):
@ -365,9 +365,7 @@ class Sdt(object):
for net in nets: for net in nets:
all_links = net.all_link_data(flags=MessageFlags.ADD.value) all_links = net.all_link_data(flags=MessageFlags.ADD.value)
for link_data in all_links: for link_data in all_links:
is_wireless = nodeutils.is_node( is_wireless = isinstance(net, (WlanNode, EmaneNode))
net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)
)
wireless_link = link_data.message_type == LinkTypes.WIRELESS.value wireless_link = link_data.message_type == LinkTypes.WIRELESS.value
if is_wireless and link_data.node1_id == net.id: if is_wireless and link_data.node1_id == net.id:
continue continue
@ -401,7 +399,7 @@ class Sdt(object):
def handlenodemsg(self, msg): def handlenodemsg(self, msg):
""" """
Process a Node Message to add/delete or move a node on Process a Node Message to add/delete or move a node on
the SDT display. Node properties are found in session._objs or the SDT display. Node properties are found in a session or
self.remotes for remote nodes (or those not yet instantiated). self.remotes for remote nodes (or those not yet instantiated).
:param msg: node message to handle :param msg: node message to handle
@ -430,7 +428,8 @@ class Sdt(object):
model = "router" model = "router"
nodetype = model nodetype = model
elif nodetype is not None: elif nodetype is not None:
nodetype = nodeutils.get_node_class(NodeTypes(nodetype)).type nodetype = NodeTypes(nodetype)
nodetype = self.session.get_node_class(nodetype).type
net = True net = True
else: else:
nodetype = None nodetype = None
@ -509,6 +508,6 @@ class Sdt(object):
n = self.session.get_node(nodenum) n = self.session.get_node(nodenum)
except CoreError: except CoreError:
return False return False
if nodeutils.is_node(n, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)): if isinstance(n, (WlanNode, EmaneNode)):
return True return True
return False return False

View file

@ -1,5 +1,4 @@
from core.emulator.enumerations import NodeTypes from core.emane.nodes import EmaneNode
from core.nodes import nodeutils
from core.services.coreservices import CoreService from core.services.coreservices import CoreService
from core.xml import emanexml from core.xml import emanexml
@ -22,7 +21,7 @@ class EmaneTransportService(CoreService):
transport_commands = [] transport_commands = []
for interface in node.netifs(sort=True): for interface in node.netifs(sort=True):
network_node = node.session.get_node(interface.net.id) network_node = node.session.get_node(interface.net.id)
if nodeutils.is_node(network_node, NodeTypes.EMANE): if isinstance(network_node, EmaneNode):
config = node.session.emane.get_configs( config = node.session.emane.get_configs(
network_node.id, network_node.model.name network_node.id, network_node.model.name
) )

View file

@ -4,8 +4,10 @@ Assumes installation of FRR via https://deb.frrouting.org/
""" """
from core import constants from core import constants
from core.emulator.enumerations import LinkTypes, NodeTypes from core.emulator.enumerations import LinkTypes
from core.nodes import ipaddress, nodeutils from core.nodes import ipaddress
from core.nodes.network import PtpNet
from core.nodes.physical import Rj45Node
from core.services.coreservices import CoreService from core.services.coreservices import CoreService
@ -341,7 +343,7 @@ class FrrService(CoreService):
for peerifc in ifc.net.netifs(): for peerifc in ifc.net.netifs():
if peerifc == ifc: if peerifc == ifc:
continue continue
if nodeutils.is_node(peerifc, NodeTypes.RJ45): if isinstance(peerifc, Rj45Node):
return True return True
return False return False
@ -395,7 +397,7 @@ class FRROspfv2(FrrService):
Helper to detect whether interface is connected to a notional Helper to detect whether interface is connected to a notional
point-to-point link. point-to-point link.
""" """
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER): if isinstance(ifc.net, PtpNet):
return " ip ospf network point-to-point\n" return " ip ospf network point-to-point\n"
return "" return ""
@ -481,7 +483,7 @@ class FRROspfv3(FrrService):
Helper to detect whether interface is connected to a notional Helper to detect whether interface is connected to a notional
point-to-point link. point-to-point link.
""" """
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER): if isinstance(ifc.net, PtpNet):
return " ipv6 ospf6 network point-to-point\n" return " ipv6 ospf6 network point-to-point\n"
return "" return ""

View file

@ -3,8 +3,11 @@ quagga.py: defines routing services provided by Quagga.
""" """
from core import constants from core import constants
from core.emulator.enumerations import LinkTypes, NodeTypes from core.emane.nodes import EmaneNode
from core.nodes import ipaddress, nodeutils from core.emulator.enumerations import LinkTypes
from core.nodes import ipaddress
from core.nodes.network import PtpNet, WlanNode
from core.nodes.physical import Rj45Node
from core.services.coreservices import CoreService from core.services.coreservices import CoreService
@ -267,7 +270,7 @@ class QuaggaService(CoreService):
for peerifc in ifc.net.netifs(): for peerifc in ifc.net.netifs():
if peerifc == ifc: if peerifc == ifc:
continue continue
if nodeutils.is_node(peerifc, NodeTypes.RJ45): if isinstance(peerifc, Rj45Node):
return True return True
return False return False
@ -321,7 +324,7 @@ class Ospfv2(QuaggaService):
Helper to detect whether interface is connected to a notional Helper to detect whether interface is connected to a notional
point-to-point link. point-to-point link.
""" """
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER): if isinstance(ifc.net, PtpNet):
return " ip ospf network point-to-point\n" return " ip ospf network point-to-point\n"
return "" return ""
@ -407,7 +410,7 @@ class Ospfv3(QuaggaService):
Helper to detect whether interface is connected to a notional Helper to detect whether interface is connected to a notional
point-to-point link. point-to-point link.
""" """
if nodeutils.is_node(ifc.net, NodeTypes.PEER_TO_PEER): if isinstance(ifc.net, PtpNet):
return " ipv6 ospf6 network point-to-point\n" return " ipv6 ospf6 network point-to-point\n"
return "" return ""
@ -457,9 +460,7 @@ class Ospfv3mdr(Ospfv3):
cfg = cls.mtucheck(ifc) cfg = cls.mtucheck(ifc)
# Uncomment the following line to use Address Family Translation for IPv4 # Uncomment the following line to use Address Family Translation for IPv4
cfg += " ipv6 ospf6 instance-id 65\n" cfg += " ipv6 ospf6 instance-id 65\n"
if ifc.net is not None and nodeutils.is_node( if ifc.net is not None and isinstance(ifc.net, (WlanNode, EmaneNode)):
ifc.net, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)
):
return ( return (
cfg cfg
+ """\ + """\

View file

@ -4,11 +4,12 @@ from lxml import etree
import core.nodes.base import core.nodes.base
import core.nodes.physical import core.nodes.physical
from core.emane.nodes import EmaneNode
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
from core.emulator.enumerations import NodeTypes from core.emulator.enumerations import NodeTypes
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase from core.nodes.base import CoreNetworkBase
from core.nodes.ipaddress import MacAddress from core.nodes.ipaddress import MacAddress
from core.nodes.network import CtrlNet
def write_xml_file(xml_element, file_path, doctype=None): def write_xml_file(xml_element, file_path, doctype=None):
@ -408,7 +409,7 @@ class CoreXmlWriter(object):
is_network_or_rj45 = isinstance( is_network_or_rj45 = isinstance(
node, (core.nodes.base.CoreNetworkBase, core.nodes.physical.Rj45Node) node, (core.nodes.base.CoreNetworkBase, core.nodes.physical.Rj45Node)
) )
is_controlnet = nodeutils.is_node(node, NodeTypes.CONTROL_NET) is_controlnet = isinstance(node, CtrlNet)
if is_network_or_rj45 and not is_controlnet: if is_network_or_rj45 and not is_controlnet:
self.write_network(node) self.write_network(node)
# device node # device node
@ -457,7 +458,7 @@ class CoreXmlWriter(object):
interface_name = node_interface.name interface_name = node_interface.name
# check if emane interface # check if emane interface
if nodeutils.is_node(node_interface.net, NodeTypes.EMANE): if isinstance(node_interface.net, EmaneNode):
nem = node_interface.net.getnemid(node_interface) nem = node_interface.net.getnemid(node_interface)
add_attribute(interface, "nem", nem) add_attribute(interface, "nem", nem)

View file

@ -4,8 +4,8 @@ import socket
from lxml import etree from lxml import etree
from core import constants, utils from core import constants, utils
from core.emulator.enumerations import NodeTypes from core.emane.nodes import EmaneNode
from core.nodes import ipaddress, nodeutils from core.nodes import ipaddress
from core.nodes.base import CoreNodeBase from core.nodes.base import CoreNodeBase
@ -144,7 +144,7 @@ class CoreXmlDeployment(object):
for netif in node.netifs(): for netif in node.netifs():
emane_element = None emane_element = None
if nodeutils.is_node(netif.net, NodeTypes.EMANE): if isinstance(netif.net, EmaneNode):
emane_element = add_emane_interface(host_element, netif) emane_element = add_emane_interface(host_element, netif)
parent_element = host_element parent_element = host_element

View file

@ -44,12 +44,11 @@ def start_udp(mainserver, server_address):
mainserver.udpthread.start() mainserver.udpthread.start()
def cored(cfg, use_ovs): def cored(cfg):
""" """
Start the CoreServer object and enter the server loop. Start the CoreServer object and enter the server loop.
:param dict cfg: core configuration :param dict cfg: core configuration
:param bool use_ovs: flag to determine if ovs nodes should be used
:return: nothing :return: nothing
""" """
host = cfg["listenaddr"] host = cfg["listenaddr"]
@ -60,9 +59,6 @@ def cored(cfg, use_ovs):
try: try:
address = (host, port) address = (host, port)
server = CoreServer(address, CoreHandler, cfg) server = CoreServer(address, CoreHandler, cfg)
if use_ovs:
from core.nodes.openvswitch import OVS_NODES
server.coreemu.update_nodes(OVS_NODES)
except: except:
logging.exception("error starting main server on: %s:%s", host, port) logging.exception("error starting main server on: %s:%s", host, port)
sys.exit(1) sys.exit(1)
@ -156,11 +152,8 @@ def main():
cfg = get_merged_config("%s/core.conf" % constants.CORE_CONF_DIR) cfg = get_merged_config("%s/core.conf" % constants.CORE_CONF_DIR)
banner() banner()
# check if ovs flag was provided
use_ovs = len(sys.argv) == 2 and sys.argv[1] == "ovs"
try: try:
cored(cfg, use_ovs) cored(cfg)
except KeyboardInterrupt: except KeyboardInterrupt:
logging.info("keyboard interrupt, stopping core daemon") logging.info("keyboard interrupt, stopping core daemon")

View file

@ -10,17 +10,16 @@ import sys
import ns.core import ns.core
import ns.mobility import ns.mobility
from core.nodes import nodeutils, nodemaps, ipaddress
from corens3.obj import Ns3LteNet from corens3.obj import Ns3LteNet
from corens3.obj import Ns3Session from corens3.obj import Ns3Session
from core.nodes import ipaddress
def ltesession(opt): def ltesession(opt):
""" """
Run a test LTE session. Run a test LTE session.
""" """
nodeutils.set_node_map(nodemaps.NODES)
session = Ns3Session(1, persistent=True, duration=opt.duration) session = Ns3Session(1, persistent=True, duration=opt.duration)
lte = session.create_node(cls=Ns3LteNet, name="wlan1") lte = session.create_node(cls=Ns3LteNet, name="wlan1")
lte.setsubchannels(range(25), range(50, 100)) lte.setsubchannels(range(25), range(50, 100))

View file

@ -27,11 +27,11 @@ import optparse
import sys import sys
import ns.core import ns.core
from core.nodes import nodeutils, nodemaps, ipaddress
from corens3.obj import Ns3Session from corens3.obj import Ns3Session
from corens3.obj import Ns3WifiNet from corens3.obj import Ns3WifiNet
from core.nodes import ipaddress
def add_to_server(session): def add_to_server(session):
""" """
@ -50,7 +50,6 @@ def wifisession(opt):
""" """
Run a test wifi session. Run a test wifi session.
""" """
nodeutils.set_node_map(nodemaps.NODES)
session = Ns3Session(1, persistent=True, duration=opt.duration) session = Ns3Session(1, persistent=True, duration=opt.duration)
session.name = "ns3wifi" session.name = "ns3wifi"
session.filename = session.name + ".py" session.filename = session.name + ".py"

View file

@ -14,13 +14,14 @@ How to run this:
import logging import logging
import optparse import optparse
import sys import sys
from builtins import range
import ns.core import ns.core
import ns.network import ns.network
from corens3.obj import Ns3Session from corens3.obj import Ns3Session
from corens3.obj import Ns3WifiNet from corens3.obj import Ns3WifiNet
from core.nodes import nodeutils, nodemaps, ipaddress from core.nodes import ipaddress
def add_to_server(session): def add_to_server(session):
@ -40,7 +41,6 @@ def wifisession(opt):
""" """
Run a random walk wifi session. Run a random walk wifi session.
""" """
nodeutils.set_node_map(nodemaps.NODES)
session = Ns3Session(1, persistent=True, duration=opt.duration) session = Ns3Session(1, persistent=True, duration=opt.duration)
session.name = "ns3wifirandomwalk" session.name = "ns3wifirandomwalk"
session.filename = session.name + ".py" session.filename = session.name + ".py"
@ -54,7 +54,7 @@ def wifisession(opt):
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16") prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
services_str = "zebra|OSPFv3MDR|IPForward" services_str = "zebra|OSPFv3MDR|IPForward"
nodes = [] nodes = []
for i in xrange(1, opt.numnodes + 1): for i in range(1, opt.numnodes + 1):
node = session.addnode(name="n%d" % i) node = session.addnode(name="n%d" % i)
node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
nodes.append(node) nodes.append(node)

View file

@ -12,17 +12,18 @@ Current issues:
import logging import logging
import optparse import optparse
import sys import sys
from builtins import range
from core.nodes import nodeutils, nodemaps, ipaddress
from corens3.obj import Ns3Session from corens3.obj import Ns3Session
from corens3.obj import Ns3WimaxNet from corens3.obj import Ns3WimaxNet
from core.nodes import ipaddress
def wimaxsession(opt): def wimaxsession(opt):
""" """
Run a test wimax session. Run a test wimax session.
""" """
nodeutils.set_node_map(nodemaps.NODES)
session = Ns3Session(1, persistent=True, duration=opt.duration) session = Ns3Session(1, persistent=True, duration=opt.duration)
wimax = session.create_node(cls=Ns3WimaxNet, name="wlan1") wimax = session.create_node(cls=Ns3WimaxNet, name="wlan1")
# wimax.wimax.EnableLogComponents() # wimax.wimax.EnableLogComponents()
@ -33,7 +34,7 @@ def wimaxsession(opt):
# classifier = (0, 65000, 0, 65000, 1, 1) # classifier = (0, 65000, 0, 65000, 1, 1)
classifier = (0, 65000, 0, 65000, 17, 1) classifier = (0, 65000, 0, 65000, 17, 1)
nodes = [] nodes = []
for i in xrange(1, opt.numnodes + 1): for i in range(1, opt.numnodes + 1):
node = session.addnode(name="n%d" % i) node = session.addnode(name="n%d" % i)
if i == 1: if i == 1:
wimax.setbasestation(node) wimax.setbasestation(node)