updates to make future apis a bit better, updated handlers and all tests to account for changes

This commit is contained in:
Blake J. Harnden 2018-04-25 10:55:48 -07:00
parent 3ea885e2eb
commit c0b450789a
9 changed files with 94 additions and 155 deletions

View file

@ -7,11 +7,9 @@ import core.services
from core import logger from core import logger
from core.coreobj import PyCoreNode, PyCoreNet from core.coreobj import PyCoreNode, PyCoreNet
from core.data import NodeData from core.data import NodeData
from core.emane.nodes import EmaneNode
from core.enumerations import NodeTypes, EventTypes, LinkTypes 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.misc import nodeutils
from core.netns.nodes import CoreNode
from core.session import Session from core.session import Session
from core.xml.xmlparser import core_document_parser from core.xml.xmlparser import core_document_parser
from core.xml.xmlwriter import core_document_writer from core.xml.xmlwriter import core_document_writer
@ -475,46 +473,47 @@ class FutureSession(Session):
if node_two: if node_two:
node_two.lock.release() 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. 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 :param core.future.futuredata.NodeOptions node_options: data to create node with
:return: created node :return: created node
""" """
# retrieve node class for given node type # retrieve node class for given node type
try: try:
node_class = nodeutils.get_node_class(node_options.type) node_class = nodeutils.get_node_class(_type)
except KeyError: except KeyError:
logger.error("invalid node type to create: %s", node_options.type) logger.error("invalid node type to create: %s", _type)
return None 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
enable_rj45 = getattr(self.options, "enablerj45", "0") == "1" 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 start = False
# determine node id # determine node id
node_id = node_options.id if not _id:
if not node_id:
while True: while True:
node_id = self.node_id_gen.next() _id = self.node_id_gen.next()
if node_id not in self.objects: if _id not in self.objects:
break break
# generate name if not provided # generate name if not provided
name = node_options.name name = node_options.name
if not name: if not name:
name = "%s%s" % (node_class.__name__, node_id) name = "%s%s" % (node_class.__name__, _id)
# create node # create node
logger.info("creating node(%s) id(%s) name(%s) start(%s)", node_class, node_id, name, 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=node_id, name=name, start=start) node = self.add_object(cls=node_class, objid=_id, name=name, start=start)
# set node attributes # set node attributes
node.type = node_options.model or "router" node.type = node_options.model
node.icon = node_options.icon node.icon = node_options.icon
node.canvas = node_options.canvas node.canvas = node_options.canvas
node.opaque = node_options.opaque node.opaque = node_options.opaque
@ -523,7 +522,7 @@ class FutureSession(Session):
self.set_node_position(node, node_options) self.set_node_position(node, node_options)
# add services to default and physical nodes only # 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) logger.info("setting model (%s) with services (%s)", node.type, node_options.services)
services = "|".join(node_options.services) or None services = "|".join(node_options.services) or None
self.services.addservicestonode(node, node.type, services) self.services.addservicestonode(node, node.type, services)
@ -539,16 +538,19 @@ class FutureSession(Session):
return node return node
def update_node(self, node_options): def update_node(self, node_id, node_options):
""" """
Update node information. Update node information.
:param int node_id: id of node to update
:param core.future.futuredata.NodeOptions node_options: data to update node with :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: try:
# get node to update # get node to update
node = self.get_object(node_options.id) node = self.get_object(node_id)
# set node position and broadcast it # set node position and broadcast it
self.set_node_position(node, node_options) self.set_node_position(node, node_options)
@ -556,14 +558,19 @@ class FutureSession(Session):
# update attributes # update attributes
node.canvas = node_options.canvas node.canvas = node_options.canvas
node.icon = node_options.icon node.icon = node_options.icon
# set node as updated successfully
result = True
except KeyError: except KeyError:
logger.error("failure to update node that does not exist: %s", node_options.id) logger.error("failure to update node that does not exist: %s", node_options.id)
return result
def delete_node(self, node_id): def delete_node(self, node_id):
""" """
Delete a node from the session and check if session should shutdown, if no nodes are left. 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 :return: True if node deleted, False otherwise
:rtype: bool :rtype: bool
""" """
@ -796,23 +803,26 @@ class FutureSession(Session):
return node 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. Create an EMANE node for use within an EMANE network.
:param str name: name to five node :param int _id: int for node, defaults to None and will be generated
:return: CoreNode :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. Convenience method for creating an emane network.
:param model: emane model to use for 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_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 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 :return: create emane network
""" """
# required to be set for emane to function properly # required to be set for emane to function properly
@ -821,7 +831,7 @@ class FutureSession(Session):
self.location.refscale = geo_scale self.location.refscale = geo_scale
# create and return network # 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) self.set_emane_model(emane_network, model)
return emane_network return emane_network

