diff --git a/daemon/core/future/coreemu.py b/daemon/core/future/coreemu.py index 73e948a7..39ab6b00 100644 --- a/daemon/core/future/coreemu.py +++ b/daemon/core/future/coreemu.py @@ -7,11 +7,9 @@ import core.services from core import logger from core.coreobj import PyCoreNode, PyCoreNet from core.data import NodeData -from core.emane.nodes import EmaneNode from core.enumerations import NodeTypes, EventTypes, LinkTypes -from core.future.futuredata import InterfaceData, LinkOptions +from core.future.futuredata import InterfaceData, LinkOptions, NodeOptions from core.misc import nodeutils -from core.netns.nodes import CoreNode from core.session import Session from core.xml.xmlparser import core_document_parser from core.xml.xmlwriter import core_document_writer @@ -475,46 +473,47 @@ class FutureSession(Session): if node_two: node_two.lock.release() - def add_node(self, node_options): + def add_node(self, _type=NodeTypes.DEFAULT, _id=None, node_options=NodeOptions()): """ Add a node to the session, based on the provided node data. + :param core.enumerations.NodeTypes _type: type of node to create + :param int _id: id for node, defaults to None for generated id :param core.future.futuredata.NodeOptions node_options: data to create node with :return: created node """ # retrieve node class for given node type try: - node_class = nodeutils.get_node_class(node_options.type) + node_class = nodeutils.get_node_class(_type) except KeyError: - logger.error("invalid node type to create: %s", node_options.type) + logger.error("invalid node type to create: %s", _type) return None # set node start based on current session state, override and check when rj45 start = self.state > EventTypes.DEFINITION_STATE.value enable_rj45 = getattr(self.options, "enablerj45", "0") == "1" - if node_options.type == NodeTypes.RJ45 and not enable_rj45: + if _type == NodeTypes.RJ45 and not enable_rj45: start = False # determine node id - node_id = node_options.id - if not node_id: + if not _id: while True: - node_id = self.node_id_gen.next() - if node_id not in self.objects: + _id = self.node_id_gen.next() + if _id not in self.objects: break # generate name if not provided name = node_options.name if not name: - name = "%s%s" % (node_class.__name__, node_id) + name = "%s%s" % (node_class.__name__, _id) # create node - logger.info("creating node(%s) id(%s) name(%s) start(%s)", node_class, node_id, name, start) - node = self.add_object(cls=node_class, objid=node_id, name=name, start=start) + logger.info("creating node(%s) id(%s) name(%s) start(%s)", node_class, _id, name, start) + node = self.add_object(cls=node_class, objid=_id, name=name, start=start) # set node attributes - node.type = node_options.model or "router" + node.type = node_options.model node.icon = node_options.icon node.canvas = node_options.canvas node.opaque = node_options.opaque @@ -523,7 +522,7 @@ class FutureSession(Session): self.set_node_position(node, node_options) # add services to default and physical nodes only - if node_options.type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]: + if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]: logger.info("setting model (%s) with services (%s)", node.type, node_options.services) services = "|".join(node_options.services) or None self.services.addservicestonode(node, node.type, services) @@ -539,16 +538,19 @@ class FutureSession(Session): return node - def update_node(self, node_options): + def update_node(self, node_id, node_options): """ Update node information. + :param int node_id: id of node to update :param core.future.futuredata.NodeOptions node_options: data to update node with - :return: nothing + :return: True if node updated, False otherwise + :rtype: bool """ + result = False try: # get node to update - node = self.get_object(node_options.id) + node = self.get_object(node_id) # set node position and broadcast it self.set_node_position(node, node_options) @@ -556,14 +558,19 @@ class FutureSession(Session): # update attributes node.canvas = node_options.canvas node.icon = node_options.icon + + # set node as updated successfully + result = True except KeyError: logger.error("failure to update node that does not exist: %s", node_options.id) + return result + def delete_node(self, node_id): """ Delete a node from the session and check if session should shutdown, if no nodes are left. - :param int node_id: + :param int node_id: id of node to delete :return: True if node deleted, False otherwise :rtype: bool """ @@ -796,23 +803,26 @@ class FutureSession(Session): return node - def create_emane_node(self, name=None): + def create_emane_node(self, _id=None, node_options=NodeOptions()): """ Create an EMANE node for use within an EMANE network. - :param str name: name to five node - :return: CoreNode + :param int _id: int for node, defaults to None and will be generated + :param core.future.futuredata.NodeOptions node_options: options for emane node, model will always be "mdr" + :return: new emane node + :rtype: core.netns.nodes.CoreNode """ - return self.create_node(cls=CoreNode, name=name, model="mdr") + node_options.model = "mdr" + return self.add_node(_type=NodeTypes.DEFAULT, _id=_id, node_options=node_options) - def create_emane_network(self, model, geo_reference, geo_scale=None, name=None): + def create_emane_network(self, model, geo_reference, geo_scale=None, node_options=NodeOptions()): """ Convenience method for creating an emane network. :param model: emane model to use for emane network :param geo_reference: geo reference point to use for emane node locations :param geo_scale: geo scale to use for emane node locations, defaults to 1.0 - :param name: name for emane network, defaults to node class name + :param core.future.futuredata.NodeOptions node_options: options for emane node being created :return: create emane network """ # required to be set for emane to function properly @@ -821,7 +831,7 @@ class FutureSession(Session): self.location.refscale = geo_scale # create and return network - emane_network = self.create_node(cls=EmaneNode, name=name) + emane_network = self.add_node(_type=NodeTypes.EMANE, node_options=node_options) self.set_emane_model(emane_network, model) return emane_network diff --git a/daemon/core/future/futuredata.py b/daemon/core/future/futuredata.py index b23189ee..fac64bf2 100644 --- a/daemon/core/future/futuredata.py +++ b/daemon/core/future/futuredata.py @@ -7,18 +7,14 @@ class NodeOptions(object): Options for creating and updating nodes within core. """ - def __init__(self, _type=None, _id=None, name=None, model=None): + def __init__(self, name=None, model="router"): """ Create a NodeOptions object. - :param core.enumerations.NodeType _type: type of node to create - :param int _id: id for node being created, defaults to generated id :param str name: name of node, defaults to node class name postfix with its id - :param str model: model to use for this node, defines services + :param str model: model to use for this node, defines services, defaults to "router" """ - self.id = _id self.name = name - self.type = _type self.model = model self.canvas = None self.icon = None diff --git a/daemon/core/future/futurehandler.py b/daemon/core/future/futurehandler.py index 3f5a63e2..3ea50e88 100644 --- a/daemon/core/future/futurehandler.py +++ b/daemon/core/future/futurehandler.py @@ -647,9 +647,9 @@ class FutureHandler(SocketServer.BaseRequestHandler): if node_type_value is not None: node_type = NodeTypes(node_type_value) + node_id = message.get_tlv(NodeTlvs.NUMBER.value) + node_options = NodeOptions( - _type=node_type, - _id=message.get_tlv(NodeTlvs.NUMBER.value), name=message.get_tlv(NodeTlvs.NAME.value), model=message.get_tlv(NodeTlvs.MODEL.value) ) @@ -674,7 +674,7 @@ class FutureHandler(SocketServer.BaseRequestHandler): node_options.services = services.split("|") if message.flags & MessageFlags.ADD.value: - node = self.session.add_node(node_options) + node = self.session.add_node(node_type, node_id, node_options) if node: if message.flags & MessageFlags.STRING.value: self.node_status_request[node.objid] = True @@ -683,17 +683,17 @@ class FutureHandler(SocketServer.BaseRequestHandler): self.send_node_emulation_id(node.objid) elif message.flags & MessageFlags.DELETE.value: with self._shutdown_lock: - result = self.session.delete_node(node_options.id) + result = self.session.delete_node(node_id) # if we deleted a node broadcast out its removal if result and message.flags & MessageFlags.STRING.value: tlvdata = "" - tlvdata += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_options.id) + tlvdata += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_id) flags = MessageFlags.DELETE.value | MessageFlags.LOCAL.value replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata)) # node update else: - self.session.update_node(node_options) + self.session.update_node(node_id, node_options) return replies diff --git a/daemon/examples/future/emane80211.py b/daemon/examples/future/emane80211_api.py similarity index 82% rename from daemon/examples/future/emane80211.py rename to daemon/examples/future/emane80211_api.py index 03bcd1cf..1b16bc96 100644 --- a/daemon/examples/future/emane80211.py +++ b/daemon/examples/future/emane80211_api.py @@ -6,6 +6,7 @@ import datetime import parser from core.emane.ieee80211abg import EmaneIeee80211abgModel +from core.enumerations import EventTypes from core.future.coreemu import CoreEmu from core.future.futuredata import IpPrefixes @@ -18,6 +19,9 @@ def example(options): coreemu = CoreEmu() session = coreemu.create_session() + # must be in configuration state for nodes to start, when using "node_add" below + session.set_state(EventTypes.CONFIGURATION_STATE.value) + # create emane network node emane_network = session.create_emane_network( model=EmaneIeee80211abgModel, @@ -29,7 +33,8 @@ def example(options): for i in xrange(options.nodes): node = session.create_emane_node() node.setposition(x=150 * (i + 1), y=150) - coreemu.add_interface(emane_network, node, prefixes) + interface = prefixes.create_interface(node) + session.add_link(node.objid, emane_network.objid, interface_one=interface) # instantiate session session.instantiate() diff --git a/daemon/examples/future/switch.py b/daemon/examples/future/switch.py deleted file mode 100644 index 60ea4fb5..00000000 --- a/daemon/examples/future/switch.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python -# -# run iperf to measure the effective throughput between two nodes when -# n nodes are connected to a virtual wlan; run test for testsec -# and repeat for minnodes <= n <= maxnodes with a step size of -# nodestep - -import datetime - -import parser -from core.future.coreemu import CoreEmu -from core.future.futuredata import IpPrefixes -from core.netns.nodes import CoreNode, SwitchNode - - -def example(options): - # ip generator for example - prefixes = IpPrefixes("10.83.0.0/16") - - # create emulator instance for creating sessions and utility methods - coreemu = CoreEmu() - session = coreemu.create_session() - - # create switch network node - switch_network = session.create_node(cls=SwitchNode) - - # create nodes - for _ in xrange(options.nodes): - node = session.create_node(cls=CoreNode) - coreemu.add_interface(switch_network, node, prefixes) - - # instantiate session - session.instantiate() - - # get nodes to run example - first_node = session.get_object(2) - last_node = session.get_object(options.nodes + 1) - - print "starting iperf server on node: %s" % first_node.name - first_node.cmd(["iperf", "-s", "-D"]) - address = prefixes.ip4_address(first_node) - print "node %s connecting to %s" % (last_node.name, address) - last_node.client.icmd(["iperf", "-t", str(options.time), "-c", address]) - first_node.cmd(["killall", "-9", "iperf"]) - - # shutdown session - coreemu.shutdown() - - -def main(): - options = parser.parse_options("switch") - - start = datetime.datetime.now() - print "running switch example: nodes(%s) time(%s)" % (options.nodes, options.time) - example(options) - print "elapsed time: %s" % (datetime.datetime.now() - start) - - -if __name__ == "__main__": - main() diff --git a/daemon/examples/future/switch_api.py b/daemon/examples/future/switch_api.py index 8d9e64d3..1dc914ec 100644 --- a/daemon/examples/future/switch_api.py +++ b/daemon/examples/future/switch_api.py @@ -10,7 +10,7 @@ import datetime import parser from core.enumerations import NodeTypes, EventTypes from core.future.coreemu import CoreEmu -from core.future.futuredata import IpPrefixes, NodeOptions +from core.future.futuredata import IpPrefixes def example(options): @@ -25,13 +25,11 @@ def example(options): session.set_state(EventTypes.CONFIGURATION_STATE.value) # create switch network node - node_options = NodeOptions(_type=NodeTypes.SWITCH) - switch = session.add_node(node_options) + switch = session.add_node(_type=NodeTypes.SWITCH) # create nodes for _ in xrange(options.nodes): - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node = session.add_node(node_options) + node = session.add_node() interface = prefixes.create_interface(node) session.add_link(node.objid, switch.objid, interface_one=interface) diff --git a/daemon/examples/future/switch_api_inject.py b/daemon/examples/future/switch_api_inject.py index 9444ef65..215bddb8 100644 --- a/daemon/examples/future/switch_api_inject.py +++ b/daemon/examples/future/switch_api_inject.py @@ -6,7 +6,7 @@ # nodestep from core.enumerations import NodeTypes, EventTypes -from core.future.futuredata import IpPrefixes, NodeOptions +from core.future.futuredata import IpPrefixes def example(nodes): @@ -15,19 +15,17 @@ def example(nodes): # create emulator instance for creating sessions and utility methods coreemu = globals()["coreemu"] - session = coreemu.create_session(master=True) + session = coreemu.create_session() # must be in configuration state for nodes to start, when using "node_add" below session.set_state(EventTypes.CONFIGURATION_STATE.value) # create switch network node - node_options = NodeOptions(_type=NodeTypes.SWITCH) - switch = session.add_node(node_options) + switch = session.add_node(_type=NodeTypes.SWITCH) # create nodes for _ in xrange(nodes): - node_options = NodeOptions(_type=NodeTypes.DEFAULT.value) - node = session.add_node(node_options) + node = session.add_node() interface = prefixes.create_interface(node) session.add_link(node.objid, switch.objid, interface_one=interface) diff --git a/daemon/examples/future/wlan.py b/daemon/examples/future/wlan_api.py similarity index 76% rename from daemon/examples/future/wlan.py rename to daemon/examples/future/wlan_api.py index 1e766846..ed34ca55 100644 --- a/daemon/examples/future/wlan.py +++ b/daemon/examples/future/wlan_api.py @@ -8,10 +8,10 @@ import datetime import parser +from core.enumerations import NodeTypes, EventTypes from core.future.coreemu import CoreEmu from core.future.futuredata import IpPrefixes from core.mobility import BasicRangeModel -from core.netns.nodes import WlanNode, CoreNode def example(options): @@ -22,19 +22,23 @@ def example(options): coreemu = CoreEmu() session = coreemu.create_session() + # must be in configuration state for nodes to start, when using "node_add" below + session.set_state(EventTypes.CONFIGURATION_STATE.value) + # create wlan network node - wlan_network = session.create_node(cls=WlanNode) - coreemu.set_wireless_model(wlan_network, BasicRangeModel) + wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN) + coreemu.set_wireless_model(wlan, BasicRangeModel) # create nodes wireless_nodes = [] for _ in xrange(options.nodes): - node = session.create_node(cls=CoreNode) - coreemu.add_interface(wlan_network, node, prefixes) + node = session.add_node() + interface = prefixes.create_interface(node) + session.add_link(node.objid, wlan.objid, interface_one=interface) wireless_nodes.append(node) # link all created nodes with the wireless network - coreemu.wireless_link_all(wlan_network, wireless_nodes) + coreemu.wireless_link_all(wlan, wireless_nodes) # instantiate session session.instantiate() diff --git a/daemon/tests/test_future.py b/daemon/tests/test_future.py index 7bf4d0f3..eae42799 100644 --- a/daemon/tests/test_future.py +++ b/daemon/tests/test_future.py @@ -23,6 +23,8 @@ def future_session(): coreemu.shutdown() +IP4_PREFIX = "10.83.0.0/16" + MODELS = [ "router", "host", @@ -41,10 +43,10 @@ class TestFuture: @pytest.mark.parametrize("model", MODELS) def test_node_add(self, future_session, model): # given - node_options = NodeOptions(_type=NodeTypes.DEFAULT, model=model) + node_options = NodeOptions(model=model) # when - node = future_session.add_node(node_options) + node = future_session.add_node(node_options=node_options) # give time for node services to boot time.sleep(1) @@ -59,14 +61,13 @@ class TestFuture: def test_node_update(self, future_session): # given - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node = future_session.add_node(node_options) + node = future_session.add_node() position_value = 100 - update_options = NodeOptions(_id=node.objid) + update_options = NodeOptions() update_options.set_position(x=position_value, y=position_value) # when - future_session.update_node(update_options) + future_session.update_node(node.objid, update_options) # then assert node.position.x == position_value @@ -74,8 +75,7 @@ class TestFuture: def test_node_delete(self, future_session): # given - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node = future_session.add_node(node_options) + node = future_session.add_node() # when future_session.delete_node(node.objid) @@ -87,10 +87,9 @@ class TestFuture: @pytest.mark.parametrize("net_type", NET_TYPES) def test_net(self, future_session, net_type): # given - node_options = NodeOptions(_type=net_type) # when - node = future_session.add_node(node_options) + node = future_session.add_node(_type=net_type) # then assert node @@ -99,10 +98,9 @@ class TestFuture: def test_ptp(self, future_session): # given - prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node_one = future_session.add_node(node_options) - node_two = future_session.add_node(node_options) + prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX) + node_one = future_session.add_node() + node_two = future_session.add_node() interface_one = prefixes.create_interface(node_one) inteface_two = prefixes.create_interface(node_two) @@ -115,11 +113,9 @@ class TestFuture: def test_node_to_net(self, future_session): # given - prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node_one = future_session.add_node(node_options) - node_options = NodeOptions(_type=NodeTypes.SWITCH) - node_two = future_session.add_node(node_options) + prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX) + node_one = future_session.add_node() + node_two = future_session.add_node(_type=NodeTypes.SWITCH) interface_one = prefixes.create_interface(node_one) # when @@ -131,12 +127,9 @@ class TestFuture: def test_net_to_node(self, future_session): # given - prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") - - node_options = NodeOptions(_type=NodeTypes.SWITCH) - node_one = future_session.add_node(node_options) - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node_two = future_session.add_node(node_options) + prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX) + node_one = future_session.add_node(_type=NodeTypes.SWITCH) + node_two = future_session.add_node() interface_two = prefixes.create_interface(node_two) # when @@ -148,10 +141,8 @@ class TestFuture: def test_net_to_net(self, future_session): # given - node_options = NodeOptions(_type=NodeTypes.SWITCH) - node_one = future_session.add_node(node_options) - node_options = NodeOptions(_type=NodeTypes.SWITCH) - node_two = future_session.add_node(node_options) + node_one = future_session.add_node(_type=NodeTypes.SWITCH) + node_two = future_session.add_node(_type=NodeTypes.SWITCH) # when future_session.add_link(node_one.objid, node_two.objid) @@ -161,11 +152,9 @@ class TestFuture: def test_link_update(self, future_session): # given - prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node_one = future_session.add_node(node_options) - node_options = NodeOptions(_type=NodeTypes.SWITCH) - node_two = future_session.add_node(node_options) + prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX) + node_one = future_session.add_node() + node_two = future_session.add_node(_type=NodeTypes.SWITCH) interface_one = prefixes.create_interface(node_one) future_session.add_link(node_one.objid, node_two.objid, interface_one) interface = node_one.netif(interface_one.id) @@ -193,10 +182,9 @@ class TestFuture: def test_link_delete(self, future_session): # given - prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") - node_options = NodeOptions(_type=NodeTypes.DEFAULT) - node_one = future_session.add_node(node_options) - node_two = future_session.add_node(node_options) + prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX) + node_one = future_session.add_node() + node_two = future_session.add_node() interface_one = prefixes.create_interface(node_one) interface_two = prefixes.create_interface(node_two) future_session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)