core-extra/daemon/core/xml/xmlwriter1.py

998 lines
38 KiB
Python

import collections
import os
from xml.dom.minidom import Document
import pwd
from core import coreobj
from core import logger
from core.enumerations import EventTypes
from core.enumerations import NodeTypes
from core.enumerations import RegisterTlvs
from core.misc import ipaddress
from core.misc import nodeutils
from core.netns import nodes
from core.xml import xmlutils
from core.xml.xmldeployment import CoreDeploymentWriter
class Alias:
ID = "COREID"
class MembType:
INTERFACE = "interface"
CHANNEL = "channel"
SWITCH = "switch"
HUB = "hub"
TUNNEL = "tunnel"
NETWORK = "network"
class NodeType:
ROUTER = "router"
HOST = "host"
MDR = "mdr"
PC = "PC"
RJ45 = "rj45"
SWITCH = "lanswitch"
HUB = "hub"
class DevType:
HOST = "host"
ROUTER = "router"
SWITCH = "switch"
HUB = "hub"
class NetType:
WIRELESS = "wireless"
ETHERNET = "ethernet"
PTP_WIRED = "point-to-point-wired"
PTP_WIRELESS = "point-to-point-wireless"
"""
A link endpoint in CORE
net: the network that the endpoint belongs to
netif: the network interface at this end
id: the identifier for the endpoint
l2devport: if the other end is a layer 2 device, this is the assigned port in that device
params: link/interface parameters
"""
Endpoint = collections.namedtuple('Endpoint',
['net', 'netif', 'type', 'id', 'l2devport', 'params'])
class CoreDocumentWriter1(Document):
"""
Utility class for writing a CoreSession to XML in the NMF scenPlan schema. The init
method builds an xml.dom.minidom.Document, and the writexml() method saves the XML file.
"""
def __init__(self, session):
"""
Create an empty Scenario XML Document, then populate it with
objects from the given session.
"""
Document.__init__(self)
logger.debug('Exporting to NMF XML version 1.0')
with session._objects_lock:
self.scenarioPlan = ScenarioPlan(self, session)
if session.state == EventTypes.RUNTIME_STATE.value:
deployment = CoreDeploymentWriter(self, self.scenarioPlan, session)
deployment.add_deployment()
self.scenarioPlan.setAttribute('deployed', 'true')
def writexml(self, filename):
"""
Commit to file
"""
logger.info("saving session XML file %s", filename)
f = open(filename, "w")
Document.writexml(self, writer=f, indent="", addindent=" ", newl="\n", encoding="UTF-8")
f.close()
if self.scenarioPlan.coreSession.user is not None:
uid = pwd.getpwnam(self.scenarioPlan.coreSession.user).pw_uid
gid = os.stat(self.scenarioPlan.coreSession.session_dir).st_gid
os.chown(filename, uid, gid)
class XmlElement(object):
"""
The base class for all XML elements in the scenario plan. Includes
convenience functions.
"""
def __init__(self, document, parent, element_type):
self.document = document
self.parent = parent
self.base_element = document.createElement("%s" % element_type)
if self.parent is not None:
self.parent.appendChild(self.base_element)
def createElement(self, element_tag):
return self.document.createElement(element_tag)
def getTagName(self):
return self.base_element.tagName
def createTextNode(self, node_tag):
return self.document.createTextNode(node_tag)
def appendChild(self, child):
if isinstance(child, XmlElement):
self.base_element.appendChild(child.base_element)
else:
self.base_element.appendChild(child)
@staticmethod
def add_parameter(doc, parent, key, value):
if key and value:
parm = doc.createElement("parameter")
parm.setAttribute("name", str(key))
parm.appendChild(doc.createTextNode(str(value)))
parent.appendChild(parm)
def addParameter(self, key, value):
"""
Add a parameter to the xml element
"""
self.add_parameter(self.document, self, key, value)
def setAttribute(self, name, val):
self.base_element.setAttribute(name, val)
def getAttribute(self, name):
return self.base_element.getAttribute(name)
class NamedXmlElement(XmlElement):
"""
The base class for all "named" xml elements. Named elements are
xml elements in the scenario plan that have an id and a name attribute.
"""
def __init__(self, scen_plan, parent, element_type, element_name):
XmlElement.__init__(self, scen_plan.document, parent, element_type)
self.scenPlan = scen_plan
self.coreSession = scen_plan.coreSession
element_path = ''
self.id = None
if self.parent is not None and isinstance(self.parent, XmlElement) and self.parent.getTagName() != "scenario":
element_path = "%s/" % self.parent.getAttribute("id")
self.id = "%s%s" % (element_path, element_name)
self.setAttribute("name", element_name)
self.setAttribute("id", self.id)
def addPoint(self, core_object):
"""
Add position to an object
"""
(x, y, z) = core_object.position.get()
if x is None or y is None:
return
lat, lon, alt = self.coreSession.location.getgeo(x, y, z)
pt = self.createElement("point")
pt.setAttribute("type", "gps")
pt.setAttribute("lat", "%s" % lat)
pt.setAttribute("lon", "%s" % lon)
if z:
pt.setAttribute("z", "%s" % alt)
self.appendChild(pt)
def createAlias(self, domain, value_str):
"""
Create an alias element for CORE specific information
"""
a = self.createElement("alias")
a.setAttribute("domain", "%s" % domain)
a.appendChild(self.createTextNode(value_str))
return a
class ScenarioPlan(XmlElement):
"""
Container class for ScenarioPlan.
"""
def __init__(self, document, session):
XmlElement.__init__(self, document, parent=document, element_type='scenario')
self.coreSession = session
self.setAttribute('version', '1.0')
self.setAttribute("name", "%s" % session.name)
self.setAttribute('xmlns', 'nmfPlan')
self.setAttribute('xmlns:CORE', 'coreSpecific')
self.setAttribute('compiled', 'true')
self.all_channel_members = {}
self.last_network_id = 0
self.addNetworks()
self.addDevices()
self.addDefaultServices()
self.addSessionConfiguration()
def addNetworks(self):
"""
Add networks in the session to the scenPlan.
"""
for net in self.coreSession.objects.itervalues():
if not isinstance(net, coreobj.PyCoreNet):
continue
if nodeutils.is_node(net, NodeTypes.CONTROL_NET):
continue
# Do not add switches and hubs that belong to another network
if nodeutils.is_node(net, (NodeTypes.SWITCH, NodeTypes.HUB)):
if in_other_network(net):
continue
try:
NetworkElement(self, self, net)
except:
logger.exception("error adding node")
if hasattr(net, "name") and net.name:
logger.warn('Unsupported net name: %s, class: %s, type: %s',
net.name, net.__class__.__name__, net.type)
else:
logger.warn('Unsupported net class: %s', net.__class__.__name__)
def addDevices(self):
"""
Add device elements to the scenario plan.
"""
for node in self.coreSession.objects.itervalues():
if not isinstance(node, nodes.PyCoreNode):
continue
try:
DeviceElement(self, self, node)
except:
logger.exception("error adding device")
if hasattr(node, "name") and node.name:
logger.warn('Unsupported device name: %s, class: %s, type: %s',
node.name, node.__class__.__name__, node.type)
else:
logger.warn('Unsupported device: %s', node.__class__.__name__)
def addDefaultServices(self):
"""
Add default services and node types to the ServicePlan.
"""
defaultservices = self.createElement("CORE:defaultservices")
for type in self.coreSession.services.default_services:
defaults = self.coreSession.services.get_default_services(type)
spn = self.createElement("device")
spn.setAttribute("type", type)
defaultservices.appendChild(spn)
for svc in defaults:
s = self.createElement("service")
spn.appendChild(s)
s.setAttribute("name", str(svc.name))
if defaultservices.hasChildNodes():
self.appendChild(defaultservices)
def addSessionConfiguration(self):
"""
Add CORE-specific session configuration XML elements.
"""
config = self.createElement("CORE:sessionconfig")
# origin: geolocation of cartesian coordinate 0,0,0
refgeo = self.coreSession.location.refgeo
origin = self.createElement("origin")
attrs = ("lat", "lon", "alt")
have_origin = False
for i in xrange(3):
if refgeo[i] is not None:
origin.setAttribute(attrs[i], str(refgeo[i]))
have_origin = True
if have_origin:
if self.coreSession.location.refscale != 1.0: # 100 pixels = refscale m
origin.setAttribute("scale100", str(self.coreSession.location.refscale))
if self.coreSession.location.refxyz != (0.0, 0.0, 0.0):
pt = self.createElement("point")
origin.appendChild(pt)
x, y, z = self.coreSession.location.refxyz
coordstxt = "%s,%s" % (x, y)
if z:
coordstxt += ",%s" % z
coords = self.createTextNode(coordstxt)
pt.appendChild(coords)
config.appendChild(origin)
# options
options = self.createElement("options")
options_config = self.coreSession.options.get_configs()
for _id, default_value in self.coreSession.options.default_values().iteritems():
value = options_config[_id]
if value != default_value:
XmlElement.add_parameter(self.document, options, _id, value)
if options.hasChildNodes():
config.appendChild(options)
# hook scripts
hooks = self.createElement("hooks")
for state in sorted(self.coreSession._hooks.keys()):
for filename, data in self.coreSession._hooks[state]:
hook = self.createElement("hook")
hook.setAttribute("name", filename)
hook.setAttribute("state", str(state))
txt = self.createTextNode(data)
hook.appendChild(txt)
hooks.appendChild(hook)
if hooks.hasChildNodes():
config.appendChild(hooks)
# metadata
meta = self.createElement("metadata")
for k, v in self.coreSession.metadata.get_configs().iteritems():
XmlElement.add_parameter(self.document, meta, k, v)
if meta.hasChildNodes():
config.appendChild(meta)
if config.hasChildNodes():
self.appendChild(config)
class NetworkElement(NamedXmlElement):
def __init__(self, scen_plan, parent, network_object):
"""
Add one PyCoreNet object as one network XML element.
"""
element_name = self.getNetworkName(scen_plan, network_object)
NamedXmlElement.__init__(self, scen_plan, parent, "network", element_name)
self.scenPlan = scen_plan
self.addPoint(network_object)
network_type = None
if nodeutils.is_node(network_object, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
network_type = NetType.WIRELESS
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB,
NodeTypes.PEER_TO_PEER, NodeTypes.TUNNEL)):
network_type = NetType.ETHERNET
else:
network_type = "%s" % network_object.__class__.__name__
type_element = self.createElement("type")
type_element.appendChild(self.createTextNode(network_type))
self.appendChild(type_element)
# Gather all endpoints belonging to this network
self.endpoints = get_endpoints(network_object)
# Special case for a network of switches and hubs
create_alias = True
self.l2devices = []
if nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB)):
create_alias = False
self.appendChild(type_element)
self.addL2Devices(network_object)
if create_alias:
a = self.createAlias(Alias.ID, "%d" % int(network_object.objid))
self.appendChild(a)
# XXXX TODO: Move this to channel?
# key used with tunnel node
if hasattr(network_object, 'grekey') and network_object.grekey is not None:
a = self.createAlias("COREGREKEY", "%s" % network_object.grekey)
self.appendChild(a)
self.addNetMembers(network_object)
self.addChannels(network_object)
presentation_element = self.createElement("CORE:presentation")
add_presentation_element = False
if network_object.icon and not network_object.icon.isspace():
presentation_element.setAttribute("icon", network_object.icon)
add_presentation_element = True
if network_object.canvas:
presentation_element.setAttribute("canvas", str(network_object.canvas))
add_presentation_element = True
if add_presentation_element:
self.appendChild(presentation_element)
def getNetworkName(self, scenario_plan, network_object):
"""
Determine the name to use for this network element
:param ScenarioPlan scenario_plan:
:param network_object:
:return:
"""
if nodeutils.is_node(network_object, (NodeTypes.PEER_TO_PEER, NodeTypes.TUNNEL)):
name = "net%s" % scenario_plan.last_network_id
scenario_plan.last_network_id += 1
elif network_object.name:
name = str(network_object.name) # could use net.brname for bridges?
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB)):
name = "lan%s" % network_object.objid
else:
name = ''
return name
def addL2Devices(self, network_object):
"""
Add switches and hubs
"""
# Add the netObj as a device
self.l2devices.append(DeviceElement(self.scenPlan, self, network_object))
# Add downstream switches/hubs
l2devs = []
neweps = []
for ep in self.endpoints:
if ep.type and ep.net.objid != network_object.objid:
l2s, eps = get_dowmstream_l2_devices(ep.net)
l2devs.extend(l2s)
neweps.extend(eps)
for l2dev in l2devs:
self.l2devices.append(DeviceElement(self.scenPlan, self, l2dev))
self.endpoints.extend(neweps)
# XXX: Optimize later
def addNetMembers(self, network_object):
"""
Add members to a network XML element.
"""
for ep in self.endpoints:
if ep.type:
MemberElement(self.scenPlan, self, referenced_type=ep.type, referenced_id=ep.id)
if ep.l2devport:
MemberElement(self.scenPlan,
self,
referenced_type=MembType.INTERFACE,
referenced_id="%s/%s" % (self.id, ep.l2devport))
# XXX Revisit this
# Create implied members given the network type
if nodeutils.is_node(network_object, NodeTypes.TUNNEL):
MemberElement(self.scenPlan, self, referenced_type=MembType.TUNNEL,
referenced_id="%s/%s" % (network_object.name, network_object.name))
# XXX: Optimize later
def addChannels(self, network_object):
"""
Add channels to a network XML element
"""
if nodeutils.is_node(network_object, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
modelconfigs = network_object.session.mobility.get_models(network_object)
modelconfigs += network_object.session.emane.get_models(network_object)
chan = None
for model, conf in modelconfigs:
# Handle mobility parameters below
if model.config_type == RegisterTlvs.MOBILITY.value:
continue
# Create the channel
if chan is None:
name = "wireless"
chan = ChannelElement(self.scenPlan, self, network_object,
channel_type=model.name,
channel_name=name,
channel_domain="CORE")
# Add wireless model parameters
for key, value in conf.iteritems():
if value is not None:
chan.addParameter(key, value)
for model, conf in modelconfigs:
if model.config_type == RegisterTlvs.MOBILITY.value:
# Add wireless mobility parameters
mobility = XmlElement(self.scenPlan, chan, "CORE:mobility")
# Add a type child
type_element = self.createElement("type")
type_element.appendChild(self.createTextNode(model.name))
mobility.appendChild(type_element)
for key, value in conf.iteritems():
if value is not None:
mobility.addParameter(key, value)
# Add members to the channel
if chan is not None:
chan.addChannelMembers(self.endpoints)
self.appendChild(chan.base_element)
elif nodeutils.is_node(network_object, NodeTypes.PEER_TO_PEER):
if len(self.endpoints) < 2:
if len(self.endpoints) == 1:
logger.warn('Pt2Pt network with only 1 endpoint: %s', self.endpoints[0].id)
else:
logger.warn('Pt2Pt network with no endpoints encountered in %s', network_object.name)
return
name = "chan%d" % (0)
chan = ChannelElement(self.scenPlan, self, network_object,
channel_type=NetType.ETHERNET,
channel_name=name)
# Add interface parameters
if self.endpoints[0].params != self.endpoints[1].params:
logger.warn('Pt2Pt Endpoint parameters do not match in %s', network_object.name)
for key, value in self.endpoints[0].params:
# XXX lifted from original addnetem function. revisit this.
# default netem parameters are 0 or None
if value is None or value == 0:
continue
if key == "has_netem" or key == "has_tbf":
continue
chan.addParameter(key, value)
# Add members to the channel
chan.addChannelMembers(self.endpoints)
self.appendChild(chan)
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.TUNNEL)):
cidx = 0
channels = []
for ep in self.endpoints:
# Create one channel member per ep
if ep.type:
name = "chan%d" % cidx
chan = ChannelElement(self.scenPlan, self, network_object, channel_type=NetType.ETHERNET,
channel_name=name)
# Add interface parameters
for key, value in ep.params:
# XXX lifted from original addnetem function. revisit this.
# default netem parameters are 0 or None
if value is None or value == 0:
continue
if key == "has_netem" or key == "has_tbf":
continue
chan.addParameter(key, value)
# Add members to the channel
chan.addChannelMembers(ep)
channels.append(chan)
cidx += 1
for chan in channels:
self.appendChild(chan)
class DeviceElement(NamedXmlElement):
"""
A device element in the scenario plan.
"""
def __init__(self, scen_plan, parent, device_object):
"""
Add a PyCoreNode object as a device element.
"""
device_type = None
core_device_type = None
if hasattr(device_object, "type") and device_object.type:
core_device_type = device_object.type
if device_object.type in [NodeType.ROUTER, NodeType.MDR]:
device_type = DevType.ROUTER
elif device_object.type == NodeType.HUB:
device_type = DevType.HUB
elif device_object.type == NodeType.SWITCH:
device_type = DevType.SWITCH
# includes known node types (HOST, PC, RJ45)
# Default custom types (defined in ~/.core/nodes.conf) to HOST
else:
device_type = DevType.HOST
if device_type is None:
raise ValueError("unknown device type: %s" % core_device_type)
NamedXmlElement.__init__(self, scen_plan, parent, device_type, device_object.name)
if core_device_type is not None:
type_element = self.createElement("type")
type_element.setAttribute("domain", "CORE")
type_element.appendChild(self.createTextNode("%s" % core_device_type))
self.appendChild(type_element)
self.interfaces = []
self.addInterfaces(device_object)
alias = self.createAlias(Alias.ID, "%s" % device_object.objid)
self.appendChild(alias)
self.addPoint(device_object)
self.addServices(device_object)
presentation_element = self.createElement("CORE:presentation")
add_presentation_element = False
if device_object.icon and not device_object.icon.isspace():
presentation_element.setAttribute("icon", device_object.icon)
add_presentation_element = True
if device_object.canvas:
presentation_element.setAttribute("canvas", str(device_object.canvas))
add_presentation_element = True
if add_presentation_element:
self.appendChild(presentation_element)
def addInterfaces(self, device_object):
"""
Add interfaces to a device element.
"""
idx = 0
for interface_object in device_object.netifs(sort=True):
if interface_object.net and nodeutils.is_node(interface_object.net, NodeTypes.CONTROL_NET):
continue
if isinstance(device_object, nodes.PyCoreNode):
interface_element = InterfaceElement(self.scenPlan, self, device_object, interface_object)
else: # isinstance(node, (nodes.HubNode nodes.SwitchNode)):
interface_element = InterfaceElement(self.scenPlan, self, device_object, interface_object, idx)
idx += 1
netmodel = None
if interface_object.net:
if hasattr(interface_object.net, "model"):
netmodel = interface_object.net.model
if interface_object.mtu and interface_object.mtu != 1500:
interface_element.setAttribute("mtu", "%s" % interface_object.mtu)
# The interfaces returned for Switches and Hubs are the interfaces of the nodes connected to them.
# The addresses are for those interfaces. Don't include them here.
if isinstance(device_object, nodes.PyCoreNode):
# could use ifcObj.params, transport_type
interface_element.addAddresses(interface_object)
# per-interface models
# XXX Remove???
if netmodel and netmodel.name[:6] == "emane_":
cfg = self.coreSession.emane.getifcconfig(device_object.objid, interface_object, netmodel.name)
if cfg:
interface_element.addModels(((netmodel, cfg),))
self.interfaces.append(interface_element)
def addServices(self, device_object):
"""
Add services and their customizations to the ServicePlan.
"""
if not hasattr(device_object, "services"):
return
if len(device_object.services) == 0:
return
defaults = self.coreSession.services.get_default_services(device_object.type)
if device_object.services == defaults:
return
spn = self.createElement("CORE:services")
spn.setAttribute("name", device_object.name)
self.appendChild(spn)
for svc in device_object.services:
s = self.createElement("service")
spn.appendChild(s)
s.setAttribute("name", str(svc.name))
# only record service names if not a customized service
if not svc.custom:
continue
s.setAttribute("custom", str(svc.custom))
xmlutils.add_elements_from_list(self, s, svc.dirs, "directory", "name")
for fn in svc.configs:
if len(fn) == 0:
continue
f = self.createElement("file")
f.setAttribute("name", fn)
# all file names are added to determine when a file has been deleted
s.appendChild(f)
data = svc.config_data.get(fn)
if data is None:
# this includes only customized file contents and skips
# the auto-generated files
continue
txt = self.createTextNode("\n" + data)
f.appendChild(txt)
xmlutils.add_text_elements_from_list(self, s, svc.startup, "command", (("type", "start"),))
xmlutils.add_text_elements_from_list(self, s, svc.shutdown, "command", (("type", "stop"),))
xmlutils.add_text_elements_from_list(self, s, svc.validate, "command", (("type", "validate"),))
class ChannelElement(NamedXmlElement):
"""
A channel element in the scenario plan
"""
def __init__(self, scen_plan, parent, network_object, channel_type, channel_name, channel_domain=None):
NamedXmlElement.__init__(self, scen_plan, parent, "channel", channel_name)
'''
Create a channel element and append a member child referencing this channel element
in the parent element.
'''
# Create a member element for this channel in the parent
MemberElement(self.scenPlan, parent, referenced_type=MembType.CHANNEL, referenced_id=self.id)
# Add a type child
type_element = self.createElement("type")
if channel_domain is not None:
type_element.setAttribute("domain", "%s" % channel_domain)
type_element.appendChild(self.createTextNode(channel_type))
self.appendChild(type_element)
def addChannelMembers(self, endpoints):
"""
Add network channel members referencing interfaces in the channel
"""
if isinstance(endpoints, list):
# A list of endpoints is given. Create one channel member per endpoint
idx = 0
for ep in endpoints:
self.addChannelMember(ep.type, ep.id, idx)
idx += 1
else:
# A single endpoint is given. Create one channel member for the endpoint,
# and if the endpoint is associated with a Layer 2 device port, add the
# port as a second member
ep = endpoints
self.addChannelMember(ep.type, ep.id, 0)
if ep.l2devport is not None:
member_id = "%s/%s" % (self.parent.getAttribute("id"), ep.l2devport)
self.addChannelMember(ep.type, member_id, 1)
def addChannelMember(self, member_interface_type, member_interface_id, member_index):
"""
add a member to a given channel
"""
m = MemberElement(self.scenPlan,
self,
referenced_type=member_interface_type,
referenced_id=member_interface_id,
index=member_index)
self.scenPlan.all_channel_members[member_interface_id] = m
class InterfaceElement(NamedXmlElement):
"""
A network interface element
"""
def __init__(self, scen_plan, parent, device_object, interface_object, interface_index=None):
"""
Create a network interface element with references to channel that this
interface is used.
"""
element_name = None
if interface_index is not None:
element_name = "e%d" % interface_index
else:
element_name = interface_object.name
NamedXmlElement.__init__(self, scen_plan, parent, "interface", element_name)
self.ifcObj = interface_object
self.addChannelReference()
def addChannelReference(self):
"""
Add a reference to the channel that uses this interface
"""
# cm is None when an interface belongs to a switch
# or a hub within a network and the channel is yet to be defined
cm = self.scenPlan.all_channel_members.get(self.id)
if cm is not None:
ch = cm.base_element.parentNode
if ch is not None:
net = ch.parentNode
if net is not None:
MemberElement(self.scenPlan,
self,
referenced_type=MembType.CHANNEL,
referenced_id=ch.getAttribute("id"),
index=int(cm.getAttribute("index")))
MemberElement(self.scenPlan,
self,
referenced_type=MembType.NETWORK,
referenced_id=net.getAttribute("id"))
def addAddresses(self, interface_object):
"""
Add MAC and IP addresses to interface XML elements.
"""
if interface_object.hwaddr:
h = self.createElement("address")
self.appendChild(h)
h.setAttribute("type", "mac")
htxt = self.createTextNode("%s" % interface_object.hwaddr)
h.appendChild(htxt)
for addr in interface_object.addrlist:
a = self.createElement("address")
self.appendChild(a)
(ip, sep, mask) = addr.partition('/')
# mask = int(mask) XXX?
if ipaddress.is_ipv4_address(ip):
a.setAttribute("type", "IPv4")
else:
a.setAttribute("type", "IPv6")
# a.setAttribute("type", )
atxt = self.createTextNode("%s" % addr)
a.appendChild(atxt)
# XXX Remove?
def addModels(self, configs):
"""
Add models from a list of model-class, config values tuples.
"""
for m, conf in configs:
node_element = self.createElement("model")
node_element.setAttribute("name", m.name)
type_string = "wireless"
if m.config_type == RegisterTlvs.MOBILITY.value:
type_string = "mobility"
node_element.setAttribute("type", type_string)
for i, k in enumerate(m.getnames()):
key = self.createElement(k)
value = conf[i]
if value is None:
value = ""
key.appendChild(self.createTextNode("%s" % value))
node_element.appendChild(key)
self.appendChild(node_element)
class MemberElement(XmlElement):
"""
Member elements are references to other elements in the network plan elements of the scenario.
They are used in networks to reference channels, in channels to reference interfaces,
and in interfaces to reference networks/channels. Member elements provided allow bi-directional
traversal of network plan components.
"""
def __init__(self, scene_plan, parent, referenced_type, referenced_id, index=None):
"""
Create a member element
"""
XmlElement.__init__(self, scene_plan.document, parent, "member")
self.setAttribute("type", "%s" % referenced_type)
# See'Understanding the Network Modeling Framework document'
if index is not None:
self.setAttribute("index", "%d" % index)
self.appendChild(self.createTextNode("%s" % referenced_id))
#
# =======================================================================================
# Helpers
# =======================================================================================
def get_endpoint(network_object, interface_object):
"""
Create an Endpoint object given the network and the interface of interest
"""
ep = None
l2devport = None
# skip if either are none
if not network_object or not interface_object:
return ep
# if ifcObj references an interface of a node and is part of this network
if interface_object.net.objid == network_object.objid and hasattr(interface_object,
'node') and interface_object.node:
params = interface_object.getparams()
if nodeutils.is_node(interface_object.net, (NodeTypes.HUB, NodeTypes.SWITCH)):
l2devport = "%s/e%d" % (interface_object.net.name, interface_object.net.getifindex(interface_object))
ep = Endpoint(network_object,
interface_object,
type=MembType.INTERFACE,
id="%s/%s" % (interface_object.node.name, interface_object.name),
l2devport=l2devport,
params=params)
# else if ifcObj references another node and is connected to this network
elif hasattr(interface_object, "othernet"):
if interface_object.othernet.objid == network_object.objid:
# #hack used for upstream parameters for link between switches
# #(see LxBrNet.linknet())
interface_object.swapparams('_params_up')
params = interface_object.getparams()
interface_object.swapparams('_params_up')
owner = interface_object.net
l2devport = "%s/e%d" % (
interface_object.othernet.name, interface_object.othernet.getifindex(interface_object))
# Create the endpoint.
# XXX the interface index might not match what is shown in the gui. For switches and hubs,
# The gui assigns its index but doesn't pass it to the daemon and vice versa.
# The gui stores it's index in the IMN file, which it reads and writes without daemon intervention.
# Fix this!
ep = Endpoint(owner,
interface_object,
type=MembType.INTERFACE,
id="%s/%s/e%d" % (network_object.name, owner.name, owner.getifindex(interface_object)),
l2devport=l2devport,
params=params)
# else this node has an interface that belongs to another network
# i.e. a switch/hub interface connected to another switch/hub and CORE has the other switch/hub
# as the containing network
else:
ep = Endpoint(network_object, interface_object, type=None, id=None, l2devport=None, params=None)
return ep
def get_endpoints(network_object):
"""
Gather all endpoints of the given network
"""
# Get all endpoints
endpoints = []
# XXX TODO: How to represent physical interfaces.
#
# NOTE: The following code works except it would be missing physical (rj45) interfaces from Pt2pt links
# TODO: Fix data in net.netifs to include Pt2Pt physical interfaces
#
# Iterate through all the nodes in the scenario, then iterate through all the interface for each node,
# and check if the interface is connected to this network.
for interface_object in network_object.netifs(sort=True):
try:
ep = get_endpoint(network_object, interface_object)
if ep is not None:
endpoints.append(ep)
except:
logger.debug("error geting endpoints, was skipped before")
return endpoints
def get_dowmstream_l2_devices(network_object):
"""
Helper function for getting a list of all downstream layer 2 devices from the given netObj
"""
l2_device_objects = [network_object]
allendpoints = []
myendpoints = get_endpoints(network_object)
allendpoints.extend(myendpoints)
for ep in myendpoints:
if ep.type and ep.net.objid != network_object.objid:
l2s, eps = get_dowmstream_l2_devices(ep.net)
l2_device_objects.extend(l2s)
allendpoints.extend(eps)
return l2_device_objects, allendpoints
def get_all_network_interfaces(session):
"""
Gather all network interfacecs in the session
"""
netifs = []
for node in session.objects.itervalues():
for netif in node.netifs(sort=True):
if netif not in netifs:
netifs.append(netif)
return netifs
def in_other_network(network_object):
"""
Determine if CORE considers a given network object to be part of another network.
Note: CORE considers layer 2 devices to be their own networks. However, if a l2 device
is connected to another device, it is possible that one of its ports belong to the other
l2 device's network (thus, "othernet").
"""
for netif in network_object.netifs(sort=True):
if hasattr(netif, "othernet"):
if netif.othernet.objid != network_object.objid:
return True
return False