View file

@ -7,18 +7,14 @@ class NodeOptions(object):
Options for creating and updating nodes within core. 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. 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 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.name = name
self.type = _type
self.model = model self.model = model
self.canvas = None self.canvas = None
self.icon = None self.icon = None

View file

@ -647,9 +647,9 @@ class FutureHandler(SocketServer.BaseRequestHandler):
if node_type_value is not None: if node_type_value is not None:
node_type = NodeTypes(node_type_value) node_type = NodeTypes(node_type_value)
node_id = message.get_tlv(NodeTlvs.NUMBER.value)
node_options = NodeOptions( node_options = NodeOptions(
_type=node_type,
_id=message.get_tlv(NodeTlvs.NUMBER.value),
name=message.get_tlv(NodeTlvs.NAME.value), name=message.get_tlv(NodeTlvs.NAME.value),
model=message.get_tlv(NodeTlvs.MODEL.value) model=message.get_tlv(NodeTlvs.MODEL.value)
) )
@ -674,7 +674,7 @@ class FutureHandler(SocketServer.BaseRequestHandler):
node_options.services = services.split("|") node_options.services = services.split("|")
if message.flags & MessageFlags.ADD.value: 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 node:
if message.flags & MessageFlags.STRING.value: if message.flags & MessageFlags.STRING.value:
self.node_status_request[node.objid] = True self.node_status_request[node.objid] = True
@ -683,17 +683,17 @@ class FutureHandler(SocketServer.BaseRequestHandler):
self.send_node_emulation_id(node.objid) self.send_node_emulation_id(node.objid)
elif message.flags & MessageFlags.DELETE.value: elif message.flags & MessageFlags.DELETE.value:
with self._shutdown_lock: 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 we deleted a node broadcast out its removal
if result and message.flags & MessageFlags.STRING.value: if result and message.flags & MessageFlags.STRING.value:
tlvdata = "" 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 flags = MessageFlags.DELETE.value | MessageFlags.LOCAL.value
replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata)) replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata))
# node update # node update
else: else:
self.session.update_node(node_options) self.session.update_node(node_id, node_options)
return replies return replies

View file

