initial commit after bringing over cleaned up code and testing some examples

This commit is contained in:
Blake J. Harnden 2017-04-25 08:45:34 -07:00
parent c4858e6e0d
commit 00f4ebf5a9
93 changed files with 15189 additions and 13083 deletions

View file

@ -1,32 +1,37 @@
#
# CORE
# Copyright (c)2010-2013 the Boeing Company.
# See the LICENSE file included in this distribution.
#
# authors: Tom Goff <thomas.goff@boeing.com>
# Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
#
'''
coreobj.py: defines the basic objects for emulation: the PyCoreObj base class,
"""
coreobj.py: defines the basic objects for emulation: the PyCoreObj base class,
along with PyCoreNode, PyCoreNet, and PyCoreNetIf
'''
import sys, threading, os, shutil
"""
import os
import shutil
import socket
import threading
from socket import AF_INET
from socket import AF_INET6
from core.api import coreapi
from core.misc.ipaddr import *
from core.data import NodeData, LinkData
from core.enumerations import LinkTlvs
from core.enumerations import LinkTypes
from core.misc import ipaddress
class Position(object):
''' Helper class for Cartesian coordinate position
'''
def __init__(self, x = None, y = None, z = None):
"""
Helper class for Cartesian coordinate position
"""
def __init__(self, x=None, y=None, z=None):
self.x = None
self.y = None
self.z = None
self.set(x, y, z)
def set(self, x = None, y = None, z = None):
''' Returns True if the position has actually changed.
'''
def set(self, x=None, y=None, z=None):
"""
Returns True if the position has actually changed.
"""
if self.x == x and self.y == y and self.z == z:
return False
self.x = x
@ -35,20 +40,22 @@ class Position(object):
return True
def get(self):
''' Fetch the (x,y,z) position tuple.
'''
return (self.x, self.y, self.z)
"""
Fetch the (x,y,z) position tuple.
"""
return self.x, self.y, self.z
class PyCoreObj(object):
''' Base class for pycore objects (nodes and nets)
'''
"""
Base class for pycore objects (nodes and nets)
"""
apitype = None
def __init__(self, session, objid = None, name = None, verbose = False,
start = True):
def __init__(self, session, objid=None, name=None, start=True):
self.session = session
if objid is None:
objid = session.getobjid()
objid = session.get_object_id()
self.objid = objid
if name is None:
name = "o%s" % self.objid
@ -59,45 +66,50 @@ class PyCoreObj(object):
self.canvas = None
self.icon = None
self.opaque = None
self.verbose = verbose
self.position = Position()
def startup(self):
''' Each object implements its own startup method.
'''
"""
Each object implements its own startup method.
"""
raise NotImplementedError
def shutdown(self):
''' Each object implements its own shutdown method.
'''
"""
Each object implements its own shutdown method.
"""
raise NotImplementedError
def setposition(self, x = None, y = None, z = None):
''' Set the (x,y,z) position of the object.
'''
return self.position.set(x = x, y = y, z = z)
def setposition(self, x=None, y=None, z=None):
"""
Set the (x,y,z) position of the object.
"""
return self.position.set(x=x, y=y, z=z)
def getposition(self):
''' Return an (x,y,z) tuple representing this object's position.
'''
"""
Return an (x,y,z) tuple representing this object's position.
"""
return self.position.get()
def ifname(self, ifindex):
return self.netif(ifindex).name
def netifs(self, sort=False):
''' Iterate over attached network interfaces.
'''
"""
Iterate over attached network interfaces.
"""
if sort:
return map(lambda k: self._netif[k], sorted(self._netif.keys()))
else:
return self._netif.itervalues()
def numnetif(self):
''' Return the attached interface count.
'''
"""
Return the attached interface count.
"""
return len(self._netif)
def getifindex(self, netif):
for ifindex in self._netif:
if self._netif[ifindex] is netif:
@ -111,95 +123,71 @@ class PyCoreObj(object):
self.ifindex += 1
return ifindex
def tonodemsg(self, flags):
''' Build a CORE API Node Message for this object. Both nodes and
networks can be represented by a Node Message.
'''
def data(self, message_type):
"""
Build a data object for this node.
:param message_type: purpose for the data object we are creating
:return: node data object
:rtype: core.data.NodeData
"""
if self.apitype is None:
return None
tlvdata = ""
(x, y, z) = self.getposition()
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NUMBER,
self.objid)
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_TYPE,
self.apitype)
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NAME,
self.name)
if hasattr(self, "type") and self.type is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_MODEL,
self.type)
if hasattr(self, "server") and self.server is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_EMUSRV,
self.server)
x, y, z = self.getposition()
model = None
if hasattr(self, "type"):
model = self.type
emulation_server = None
if hasattr(self, "server"):
emulation_server = self.server
services = None
if hasattr(self, "services") and len(self.services) != 0:
nodeservices = []
for s in self.services:
nodeservices.append(s._name)
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_SERVICES,
"|".join(nodeservices))
nodeservices.append(s._name)
services = "|".join(nodeservices)
node_data = NodeData(
message_type=message_type,
id=self.objid,
node_type=self.apitype,
name=self.name,
emulation_id=self.objid,
canvas=self.canvas,
icon=self.icon,
opaque=self.opaque,
x_position=x,
y_position=y,
model=model,
emulation_server=emulation_server,
services=services
)
if x is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_XPOS, x)
if y is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_YPOS, y)
if self.canvas is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_CANVAS,
self.canvas)
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_EMUID,
self.objid)
if self.icon is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_ICON,
self.icon)
if self.opaque is not None:
tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_OPAQUE,
self.opaque)
msg = coreapi.CoreNodeMessage.pack(flags, tlvdata)
return msg
return node_data
def tolinkmsgs(self, flags):
''' Build CORE API Link Messages for this object. There is no default
method for PyCoreObjs as PyCoreNodes do not implement this but
PyCoreNets do.
'''
def all_link_data(self, flags):
"""
Build CORE API Link Messages for this object. There is no default
method for PyCoreObjs as PyCoreNodes do not implement this but
PyCoreNets do.
"""
return []
def info(self, msg):
''' Utility method for printing informational messages when verbose
is turned on.
'''
if self.verbose:
print "%s: %s" % (self.name, msg)
sys.stdout.flush()
def warn(self, msg):
''' Utility method for printing warning/error messages
'''
print >> sys.stderr, "%s: %s" % (self.name, msg)
sys.stderr.flush()
def exception(self, level, source, text):
''' Generate an Exception Message for this session, providing this
object number.
'''
if self.session:
id = None
if isinstance(self.objid, int):
id = self.objid
elif isinstance(self.objid, str) and self.objid.isdigit():
id = int(self.objid)
self.session.exception(level, source, id, text)
class PyCoreNode(PyCoreObj):
''' Base class for nodes
'''
def __init__(self, session, objid = None, name = None, verbose = False,
start = True):
''' Initialization for node objects.
'''
PyCoreObj.__init__(self, session, objid, name, verbose=verbose,
start=start)
"""
Base class for nodes
"""
def __init__(self, session, objid=None, name=None, start=True):
"""
Initialization for node objects.
"""
PyCoreObj.__init__(self, session, objid, name, start=start)
self.services = []
if not hasattr(self, "type"):
self.type = None
@ -207,26 +195,26 @@ class PyCoreNode(PyCoreObj):
def nodeid(self):
return self.objid
def addservice(self, service):
def addservice(self, service):
if service is not None:
self.services.append(service)
def makenodedir(self):
if self.nodedir is None:
self.nodedir = \
os.path.join(self.session.sessiondir, self.name + ".conf")
os.path.join(self.session.session_dir, self.name + ".conf")
os.makedirs(self.nodedir)
self.tmpnodedir = True
else:
self.tmpnodedir = False
def rmnodedir(self):
if hasattr(self.session.options, 'preservedir'):
if self.session.options.preservedir == '1':
return
if self.tmpnodedir:
shutil.rmtree(self.nodedir, ignore_errors = True)
shutil.rmtree(self.nodedir, ignore_errors=True)
def addnetif(self, netif, ifindex):
if ifindex in self._netif:
@ -241,12 +229,12 @@ class PyCoreNode(PyCoreObj):
netif.shutdown()
del netif
def netif(self, ifindex, net = None):
def netif(self, ifindex, net=None):
if ifindex in self._netif:
return self._netif[ifindex]
else:
return None
def attachnet(self, ifindex, net):
if ifindex not in self._netif:
raise ValueError, "ifindex %s does not exist" % ifindex
@ -257,8 +245,8 @@ class PyCoreNode(PyCoreObj):
raise ValueError, "ifindex %s does not exist" % ifindex
self._netif[ifindex].detachnet()
def setposition(self, x = None, y = None, z = None):
changed = PyCoreObj.setposition(self, x = x, y = y, z = z)
def setposition(self, x=None, y=None, z=None):
changed = PyCoreObj.setposition(self, x=x, y=y, z=z)
if not changed:
# save extra interface range calculations
return
@ -266,31 +254,32 @@ class PyCoreNode(PyCoreObj):
netif.setposition(x, y, z)
def commonnets(self, obj, want_ctrl=False):
''' Given another node or net object, return common networks between
this node and that object. A list of tuples is returned, with each tuple
consisting of (network, interface1, interface2).
'''
"""
Given another node or net object, return common networks between
this node and that object. A list of tuples is returned, with each tuple
consisting of (network, interface1, interface2).
"""
r = []
for netif1 in self.netifs():
if not want_ctrl and hasattr(netif1, 'control'):
continue
for netif2 in obj.netifs():
if netif1.net == netif2.net:
r += (netif1.net, netif1, netif2),
r += (netif1.net, netif1, netif2),
return r
class PyCoreNet(PyCoreObj):
''' Base class for networks
'''
linktype = coreapi.CORE_LINK_WIRED
"""
Base class for networks
"""
linktype = LinkTypes.WIRED.value
def __init__(self, session, objid, name, verbose = False, start = True):
''' Initialization for network objects.
'''
PyCoreObj.__init__(self, session, objid, name, verbose=verbose,
start=start)
def __init__(self, session, objid, name, start=True):
"""
Initialization for network objects.
"""
PyCoreObj.__init__(self, session, objid, name, start=start)
self._linked = {}
self._linked_lock = threading.Lock()
@ -300,7 +289,7 @@ class PyCoreNet(PyCoreObj):
netif.netifi = i
with self._linked_lock:
self._linked[netif] = {}
def detach(self, netif):
del self._netif[netif.netifi]
netif.netifi = None
@ -308,37 +297,37 @@ class PyCoreNet(PyCoreObj):
del self._linked[netif]
def netifparamstolink(self, netif):
''' Helper for tolinkmsgs() to build TLVs having link parameters
from interface parameters.
'''
tlvdata = ""
"""
Helper for tolinkmsgs() to build TLVs having link parameters
from interface parameters.
"""
delay = netif.getparam('delay')
bw = netif.getparam('bw')
loss = netif.getparam('loss')
duplicate = netif.getparam('duplicate')
jitter = netif.getparam('jitter')
tlvdata = ""
if delay is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY,
delay)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.DELAY.value, delay)
if bw is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW, bw)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.BANDWIDTH.value, bw)
if loss is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER,
str(loss))
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.PER.value, str(loss))
if duplicate is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP,
str(duplicate))
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.DUP.value, str(duplicate))
if jitter is not None:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER,
jitter)
tlvdata += coreapi.CoreLinkTlv.pack(LinkTlvs.JITTER.value, jitter)
return tlvdata
def tolinkmsgs(self, flags):
''' Build CORE API Link Messages for this network. Each link message
describes a link between this network and a node.
'''
msgs = []
def all_link_data(self, flags):
"""
Build CORE API Link Messages for this network. Each link message
describes a link between this network and a node.
"""
all_links = []
# build a link message from this network node to each node having a
# connected interface
for netif in self.netifs(sort=True):
@ -358,61 +347,77 @@ class PyCoreNet(PyCoreObj):
netif.swapparams('_params_up')
if netif.getparams() != upstream_params:
uni = True
tlvdata = ""
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER,
self.objid)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER,
otherobj.objid)
tlvdata += self.netifparamstolink(netif)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE,
self.linktype)
unidirectional = 0
if uni:
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI,
1)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM,
otherobj.getifindex(netif))
if netif.hwaddr:
tlvdata += \
coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2MAC,
netif.hwaddr)
for addr in netif.addrlist:
(ip, sep, mask) = addr.partition('/')
unidirectional = 1
interface2_ip4 = None
interface2_ip4_mask = None
interface2_ip6 = None
interface2_ip6_mask = None
for address in netif.addrlist:
ip, sep, mask = address.partition('/')
mask = int(mask)
if isIPv4Address(ip):
if ipaddress.is_ipv4_address(ip):
family = AF_INET
tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP4
tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP4MASK
ipl = socket.inet_pton(family, ip)
interface2_ip4 = ipaddress.IpAddress(af=family, address=ipl)
interface2_ip4_mask = mask
else:
family = AF_INET6
tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP6
tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP6MASK
ipl = socket.inet_pton(family, ip)
tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, \
IPAddr(af=family, addr=ipl))
tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask)
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=self.objid,
node2_id=otherobj.objid,
link_type=self.linktype,
unidirectional=unidirectional,
interface2_id=otherobj.getifindex(netif),
interface2_mac=netif.hwaddr,
interface2_ip4=interface2_ip4,
interface2_ip4_mask=interface2_ip4_mask,
interface2_ip6=interface2_ip6,
interface2_ip6_mask=interface2_ip6_mask,
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter")
)
all_links.append(link_data)
msg = coreapi.CoreLinkMessage.pack(flags, tlvdata)
msgs.append(msg)
if not uni:
continue
# build a 2nd link message for any upstream link parameters
tlvdata = ""
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER,
otherobj.objid)
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER,
self.objid)
netif.swapparams('_params_up')
tlvdata += self.netifparamstolink(netif)
link_data = LinkData(
message_type=0,
node1_id=otherobj.objid,
node2_id=self.objid,
unidirectional=1,
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
jitter=netif.getparam("jitter")
)
netif.swapparams('_params_up')
tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1)
msg = coreapi.CoreLinkMessage.pack(0, tlvdata)
msgs.append(msg)
return msgs
all_links.append(link_data)
return all_links
class PyCoreNetIf(object):
''' Base class for interfaces.
'''
"""
Base class for interfaces.
"""
def __init__(self, node, name, mtu):
self.node = node
self.name = name
@ -428,13 +433,15 @@ class PyCoreNetIf(object):
self.transport_type = None
# interface index on the network
self.netindex = None
# index used to find flow data
self.flow_id = None
def startup(self):
pass
def shutdown(self):
pass
def attachnet(self, net):
if self.net:
self.detachnet()
@ -456,25 +463,28 @@ class PyCoreNetIf(object):
self.hwaddr = addr
def getparam(self, key):
''' Retrieve a parameter from the _params dict,
or None if the parameter does not exist.
'''
"""
Retrieve a parameter from the _params dict,
or None if the parameter does not exist.
"""
if key not in self._params:
return None
return self._params[key]
def getparams(self):
''' Return (key, value) pairs from the _params dict.
'''
"""
Return (key, value) pairs from the _params dict.
"""
r = []
for k in sorted(self._params.keys()):
r.append((k, self._params[k]))
return r
def setparam(self, key, value):
''' Set a parameter in the _params dict.
Returns True if the parameter has changed.
'''
"""
Set a parameter in the _params dict.
Returns True if the parameter has changed.
"""
if key in self._params:
if self._params[key] == value:
return False
@ -483,12 +493,13 @@ class PyCoreNetIf(object):
return False
self._params[key] = value
return True
def swapparams(self, name):
''' Swap out the _params dict for name. If name does not exist,
"""
Swap out the _params dict for name. If name does not exist,
intialize it. This is for supporting separate upstream/downstream
parameters when two layer-2 nodes are linked together.
'''
"""
tmp = self._params
if not hasattr(self, name):
setattr(self, name, {})
@ -496,8 +507,8 @@ class PyCoreNetIf(object):
setattr(self, name, tmp)
def setposition(self, x, y, z):
''' Dispatch to any position hook (self.poshook) handler.
'''
"""
Dispatch to any position hook (self.poshook) handler.
"""
if self.poshook is not None:
self.poshook(self, x, y, z)