@ -6,6 +6,7 @@ import datetime
import parser import parser
from core.emane.ieee80211abg import EmaneIeee80211abgModel from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.enumerations import EventTypes
from core.future.coreemu import CoreEmu from core.future.coreemu import CoreEmu
from core.future.futuredata import IpPrefixes from core.future.futuredata import IpPrefixes
@ -18,6 +19,9 @@ def example(options):
coreemu = CoreEmu() coreemu = CoreEmu()
session = coreemu.create_session() 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 # create emane network node
emane_network = session.create_emane_network( emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel, model=EmaneIeee80211abgModel,
@ -29,7 +33,8 @@ def example(options):
for i in xrange(options.nodes): for i in xrange(options.nodes):
node = session.create_emane_node() node = session.create_emane_node()
node.setposition(x=150 * (i + 1), y=150) 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 # instantiate session
session.instantiate() session.instantiate()

View file

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

View file

@ -10,7 +10,7 @@ import datetime
import parser import parser
from core.enumerations import NodeTypes, EventTypes from core.enumerations import NodeTypes, EventTypes
from core.future.coreemu import CoreEmu from core.future.coreemu import CoreEmu
from core.future.futuredata import IpPrefixes, NodeOptions from core.future.futuredata import IpPrefixes
def example(options): def example(options):
@ -25,13 +25,11 @@ def example(options):
session.set_state(EventTypes.CONFIGURATION_STATE.value) session.set_state(EventTypes.CONFIGURATION_STATE.value)
# create switch network node # create switch network node
node_options = NodeOptions(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
switch = session.add_node(node_options)
# create nodes # create nodes
for _ in xrange(options.nodes): for _ in xrange(options.nodes):
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node = session.add_node()
node = session.add_node(node_options)
interface = prefixes.create_interface(node) interface = prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface_one=interface) session.add_link(node.objid, switch.objid, interface_one=interface)

View file

@ -6,7 +6,7 @@
# nodestep # nodestep
from core.enumerations import NodeTypes, EventTypes from core.enumerations import NodeTypes, EventTypes
from core.future.futuredata import IpPrefixes, NodeOptions from core.future.futuredata import IpPrefixes
def example(nodes): def example(nodes):
@ -15,19 +15,17 @@ def example(nodes):
# create emulator instance for creating sessions and utility methods # create emulator instance for creating sessions and utility methods
coreemu = globals()["coreemu"] 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 # must be in configuration state for nodes to start, when using "node_add" below
session.set_state(EventTypes.CONFIGURATION_STATE.value) session.set_state(EventTypes.CONFIGURATION_STATE.value)
# create switch network node # create switch network node
node_options = NodeOptions(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
switch = session.add_node(node_options)
# create nodes # create nodes
for _ in xrange(nodes): for _ in xrange(nodes):
node_options = NodeOptions(_type=NodeTypes.DEFAULT.value) node = session.add_node()
node = session.add_node(node_options)
interface = prefixes.create_interface(node) interface = prefixes.create_interface(node)
session.add_link(node.objid, switch.objid, interface_one=interface) session.add_link(node.objid, switch.objid, interface_one=interface)

View file

@ -8,10 +8,10 @@
import datetime import datetime
import parser import parser
from core.enumerations import NodeTypes, EventTypes
from core.future.coreemu import CoreEmu from core.future.coreemu import CoreEmu
from core.future.futuredata import IpPrefixes from core.future.futuredata import IpPrefixes
from core.mobility import BasicRangeModel from core.mobility import BasicRangeModel
from core.netns.nodes import WlanNode, CoreNode
def example(options): def example(options):
@ -22,19 +22,23 @@ def example(options):
coreemu = CoreEmu() coreemu = CoreEmu()
session = coreemu.create_session() 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 # create wlan network node
wlan_network = session.create_node(cls=WlanNode) wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
coreemu.set_wireless_model(wlan_network, BasicRangeModel) coreemu.set_wireless_model(wlan, BasicRangeModel)
# create nodes # create nodes
wireless_nodes = [] wireless_nodes = []
for _ in xrange(options.nodes): for _ in xrange(options.nodes):
node = session.create_node(cls=CoreNode) node = session.add_node()
coreemu.add_interface(wlan_network, node, prefixes) interface = prefixes.create_interface(node)
session.add_link(node.objid, wlan.objid, interface_one=interface)
wireless_nodes.append(node) wireless_nodes.append(node)
# link all created nodes with the wireless network # 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 # instantiate session
session.instantiate() session.instantiate()

View file

@ -23,6 +23,8 @@ def future_session():
coreemu.shutdown() coreemu.shutdown()
IP4_PREFIX = "10.83.0.0/16"
MODELS = [ MODELS = [
"router", "router",
"host", "host",
@ -41,10 +43,10 @@ class TestFuture:
@pytest.mark.parametrize("model", MODELS) @pytest.mark.parametrize("model", MODELS)
def test_node_add(self, future_session, model): def test_node_add(self, future_session, model):
# given # given
node_options = NodeOptions(_type=NodeTypes.DEFAULT, model=model) node_options = NodeOptions(model=model)
# when # when
node = future_session.add_node(node_options) node = future_session.add_node(node_options=node_options)
# give time for node services to boot # give time for node services to boot
time.sleep(1) time.sleep(1)
@ -59,14 +61,13 @@ class TestFuture:
def test_node_update(self, future_session): def test_node_update(self, future_session):
# given # given
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node = future_session.add_node()
node = future_session.add_node(node_options)
position_value = 100 position_value = 100
update_options = NodeOptions(_id=node.objid) update_options = NodeOptions()
update_options.set_position(x=position_value, y=position_value) update_options.set_position(x=position_value, y=position_value)
# when # when
future_session.update_node(update_options) future_session.update_node(node.objid, update_options)
# then # then
assert node.position.x == position_value assert node.position.x == position_value
@ -74,8 +75,7 @@ class TestFuture:
def test_node_delete(self, future_session): def test_node_delete(self, future_session):
# given # given
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node = future_session.add_node()
node = future_session.add_node(node_options)
# when # when
future_session.delete_node(node.objid) future_session.delete_node(node.objid)
@ -87,10 +87,9 @@ class TestFuture:
@pytest.mark.parametrize("net_type", NET_TYPES) @pytest.mark.parametrize("net_type", NET_TYPES)
def test_net(self, future_session, net_type): def test_net(self, future_session, net_type):
# given # given
node_options = NodeOptions(_type=net_type)
# when # when
node = future_session.add_node(node_options) node = future_session.add_node(_type=net_type)
# then # then
assert node assert node
@ -99,10 +98,9 @@ class TestFuture:
def test_ptp(self, future_session): def test_ptp(self, future_session):
# given # given
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node_one = future_session.add_node()
node_one = future_session.add_node(node_options) node_two = future_session.add_node()
node_two = future_session.add_node(node_options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
inteface_two = prefixes.create_interface(node_two) inteface_two = prefixes.create_interface(node_two)
@ -115,11 +113,9 @@ class TestFuture:
def test_node_to_net(self, future_session): def test_node_to_net(self, future_session):
# given # given
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node_one = future_session.add_node()
node_one = future_session.add_node(node_options) node_two = future_session.add_node(_type=NodeTypes.SWITCH)
node_options = NodeOptions(_type=NodeTypes.SWITCH)
node_two = future_session.add_node(node_options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# when # when
@ -131,12 +127,9 @@ class TestFuture:
def test_net_to_node(self, future_session): def test_net_to_node(self, future_session):
# given # given
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
node_one = future_session.add_node(_type=NodeTypes.SWITCH)
node_options = NodeOptions(_type=NodeTypes.SWITCH) node_two = future_session.add_node()
node_one = future_session.add_node(node_options)
node_options = NodeOptions(_type=NodeTypes.DEFAULT)
node_two = future_session.add_node(node_options)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
# when # when
@ -148,10 +141,8 @@ class TestFuture:
def test_net_to_net(self, future_session): def test_net_to_net(self, future_session):
# given # given
node_options = NodeOptions(_type=NodeTypes.SWITCH) node_one = future_session.add_node(_type=NodeTypes.SWITCH)
node_one = future_session.add_node(node_options) node_two = future_session.add_node(_type=NodeTypes.SWITCH)
node_options = NodeOptions(_type=NodeTypes.SWITCH)
node_two = future_session.add_node(node_options)
# when # when
future_session.add_link(node_one.objid, node_two.objid) future_session.add_link(node_one.objid, node_two.objid)
@ -161,11 +152,9 @@ class TestFuture:
def test_link_update(self, future_session): def test_link_update(self, future_session):
# given # given
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node_one = future_session.add_node()
node_one = future_session.add_node(node_options) node_two = future_session.add_node(_type=NodeTypes.SWITCH)
node_options = NodeOptions(_type=NodeTypes.SWITCH)
node_two = future_session.add_node(node_options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
future_session.add_link(node_one.objid, node_two.objid, interface_one) future_session.add_link(node_one.objid, node_two.objid, interface_one)
interface = node_one.netif(interface_one.id) interface = node_one.netif(interface_one.id)
@ -193,10 +182,9 @@ class TestFuture:
def test_link_delete(self, future_session): def test_link_delete(self, future_session):
# given # given
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
node_options = NodeOptions(_type=NodeTypes.DEFAULT) node_one = future_session.add_node()
node_one = future_session.add_node(node_options) node_two = future_session.add_node()
node_two = future_session.add_node(node_options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
future_session.add_link(node_one.objid, node_two.objid, interface_one, interface_two) future_session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)