initial commit with things working for the most part
This commit is contained in:
parent
c1b6747a26
commit
2ede43e3ae
21 changed files with 1018 additions and 1397 deletions
|
@ -11,7 +11,6 @@ import threading
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.api import coreapi
|
from core.api import coreapi
|
||||||
from core.conf import ConfigurableManager
|
|
||||||
from core.coreobj import PyCoreNet
|
from core.coreobj import PyCoreNet
|
||||||
from core.coreobj import PyCoreNode
|
from core.coreobj import PyCoreNode
|
||||||
from core.enumerations import ConfigDataTypes
|
from core.enumerations import ConfigDataTypes
|
||||||
|
@ -81,7 +80,7 @@ class CoreDistributedServer(object):
|
||||||
self.sock = None
|
self.sock = None
|
||||||
|
|
||||||
|
|
||||||
class CoreBroker(ConfigurableManager):
|
class CoreBroker(object):
|
||||||
"""
|
"""
|
||||||
Helps with brokering messages between CORE daemon servers.
|
Helps with brokering messages between CORE daemon servers.
|
||||||
"""
|
"""
|
||||||
|
@ -100,7 +99,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ConfigurableManager.__init__(self)
|
# ConfigurableManager.__init__(self)
|
||||||
self.session = session
|
self.session = session
|
||||||
self.session_clients = []
|
self.session_clients = []
|
||||||
self.session_id_master = None
|
self.session_id_master = None
|
||||||
|
@ -611,62 +610,6 @@ class CoreBroker(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
self.physical_nodes.add(nodenum)
|
self.physical_nodes.add(nodenum)
|
||||||
|
|
||||||
def configure_reset(self, config_data):
|
|
||||||
"""
|
|
||||||
Ignore reset messages, because node delete responses may still
|
|
||||||
arrive and require the use of nodecounts.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Receive configuration message with a list of server:host:port
|
|
||||||
combinations that we"ll need to connect with.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
values = config_data.data_values
|
|
||||||
session_id = config_data.session
|
|
||||||
|
|
||||||
if values is None:
|
|
||||||
logger.info("emulation server data missing")
|
|
||||||
return None
|
|
||||||
values = values.split("|")
|
|
||||||
|
|
||||||
# string of "server:ip:port,server:ip:port,..."
|
|
||||||
server_strings = values[0]
|
|
||||||
server_list = server_strings.split(",")
|
|
||||||
|
|
||||||
for server in server_list:
|
|
||||||
server_items = server.split(":")
|
|
||||||
(name, host, port) = server_items[:3]
|
|
||||||
|
|
||||||
if host == "":
|
|
||||||
host = None
|
|
||||||
|
|
||||||
if port == "":
|
|
||||||
port = None
|
|
||||||
else:
|
|
||||||
port = int(port)
|
|
||||||
|
|
||||||
if session_id is not None:
|
|
||||||
# receive session ID and my IP from master
|
|
||||||
self.session_id_master = int(session_id.split("|")[0])
|
|
||||||
self.myip = host
|
|
||||||
host = None
|
|
||||||
port = None
|
|
||||||
|
|
||||||
# this connects to the server immediately; maybe we should wait
|
|
||||||
# or spin off a new "client" thread here
|
|
||||||
self.addserver(name, host, port)
|
|
||||||
self.setupserver(name)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def handle_message(self, message):
|
def handle_message(self, message):
|
||||||
"""
|
"""
|
||||||
Handle an API message. Determine whether this needs to be handled
|
Handle an API message. Determine whether this needs to be handled
|
||||||
|
@ -733,6 +676,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
if server is None:
|
if server is None:
|
||||||
logger.warn("ignoring unknown server: %s", servername)
|
logger.warn("ignoring unknown server: %s", servername)
|
||||||
return
|
return
|
||||||
|
|
||||||
if server.sock is None or server.host is None or server.port is None:
|
if server.sock is None or server.host is None or server.port is None:
|
||||||
logger.info("ignoring disconnected server: %s", servername)
|
logger.info("ignoring disconnected server: %s", servername)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,384 +2,24 @@
|
||||||
Common support for configurable CORE objects.
|
Common support for configurable CORE objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string
|
from collections import OrderedDict
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.data import ConfigData
|
from core.data import ConfigData
|
||||||
from core.enumerations import ConfigDataTypes
|
|
||||||
from core.enumerations import ConfigFlags
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurableManager(object):
|
class ConfigShim(object):
|
||||||
"""
|
@classmethod
|
||||||
A generic class for managing Configurables. This class can register
|
def str_to_dict(cls, key_values):
|
||||||
with a session to receive Config Messages for setting some parameters
|
key_values = key_values.split("|")
|
||||||
for itself or for the Configurables that it manages.
|
values = OrderedDict()
|
||||||
"""
|
for key_value in key_values:
|
||||||
# name corresponds to configuration object field
|
key, value = key_value.split("=", 1)
|
||||||
name = ""
|
values[key] = value
|
||||||
|
return values
|
||||||
# type corresponds with register message types
|
|
||||||
config_type = None
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
Creates a ConfigurableManager instance.
|
|
||||||
"""
|
|
||||||
# configurable key=values, indexed by node number
|
|
||||||
self.configs = {}
|
|
||||||
|
|
||||||
# TODO: fix the need for this and isolate to the mobility class that wants it
|
|
||||||
self._modelclsmap = {}
|
|
||||||
|
|
||||||
def configure(self, session, config_data):
|
|
||||||
"""
|
|
||||||
Handle configure messages. The configuration message sent to a
|
|
||||||
ConfigurableManager usually is used to:
|
|
||||||
1. Request a list of Configurables (request flag)
|
|
||||||
2. Reset manager and clear configs (reset flag)
|
|
||||||
3. Send values that configure the manager or one of its Configurables
|
|
||||||
|
|
||||||
:param core.session.Session session: CORE session object
|
|
||||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: response messages
|
|
||||||
"""
|
|
||||||
|
|
||||||
if config_data.type == ConfigFlags.REQUEST.value:
|
|
||||||
return self.configure_request(config_data)
|
|
||||||
elif config_data.type == ConfigFlags.RESET.value:
|
|
||||||
return self.configure_reset(config_data)
|
|
||||||
else:
|
|
||||||
return self.configure_values(config_data)
|
|
||||||
|
|
||||||
def configure_request(self, config_data):
|
|
||||||
"""
|
|
||||||
Request configuration data.
|
|
||||||
|
|
||||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def configure_reset(self, config_data):
|
|
||||||
"""
|
|
||||||
By default, resets this manager to clear configs.
|
|
||||||
|
|
||||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: reset response messages, or None
|
|
||||||
"""
|
|
||||||
return self.reset()
|
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Values have been sent to this manager.
|
|
||||||
|
|
||||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def configure_values_keyvalues(self, config_data, target, keys):
|
|
||||||
"""
|
|
||||||
Helper that can be used for configure_values for parsing in
|
|
||||||
'key=value' strings from a values field. The key name must be
|
|
||||||
in the keys list, and target.key=value is set.
|
|
||||||
|
|
||||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:param target: target to set attribute values on
|
|
||||||
:param keys: list of keys to verify validity
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
values = config_data.data_values
|
|
||||||
|
|
||||||
if values is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
kvs = values.split('|')
|
|
||||||
for kv in kvs:
|
|
||||||
try:
|
|
||||||
key, value = kv.split('=', 1)
|
|
||||||
if value is not None and not value.strip():
|
|
||||||
value = None
|
|
||||||
except ValueError:
|
|
||||||
# value only
|
|
||||||
key = keys[kvs.index(kv)]
|
|
||||||
value = kv
|
|
||||||
if key not in keys:
|
|
||||||
raise ValueError("invalid key: %s" % key)
|
|
||||||
if value is not None:
|
|
||||||
setattr(target, key, value)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
"""
|
|
||||||
Reset functionality for the configurable class.
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
return None
|
|
||||||
|
|
||||||
def setconfig(self, nodenum, conftype, values):
|
|
||||||
"""
|
|
||||||
Add configuration values for a node to a dictionary; values are
|
|
||||||
usually received from a Configuration Message, and may refer to a
|
|
||||||
node for which no object exists yet
|
|
||||||
|
|
||||||
:param int nodenum: node id
|
|
||||||
:param conftype: configuration types
|
|
||||||
:param values: configuration values
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
logger.info("setting config for node(%s): %s - %s", nodenum, conftype, values)
|
|
||||||
conflist = []
|
|
||||||
if nodenum in self.configs:
|
|
||||||
oldlist = self.configs[nodenum]
|
|
||||||
found = False
|
|
||||||
for t, v in oldlist:
|
|
||||||
if t == conftype:
|
|
||||||
# replace existing config
|
|
||||||
found = True
|
|
||||||
conflist.append((conftype, values))
|
|
||||||
else:
|
|
||||||
conflist.append((t, v))
|
|
||||||
if not found:
|
|
||||||
conflist.append((conftype, values))
|
|
||||||
else:
|
|
||||||
conflist.append((conftype, values))
|
|
||||||
self.configs[nodenum] = conflist
|
|
||||||
|
|
||||||
def getconfig(self, nodenum, conftype, defaultvalues):
|
|
||||||
"""
|
|
||||||
Get configuration values for a node; if the values don't exist in
|
|
||||||
our dictionary then return the default values supplied
|
|
||||||
|
|
||||||
:param int nodenum: node id
|
|
||||||
:param conftype: configuration type
|
|
||||||
:param defaultvalues: default values
|
|
||||||
:return: configuration type and default values
|
|
||||||
:type: tuple
|
|
||||||
"""
|
|
||||||
logger.info("getting config for node(%s): %s - default(%s)",
|
|
||||||
nodenum, conftype, defaultvalues)
|
|
||||||
if nodenum in self.configs:
|
|
||||||
# return configured values
|
|
||||||
conflist = self.configs[nodenum]
|
|
||||||
for t, v in conflist:
|
|
||||||
if conftype is None or t == conftype:
|
|
||||||
return t, v
|
|
||||||
# return default values provided (may be None)
|
|
||||||
return conftype, defaultvalues
|
|
||||||
|
|
||||||
def getallconfigs(self, use_clsmap=True):
|
|
||||||
"""
|
|
||||||
Return (nodenum, conftype, values) tuples for all stored configs.
|
|
||||||
Used when reconnecting to a session.
|
|
||||||
|
|
||||||
:param bool use_clsmap: should a class map be used, default to True
|
|
||||||
:return: list of all configurations
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
r = []
|
|
||||||
for nodenum in self.configs:
|
|
||||||
for t, v in self.configs[nodenum]:
|
|
||||||
if use_clsmap:
|
|
||||||
t = self._modelclsmap[t]
|
|
||||||
r.append((nodenum, t, v))
|
|
||||||
return r
|
|
||||||
|
|
||||||
def clearconfig(self, nodenum):
|
|
||||||
"""
|
|
||||||
remove configuration values for the specified node;
|
|
||||||
when nodenum is None, remove all configuration values
|
|
||||||
|
|
||||||
:param int nodenum: node id
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
if nodenum is None:
|
|
||||||
self.configs = {}
|
|
||||||
return
|
|
||||||
if nodenum in self.configs:
|
|
||||||
self.configs.pop(nodenum)
|
|
||||||
|
|
||||||
def setconfig_keyvalues(self, nodenum, conftype, keyvalues):
|
|
||||||
"""
|
|
||||||
Key values list of tuples for a node.
|
|
||||||
|
|
||||||
:param int nodenum: node id
|
|
||||||
:param conftype: configuration type
|
|
||||||
:param keyvalues: key valyes
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
if conftype not in self._modelclsmap:
|
|
||||||
logger.warn("unknown model type '%s'", conftype)
|
|
||||||
return
|
|
||||||
model = self._modelclsmap[conftype]
|
|
||||||
keys = model.getnames()
|
|
||||||
# defaults are merged with supplied values here
|
|
||||||
values = list(model.getdefaultvalues())
|
|
||||||
for key, value in keyvalues:
|
|
||||||
if key not in keys:
|
|
||||||
logger.warn("Skipping unknown configuration key for %s: '%s'", conftype, key)
|
|
||||||
continue
|
|
||||||
i = keys.index(key)
|
|
||||||
values[i] = value
|
|
||||||
self.setconfig(nodenum, conftype, values)
|
|
||||||
|
|
||||||
def getmodels(self, n):
|
|
||||||
"""
|
|
||||||
Return a list of model classes and values for a net if one has been
|
|
||||||
configured. This is invoked when exporting a session to XML.
|
|
||||||
This assumes self.configs contains an iterable of (model-names, values)
|
|
||||||
and a self._modelclsmapdict exists.
|
|
||||||
|
|
||||||
:param n: network node to get models for
|
|
||||||
:return: list of model and values tuples for the network node
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
r = []
|
|
||||||
if n.objid in self.configs:
|
|
||||||
v = self.configs[n.objid]
|
|
||||||
for model in v:
|
|
||||||
cls = self._modelclsmap[model[0]]
|
|
||||||
vals = model[1]
|
|
||||||
r.append((cls, vals))
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
class Configurable(object):
|
|
||||||
"""
|
|
||||||
A generic class for managing configuration parameters.
|
|
||||||
Parameters are sent via Configuration Messages, which allow the GUI
|
|
||||||
to build dynamic dialogs depending on what is being configured.
|
|
||||||
"""
|
|
||||||
name = ""
|
|
||||||
# Configuration items:
|
|
||||||
# ('name', 'type', 'default', 'possible-value-list', 'caption')
|
|
||||||
config_matrix = []
|
|
||||||
config_groups = None
|
|
||||||
bitmap = None
|
|
||||||
|
|
||||||
def __init__(self, session=None, object_id=None):
|
|
||||||
"""
|
|
||||||
Creates a Configurable instance.
|
|
||||||
|
|
||||||
:param core.session.Session session: session for this configurable
|
|
||||||
:param object_id:
|
|
||||||
"""
|
|
||||||
self.session = session
|
|
||||||
self.object_id = object_id
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
"""
|
|
||||||
Reset method.
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def register(self):
|
|
||||||
"""
|
|
||||||
Register method.
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getdefaultvalues(cls):
|
def config_data(cls, flags, node_id, type_flags, configurable_options, config):
|
||||||
"""
|
|
||||||
Retrieve default values from configuration matrix.
|
|
||||||
|
|
||||||
:return: tuple of default values
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
return tuple(map(lambda x: x[2], cls.config_matrix))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def getnames(cls):
|
|
||||||
"""
|
|
||||||
Retrieve name values from configuration matrix.
|
|
||||||
|
|
||||||
:return: tuple of name values
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
return tuple(map(lambda x: x[0], cls.config_matrix))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def configure(cls, manager, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration messages for this object.
|
|
||||||
|
|
||||||
:param ConfigurableManager manager: configuration manager
|
|
||||||
:param config_data: configuration data
|
|
||||||
:return: configuration data object
|
|
||||||
:rtype: ConfigData
|
|
||||||
"""
|
|
||||||
reply = None
|
|
||||||
node_id = config_data.node
|
|
||||||
object_name = config_data.object
|
|
||||||
config_type = config_data.type
|
|
||||||
interface_id = config_data.interface_number
|
|
||||||
values_str = config_data.data_values
|
|
||||||
|
|
||||||
if interface_id is not None:
|
|
||||||
node_id = node_id * 1000 + interface_id
|
|
||||||
|
|
||||||
logger.debug("received configure message for %s nodenum:%s", cls.name, str(node_id))
|
|
||||||
if config_type == ConfigFlags.REQUEST.value:
|
|
||||||
logger.info("replying to configure request for %s model", cls.name)
|
|
||||||
# when object name is "all", the reply to this request may be None
|
|
||||||
# if this node has not been configured for this model; otherwise we
|
|
||||||
# reply with the defaults for this model
|
|
||||||
if object_name == "all":
|
|
||||||
defaults = None
|
|
||||||
typeflags = ConfigFlags.UPDATE.value
|
|
||||||
else:
|
|
||||||
defaults = cls.getdefaultvalues()
|
|
||||||
typeflags = ConfigFlags.NONE.value
|
|
||||||
values = manager.getconfig(node_id, cls.name, defaults)[1]
|
|
||||||
if values is None:
|
|
||||||
logger.warn("no active configuration for node (%s), ignoring request")
|
|
||||||
# node has no active config for this model (don't send defaults)
|
|
||||||
return None
|
|
||||||
# reply with config options
|
|
||||||
reply = cls.config_data(0, node_id, typeflags, values)
|
|
||||||
elif config_type == ConfigFlags.RESET.value:
|
|
||||||
if object_name == "all":
|
|
||||||
manager.clearconfig(node_id)
|
|
||||||
# elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE:
|
|
||||||
else:
|
|
||||||
# store the configuration values for later use, when the node
|
|
||||||
# object has been created
|
|
||||||
if object_name is None:
|
|
||||||
logger.info("no configuration object for node %s", node_id)
|
|
||||||
return None
|
|
||||||
defaults = cls.getdefaultvalues()
|
|
||||||
if values_str is None:
|
|
||||||
# use default or preconfigured values
|
|
||||||
values = manager.getconfig(node_id, cls.name, defaults)[1]
|
|
||||||
else:
|
|
||||||
# use new values supplied from the conf message
|
|
||||||
values = values_str.split('|')
|
|
||||||
# determine new or old style config
|
|
||||||
new = cls.haskeyvalues(values)
|
|
||||||
if new:
|
|
||||||
new_values = list(defaults)
|
|
||||||
keys = cls.getnames()
|
|
||||||
for v in values:
|
|
||||||
key, value = v.split('=', 1)
|
|
||||||
try:
|
|
||||||
new_values[keys.index(key)] = value
|
|
||||||
except ValueError:
|
|
||||||
logger.info("warning: ignoring invalid key '%s'" % key)
|
|
||||||
values = new_values
|
|
||||||
manager.setconfig(node_id, object_name, values)
|
|
||||||
|
|
||||||
return reply
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def config_data(cls, flags, node_id, type_flags, values):
|
|
||||||
"""
|
"""
|
||||||
Convert this class to a Config API message. Some TLVs are defined
|
Convert this class to a Config API message. Some TLVs are defined
|
||||||
by the class, but node number, conf type flags, and values must
|
by the class, but node number, conf type flags, and values must
|
||||||
|
@ -388,106 +28,143 @@ class Configurable(object):
|
||||||
:param flags: message flags
|
:param flags: message flags
|
||||||
:param int node_id: node id
|
:param int node_id: node id
|
||||||
:param type_flags: type flags
|
:param type_flags: type flags
|
||||||
:param values: values
|
:param ConfigurableOptions configurable_options: options to create config data for
|
||||||
|
:param dict config: configuration values for options
|
||||||
:return: configuration data object
|
:return: configuration data object
|
||||||
:rtype: ConfigData
|
:rtype: ConfigData
|
||||||
"""
|
"""
|
||||||
keys = cls.getnames()
|
key_values = None
|
||||||
keyvalues = map(lambda a, b: "%s=%s" % (a, b), keys, values)
|
captions = None
|
||||||
values_str = string.join(keyvalues, '|')
|
data_types = []
|
||||||
datatypes = tuple(map(lambda x: x[1], cls.config_matrix))
|
possible_values = []
|
||||||
captions = reduce(lambda a, b: a + '|' + b, map(lambda x: x[4], cls.config_matrix))
|
logger.debug("configurable: %s", configurable_options)
|
||||||
possible_valuess = reduce(lambda a, b: a + '|' + b, map(lambda x: x[3], cls.config_matrix))
|
logger.debug("configuration options: %s", configurable_options.configurations)
|
||||||
|
logger.debug("configuration data: %s", config)
|
||||||
|
for configuration in configurable_options.configurations():
|
||||||
|
if not captions:
|
||||||
|
captions = configuration.label
|
||||||
|
else:
|
||||||
|
captions += "|%s" % configuration.label
|
||||||
|
|
||||||
|
data_types.append(configuration.type.value)
|
||||||
|
|
||||||
|
options = ",".join(configuration.options)
|
||||||
|
possible_values.append(options)
|
||||||
|
|
||||||
|
_id = configuration.id
|
||||||
|
config_value = config.get(_id, configuration.default)
|
||||||
|
key_value = "%s=%s" % (_id, config_value)
|
||||||
|
if not key_values:
|
||||||
|
key_values = key_value
|
||||||
|
else:
|
||||||
|
key_values += "|%s" % key_value
|
||||||
|
|
||||||
return ConfigData(
|
return ConfigData(
|
||||||
message_type=flags,
|
message_type=flags,
|
||||||
node=node_id,
|
node=node_id,
|
||||||
object=cls.name,
|
object=configurable_options.name,
|
||||||
type=type_flags,
|
type=type_flags,
|
||||||
data_types=datatypes,
|
data_types=tuple(data_types),
|
||||||
data_values=values_str,
|
data_values=key_values,
|
||||||
captions=captions,
|
captions=captions,
|
||||||
possible_values=possible_valuess,
|
possible_values="|".join(possible_values),
|
||||||
bitmap=cls.bitmap,
|
bitmap=configurable_options.bitmap,
|
||||||
groups=cls.config_groups
|
groups=configurable_options.config_groups()
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def booltooffon(value):
|
|
||||||
"""
|
|
||||||
Convenience helper turns bool into on (True) or off (False) string.
|
|
||||||
|
|
||||||
:param str value: value to retrieve on/off value for
|
class Configuration(object):
|
||||||
:return: on or off string
|
def __init__(self, _id, _type, label, default="", options=None):
|
||||||
:rtype: str
|
self.id = _id
|
||||||
"""
|
self.type = _type
|
||||||
if value == "1" or value == "true" or value == "on":
|
self.default = default
|
||||||
return "on"
|
if not options:
|
||||||
else:
|
options = []
|
||||||
return "off"
|
self.options = options
|
||||||
|
if not label:
|
||||||
|
label = _id
|
||||||
|
self.label = label
|
||||||
|
|
||||||
@staticmethod
|
def __str__(self):
|
||||||
def offontobool(value):
|
return "%s(id=%s, type=%s, default=%s, options=%s)" % (
|
||||||
"""
|
self.__class__.__name__, self.id, self.type, self.default, self.options)
|
||||||
Convenience helper for converting an on/off string to a integer.
|
|
||||||
|
|
||||||
:param str value: on/off string
|
|
||||||
:return: on/off integer value
|
class ConfigurableOptions(object):
|
||||||
:rtype: int
|
# unique name to receive configuration changes
|
||||||
"""
|
name = None
|
||||||
if type(value) == str:
|
bitmap = None
|
||||||
if value.lower() == "on":
|
|
||||||
return 1
|
|
||||||
elif value.lower() == "off":
|
|
||||||
return 0
|
|
||||||
return value
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def valueof(cls, name, values):
|
def configurations(cls):
|
||||||
"""
|
"""
|
||||||
Helper to return a value by the name defined in confmatrix.
|
Returns configuration options supported by this class.
|
||||||
Checks if it is boolean
|
|
||||||
|
|
||||||
:param str name: name to get value of
|
:return: list of configuration options
|
||||||
:param values: values to get value from
|
:rtype: list[Configuration]
|
||||||
:return: value for name
|
|
||||||
"""
|
"""
|
||||||
i = cls.getnames().index(name)
|
return []
|
||||||
if cls.config_matrix[i][1] == ConfigDataTypes.BOOL.value and values[i] != "":
|
|
||||||
return cls.booltooffon(values[i])
|
|
||||||
else:
|
|
||||||
return values[i]
|
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def haskeyvalues(values):
|
def config_groups(cls):
|
||||||
"""
|
"""
|
||||||
Helper to check for list of key=value pairs versus a plain old
|
String formatted to specify configuration groupings, using list index positions.
|
||||||
list of values. Returns True if all elements are "key=value".
|
|
||||||
|
|
||||||
:param values: items to check for key/value pairs
|
Example:
|
||||||
:return: True if all values are key/value pairs, False otherwise
|
"Group1:start-stop|Group2:start-stop"
|
||||||
:rtype: bool
|
|
||||||
|
:return: config groups
|
||||||
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
if len(values) == 0:
|
return None
|
||||||
return False
|
|
||||||
for v in values:
|
|
||||||
if "=" not in v:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def getkeyvaluelist(self):
|
@classmethod
|
||||||
|
def default_values(cls):
|
||||||
"""
|
"""
|
||||||
Helper to return a list of (key, value) tuples. Keys come from
|
Retrieves default values for configurations.
|
||||||
configuration matrix and values are instance attributes.
|
|
||||||
|
|
||||||
:return: tuples of key value pairs
|
:return: mapping of configuration options that can also be iterated in order of definition
|
||||||
:rtype: list
|
:rtype: OrderedDict
|
||||||
"""
|
"""
|
||||||
key_values = []
|
return OrderedDict([(config.id, config.default) for config in cls.configurations()])
|
||||||
|
|
||||||
for name in self.getnames():
|
|
||||||
if hasattr(self, name):
|
|
||||||
value = getattr(self, name)
|
|
||||||
key_values.append((name, value))
|
|
||||||
|
|
||||||
return key_values
|
class NewConfigurableManager(object):
|
||||||
|
_default_node = -1
|
||||||
|
_default_type = "default"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._configuration_maps = {}
|
||||||
|
|
||||||
|
def nodes(self):
|
||||||
|
return [node_id for node_id in self._configuration_maps.iterkeys() if node_id != self._default_node]
|
||||||
|
|
||||||
|
def config_reset(self, node_id=None):
|
||||||
|
if not node_id:
|
||||||
|
self._configuration_maps.clear()
|
||||||
|
elif node_id in self._configuration_maps:
|
||||||
|
self._configuration_maps.pop(node_id)
|
||||||
|
|
||||||
|
def set_config(self, _id, value, node_id=_default_node, config_type=_default_type):
|
||||||
|
logger.debug("setting config for node(%s) type(%s): %s=%s", node_id, config_type, _id, value)
|
||||||
|
node_type_map = self.get_configs(node_id, config_type)
|
||||||
|
node_type_map[_id] = value
|
||||||
|
|
||||||
|
def set_configs(self, config, node_id=_default_node, config_type=_default_type):
|
||||||
|
logger.debug("setting config for node(%s) type(%s): %s", node_id, config_type, config)
|
||||||
|
node_type_map = self.get_configs(node_id, config_type)
|
||||||
|
node_type_map.clear()
|
||||||
|
node_type_map.update(config)
|
||||||
|
|
||||||
|
def get_config(self, _id, node_id=_default_node, config_type=_default_type):
|
||||||
|
logger.debug("getting config for node(%s) type(%s): %s", node_id, config_type, _id)
|
||||||
|
node_type_map = self.get_configs(node_id, config_type)
|
||||||
|
return node_type_map.get(_id)
|
||||||
|
|
||||||
|
def get_configs(self, node_id=_default_node, config_type=_default_type):
|
||||||
|
logger.debug("getting configs for node(%s) type(%s)", node_id, config_type)
|
||||||
|
node_map = self._configuration_maps.setdefault(node_id, {})
|
||||||
|
return node_map.setdefault(config_type, {})
|
||||||
|
|
||||||
|
def get_config_types(self, node_id=_default_node):
|
||||||
|
return self._configuration_maps.get(node_id, {})
|
||||||
|
|
|
@ -10,15 +10,17 @@ import shutil
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from itertools import repeat
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.api import coreapi
|
from core.api import coreapi
|
||||||
|
from core.conf import ConfigShim
|
||||||
from core.data import ConfigData
|
from core.data import ConfigData
|
||||||
from core.data import EventData
|
from core.data import EventData
|
||||||
from core.emulator.emudata import InterfaceData
|
from core.emulator.emudata import InterfaceData
|
||||||
from core.emulator.emudata import LinkOptions
|
from core.emulator.emudata import LinkOptions
|
||||||
from core.emulator.emudata import NodeOptions
|
from core.emulator.emudata import NodeOptions
|
||||||
from core.enumerations import ConfigTlvs
|
from core.enumerations import ConfigTlvs, ConfigFlags, ConfigDataTypes
|
||||||
from core.enumerations import EventTlvs
|
from core.enumerations import EventTlvs
|
||||||
from core.enumerations import EventTypes
|
from core.enumerations import EventTypes
|
||||||
from core.enumerations import ExceptionTlvs
|
from core.enumerations import ExceptionTlvs
|
||||||
|
@ -35,6 +37,8 @@ from core.enumerations import SessionTlvs
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.misc import structutils
|
from core.misc import structutils
|
||||||
from core.misc import utils
|
from core.misc import utils
|
||||||
|
from core.mobility import BasicRangeModel, Ns2ScriptedMobility
|
||||||
|
from core.service import ServiceManager
|
||||||
|
|
||||||
|
|
||||||
class CoreHandler(SocketServer.BaseRequestHandler):
|
class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
|
@ -407,12 +411,19 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
tlv_data = ""
|
tlv_data = ""
|
||||||
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, "core-daemon")
|
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, "core-daemon")
|
||||||
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EMULATION_SERVER.value, "core-daemon")
|
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EMULATION_SERVER.value, "core-daemon")
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.broker.config_type, self.session.broker.name)
|
||||||
# get config objects for session
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.location.config_type, self.session.location.name)
|
||||||
for name in self.session.config_objects:
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.mobility.config_type, self.session.mobility.name)
|
||||||
config_type, callback = self.session.config_objects[name]
|
for model_name in self.session.mobility.mobility_models():
|
||||||
# type must be in coreapi.reg_tlvs
|
model_class = self.session.mobility.get_model_class(model_name)
|
||||||
tlv_data += coreapi.CoreRegisterTlv.pack(config_type, name)
|
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.services.config_type, self.session.services.name)
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.emane.config_type, self.session.emane.name)
|
||||||
|
for model_name in self.session.emane.emane_models():
|
||||||
|
model_class = self.session.emane.get_model_class(model_name)
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.options.config_type, self.session.options.name)
|
||||||
|
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.metadata.config_type, self.session.metadata.name)
|
||||||
|
|
||||||
return coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlv_data)
|
return coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlv_data)
|
||||||
|
|
||||||
|
@ -941,15 +952,399 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
opaque=message.get_tlv(ConfigTlvs.OPAQUE.value)
|
opaque=message.get_tlv(ConfigTlvs.OPAQUE.value)
|
||||||
)
|
)
|
||||||
logger.debug("configuration message for %s node %s", config_data.object, config_data.node)
|
logger.debug("configuration message for %s node %s", config_data.object, config_data.node)
|
||||||
|
message_type = ConfigFlags(config_data.type)
|
||||||
|
|
||||||
# dispatch to any registered callback for this object type
|
replies = []
|
||||||
replies = self.session.config_object(config_data)
|
|
||||||
|
# handle session configuration
|
||||||
|
if config_data.object == "all":
|
||||||
|
replies = self.handle_config_all(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.options.name:
|
||||||
|
replies = self.handle_config_session(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.location.name:
|
||||||
|
self.handle_config_location(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.metadata.name:
|
||||||
|
replies = self.handle_config_metadata(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.broker.name:
|
||||||
|
self.handle_config_broker(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.services.name:
|
||||||
|
replies = self.handle_config_services(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.mobility.name:
|
||||||
|
self.handle_config_mobility(message_type, config_data)
|
||||||
|
elif config_data.object in [BasicRangeModel.name, Ns2ScriptedMobility.name]:
|
||||||
|
replies = self.handle_config_mobility_models(message_type, config_data)
|
||||||
|
elif config_data.object == self.session.emane.name:
|
||||||
|
replies = self.handle_config_emane(message_type, config_data)
|
||||||
|
elif config_data.object in self.session.emane.emane_models():
|
||||||
|
replies = self.handle_config_emane_models(message_type, config_data)
|
||||||
|
else:
|
||||||
|
raise Exception("no handler for configuration: %s", config_data.object)
|
||||||
|
|
||||||
for reply in replies:
|
for reply in replies:
|
||||||
self.handle_broadcast_config(reply)
|
self.handle_broadcast_config(reply)
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def handle_config_all(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
|
||||||
|
if message_type == ConfigFlags.RESET:
|
||||||
|
node_id = config_data.node
|
||||||
|
self.session.location.reset()
|
||||||
|
self.session.services.reset()
|
||||||
|
self.session.mobility.reset()
|
||||||
|
self.session.mobility.config_reset(node_id)
|
||||||
|
self.session.emane.config_reset(node_id)
|
||||||
|
else:
|
||||||
|
raise Exception("cant handle config all: %s" % message_type)
|
||||||
|
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_session(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
type_flags = ConfigFlags.NONE.value
|
||||||
|
config = self.session.options.get_configs()
|
||||||
|
config_response = ConfigShim.config_data(0, None, type_flags, self.session.options, config)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif message_type != ConfigFlags.RESET and config_data.data_values:
|
||||||
|
values = ConfigShim.str_to_dict(config_data.data_values)
|
||||||
|
for key, value in values.iteritems():
|
||||||
|
self.session.options.set_config(key, value)
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_location(self, message_type, config_data):
|
||||||
|
if message_type == ConfigFlags.RESET:
|
||||||
|
self.session.location.reset()
|
||||||
|
else:
|
||||||
|
if not config_data.data_values:
|
||||||
|
logger.warn("location data missing")
|
||||||
|
else:
|
||||||
|
values = config_data.data_values.split("|")
|
||||||
|
|
||||||
|
# Cartesian coordinate reference point
|
||||||
|
refx, refy = map(lambda x: float(x), values[0:2])
|
||||||
|
refz = 0.0
|
||||||
|
lat, lon, alt = map(lambda x: float(x), values[2:5])
|
||||||
|
# xyz point
|
||||||
|
self.session.location.refxyz = (refx, refy, refz)
|
||||||
|
# geographic reference point
|
||||||
|
self.session.location.setrefgeo(lat, lon, alt)
|
||||||
|
self.session.location.refscale = float(values[5])
|
||||||
|
logger.info("location configured: %s = %s scale=%s", self.session.location.refxyz,
|
||||||
|
self.session.location.refgeo, self.session.location.refscale)
|
||||||
|
logger.info("location configured: UTM%s", self.session.location.refutm)
|
||||||
|
|
||||||
|
def handle_config_metadata(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
node_id = config_data.node
|
||||||
|
data_values = "|".join(["%s=%s" % item for item in self.session.metadata.get_configs().iteritems()])
|
||||||
|
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.session.metadata.get_configs())
|
||||||
|
config_response = ConfigData(
|
||||||
|
message_type=0,
|
||||||
|
node=node_id,
|
||||||
|
object=self.session.metadata.name,
|
||||||
|
type=ConfigFlags.NONE.value,
|
||||||
|
data_types=data_types,
|
||||||
|
data_values=data_values
|
||||||
|
)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif message_type != ConfigFlags.RESET and config_data.data_values:
|
||||||
|
values = ConfigShim.str_to_dict(config_data.data_values)
|
||||||
|
for key, value in values.iteritems():
|
||||||
|
self.session.metadata.set_config(key, value)
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_broker(self, message_type, config_data):
|
||||||
|
if message_type not in [ConfigFlags.REQUEST, ConfigFlags.RESET]:
|
||||||
|
session_id = config_data.session
|
||||||
|
if not config_data.data_values:
|
||||||
|
logger.info("emulation server data missing")
|
||||||
|
else:
|
||||||
|
values = config_data.data_values.split("|")
|
||||||
|
|
||||||
|
# string of "server:ip:port,server:ip:port,..."
|
||||||
|
server_strings = values[0]
|
||||||
|
server_list = server_strings.split(",")
|
||||||
|
|
||||||
|
for server in server_list:
|
||||||
|
server_items = server.split(":")
|
||||||
|
name, host, port = server_items[:3]
|
||||||
|
|
||||||
|
if host == "":
|
||||||
|
host = None
|
||||||
|
|
||||||
|
if port == "":
|
||||||
|
port = None
|
||||||
|
else:
|
||||||
|
port = int(port)
|
||||||
|
|
||||||
|
if session_id is not None:
|
||||||
|
# receive session ID and my IP from master
|
||||||
|
self.session.broker.session_id_master = int(session_id.split("|")[0])
|
||||||
|
self.session.broker.myip = host
|
||||||
|
host = None
|
||||||
|
port = None
|
||||||
|
|
||||||
|
# this connects to the server immediately; maybe we should wait
|
||||||
|
# or spin off a new "client" thread here
|
||||||
|
self.session.broker.addserver(name, host, port)
|
||||||
|
self.session.broker.setupserver(name)
|
||||||
|
|
||||||
|
def handle_config_services(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
node_id = config_data.node
|
||||||
|
opaque = config_data.opaque
|
||||||
|
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
session_id = config_data.session
|
||||||
|
opaque = config_data.opaque
|
||||||
|
|
||||||
|
logger.debug("configuration request: node(%s) session(%s) opaque(%s)", node_id, session_id, opaque)
|
||||||
|
|
||||||
|
# send back a list of available services
|
||||||
|
if opaque is None:
|
||||||
|
type_flag = ConfigFlags.NONE.value
|
||||||
|
data_types = tuple(repeat(ConfigDataTypes.BOOL.value, len(ServiceManager.services)))
|
||||||
|
values = "|".join(repeat('0', len(ServiceManager.services)))
|
||||||
|
names = map(lambda x: x._name, ServiceManager.services)
|
||||||
|
captions = "|".join(names)
|
||||||
|
possible_values = ""
|
||||||
|
for s in ServiceManager.services:
|
||||||
|
if s._custom_needed:
|
||||||
|
possible_values += '1'
|
||||||
|
possible_values += '|'
|
||||||
|
groups = self.session.services.buildgroups(ServiceManager.services)
|
||||||
|
# send back the properties for this service
|
||||||
|
else:
|
||||||
|
if not node_id:
|
||||||
|
return replies
|
||||||
|
|
||||||
|
node = self.session.get_object(node_id)
|
||||||
|
if node is None:
|
||||||
|
logger.warn("Request to configure service for unknown node %s", node_id)
|
||||||
|
return replies
|
||||||
|
servicesstring = opaque.split(':')
|
||||||
|
services, unknown = self.session.services.servicesfromopaque(opaque, node.objid)
|
||||||
|
for u in unknown:
|
||||||
|
logger.warn("Request for unknown service '%s'" % u)
|
||||||
|
|
||||||
|
if not services:
|
||||||
|
return replies
|
||||||
|
|
||||||
|
if len(servicesstring) == 3:
|
||||||
|
# a file request: e.g. "service:zebra:quagga.conf"
|
||||||
|
file_data = self.session.services.getservicefile(services, node, servicesstring[2])
|
||||||
|
self.session.broadcast_file(file_data)
|
||||||
|
# short circuit this request early to avoid returning response below
|
||||||
|
return replies
|
||||||
|
|
||||||
|
# the first service in the list is the one being configured
|
||||||
|
svc = services[0]
|
||||||
|
# send back:
|
||||||
|
# dirs, configs, startindex, startup, shutdown, metadata, config
|
||||||
|
type_flag = ConfigFlags.UPDATE.value
|
||||||
|
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(svc.keys)))
|
||||||
|
values = svc.tovaluelist(node, services)
|
||||||
|
captions = None
|
||||||
|
possible_values = None
|
||||||
|
groups = None
|
||||||
|
|
||||||
|
config_response = ConfigData(
|
||||||
|
message_type=0,
|
||||||
|
node=node_id,
|
||||||
|
object=self.session.services.name,
|
||||||
|
type=type_flag,
|
||||||
|
data_types=data_types,
|
||||||
|
data_values=values,
|
||||||
|
captions=captions,
|
||||||
|
possible_values=possible_values,
|
||||||
|
groups=groups,
|
||||||
|
session=session_id,
|
||||||
|
opaque=opaque
|
||||||
|
)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif message_type == ConfigFlags.RESET:
|
||||||
|
self.session.services.reset()
|
||||||
|
else:
|
||||||
|
data_types = config_data.data_types
|
||||||
|
values = config_data.data_values
|
||||||
|
|
||||||
|
error_message = "services config message that I don't know how to handle"
|
||||||
|
if values is None:
|
||||||
|
logger.error(error_message)
|
||||||
|
else:
|
||||||
|
if opaque is None:
|
||||||
|
values = values.split('|')
|
||||||
|
# store default services for a node type in self.defaultservices[]
|
||||||
|
if data_types is None or data_types[0] != ConfigDataTypes.STRING.value:
|
||||||
|
logger.info(error_message)
|
||||||
|
return None
|
||||||
|
key = values.pop(0)
|
||||||
|
self.session.services.defaultservices[key] = values
|
||||||
|
logger.debug("default services for type %s set to %s", key, values)
|
||||||
|
elif node_id:
|
||||||
|
# store service customized config in self.customservices[]
|
||||||
|
services, unknown = self.session.services.servicesfromopaque(opaque, node_id)
|
||||||
|
for u in unknown:
|
||||||
|
logger.warn("Request for unknown service '%s'" % u)
|
||||||
|
|
||||||
|
if services:
|
||||||
|
svc = services[0]
|
||||||
|
values = ConfigShim.str_to_dict(values)
|
||||||
|
self.session.services.setcustomservice(node_id, svc, values)
|
||||||
|
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_mobility(self, message_type, _):
|
||||||
|
if message_type == ConfigFlags.RESET:
|
||||||
|
self.session.mobility.reset()
|
||||||
|
|
||||||
|
def handle_config_mobility_models(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
node_id = config_data.node
|
||||||
|
object_name = config_data.object
|
||||||
|
interface_id = config_data.interface_number
|
||||||
|
values_str = config_data.data_values
|
||||||
|
|
||||||
|
if interface_id is not None:
|
||||||
|
node_id = node_id * 1000 + interface_id
|
||||||
|
|
||||||
|
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
logger.info("replying to configure request for model: %s", object_name)
|
||||||
|
if object_name == "all":
|
||||||
|
typeflags = ConfigFlags.UPDATE.value
|
||||||
|
else:
|
||||||
|
typeflags = ConfigFlags.NONE.value
|
||||||
|
|
||||||
|
model_class = self.session.mobility.get_model_class(object_name)
|
||||||
|
if not model_class:
|
||||||
|
logger.warn("model class does not exist: %s", object_name)
|
||||||
|
return []
|
||||||
|
|
||||||
|
config = self.session.mobility.get_configs(node_id, object_name)
|
||||||
|
if not config:
|
||||||
|
config = model_class.default_values()
|
||||||
|
|
||||||
|
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif message_type == ConfigFlags.RESET:
|
||||||
|
if object_name == "all":
|
||||||
|
self.session.mobility.config_reset(node_id)
|
||||||
|
else:
|
||||||
|
# store the configuration values for later use, when the node
|
||||||
|
if not object_name:
|
||||||
|
logger.warn("no configuration object for node: %s", node_id)
|
||||||
|
return []
|
||||||
|
|
||||||
|
model_class = self.session.mobility.get_model_class(object_name)
|
||||||
|
if not model_class:
|
||||||
|
logger.warn("model class does not exist: %s", object_name)
|
||||||
|
return []
|
||||||
|
|
||||||
|
if values_str:
|
||||||
|
config = ConfigShim.str_to_dict(values_str)
|
||||||
|
else:
|
||||||
|
config = model_class.default_values()
|
||||||
|
|
||||||
|
self.session.mobility.set_configs(config, node_id, object_name)
|
||||||
|
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_emane(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
node_id = config_data.node
|
||||||
|
object_name = config_data.object
|
||||||
|
config_type = config_data.type
|
||||||
|
interface_id = config_data.interface_number
|
||||||
|
values_str = config_data.data_values
|
||||||
|
|
||||||
|
if interface_id is not None:
|
||||||
|
node_id = node_id * 1000 + interface_id
|
||||||
|
|
||||||
|
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
logger.info("replying to configure request for %s model", object_name)
|
||||||
|
if object_name == "all":
|
||||||
|
typeflags = ConfigFlags.UPDATE.value
|
||||||
|
else:
|
||||||
|
typeflags = ConfigFlags.NONE.value
|
||||||
|
config = self.session.emane.get_configs()
|
||||||
|
config_response = ConfigShim.config_data(0, node_id, typeflags, self.session.emane.emane_config, config)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif config_type == ConfigFlags.RESET.value:
|
||||||
|
if object_name == "all":
|
||||||
|
self.session.emane.config_reset(node_id)
|
||||||
|
else:
|
||||||
|
if not object_name:
|
||||||
|
logger.info("no configuration object for node %s", node_id)
|
||||||
|
return []
|
||||||
|
|
||||||
|
if values_str:
|
||||||
|
config = ConfigShim.str_to_dict(values_str)
|
||||||
|
self.session.emane.set_configs(config)
|
||||||
|
|
||||||
|
# extra logic to start slave Emane object after nemid has been configured from the master
|
||||||
|
if message_type == ConfigFlags.UPDATE and self.session.master is False:
|
||||||
|
# instantiation was previously delayed by setup returning Emane.NOT_READY
|
||||||
|
self.session.instantiate()
|
||||||
|
|
||||||
|
return replies
|
||||||
|
|
||||||
|
def handle_config_emane_models(self, message_type, config_data):
|
||||||
|
replies = []
|
||||||
|
node_id = config_data.node
|
||||||
|
object_name = config_data.object
|
||||||
|
interface_id = config_data.interface_number
|
||||||
|
values_str = config_data.data_values
|
||||||
|
|
||||||
|
if interface_id is not None:
|
||||||
|
node_id = node_id * 1000 + interface_id
|
||||||
|
|
||||||
|
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||||
|
if message_type == ConfigFlags.REQUEST:
|
||||||
|
logger.info("replying to configure request for model: %s", object_name)
|
||||||
|
if object_name == "all":
|
||||||
|
typeflags = ConfigFlags.UPDATE.value
|
||||||
|
else:
|
||||||
|
typeflags = ConfigFlags.NONE.value
|
||||||
|
|
||||||
|
model_class = self.session.emane.get_model_class(object_name)
|
||||||
|
if not model_class:
|
||||||
|
logger.warn("model class does not exist: %s", object_name)
|
||||||
|
return []
|
||||||
|
|
||||||
|
config = self.session.emane.get_configs(node_id, object_name)
|
||||||
|
if not config:
|
||||||
|
config = model_class.default_values()
|
||||||
|
|
||||||
|
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||||
|
replies.append(config_response)
|
||||||
|
elif message_type == ConfigFlags.RESET:
|
||||||
|
if object_name == "all":
|
||||||
|
self.session.emane.config_reset(node_id)
|
||||||
|
else:
|
||||||
|
# store the configuration values for later use, when the node
|
||||||
|
if not object_name:
|
||||||
|
logger.warn("no configuration object for node: %s", node_id)
|
||||||
|
return []
|
||||||
|
|
||||||
|
model_class = self.session.emane.get_model_class(object_name)
|
||||||
|
if not model_class:
|
||||||
|
logger.warn("model class does not exist: %s", object_name)
|
||||||
|
return []
|
||||||
|
|
||||||
|
if values_str:
|
||||||
|
config = ConfigShim.str_to_dict(values_str)
|
||||||
|
else:
|
||||||
|
config = model_class.default_values()
|
||||||
|
|
||||||
|
self.session.emane.set_configs(config, node_id, object_name)
|
||||||
|
|
||||||
|
return replies
|
||||||
|
|
||||||
def handle_file_message(self, message):
|
def handle_file_message(self, message):
|
||||||
"""
|
"""
|
||||||
File Message handler
|
File Message handler
|
||||||
|
|
|
@ -305,8 +305,8 @@ class PyCoreNode(PyCoreObj):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
preserve = getattr(self.session.options, "preservedir", None)
|
preserve = self.session.options.get_config("preservedir") == "1"
|
||||||
if preserve == "1":
|
if preserve:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.tmpnodedir:
|
if self.tmpnodedir:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
EMANE Bypass model for CORE
|
EMANE Bypass model for CORE
|
||||||
"""
|
"""
|
||||||
|
from core.conf import Configuration
|
||||||
from core.emane import emanemodel
|
from core.emane import emanemodel
|
||||||
from core.enumerations import ConfigDataTypes
|
from core.enumerations import ConfigDataTypes
|
||||||
|
|
||||||
|
@ -15,13 +15,20 @@ class EmaneBypassModel(emanemodel.EmaneModel):
|
||||||
# mac definitions
|
# mac definitions
|
||||||
mac_library = "bypassmaclayer"
|
mac_library = "bypassmaclayer"
|
||||||
mac_config = [
|
mac_config = [
|
||||||
("none", ConfigDataTypes.BOOL.value, "0", "True,False",
|
Configuration(
|
||||||
"There are no parameters for the bypass model."),
|
_id="none",
|
||||||
|
_type=ConfigDataTypes.BOOL,
|
||||||
|
default="0",
|
||||||
|
options=["True", "False"],
|
||||||
|
label="There are no parameters for the bypass model."
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# phy definitions
|
# phy definitions
|
||||||
phy_library = "bypassphylayer"
|
phy_library = "bypassphylayer"
|
||||||
phy_config = []
|
phy_config = []
|
||||||
|
|
||||||
# override gui display tabs
|
# override config groups
|
||||||
config_groups_override = "Bypass Parameters:1-1"
|
@classmethod
|
||||||
|
def config_groups(cls):
|
||||||
|
return "Bypass Parameters:1-1"
|
||||||
|
|
|
@ -35,8 +35,13 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
||||||
shim_defaults = {}
|
shim_defaults = {}
|
||||||
config_shim = emanemanifest.parse(shim_xml, shim_defaults)
|
config_shim = emanemanifest.parse(shim_xml, shim_defaults)
|
||||||
|
|
||||||
config_groups_override = "CommEffect SHIM Parameters:1-%d" % len(config_shim)
|
@classmethod
|
||||||
config_matrix_override = config_shim
|
def configurations(cls):
|
||||||
|
return cls.config_shim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_groups(cls):
|
||||||
|
return "CommEffect SHIM Parameters:1-%d" % len(cls.configurations())
|
||||||
|
|
||||||
def build_xml_files(self, emane_manager, interface):
|
def build_xml_files(self, emane_manager, interface):
|
||||||
"""
|
"""
|
||||||
|
@ -49,8 +54,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
||||||
:param interface: interface for the emane node
|
:param interface: interface for the emane node
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
values = emane_manager.getifcconfig(self.object_id, self.name, self.getdefaultvalues(), interface)
|
default_values = self.default_values()
|
||||||
if values is None:
|
config = emane_manager.getifcconfig(self.object_id, self.name, default_values, interface)
|
||||||
|
if not config:
|
||||||
return
|
return
|
||||||
|
|
||||||
# retrieve xml names
|
# retrieve xml names
|
||||||
|
@ -67,23 +73,22 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
||||||
nem_element.appendChild(shim_xml)
|
nem_element.appendChild(shim_xml)
|
||||||
emane_manager.xmlwrite(nem_document, nem_name)
|
emane_manager.xmlwrite(nem_document, nem_name)
|
||||||
|
|
||||||
names = self.getnames()
|
|
||||||
shim_names = list(names)
|
|
||||||
shim_names.remove("filterfile")
|
|
||||||
|
|
||||||
shim_document = emane_manager.xmldoc("shim")
|
shim_document = emane_manager.xmldoc("shim")
|
||||||
shim_element = shim_document.getElementsByTagName("shim").pop()
|
shim_element = shim_document.getElementsByTagName("shim").pop()
|
||||||
shim_element.setAttribute("name", "%s SHIM" % self.name)
|
shim_element.setAttribute("name", "%s SHIM" % self.name)
|
||||||
shim_element.setAttribute("library", self.shim_library)
|
shim_element.setAttribute("library", self.shim_library)
|
||||||
|
|
||||||
# append all shim options (except filterfile) to shimdoc
|
# append all shim options (except filterfile) to shimdoc
|
||||||
for name in shim_names:
|
for configuration in self.config_shim:
|
||||||
value = self.valueof(name, values)
|
name = configuration.id
|
||||||
|
if name == "filterfile":
|
||||||
|
continue
|
||||||
|
value = config[name]
|
||||||
param = emane_manager.xmlparam(shim_document, name, value)
|
param = emane_manager.xmlparam(shim_document, name, value)
|
||||||
shim_element.appendChild(param)
|
shim_element.appendChild(param)
|
||||||
|
|
||||||
# empty filterfile is not allowed
|
# empty filterfile is not allowed
|
||||||
ff = self.valueof("filterfile", values)
|
ff = config["filterfile"]
|
||||||
if ff.strip() != "":
|
if ff.strip() != "":
|
||||||
shim_element.appendChild(emane_manager.xmlparam(shim_document, "filterfile", ff))
|
shim_element.appendChild(emane_manager.xmlparam(shim_document, "filterfile", ff))
|
||||||
emane_manager.xmlwrite(shim_document, shim_name)
|
emane_manager.xmlwrite(shim_document, shim_name)
|
||||||
|
|
|
@ -10,7 +10,9 @@ from core import CoreCommandError
|
||||||
from core import constants
|
from core import constants
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.api import coreapi
|
from core.api import coreapi
|
||||||
from core.conf import ConfigurableManager
|
from core.conf import ConfigShim
|
||||||
|
from core.conf import Configuration
|
||||||
|
from core.conf import NewConfigurableManager
|
||||||
from core.emane import emanemanifest
|
from core.emane import emanemanifest
|
||||||
from core.emane.bypass import EmaneBypassModel
|
from core.emane.bypass import EmaneBypassModel
|
||||||
from core.emane.commeffect import EmaneCommEffectModel
|
from core.emane.commeffect import EmaneCommEffectModel
|
||||||
|
@ -50,7 +52,7 @@ EMANE_MODELS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class EmaneManager(ConfigurableManager):
|
class EmaneManager(NewConfigurableManager):
|
||||||
"""
|
"""
|
||||||
EMANE controller object. Lives in a Session instance and is used for
|
EMANE controller object. Lives in a Session instance and is used for
|
||||||
building EMANE config files from all of the EmaneNode objects in this
|
building EMANE config files from all of the EmaneNode objects in this
|
||||||
|
@ -70,7 +72,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
:param core.session.Session session: session this manager is tied to
|
:param core.session.Session session: session this manager is tied to
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
ConfigurableManager.__init__(self)
|
super(EmaneManager, self).__init__()
|
||||||
self.session = session
|
self.session = session
|
||||||
self._emane_nodes = {}
|
self._emane_nodes = {}
|
||||||
self._emane_node_lock = threading.Lock()
|
self._emane_node_lock = threading.Lock()
|
||||||
|
@ -84,16 +86,22 @@ class EmaneManager(ConfigurableManager):
|
||||||
|
|
||||||
# model for global EMANE configuration options
|
# model for global EMANE configuration options
|
||||||
self.emane_config = EmaneGlobalModel(session, None)
|
self.emane_config = EmaneGlobalModel(session, None)
|
||||||
|
self.set_configs(self.emane_config.default_values())
|
||||||
|
|
||||||
session.broker.handlers.add(self.handledistributed)
|
session.broker.handlers.add(self.handledistributed)
|
||||||
self.service = None
|
self.service = None
|
||||||
self.event_device = None
|
self.event_device = None
|
||||||
self._modelclsmap = {
|
self._modelclsmap = {}
|
||||||
self.emane_config.name: self.emane_config
|
|
||||||
}
|
|
||||||
|
|
||||||
self.service = None
|
self.service = None
|
||||||
self.emane_check()
|
self.emane_check()
|
||||||
|
|
||||||
|
def emane_models(self):
|
||||||
|
return self._modelclsmap.keys()
|
||||||
|
|
||||||
|
def get_model_class(self, model_name):
|
||||||
|
return self._modelclsmap[model_name]
|
||||||
|
|
||||||
def emane_check(self):
|
def emane_check(self):
|
||||||
"""
|
"""
|
||||||
Check if emane is installed and load models.
|
Check if emane is installed and load models.
|
||||||
|
@ -138,9 +146,8 @@ class EmaneManager(ConfigurableManager):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the control network to be used for events
|
# Get the control network to be used for events
|
||||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
group, port = self.get_config("eventservicegroup").split(":")
|
||||||
group, port = self.emane_config.valueof("eventservicegroup", values).split(":")
|
self.event_device = self.get_config("eventservicedevice")
|
||||||
self.event_device = self.emane_config.valueof("eventservicedevice", values)
|
|
||||||
eventnetidx = self.session.get_control_net_index(self.event_device)
|
eventnetidx = self.session.get_control_net_index(self.event_device)
|
||||||
if eventnetidx < 0:
|
if eventnetidx < 0:
|
||||||
logger.error("invalid emane event service device provided: %s", self.event_device)
|
logger.error("invalid emane event service device provided: %s", self.event_device)
|
||||||
|
@ -170,7 +177,6 @@ class EmaneManager(ConfigurableManager):
|
||||||
for emane_model in emane_models:
|
for emane_model in emane_models:
|
||||||
logger.info("loading emane model: %s", emane_model.__name__)
|
logger.info("loading emane model: %s", emane_model.__name__)
|
||||||
self._modelclsmap[emane_model.name] = emane_model
|
self._modelclsmap[emane_model.name] = emane_model
|
||||||
self.session.add_config_object(emane_model.name, emane_model.config_type, emane_model.configure_emane)
|
|
||||||
|
|
||||||
def add_node(self, emane_node):
|
def add_node(self, emane_node):
|
||||||
"""
|
"""
|
||||||
|
@ -196,26 +202,31 @@ class EmaneManager(ConfigurableManager):
|
||||||
nodes.add(netif.node)
|
nodes.add(netif.node)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def getmodels(self, n):
|
def getmodels(self, node):
|
||||||
"""
|
"""
|
||||||
Used with XML export; see ConfigurableManager.getmodels()
|
Used with XML export.
|
||||||
"""
|
"""
|
||||||
r = ConfigurableManager.getmodels(self, n)
|
configs = self.get_config_types(node.objid)
|
||||||
# EMANE global params are stored with first EMANE node (if non-default
|
models = []
|
||||||
# values are configured)
|
for model_name, config in configs.iteritems():
|
||||||
sorted_ids = sorted(self.configs.keys())
|
model_class = self._modelclsmap[model_name]
|
||||||
if None in self.configs and len(sorted_ids) > 1 and n.objid == sorted_ids[1]:
|
models.append((model_class, config))
|
||||||
v = self.configs[None]
|
logger.debug("emane models: %s", models)
|
||||||
for model in v:
|
return models
|
||||||
cls = self._modelclsmap[model[0]]
|
|
||||||
vals = model[1]
|
|
||||||
r.append((cls, vals))
|
|
||||||
return r
|
|
||||||
|
|
||||||
def getifcconfig(self, nodenum, conftype, defaultvalues, ifc):
|
def getifcconfig(self, node_id, config_type, default_values, ifc):
|
||||||
|
"""
|
||||||
|
Retrieve interface configuration or node configuration if not provided.
|
||||||
|
|
||||||
|
:param int node_id: node id
|
||||||
|
:param str config_type: configuration type
|
||||||
|
:param dict default_values: default configuration values
|
||||||
|
:param ifc: node interface
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
# use the network-wide config values or interface(NEM)-specific values?
|
# use the network-wide config values or interface(NEM)-specific values?
|
||||||
if ifc is None:
|
if ifc is None:
|
||||||
return self.getconfig(nodenum, conftype, defaultvalues)[1]
|
return self.get_configs(node_id, config_type) or default_values
|
||||||
else:
|
else:
|
||||||
# don"t use default values when interface config is the same as net
|
# don"t use default values when interface config is the same as net
|
||||||
# note here that using ifc.node.objid as key allows for only one type
|
# note here that using ifc.node.objid as key allows for only one type
|
||||||
|
@ -229,16 +240,19 @@ class EmaneManager(ConfigurableManager):
|
||||||
if ifc.netindex is not None:
|
if ifc.netindex is not None:
|
||||||
key += ifc.netindex
|
key += ifc.netindex
|
||||||
|
|
||||||
values = self.getconfig(key, conftype, None)[1]
|
# try retrieve interface specific configuration
|
||||||
if not values:
|
config = self.get_configs(key, config_type)
|
||||||
values = self.getconfig(ifc.node.objid, conftype, None)[1]
|
|
||||||
|
|
||||||
if not values and ifc.transport_type == "raw":
|
# otherwise retrieve the interfaces node configuration
|
||||||
|
if not config:
|
||||||
|
config = self.get_configs(ifc.node.objid, config_type)
|
||||||
|
|
||||||
|
if not config and ifc.transport_type == "raw":
|
||||||
# with EMANE 0.9.2+, we need an extra NEM XML from
|
# with EMANE 0.9.2+, we need an extra NEM XML from
|
||||||
# model.buildnemxmlfiles(), so defaults are returned here
|
# model.buildnemxmlfiles(), so defaults are returned here
|
||||||
values = self.getconfig(nodenum, conftype, defaultvalues)[1]
|
config = self.get_configs(node_id, config_type) or default_values
|
||||||
|
|
||||||
return values
|
return config
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""
|
"""
|
||||||
|
@ -264,9 +278,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
# - needs to be configured before checkdistributed() for distributed
|
# - needs to be configured before checkdistributed() for distributed
|
||||||
# - needs to exist when eventservice binds to it (initeventservice)
|
# - needs to exist when eventservice binds to it (initeventservice)
|
||||||
if self.session.master:
|
if self.session.master:
|
||||||
values = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
otadev = self.get_config("otamanagerdevice")
|
||||||
logger.debug("emane config default values: %s", values)
|
|
||||||
otadev = self.emane_config.valueof("otamanagerdevice", values)
|
|
||||||
netidx = self.session.get_control_net_index(otadev)
|
netidx = self.session.get_control_net_index(otadev)
|
||||||
logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
|
logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
|
||||||
if netidx < 0:
|
if netidx < 0:
|
||||||
|
@ -275,7 +287,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
|
|
||||||
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
|
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
|
||||||
self.distributedctrlnet(ctrlnet)
|
self.distributedctrlnet(ctrlnet)
|
||||||
eventdev = self.emane_config.valueof("eventservicedevice", values)
|
eventdev = self.get_config("eventservicedevice")
|
||||||
logger.debug("emane event service device: eventdev(%s)", eventdev)
|
logger.debug("emane event service device: eventdev(%s)", eventdev)
|
||||||
if eventdev != otadev:
|
if eventdev != otadev:
|
||||||
netidx = self.session.get_control_net_index(eventdev)
|
netidx = self.session.get_control_net_index(eventdev)
|
||||||
|
@ -288,10 +300,11 @@ class EmaneManager(ConfigurableManager):
|
||||||
self.distributedctrlnet(ctrlnet)
|
self.distributedctrlnet(ctrlnet)
|
||||||
|
|
||||||
if self.checkdistributed():
|
if self.checkdistributed():
|
||||||
# we are slave, but haven"t received a platformid yet
|
# we are slave, but haven't received a platformid yet
|
||||||
cfgval = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
platform_id_start = "platform_id_start"
|
||||||
i = self.emane_config.getnames().index("platform_id_start")
|
default_values = self.emane_config.default_values()
|
||||||
if cfgval[i] == self.emane_config.getdefaultvalues()[i]:
|
value = self.get_config(platform_id_start)
|
||||||
|
if value == default_values[platform_id_start]:
|
||||||
return EmaneManager.NOT_READY
|
return EmaneManager.NOT_READY
|
||||||
|
|
||||||
self.setnodemodels()
|
self.setnodemodels()
|
||||||
|
@ -359,7 +372,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
with self._emane_node_lock:
|
with self._emane_node_lock:
|
||||||
self._emane_nodes.clear()
|
self._emane_nodes.clear()
|
||||||
|
|
||||||
# don"t clear self._ifccounts here; NEM counts are needed for buildxml
|
# don't clear self._ifccounts here; NEM counts are needed for buildxml
|
||||||
self.platformport = self.session.get_config_item_int("emane_platform_port", 8100)
|
self.platformport = self.session.get_config_item_int("emane_platform_port", 8100)
|
||||||
self.transformport = self.session.get_config_item_int("emane_transform_port", 8200)
|
self.transformport = self.session.get_config_item_int("emane_transform_port", 8200)
|
||||||
|
|
||||||
|
@ -416,20 +429,16 @@ class EmaneManager(ConfigurableManager):
|
||||||
if not master:
|
if not master:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cfgval = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
|
||||||
values = list(cfgval)
|
|
||||||
|
|
||||||
nemcount = 0
|
nemcount = 0
|
||||||
with self._emane_node_lock:
|
with self._emane_node_lock:
|
||||||
for key in self._emane_nodes:
|
for key in self._emane_nodes:
|
||||||
emane_node = self._emane_nodes[key]
|
emane_node = self._emane_nodes[key]
|
||||||
nemcount += emane_node.numnetif()
|
nemcount += emane_node.numnetif()
|
||||||
|
|
||||||
nemid = int(self.emane_config.valueof("nem_id_start", values))
|
nemid = int(self.get_config("nem_id_start"))
|
||||||
nemid += nemcount
|
nemid += nemcount
|
||||||
|
|
||||||
platformid = int(self.emane_config.valueof("platform_id_start", values))
|
platformid = int(self.get_config("platform_id_start"))
|
||||||
names = list(self.emane_config.getnames())
|
|
||||||
|
|
||||||
# build an ordered list of servers so platform ID is deterministic
|
# build an ordered list of servers so platform ID is deterministic
|
||||||
servers = []
|
servers = []
|
||||||
|
@ -448,9 +457,10 @@ class EmaneManager(ConfigurableManager):
|
||||||
|
|
||||||
platformid += 1
|
platformid += 1
|
||||||
typeflags = ConfigFlags.UPDATE.value
|
typeflags = ConfigFlags.UPDATE.value
|
||||||
values[names.index("platform_id_start")] = str(platformid)
|
self.set_config("platform_id_start", str(platformid))
|
||||||
values[names.index("nem_id_start")] = str(nemid)
|
self.set_config("nem_id_start", str(nemid))
|
||||||
msg = EmaneGlobalModel.config_data(flags=0, node_id=None, type_flags=typeflags, values=values)
|
msg = ConfigShim.config_data(0, None, typeflags, self.emane_config, self.get_configs())
|
||||||
|
# TODO: this needs to be converted into a sendable TLV message
|
||||||
server.sock.send(msg)
|
server.sock.send(msg)
|
||||||
# increment nemid for next server by number of interfaces
|
# increment nemid for next server by number of interfaces
|
||||||
with self._ifccountslock:
|
with self._ifccountslock:
|
||||||
|
@ -489,8 +499,9 @@ class EmaneManager(ConfigurableManager):
|
||||||
if len(servers) < 2:
|
if len(servers) < 2:
|
||||||
return
|
return
|
||||||
|
|
||||||
prefix = session.config.get("controlnet")
|
prefix = session.options.get_config("controlnet")
|
||||||
prefix = getattr(session.options, "controlnet", prefix)
|
if not prefix:
|
||||||
|
prefix = session.config.get("controlnet")
|
||||||
prefixes = prefix.split()
|
prefixes = prefix.split()
|
||||||
# normal Config messaging will distribute controlnets
|
# normal Config messaging will distribute controlnets
|
||||||
if len(prefixes) >= len(servers):
|
if len(prefixes) >= len(servers):
|
||||||
|
@ -557,24 +568,17 @@ class EmaneManager(ConfigurableManager):
|
||||||
for key in self._emane_nodes:
|
for key in self._emane_nodes:
|
||||||
self.setnodemodel(key)
|
self.setnodemodel(key)
|
||||||
|
|
||||||
def setnodemodel(self, key):
|
def setnodemodel(self, node_id):
|
||||||
logger.debug("setting emane node model: %s", key)
|
logger.debug("setting emane models for node: %s", node_id)
|
||||||
emane_node = self._emane_nodes[key]
|
node_config_types = self.get_config_types(node_id)
|
||||||
if key not in self.configs:
|
if not node_config_types:
|
||||||
logger.debug("no emane node model configuration, leaving")
|
logger.debug("no emane node model configuration, leaving: %s", node_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for t, v in self.configs[key]:
|
emane_node = self._emane_nodes[node_id]
|
||||||
logger.debug("configuration: key(%s) value(%s)", t, v)
|
for model_class, config in self.getmodels(emane_node):
|
||||||
if t is None:
|
logger.debug("setting emane model(%s) config(%s)", model_class, config)
|
||||||
continue
|
emane_node.setmodel(model_class, config)
|
||||||
if t == self.emane_config.name:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# only use the first valid EmaneModel
|
|
||||||
# convert model name to class (e.g. emane_rfpipe -> EmaneRfPipe)
|
|
||||||
cls = self._modelclsmap[t]
|
|
||||||
emane_node.setmodel(cls, v)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# no model has been configured for this EmaneNode
|
# no model has been configured for this EmaneNode
|
||||||
|
@ -588,8 +592,8 @@ class EmaneManager(ConfigurableManager):
|
||||||
emane_node = None
|
emane_node = None
|
||||||
netif = None
|
netif = None
|
||||||
|
|
||||||
for key in self._emane_nodes:
|
for node_id in self._emane_nodes:
|
||||||
emane_node = self._emane_nodes[key]
|
emane_node = self._emane_nodes[node_id]
|
||||||
netif = emane_node.getnemnetif(nemid)
|
netif = emane_node.getnemnetif(nemid)
|
||||||
if netif is not None:
|
if netif is not None:
|
||||||
break
|
break
|
||||||
|
@ -607,7 +611,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
count += len(emane_node.netifs())
|
count += len(emane_node.netifs())
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def newplatformxmldoc(self, values, otadev=None, eventdev=None):
|
def newplatformxmldoc(self, otadev=None, eventdev=None):
|
||||||
"""
|
"""
|
||||||
Start a new platform XML file. Use global EMANE config values
|
Start a new platform XML file. Use global EMANE config values
|
||||||
as keys. Override OTA manager and event service devices if
|
as keys. Override OTA manager and event service devices if
|
||||||
|
@ -615,21 +619,20 @@ class EmaneManager(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
doc = self.xmldoc("platform")
|
doc = self.xmldoc("platform")
|
||||||
plat = doc.getElementsByTagName("platform").pop()
|
plat = doc.getElementsByTagName("platform").pop()
|
||||||
names = list(self.emane_config.getnames())
|
|
||||||
platform_names = names[:len(self.emane_config.emulator_config)]
|
|
||||||
platform_names.remove("platform_id_start")
|
|
||||||
platform_values = list(values)
|
|
||||||
if otadev:
|
if otadev:
|
||||||
i = platform_names.index("otamanagerdevice")
|
self.set_config("otamanagerdevice", otadev)
|
||||||
platform_values[i] = otadev
|
|
||||||
|
|
||||||
if eventdev:
|
if eventdev:
|
||||||
i = platform_names.index("eventservicedevice")
|
self.set_config("eventservicedevice", eventdev)
|
||||||
platform_values[i] = eventdev
|
|
||||||
|
|
||||||
# append all platform options (except starting id) to doc
|
# append all platform options (except starting id) to doc
|
||||||
for name in platform_names:
|
for configuration in self.emane_config.emulator_config:
|
||||||
value = self.emane_config.valueof(name, platform_values)
|
name = configuration.id
|
||||||
|
if name == "platform_id_start":
|
||||||
|
continue
|
||||||
|
|
||||||
|
value = self.get_config(name)
|
||||||
param = self.xmlparam(doc, name, value)
|
param = self.xmlparam(doc, name, value)
|
||||||
plat.appendChild(param)
|
plat.appendChild(param)
|
||||||
|
|
||||||
|
@ -639,8 +642,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Build a platform.xml file now that all nodes are configured.
|
Build a platform.xml file now that all nodes are configured.
|
||||||
"""
|
"""
|
||||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
nemid = int(self.get_config("nem_id_start"))
|
||||||
nemid = int(self.emane_config.valueof("nem_id_start", values))
|
|
||||||
platformxmls = {}
|
platformxmls = {}
|
||||||
|
|
||||||
# assume self._objslock is already held here
|
# assume self._objslock is already held here
|
||||||
|
@ -660,7 +662,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
eventdev = None
|
eventdev = None
|
||||||
|
|
||||||
if key not in platformxmls:
|
if key not in platformxmls:
|
||||||
platformxmls[key] = self.newplatformxmldoc(values, otadev, eventdev)
|
platformxmls[key] = self.newplatformxmldoc(otadev, eventdev)
|
||||||
|
|
||||||
doc = platformxmls[key]
|
doc = platformxmls[key]
|
||||||
plat = doc.getElementsByTagName("platform").pop()
|
plat = doc.getElementsByTagName("platform").pop()
|
||||||
|
@ -713,13 +715,11 @@ class EmaneManager(ConfigurableManager):
|
||||||
Build the libemaneeventservice.xml file if event service options
|
Build the libemaneeventservice.xml file if event service options
|
||||||
were changed in the global config.
|
were changed in the global config.
|
||||||
"""
|
"""
|
||||||
defaults = self.emane_config.getdefaultvalues()
|
|
||||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
|
||||||
need_xml = False
|
need_xml = False
|
||||||
keys = ("eventservicegroup", "eventservicedevice")
|
default_values = self.emane_config.default_values()
|
||||||
for k in keys:
|
for name in ["eventservicegroup", "eventservicedevice"]:
|
||||||
a = self.emane_config.valueof(k, defaults)
|
a = default_values[name]
|
||||||
b = self.emane_config.valueof(k, values)
|
b = self.get_config(name)
|
||||||
if a != b:
|
if a != b:
|
||||||
need_xml = True
|
need_xml = True
|
||||||
|
|
||||||
|
@ -729,12 +729,12 @@ class EmaneManager(ConfigurableManager):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
group, port = self.emane_config.valueof("eventservicegroup", values).split(":")
|
group, port = self.get_config("eventservicegroup").split(":")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception("invalid eventservicegroup in EMANE config")
|
logger.exception("invalid eventservicegroup in EMANE config")
|
||||||
return
|
return
|
||||||
|
|
||||||
dev = self.emane_config.valueof("eventservicedevice", values)
|
dev = self.get_config("eventservicedevice")
|
||||||
doc = self.xmldoc("emaneeventmsgsvc")
|
doc = self.xmldoc("emaneeventmsgsvc")
|
||||||
es = doc.getElementsByTagName("emaneeventmsgsvc").pop()
|
es = doc.getElementsByTagName("emaneeventmsgsvc").pop()
|
||||||
kvs = (("group", group), ("port", port), ("device", dev), ("mcloop", "1"), ("ttl", "32"))
|
kvs = (("group", group), ("port", port), ("device", dev), ("mcloop", "1"), ("ttl", "32"))
|
||||||
|
@ -761,13 +761,12 @@ class EmaneManager(ConfigurableManager):
|
||||||
if realtime:
|
if realtime:
|
||||||
emanecmd += "-r",
|
emanecmd += "-r",
|
||||||
|
|
||||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
otagroup, otaport = self.get_config("otamanagergroup").split(":")
|
||||||
otagroup, otaport = self.emane_config.valueof("otamanagergroup", values).split(":")
|
otadev = self.get_config("otamanagerdevice")
|
||||||
otadev = self.emane_config.valueof("otamanagerdevice", values)
|
|
||||||
otanetidx = self.session.get_control_net_index(otadev)
|
otanetidx = self.session.get_control_net_index(otadev)
|
||||||
|
|
||||||
eventgroup, eventport = self.emane_config.valueof("eventservicegroup", values).split(":")
|
eventgroup, eventport = self.get_config("eventservicegroup").split(":")
|
||||||
eventdev = self.emane_config.valueof("eventservicedevice", values)
|
eventdev = self.get_config("eventservicedevice")
|
||||||
eventservicenetidx = self.session.get_control_net_index(eventdev)
|
eventservicenetidx = self.session.get_control_net_index(eventdev)
|
||||||
|
|
||||||
run_emane_on_host = False
|
run_emane_on_host = False
|
||||||
|
@ -799,8 +798,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
node.check_cmd(args)
|
node.check_cmd(args)
|
||||||
|
|
||||||
# start emane
|
# start emane
|
||||||
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n),
|
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)]
|
||||||
os.path.join(path, "platform%d.xml" % n)]
|
|
||||||
output = node.check_cmd(args)
|
output = node.check_cmd(args)
|
||||||
logger.info("node(%s) emane daemon running: %s", node.name, args)
|
logger.info("node(%s) emane daemon running: %s", node.name, args)
|
||||||
logger.info("node(%s) emane daemon output: %s", node.name, output)
|
logger.info("node(%s) emane daemon output: %s", node.name, output)
|
||||||
|
@ -855,23 +853,6 @@ class EmaneManager(ConfigurableManager):
|
||||||
emane_node = self._emane_nodes[key]
|
emane_node = self._emane_nodes[key]
|
||||||
emane_node.deinstallnetifs()
|
emane_node.deinstallnetifs()
|
||||||
|
|
||||||
def configure(self, session, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration messages for global EMANE config.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
"""
|
|
||||||
r = self.emane_config.configure_emane(session, config_data)
|
|
||||||
|
|
||||||
# extra logic to start slave Emane object after nemid has been configured from the master
|
|
||||||
config_type = config_data.type
|
|
||||||
if config_type == ConfigFlags.UPDATE.value and self.session.master is False:
|
|
||||||
# instantiation was previously delayed by self.setup()
|
|
||||||
# returning Emane.NOT_READY
|
|
||||||
self.session.instantiate()
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
def doeventmonitor(self):
|
def doeventmonitor(self):
|
||||||
"""
|
"""
|
||||||
Returns boolean whether or not EMANE events will be monitored.
|
Returns boolean whether or not EMANE events will be monitored.
|
||||||
|
@ -900,11 +881,10 @@ class EmaneManager(ConfigurableManager):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.service is None:
|
if self.service is None:
|
||||||
errmsg = "Warning: EMANE events will not be generated " \
|
logger.error("Warning: EMANE events will not be generated "
|
||||||
"because the emaneeventservice\n binding was " \
|
"because the emaneeventservice\n binding was "
|
||||||
"unable to load " \
|
"unable to load "
|
||||||
"(install the python-emaneeventservice bindings)"
|
"(install the python-emaneeventservice bindings)")
|
||||||
logger.error(errmsg)
|
|
||||||
return
|
return
|
||||||
self.doeventloop = True
|
self.doeventloop = True
|
||||||
self.eventmonthread = threading.Thread(target=self.eventmonitorloop)
|
self.eventmonthread = threading.Thread(target=self.eventmonitorloop)
|
||||||
|
@ -1019,6 +999,7 @@ class EmaneGlobalModel(EmaneModel):
|
||||||
"""
|
"""
|
||||||
Global EMANE configuration options.
|
Global EMANE configuration options.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_DEFAULT_DEV = "ctrl0"
|
_DEFAULT_DEV = "ctrl0"
|
||||||
|
|
||||||
name = "emane"
|
name = "emane"
|
||||||
|
@ -1033,19 +1014,26 @@ class EmaneGlobalModel(EmaneModel):
|
||||||
emulator_config = emanemanifest.parse(emulator_xml, emulator_defaults)
|
emulator_config = emanemanifest.parse(emulator_xml, emulator_defaults)
|
||||||
emulator_config.insert(
|
emulator_config.insert(
|
||||||
0,
|
0,
|
||||||
("platform_id_start", ConfigDataTypes.INT32.value, "1", "", "Starting Platform ID (core)")
|
Configuration(_id="platform_id_start", _type=ConfigDataTypes.INT32, default="1",
|
||||||
|
label="Starting Platform ID (core)")
|
||||||
)
|
)
|
||||||
|
|
||||||
nem_config = [
|
nem_config = [
|
||||||
("nem_id_start", ConfigDataTypes.INT32.value, "1", "", "Starting NEM ID (core)"),
|
Configuration(_id="nem_id_start", _type=ConfigDataTypes.INT32, default="1",
|
||||||
|
label="Starting NEM ID (core)")
|
||||||
]
|
]
|
||||||
|
|
||||||
config_matrix_override = emulator_config + nem_config
|
@classmethod
|
||||||
config_groups_override = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % (
|
def configurations(cls):
|
||||||
len(emulator_config), len(emulator_config) + 1, len(config_matrix_override))
|
return cls.emulator_config + cls.nem_config
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_groups(cls):
|
||||||
|
return "Platform Attributes:1-%d|NEM Parameters:%d-%d" % (
|
||||||
|
len(cls.emulator_config), len(cls.emulator_config) + 1, len(cls.configurations()))
|
||||||
|
|
||||||
def __init__(self, session, object_id=None):
|
def __init__(self, session, object_id=None):
|
||||||
EmaneModel.__init__(self, session, object_id)
|
super(EmaneGlobalModel, self).__init__(session, object_id)
|
||||||
|
|
||||||
def build_xml_files(self, emane_manager, interface):
|
def build_xml_files(self, emane_manager, interface):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from core import logger
|
from core import logger
|
||||||
|
from core.conf import Configuration
|
||||||
from core.enumerations import ConfigDataTypes
|
from core.enumerations import ConfigDataTypes
|
||||||
|
|
||||||
manifest = None
|
manifest = None
|
||||||
|
@ -23,7 +24,7 @@ def _type_value(config_type):
|
||||||
config_type = "FLOAT"
|
config_type = "FLOAT"
|
||||||
elif config_type == "INETADDR":
|
elif config_type == "INETADDR":
|
||||||
config_type = "STRING"
|
config_type = "STRING"
|
||||||
return ConfigDataTypes[config_type].value
|
return ConfigDataTypes[config_type]
|
||||||
|
|
||||||
|
|
||||||
def _get_possible(config_type, config_regex):
|
def _get_possible(config_type, config_regex):
|
||||||
|
@ -36,14 +37,13 @@ def _get_possible(config_type, config_regex):
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
if config_type == "bool":
|
if config_type == "bool":
|
||||||
return "On,Off"
|
return ["On", "Off"]
|
||||||
|
|
||||||
if config_type == "string" and config_regex:
|
if config_type == "string" and config_regex:
|
||||||
possible = config_regex[2:-2]
|
possible = config_regex[2:-2]
|
||||||
possible = possible.replace("|", ",")
|
return possible.split("|")
|
||||||
return possible
|
|
||||||
|
|
||||||
return ""
|
return []
|
||||||
|
|
||||||
|
|
||||||
def _get_default(config_type_name, config_value):
|
def _get_default(config_type_name, config_value):
|
||||||
|
@ -116,7 +116,13 @@ def parse(manifest_path, defaults):
|
||||||
if config_name.endswith("uri"):
|
if config_name.endswith("uri"):
|
||||||
config_descriptions = "%s file" % config_descriptions
|
config_descriptions = "%s file" % config_descriptions
|
||||||
|
|
||||||
config_tuple = (config_name, config_type_value, config_default, possible, config_descriptions)
|
configuration = Configuration(
|
||||||
configurations.append(config_tuple)
|
_id=config_name,
|
||||||
|
_type=config_type_value,
|
||||||
|
default=config_default,
|
||||||
|
options=possible,
|
||||||
|
label=config_descriptions
|
||||||
|
)
|
||||||
|
configurations.append(configuration)
|
||||||
|
|
||||||
return configurations
|
return configurations
|
||||||
|
|
|
@ -34,51 +34,12 @@ def value_to_params(doc, name, value):
|
||||||
return xmlutils.add_param_list_to_parent(doc, parent=None, name=name, values=values)
|
return xmlutils.add_param_list_to_parent(doc, parent=None, name=name, values=values)
|
||||||
|
|
||||||
|
|
||||||
class EmaneModelMetaClass(type):
|
|
||||||
"""
|
|
||||||
Hack into making class level properties to streamline emane model creation, until the Configurable class is
|
|
||||||
removed or refactored.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@property
|
|
||||||
def config_matrix(cls):
|
|
||||||
"""
|
|
||||||
Convenience method for creating the config matrix, allow for a custom override.
|
|
||||||
|
|
||||||
:param EmaneModel cls: emane class
|
|
||||||
:return: config matrix value
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
if cls.config_matrix_override:
|
|
||||||
return cls.config_matrix_override
|
|
||||||
else:
|
|
||||||
return cls.mac_config + cls.phy_config
|
|
||||||
|
|
||||||
@property
|
|
||||||
def config_groups(cls):
|
|
||||||
"""
|
|
||||||
Convenience method for creating the config groups, allow for a custom override.
|
|
||||||
|
|
||||||
:param EmaneModel cls: emane class
|
|
||||||
:return: config groups value
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
if cls.config_groups_override:
|
|
||||||
return cls.config_groups_override
|
|
||||||
else:
|
|
||||||
mac_len = len(cls.mac_config)
|
|
||||||
config_len = len(cls.config_matrix)
|
|
||||||
return "MAC Parameters:1-%d|PHY Parameters:%d-%d" % (mac_len, mac_len + 1, config_len)
|
|
||||||
|
|
||||||
|
|
||||||
class EmaneModel(WirelessModel):
|
class EmaneModel(WirelessModel):
|
||||||
"""
|
"""
|
||||||
EMANE models inherit from this parent class, which takes care of
|
EMANE models inherit from this parent class, which takes care of
|
||||||
handling configuration messages based on the list of
|
handling configuration messages based on the list of
|
||||||
configurable parameters. Helper functions also live here.
|
configurable parameters. Helper functions also live here.
|
||||||
"""
|
"""
|
||||||
__metaclass__ = EmaneModelMetaClass
|
|
||||||
|
|
||||||
# default mac configuration settings
|
# default mac configuration settings
|
||||||
mac_library = None
|
mac_library = None
|
||||||
mac_xml = None
|
mac_xml = None
|
||||||
|
@ -97,10 +58,20 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
config_ignore = set()
|
config_ignore = set()
|
||||||
config_groups_override = None
|
config_groups_override = None
|
||||||
config_matrix_override = None
|
configurations_override = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def configurations(cls):
|
||||||
|
return cls.mac_config + cls.phy_config
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_groups(cls):
|
||||||
|
mac_len = len(cls.mac_config)
|
||||||
|
config_len = len(cls.configurations())
|
||||||
|
return "MAC Parameters:1-%d|PHY Parameters:%d-%d" % (mac_len, mac_len + 1, config_len)
|
||||||
|
|
||||||
def __init__(self, session, object_id=None):
|
def __init__(self, session, object_id=None):
|
||||||
WirelessModel.__init__(self, session, object_id)
|
super(EmaneModel, self).__init__(session, object_id)
|
||||||
|
|
||||||
def build_xml_files(self, emane_manager, interface):
|
def build_xml_files(self, emane_manager, interface):
|
||||||
"""
|
"""
|
||||||
|
@ -111,8 +82,8 @@ class EmaneModel(WirelessModel):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
# retrieve configuration values
|
# retrieve configuration values
|
||||||
values = emane_manager.getifcconfig(self.object_id, self.name, self.getdefaultvalues(), interface)
|
config = emane_manager.getifcconfig(self.object_id, self.name, self.default_values(), interface)
|
||||||
if values is None:
|
if not config:
|
||||||
return
|
return
|
||||||
|
|
||||||
# create document and write to disk
|
# create document and write to disk
|
||||||
|
@ -122,12 +93,12 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
# create mac document and write to disk
|
# create mac document and write to disk
|
||||||
mac_name = self.mac_name(interface)
|
mac_name = self.mac_name(interface)
|
||||||
mac_document = self.create_mac_doc(emane_manager, values)
|
mac_document = self.create_mac_doc(emane_manager, config)
|
||||||
emane_manager.xmlwrite(mac_document, mac_name)
|
emane_manager.xmlwrite(mac_document, mac_name)
|
||||||
|
|
||||||
# create phy document and write to disk
|
# create phy document and write to disk
|
||||||
phy_name = self.phy_name(interface)
|
phy_name = self.phy_name(interface)
|
||||||
phy_document = self.create_phy_doc(emane_manager, values)
|
phy_document = self.create_phy_doc(emane_manager, config)
|
||||||
emane_manager.xmlwrite(phy_document, phy_name)
|
emane_manager.xmlwrite(phy_document, phy_name)
|
||||||
|
|
||||||
def create_nem_doc(self, emane_manager, interface):
|
def create_nem_doc(self, emane_manager, interface):
|
||||||
|
@ -157,18 +128,15 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
return nem_document
|
return nem_document
|
||||||
|
|
||||||
def create_mac_doc(self, emane_manager, values):
|
def create_mac_doc(self, emane_manager, config):
|
||||||
"""
|
"""
|
||||||
Create the mac xml document.
|
Create the mac xml document.
|
||||||
|
|
||||||
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
||||||
:param tuple values: all current configuration values, mac + phy
|
:param dict config: all current configuration values, mac + phy
|
||||||
:return: nem document
|
:return: nem document
|
||||||
:rtype: xml.dom.minidom.Document
|
:rtype: xml.dom.minidom.Document
|
||||||
"""
|
"""
|
||||||
names = list(self.getnames())
|
|
||||||
mac_names = names[:len(self.mac_config)]
|
|
||||||
|
|
||||||
mac_document = emane_manager.xmldoc("mac")
|
mac_document = emane_manager.xmldoc("mac")
|
||||||
mac_element = mac_document.getElementsByTagName("mac").pop()
|
mac_element = mac_document.getElementsByTagName("mac").pop()
|
||||||
mac_element.setAttribute("name", "%s MAC" % self.name)
|
mac_element.setAttribute("name", "%s MAC" % self.name)
|
||||||
|
@ -177,13 +145,14 @@ class EmaneModel(WirelessModel):
|
||||||
raise ValueError("must define emane model library")
|
raise ValueError("must define emane model library")
|
||||||
mac_element.setAttribute("library", self.mac_library)
|
mac_element.setAttribute("library", self.mac_library)
|
||||||
|
|
||||||
for name in mac_names:
|
for mac_configuration in self.mac_config:
|
||||||
# ignore custom configurations
|
# ignore custom configurations
|
||||||
|
name = mac_configuration.id
|
||||||
if name in self.config_ignore:
|
if name in self.config_ignore:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# check if value is a multi param
|
# check if value is a multi param
|
||||||
value = self.valueof(name, values)
|
value = config[name]
|
||||||
param = value_to_params(mac_document, name, value)
|
param = value_to_params(mac_document, name, value)
|
||||||
if not param:
|
if not param:
|
||||||
param = emane_manager.xmlparam(mac_document, name, value)
|
param = emane_manager.xmlparam(mac_document, name, value)
|
||||||
|
@ -192,18 +161,15 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
return mac_document
|
return mac_document
|
||||||
|
|
||||||
def create_phy_doc(self, emane_manager, values):
|
def create_phy_doc(self, emane_manager, config):
|
||||||
"""
|
"""
|
||||||
Create the phy xml document.
|
Create the phy xml document.
|
||||||
|
|
||||||
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
||||||
:param tuple values: all current configuration values, mac + phy
|
:param dict config: all current configuration values, mac + phy
|
||||||
:return: nem document
|
:return: nem document
|
||||||
:rtype: xml.dom.minidom.Document
|
:rtype: xml.dom.minidom.Document
|
||||||
"""
|
"""
|
||||||
names = list(self.getnames())
|
|
||||||
phy_names = names[len(self.mac_config):]
|
|
||||||
|
|
||||||
phy_document = emane_manager.xmldoc("phy")
|
phy_document = emane_manager.xmldoc("phy")
|
||||||
phy_element = phy_document.getElementsByTagName("phy").pop()
|
phy_element = phy_document.getElementsByTagName("phy").pop()
|
||||||
phy_element.setAttribute("name", "%s PHY" % self.name)
|
phy_element.setAttribute("name", "%s PHY" % self.name)
|
||||||
|
@ -212,13 +178,14 @@ class EmaneModel(WirelessModel):
|
||||||
phy_element.setAttribute("library", self.phy_library)
|
phy_element.setAttribute("library", self.phy_library)
|
||||||
|
|
||||||
# append all phy options
|
# append all phy options
|
||||||
for name in phy_names:
|
for phy_configuration in self.phy_config:
|
||||||
# ignore custom configurations
|
# ignore custom configurations
|
||||||
|
name = phy_configuration.id
|
||||||
if name in self.config_ignore:
|
if name in self.config_ignore:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# check if value is a multi param
|
# check if value is a multi param
|
||||||
value = self.valueof(name, values)
|
value = config[name]
|
||||||
param = value_to_params(phy_document, name, value)
|
param = value_to_params(phy_document, name, value)
|
||||||
if not param:
|
if not param:
|
||||||
param = emane_manager.xmlparam(phy_document, name, value)
|
param = emane_manager.xmlparam(phy_document, name, value)
|
||||||
|
@ -227,16 +194,6 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
return phy_document
|
return phy_document
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def configure_emane(cls, session, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration messages for configuring an emane model.
|
|
||||||
|
|
||||||
:param core.session.Session session: session to configure emane
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
"""
|
|
||||||
return cls.configure(session.emane, config_data)
|
|
||||||
|
|
||||||
def post_startup(self, emane_manager):
|
def post_startup(self, emane_manager):
|
||||||
"""
|
"""
|
||||||
Logic to execute after the emane manager is finished with startup.
|
Logic to execute after the emane manager is finished with startup.
|
||||||
|
@ -317,7 +274,7 @@ class EmaneModel(WirelessModel):
|
||||||
|
|
||||||
if interface:
|
if interface:
|
||||||
node_id = interface.node.objid
|
node_id = interface.node.objid
|
||||||
if emane_manager.getifcconfig(node_id, self.name, None, interface) is not None:
|
if emane_manager.getifcconfig(node_id, self.name, {}, interface):
|
||||||
name = interface.localname.replace(".", "_")
|
name = interface.localname.replace(".", "_")
|
||||||
|
|
||||||
return "%s%s" % (name, self.name)
|
return "%s%s" % (name, self.name)
|
||||||
|
|
|
@ -174,14 +174,9 @@ class EmaneNode(EmaneNet):
|
||||||
trans.setAttribute("library", "trans%s" % transport_type.lower())
|
trans.setAttribute("library", "trans%s" % transport_type.lower())
|
||||||
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
|
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
|
||||||
|
|
||||||
flowcontrol = False
|
config = emane.get_configs(self.objid, self.model.name)
|
||||||
names = self.model.getnames()
|
logger.debug("transport xml config: %s", config)
|
||||||
values = emane.getconfig(self.objid, self.model.name, self.model.getdefaultvalues())[1]
|
flowcontrol = config.get("flowcontrolenable", "0") == "1"
|
||||||
|
|
||||||
if "flowcontrolenable" in names and values:
|
|
||||||
i = names.index("flowcontrolenable")
|
|
||||||
if self.model.booltooffon(values[i]) == "on":
|
|
||||||
flowcontrol = True
|
|
||||||
|
|
||||||
if "virtual" in transport_type.lower():
|
if "virtual" in transport_type.lower():
|
||||||
if os.path.exists("/dev/net/tun_flowctl"):
|
if os.path.exists("/dev/net/tun_flowctl"):
|
||||||
|
@ -193,11 +188,11 @@ class EmaneNode(EmaneNet):
|
||||||
|
|
||||||
emane.xmlwrite(transdoc, self.transportxmlname(transport_type.lower()))
|
emane.xmlwrite(transdoc, self.transportxmlname(transport_type.lower()))
|
||||||
|
|
||||||
def transportxmlname(self, type):
|
def transportxmlname(self, _type):
|
||||||
"""
|
"""
|
||||||
Return the string name for the Transport XML file, e.g. 'n3transvirtual.xml'
|
Return the string name for the Transport XML file, e.g. 'n3transvirtual.xml'
|
||||||
"""
|
"""
|
||||||
return "n%strans%s.xml" % (self.objid, type)
|
return "n%strans%s.xml" % (self.objid, _type)
|
||||||
|
|
||||||
def installnetifs(self, do_netns=True):
|
def installnetifs(self, do_netns=True):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core import logger
|
from core import logger
|
||||||
|
from core.conf import Configuration
|
||||||
from core.emane import emanemanifest
|
from core.emane import emanemanifest
|
||||||
from core.emane import emanemodel
|
from core.emane import emanemodel
|
||||||
from core.enumerations import ConfigDataTypes
|
from core.enumerations import ConfigDataTypes
|
||||||
|
@ -29,7 +30,12 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
|
||||||
default_schedule = os.path.join(constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml")
|
default_schedule = os.path.join(constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml")
|
||||||
mac_config.insert(
|
mac_config.insert(
|
||||||
0,
|
0,
|
||||||
(schedule_name, ConfigDataTypes.STRING.value, default_schedule, "", "TDMA schedule file (core)")
|
Configuration(
|
||||||
|
_id=schedule_name,
|
||||||
|
_type=ConfigDataTypes.STRING,
|
||||||
|
default=default_schedule,
|
||||||
|
label="TDMA schedule file (core)"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
config_ignore = {schedule_name}
|
config_ignore = {schedule_name}
|
||||||
|
|
||||||
|
@ -41,10 +47,10 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
# get configured schedule
|
# get configured schedule
|
||||||
values = emane_manager.getconfig(self.object_id, self.name, self.getdefaultvalues())[1]
|
config = emane_manager.get_configs()
|
||||||
if values is None:
|
if not config:
|
||||||
return
|
return
|
||||||
schedule = self.valueof(self.schedule_name, values)
|
schedule = config[self.schedule_name]
|
||||||
|
|
||||||
event_device = emane_manager.event_device
|
event_device = emane_manager.event_device
|
||||||
|
|
||||||
|
|
|
@ -378,7 +378,8 @@ class EmuSession(Session):
|
||||||
if node_two:
|
if node_two:
|
||||||
node_two.lock.release()
|
node_two.lock.release()
|
||||||
|
|
||||||
def update_link(self, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None, link_options=LinkOptions()):
|
def update_link(self, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None,
|
||||||
|
link_options=LinkOptions()):
|
||||||
"""
|
"""
|
||||||
Update link information between nodes.
|
Update link information between nodes.
|
||||||
|
|
||||||
|
@ -480,7 +481,7 @@ class EmuSession(Session):
|
||||||
|
|
||||||
# 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 = self.options.get_config("enablerj45") == "1"
|
||||||
if _type == NodeTypes.RJ45 and not enable_rj45:
|
if _type == NodeTypes.RJ45 and not enable_rj45:
|
||||||
start = False
|
start = False
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,15 @@ https://pypi.python.org/pypi/utm (version 0.3.0).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.conf import ConfigurableManager
|
|
||||||
from core.enumerations import RegisterTlvs
|
from core.enumerations import RegisterTlvs
|
||||||
from core.misc import utm
|
from core.misc import utm
|
||||||
|
|
||||||
|
|
||||||
class CoreLocation(ConfigurableManager):
|
class CoreLocation(object):
|
||||||
"""
|
"""
|
||||||
Member of session class for handling global location data. This keeps
|
Member of session class for handling global location data. This keeps
|
||||||
track of a latitude/longitude/altitude reference point and scale in
|
track of a latitude/longitude/altitude reference point and scale in
|
||||||
order to convert between X,Y and geo coordinates.
|
order to convert between X,Y and geo coordinates.
|
||||||
|
|
||||||
TODO: this could be updated to use more generic
|
|
||||||
Configurable/ConfigurableManager code like other Session objects
|
|
||||||
"""
|
"""
|
||||||
name = "location"
|
name = "location"
|
||||||
config_type = RegisterTlvs.UTILITY.value
|
config_type = RegisterTlvs.UTILITY.value
|
||||||
|
@ -29,7 +25,7 @@ class CoreLocation(ConfigurableManager):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
ConfigurableManager.__init__(self)
|
# ConfigurableManager.__init__(self)
|
||||||
self.reset()
|
self.reset()
|
||||||
self.zonemap = {}
|
self.zonemap = {}
|
||||||
self.refxyz = (0.0, 0.0, 0.0)
|
self.refxyz = (0.0, 0.0, 0.0)
|
||||||
|
@ -52,35 +48,6 @@ class CoreLocation(ConfigurableManager):
|
||||||
# cached distance to refpt in other zones
|
# cached distance to refpt in other zones
|
||||||
self.zoneshifts = {}
|
self.zoneshifts = {}
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Receive configuration message for setting the reference point
|
|
||||||
and scale.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
values = config_data.data_values
|
|
||||||
|
|
||||||
if values is None:
|
|
||||||
logger.warn("location data missing")
|
|
||||||
return None
|
|
||||||
values = values.split('|')
|
|
||||||
|
|
||||||
# Cartesian coordinate reference point
|
|
||||||
refx, refy = map(lambda x: float(x), values[0:2])
|
|
||||||
refz = 0.0
|
|
||||||
self.refxyz = (refx, refy, refz)
|
|
||||||
# Geographic reference point
|
|
||||||
lat, lon, alt = map(lambda x: float(x), values[2:5])
|
|
||||||
self.setrefgeo(lat, lon, alt)
|
|
||||||
self.refscale = float(values[5])
|
|
||||||
logger.info("location configured: (%.2f,%.2f,%.2f) = (%.5f,%.5f,%.5f) scale=%.2f" %
|
|
||||||
(self.refxyz[0], self.refxyz[1], self.refxyz[2], self.refgeo[0],
|
|
||||||
self.refgeo[1], self.refgeo[2], self.refscale))
|
|
||||||
logger.info("location configured: UTM(%.5f,%.5f,%.5f)" %
|
|
||||||
(self.refutm[1], self.refutm[2], self.refutm[3]))
|
|
||||||
|
|
||||||
def px2m(self, val):
|
def px2m(self, val):
|
||||||
"""
|
"""
|
||||||
Convert the specified value in pixels to meters using the
|
Convert the specified value in pixels to meters using the
|
||||||
|
|
|
@ -9,10 +9,12 @@ import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.conf import Configurable
|
from core.conf import ConfigurableOptions
|
||||||
from core.conf import ConfigurableManager
|
from core.conf import Configuration
|
||||||
|
from core.conf import NewConfigurableManager
|
||||||
from core.coreobj import PyCoreNode
|
from core.coreobj import PyCoreNode
|
||||||
from core.data import EventData, LinkData
|
from core.data import EventData
|
||||||
|
from core.data import LinkData
|
||||||
from core.enumerations import ConfigDataTypes
|
from core.enumerations import ConfigDataTypes
|
||||||
from core.enumerations import EventTypes
|
from core.enumerations import EventTypes
|
||||||
from core.enumerations import LinkTypes
|
from core.enumerations import LinkTypes
|
||||||
|
@ -24,7 +26,7 @@ from core.misc import utils
|
||||||
from core.misc.ipaddress import IpAddress
|
from core.misc.ipaddress import IpAddress
|
||||||
|
|
||||||
|
|
||||||
class MobilityManager(ConfigurableManager):
|
class MobilityManager(NewConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Member of session class for handling configuration data for mobility and
|
Member of session class for handling configuration data for mobility and
|
||||||
range models.
|
range models.
|
||||||
|
@ -38,20 +40,42 @@ class MobilityManager(ConfigurableManager):
|
||||||
|
|
||||||
:param core.session.Session session: session this manager is tied to
|
:param core.session.Session session: session this manager is tied to
|
||||||
"""
|
"""
|
||||||
ConfigurableManager.__init__(self)
|
super(MobilityManager, self).__init__()
|
||||||
self.session = session
|
self.session = session
|
||||||
# configurations for basic range, indexed by WLAN node number, are
|
# configurations for basic range, indexed by WLAN node number, are stored in configurations
|
||||||
# stored in self.configs
|
|
||||||
# mapping from model names to their classes
|
# mapping from model names to their classes
|
||||||
self._modelclsmap = {
|
self._modelclsmap = {
|
||||||
BasicRangeModel.name: BasicRangeModel,
|
BasicRangeModel.name: BasicRangeModel,
|
||||||
Ns2ScriptedMobility.name: Ns2ScriptedMobility
|
Ns2ScriptedMobility.name: Ns2ScriptedMobility
|
||||||
}
|
}
|
||||||
|
|
||||||
# dummy node objects for tracking position of nodes on other servers
|
# dummy node objects for tracking position of nodes on other servers
|
||||||
self.phys = {}
|
self.phys = {}
|
||||||
self.physnets = {}
|
self.physnets = {}
|
||||||
self.session.broker.handlers.add(self.physnodehandlelink)
|
self.session.broker.handlers.add(self.physnodehandlelink)
|
||||||
|
|
||||||
|
def mobility_models(self):
|
||||||
|
return self._modelclsmap.keys()
|
||||||
|
|
||||||
|
def get_model_class(self, model_name):
|
||||||
|
return self._modelclsmap[model_name]
|
||||||
|
|
||||||
|
def getmodels(self, node):
|
||||||
|
"""
|
||||||
|
Return a list of model classes and values for a net if one has been
|
||||||
|
configured. This is invoked when exporting a session to XML.
|
||||||
|
|
||||||
|
:param node: network node to get models for
|
||||||
|
:return: list of model and values tuples for the network node
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
configs = self.get_config_types(node.objid)
|
||||||
|
models = []
|
||||||
|
for model_name, config in configs.iteritems():
|
||||||
|
model_class = self._modelclsmap[model_name]
|
||||||
|
models.append((model_class, config))
|
||||||
|
return models
|
||||||
|
|
||||||
def startup(self, node_ids=None):
|
def startup(self, node_ids=None):
|
||||||
"""
|
"""
|
||||||
Session is transitioning from instantiation to runtime state.
|
Session is transitioning from instantiation to runtime state.
|
||||||
|
@ -61,7 +85,7 @@ class MobilityManager(ConfigurableManager):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if node_ids is None:
|
if node_ids is None:
|
||||||
node_ids = self.configs.keys()
|
node_ids = self.nodes()
|
||||||
|
|
||||||
for node_id in node_ids:
|
for node_id in node_ids:
|
||||||
logger.info("checking mobility startup for node: %s", node_id)
|
logger.info("checking mobility startup for node: %s", node_id)
|
||||||
|
@ -69,22 +93,22 @@ class MobilityManager(ConfigurableManager):
|
||||||
try:
|
try:
|
||||||
node = self.session.get_object(node_id)
|
node = self.session.get_object(node_id)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.warn("skipping mobility configuration for unknown node %d." % node_id)
|
logger.warn("skipping mobility configuration for unknown node: %s", node_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if node_id not in self.configs:
|
node_configs = self.get_config_types(node_id)
|
||||||
logger.warn("missing mobility configuration for node %d." % node_id)
|
if not node_configs:
|
||||||
|
logger.warn("missing mobility configuration for node: %s", node_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
v = self.configs[node_id]
|
for model_name in node_configs.iterkeys():
|
||||||
|
|
||||||
for model in v:
|
|
||||||
try:
|
try:
|
||||||
logger.info("setting mobility model to node: %s", model)
|
clazz = self._modelclsmap[model_name]
|
||||||
cls = self._modelclsmap[model[0]]
|
model_config = self.get_config(node_id, model_name)
|
||||||
node.setmodel(cls, model[1])
|
logger.info("setting mobility model(%s) to node: %s", model_name, model_config)
|
||||||
|
node.setmodel(clazz, model_config)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.warn("skipping mobility configuration for unknown model '%s'" % model[0])
|
logger.warn("skipping mobility configuration for unknown model: %s", model_name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.session.master:
|
if self.session.master:
|
||||||
|
@ -99,26 +123,32 @@ class MobilityManager(ConfigurableManager):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
self.clearconfig(nodenum=None)
|
self.config_reset()
|
||||||
|
|
||||||
def setconfig(self, node_id, config_type, values):
|
def set_configs(self, config, node_id=None, config_type=None):
|
||||||
"""
|
"""
|
||||||
Normal setconfig() with check for run-time updates for WLANs.
|
Adds a check for run-time updates for WLANs after providing normal set configs.
|
||||||
|
|
||||||
|
:param dict config: configuration value
|
||||||
:param int node_id: node id
|
:param int node_id: node id
|
||||||
:param config_type: configuration type
|
:param str config_type: configuration type
|
||||||
:param values: configuration value
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
super(MobilityManager, self).setconfig(node_id, config_type, values)
|
if not node_id or not config_type:
|
||||||
|
raise ValueError("mobility manager invalid node id or config type: %s - %s", node_id, config_type)
|
||||||
|
|
||||||
|
super(MobilityManager, self).set_configs(config, node_id, config_type)
|
||||||
|
|
||||||
if self.session is None:
|
if self.session is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.session.state == EventTypes.RUNTIME_STATE.value:
|
if self.session.state == EventTypes.RUNTIME_STATE.value:
|
||||||
try:
|
try:
|
||||||
node = self.session.get_object(node_id)
|
node = self.session.get_object(node_id)
|
||||||
node.updatemodel(config_type, values)
|
# TODO: this need to be updated
|
||||||
|
node.updatemodel(config_type, config)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception("Skipping mobility configuration for unknown node %d.", node_id)
|
logger.exception("skipping mobility configuration for unknown node %s", node_id)
|
||||||
|
|
||||||
def handleevent(self, event_data):
|
def handleevent(self, event_data):
|
||||||
"""
|
"""
|
||||||
|
@ -206,13 +236,13 @@ class MobilityManager(ConfigurableManager):
|
||||||
:param list moved_netifs: moved network interfaces
|
:param list moved_netifs: moved network interfaces
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
for nodenum in self.configs:
|
for node_id in self.nodes():
|
||||||
try:
|
try:
|
||||||
n = self.session.get_object(nodenum)
|
node = self.session.get_object(node_id)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
if n.model:
|
if node.model:
|
||||||
n.model.update(moved, moved_netifs)
|
node.model.update(moved, moved_netifs)
|
||||||
|
|
||||||
def addphys(self, netnum, node):
|
def addphys(self, netnum, node):
|
||||||
"""
|
"""
|
||||||
|
@ -222,12 +252,12 @@ class MobilityManager(ConfigurableManager):
|
||||||
:param core.coreobj.PyCoreNode node: node to add physical network to
|
:param core.coreobj.PyCoreNode node: node to add physical network to
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
nodenum = node.objid
|
node_id = node.objid
|
||||||
self.phys[nodenum] = node
|
self.phys[node_id] = node
|
||||||
if netnum not in self.physnets:
|
if netnum not in self.physnets:
|
||||||
self.physnets[netnum] = [nodenum, ]
|
self.physnets[netnum] = [node_id, ]
|
||||||
else:
|
else:
|
||||||
self.physnets[netnum].append(nodenum)
|
self.physnets[netnum].append(node_id)
|
||||||
|
|
||||||
# TODO: remove need for handling old style message
|
# TODO: remove need for handling old style message
|
||||||
def physnodehandlelink(self, message):
|
def physnodehandlelink(self, message):
|
||||||
|
@ -247,8 +277,7 @@ class MobilityManager(ConfigurableManager):
|
||||||
return
|
return
|
||||||
if nn[1] in self.session.broker.physical_nodes:
|
if nn[1] in self.session.broker.physical_nodes:
|
||||||
# record the fact that this PhysicalNode is linked to a net
|
# record the fact that this PhysicalNode is linked to a net
|
||||||
dummy = PyCoreNode(session=self.session, objid=nn[1],
|
dummy = PyCoreNode(session=self.session, objid=nn[1], name="n%d" % nn[1], start=False)
|
||||||
name="n%d" % nn[1], start=False)
|
|
||||||
self.addphys(nn[0], dummy)
|
self.addphys(nn[0], dummy)
|
||||||
|
|
||||||
# TODO: remove need to handling old style messages
|
# TODO: remove need to handling old style messages
|
||||||
|
@ -291,7 +320,7 @@ class MobilityManager(ConfigurableManager):
|
||||||
netif.poshook(netif, x, y, z)
|
netif.poshook(netif, x, y, z)
|
||||||
|
|
||||||
|
|
||||||
class WirelessModel(Configurable):
|
class WirelessModel(ConfigurableOptions):
|
||||||
"""
|
"""
|
||||||
Base class used by EMANE models and the basic range model.
|
Base class used by EMANE models and the basic range model.
|
||||||
Used for managing arbitrary configuration parameters.
|
Used for managing arbitrary configuration parameters.
|
||||||
|
@ -308,9 +337,8 @@ class WirelessModel(Configurable):
|
||||||
:param int object_id: object id
|
:param int object_id: object id
|
||||||
:param values: values
|
:param values: values
|
||||||
"""
|
"""
|
||||||
Configurable.__init__(self, session, object_id)
|
self.session = session
|
||||||
# 'values' can be retrieved from a ConfigurableManager, or used here
|
self.object_id = object_id
|
||||||
# during initialization, depending on the model.
|
|
||||||
|
|
||||||
def all_link_data(self, flags):
|
def all_link_data(self, flags):
|
||||||
"""
|
"""
|
||||||
|
@ -333,12 +361,12 @@ class WirelessModel(Configurable):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def updateconfig(self, values):
|
def updateconfig(self, config):
|
||||||
"""
|
"""
|
||||||
For run-time updates of model config. Returns True when position callback and set link
|
For run-time updates of model config. Returns True when position callback and set link
|
||||||
parameters should be invoked.
|
parameters should be invoked.
|
||||||
|
|
||||||
:param values: value to update
|
:param dict config: value to update
|
||||||
:return: False
|
:return: False
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
|
@ -353,23 +381,20 @@ class BasicRangeModel(WirelessModel):
|
||||||
"""
|
"""
|
||||||
name = "basic_range"
|
name = "basic_range"
|
||||||
|
|
||||||
# configuration parameters are
|
@classmethod
|
||||||
# ( 'name', 'type', 'default', 'possible-value-list', 'caption')
|
def configurations(cls):
|
||||||
config_matrix = [
|
return [
|
||||||
("range", ConfigDataTypes.UINT32.value, '275',
|
Configuration(_id="range", _type=ConfigDataTypes.UINT32, default="275", label="wireless range (pixels)"),
|
||||||
'', 'wireless range (pixels)'),
|
Configuration(_id="bandwidth", _type=ConfigDataTypes.UINT32, default="54000", label="bandwidth (bps)"),
|
||||||
("bandwidth", ConfigDataTypes.UINT32.value, '54000',
|
Configuration(_id="jitter", _type=ConfigDataTypes.FLOAT, default="0.0", label="transmission jitter (usec)"),
|
||||||
'', 'bandwidth (bps)'),
|
Configuration(_id="delay", _type=ConfigDataTypes.FLOAT, default="5000.0",
|
||||||
("jitter", ConfigDataTypes.FLOAT.value, '0.0',
|
label="transmission delay (usec)"),
|
||||||
'', 'transmission jitter (usec)'),
|
Configuration(_id="error", _type=ConfigDataTypes.FLOAT, default="0.0", label="error rate (%)")
|
||||||
("delay", ConfigDataTypes.FLOAT.value, '5000.0',
|
]
|
||||||
'', 'transmission delay (usec)'),
|
|
||||||
("error", ConfigDataTypes.FLOAT.value, '0.0',
|
|
||||||
'', 'error rate (%)'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# value groupings
|
@classmethod
|
||||||
config_groups = "Basic Range Parameters:1-%d" % len(config_matrix)
|
def config_groups(cls):
|
||||||
|
return "Basic Range Parameters:1-%d" % len(cls.configurations())
|
||||||
|
|
||||||
def __init__(self, session, object_id, values=None):
|
def __init__(self, session, object_id, values=None):
|
||||||
"""
|
"""
|
||||||
|
@ -377,57 +402,49 @@ class BasicRangeModel(WirelessModel):
|
||||||
|
|
||||||
:param core.session.Session session: related core session
|
:param core.session.Session session: related core session
|
||||||
:param int object_id: object id
|
:param int object_id: object id
|
||||||
:param values: values
|
:param dict values: values
|
||||||
"""
|
"""
|
||||||
super(BasicRangeModel, self).__init__(session=session, object_id=object_id)
|
super(BasicRangeModel, self).__init__(session=session, object_id=object_id)
|
||||||
|
self.session = session
|
||||||
self.wlan = session.get_object(object_id)
|
self.wlan = session.get_object(object_id)
|
||||||
self._netifs = {}
|
self._netifs = {}
|
||||||
self._netifslock = threading.Lock()
|
self._netifslock = threading.Lock()
|
||||||
if values is None:
|
if not values:
|
||||||
values = session.mobility.getconfig(object_id, self.name, self.getdefaultvalues())[1]
|
values = self.default_values()
|
||||||
self.range = float(self.valueof("range", values))
|
|
||||||
logger.info("Basic range model configured for WLAN %d using range %d", object_id, self.range)
|
|
||||||
self.valuestolinkparams(values)
|
|
||||||
|
|
||||||
# link parameters
|
# TODO: can this be handled in a better spot
|
||||||
|
self.session.mobility.set_configs(values, node_id=object_id, config_type=self.name)
|
||||||
|
|
||||||
|
self.range = None
|
||||||
self.bw = None
|
self.bw = None
|
||||||
self.delay = None
|
self.delay = None
|
||||||
self.loss = None
|
self.loss = None
|
||||||
self.jitter = None
|
self.jitter = None
|
||||||
|
|
||||||
def valuestolinkparams(self, values):
|
self.values_from_config(values)
|
||||||
|
|
||||||
|
def values_from_config(self, config):
|
||||||
"""
|
"""
|
||||||
Values to convert to link parameters.
|
Values to convert to link parameters.
|
||||||
|
|
||||||
:param values: values to convert
|
:param dict config: values to convert
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
self.bw = int(self.valueof("bandwidth", values))
|
self.range = float(config["range"])
|
||||||
|
logger.info("Basic range model configured for WLAN %d using range %d", self.wlan.objid, self.range)
|
||||||
|
self.bw = int(config["bandwidth"])
|
||||||
if self.bw == 0.0:
|
if self.bw == 0.0:
|
||||||
self.bw = None
|
self.bw = None
|
||||||
self.delay = float(self.valueof("delay", values))
|
self.delay = float(config["delay"])
|
||||||
if self.delay == 0.0:
|
if self.delay == 0.0:
|
||||||
self.delay = None
|
self.delay = None
|
||||||
self.loss = float(self.valueof("error", values))
|
self.loss = float(config["error"])
|
||||||
if self.loss == 0.0:
|
if self.loss == 0.0:
|
||||||
self.loss = None
|
self.loss = None
|
||||||
self.jitter = float(self.valueof("jitter", values))
|
self.jitter = float(config["jitter"])
|
||||||
if self.jitter == 0.0:
|
if self.jitter == 0.0:
|
||||||
self.jitter = None
|
self.jitter = None
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def configure_mob(cls, session, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration messages for setting up a model.
|
|
||||||
Pass the MobilityManager object as the manager object.
|
|
||||||
|
|
||||||
:param core.session.Session session: current session calling function
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: configuration data
|
|
||||||
:rtype: core.data.ConfigData
|
|
||||||
"""
|
|
||||||
return cls.configure(session.mobility, config_data)
|
|
||||||
|
|
||||||
def setlinkparams(self):
|
def setlinkparams(self):
|
||||||
"""
|
"""
|
||||||
Apply link parameters to all interfaces. This is invoked from
|
Apply link parameters to all interfaces. This is invoked from
|
||||||
|
@ -435,8 +452,7 @@ class BasicRangeModel(WirelessModel):
|
||||||
"""
|
"""
|
||||||
with self._netifslock:
|
with self._netifslock:
|
||||||
for netif in self._netifs:
|
for netif in self._netifs:
|
||||||
self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay,
|
self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay, loss=self.loss, duplicate=None,
|
||||||
loss=self.loss, duplicate=None,
|
|
||||||
jitter=self.jitter)
|
jitter=self.jitter)
|
||||||
|
|
||||||
def get_position(self, netif):
|
def get_position(self, netif):
|
||||||
|
@ -461,7 +477,6 @@ class BasicRangeModel(WirelessModel):
|
||||||
:param z: z position
|
:param z: z position
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
# print "set_position(%s, x=%s, y=%s, z=%s)" % (netif.localname, x, y, z)
|
|
||||||
self._netifslock.acquire()
|
self._netifslock.acquire()
|
||||||
self._netifs[netif] = (x, y, z)
|
self._netifs[netif] = (x, y, z)
|
||||||
if x is None or y is None:
|
if x is None or y is None:
|
||||||
|
@ -487,7 +502,7 @@ class BasicRangeModel(WirelessModel):
|
||||||
with self._netifslock:
|
with self._netifslock:
|
||||||
while len(moved_netifs):
|
while len(moved_netifs):
|
||||||
netif = moved_netifs.pop()
|
netif = moved_netifs.pop()
|
||||||
(nx, ny, nz) = netif.node.getposition()
|
nx, ny, nz = netif.node.getposition()
|
||||||
if netif in self._netifs:
|
if netif in self._netifs:
|
||||||
self._netifs[netif] = (nx, ny, nz)
|
self._netifs[netif] = (nx, ny, nz)
|
||||||
for netif2 in self._netifs:
|
for netif2 in self._netifs:
|
||||||
|
@ -557,18 +572,17 @@ class BasicRangeModel(WirelessModel):
|
||||||
c = p1[2] - p2[2]
|
c = p1[2] - p2[2]
|
||||||
return math.hypot(math.hypot(a, b), c)
|
return math.hypot(math.hypot(a, b), c)
|
||||||
|
|
||||||
def updateconfig(self, values):
|
def updateconfig(self, config):
|
||||||
"""
|
"""
|
||||||
Configuration has changed during runtime.
|
Configuration has changed during runtime.
|
||||||
MobilityManager.setconfig() -> WlanNode.updatemodel() ->
|
MobilityManager.setconfig() -> WlanNode.updatemodel() ->
|
||||||
WirelessModel.updateconfig()
|
WirelessModel.updateconfig()
|
||||||
|
|
||||||
:param values: values to update configuration
|
:param dict config: values to update configuration
|
||||||
:return: was update successful
|
:return: was update successful
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
self.valuestolinkparams(values)
|
self.values_from_config(config)
|
||||||
self.range = float(self.valueof("range", values))
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def create_link_data(self, interface1, interface2, message_type):
|
def create_link_data(self, interface1, interface2, message_type):
|
||||||
|
@ -581,7 +595,6 @@ class BasicRangeModel(WirelessModel):
|
||||||
:return: link data
|
:return: link data
|
||||||
:rtype: LinkData
|
:rtype: LinkData
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return LinkData(
|
return LinkData(
|
||||||
message_type=message_type,
|
message_type=message_type,
|
||||||
node1_id=interface1.node.objid,
|
node1_id=interface1.node.objid,
|
||||||
|
@ -678,6 +691,7 @@ class WayPointMobility(WirelessModel):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
super(WayPointMobility, self).__init__(session=session, object_id=object_id, values=values)
|
super(WayPointMobility, self).__init__(session=session, object_id=object_id, values=values)
|
||||||
|
|
||||||
self.state = self.STATE_STOPPED
|
self.state = self.STATE_STOPPED
|
||||||
self.queue = []
|
self.queue = []
|
||||||
self.queue_copy = []
|
self.queue_copy = []
|
||||||
|
@ -705,7 +719,6 @@ class WayPointMobility(WirelessModel):
|
||||||
self.lasttime = time.time()
|
self.lasttime = time.time()
|
||||||
now = self.lasttime - self.timezero
|
now = self.lasttime - self.timezero
|
||||||
dt = self.lasttime - t
|
dt = self.lasttime - t
|
||||||
# print "runround(now=%.2f, dt=%.2f)" % (now, dt)
|
|
||||||
|
|
||||||
# keep current waypoints up-to-date
|
# keep current waypoints up-to-date
|
||||||
self.updatepoints(now)
|
self.updatepoints(now)
|
||||||
|
@ -741,7 +754,6 @@ class WayPointMobility(WirelessModel):
|
||||||
moved_netifs.append(netif)
|
moved_netifs.append(netif)
|
||||||
|
|
||||||
# calculate all ranges after moving nodes; this saves calculations
|
# calculate all ranges after moving nodes; this saves calculations
|
||||||
# self.wlan.model.update(moved)
|
|
||||||
self.session.mobility.updatewlans(moved, moved_netifs)
|
self.session.mobility.updatewlans(moved, moved_netifs)
|
||||||
|
|
||||||
# TODO: check session state
|
# TODO: check session state
|
||||||
|
@ -806,7 +818,6 @@ class WayPointMobility(WirelessModel):
|
||||||
self.endtime = self.lasttime - self.timezero
|
self.endtime = self.lasttime - self.timezero
|
||||||
del self.points[node.objid]
|
del self.points[node.objid]
|
||||||
return False
|
return False
|
||||||
# print "node %s dx,dy= <%s, %d>" % (node.name, dx, dy)
|
|
||||||
if (x1 + dx) < 0.0:
|
if (x1 + dx) < 0.0:
|
||||||
dx = 0.0 - x1
|
dx = 0.0 - x1
|
||||||
if (y1 + dy) < 0.0:
|
if (y1 + dy) < 0.0:
|
||||||
|
@ -826,7 +837,7 @@ class WayPointMobility(WirelessModel):
|
||||||
node = netif.node
|
node = netif.node
|
||||||
if node.objid not in self.initial:
|
if node.objid not in self.initial:
|
||||||
continue
|
continue
|
||||||
(x, y, z) = self.initial[node.objid].coords
|
x, y, z = self.initial[node.objid].coords
|
||||||
self.setnodeposition(node, x, y, z)
|
self.setnodeposition(node, x, y, z)
|
||||||
moved.append(node)
|
moved.append(node)
|
||||||
moved_netifs.append(netif)
|
moved_netifs.append(netif)
|
||||||
|
@ -845,7 +856,6 @@ class WayPointMobility(WirelessModel):
|
||||||
:param speed: speed
|
:param speed: speed
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
# print "addwaypoint: %s %s %s,%s,%s %s" % (time, nodenum, x, y, z, speed)
|
|
||||||
wp = WayPoint(time, nodenum, coords=(x, y, z), speed=speed)
|
wp = WayPoint(time, nodenum, coords=(x, y, z), speed=speed)
|
||||||
heapq.heappush(self.queue, wp)
|
heapq.heappush(self.queue, wp)
|
||||||
|
|
||||||
|
@ -976,25 +986,22 @@ class Ns2ScriptedMobility(WayPointMobility):
|
||||||
"""
|
"""
|
||||||
name = "ns2script"
|
name = "ns2script"
|
||||||
|
|
||||||
config_matrix = [
|
@classmethod
|
||||||
("file", ConfigDataTypes.STRING.value, '',
|
def configurations(cls):
|
||||||
'', 'mobility script file'),
|
return [
|
||||||
("refresh_ms", ConfigDataTypes.UINT32.value, '50',
|
Configuration(_id="file", _type=ConfigDataTypes.STRING, label="mobility script file"),
|
||||||
'', 'refresh time (ms)'),
|
Configuration(_id="refresh_ms", _type=ConfigDataTypes.UINT32, default="50", label="mobility script file"),
|
||||||
("loop", ConfigDataTypes.BOOL.value, '1',
|
Configuration(_id="loop", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"], label="loop"),
|
||||||
'On,Off', 'loop'),
|
Configuration(_id="autostart", _type=ConfigDataTypes.STRING, label="auto-start seconds (0.0 for runtime)"),
|
||||||
("autostart", ConfigDataTypes.STRING.value, '',
|
Configuration(_id="map", _type=ConfigDataTypes.STRING, label="node mapping (optional, e.g. 0:1,1:2,2:3)"),
|
||||||
'', 'auto-start seconds (0.0 for runtime)'),
|
Configuration(_id="script_start", _type=ConfigDataTypes.STRING, label="script file to run upon start"),
|
||||||
("map", ConfigDataTypes.STRING.value, '',
|
Configuration(_id="script_pause", _type=ConfigDataTypes.STRING, label="script file to run upon pause"),
|
||||||
'', 'node mapping (optional, e.g. 0:1,1:2,2:3)'),
|
Configuration(_id="script_stop", _type=ConfigDataTypes.STRING, label="script file to run upon stop")
|
||||||
("script_start", ConfigDataTypes.STRING.value, '',
|
]
|
||||||
'', 'script file to run upon start'),
|
|
||||||
("script_pause", ConfigDataTypes.STRING.value, '',
|
@classmethod
|
||||||
'', 'script file to run upon pause'),
|
def config_groups(cls):
|
||||||
("script_stop", ConfigDataTypes.STRING.value, '',
|
return "ns-2 Mobility Script Parameters:1-%d" % len(cls.configurations())
|
||||||
'', 'script file to run upon stop'),
|
|
||||||
]
|
|
||||||
config_groups = "ns-2 Mobility Script Parameters:1-%d" % len(config_matrix)
|
|
||||||
|
|
||||||
def __init__(self, session, object_id, values=None):
|
def __init__(self, session, object_id, values=None):
|
||||||
"""
|
"""
|
||||||
|
@ -1007,32 +1014,24 @@ class Ns2ScriptedMobility(WayPointMobility):
|
||||||
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id, values=values)
|
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id, values=values)
|
||||||
self._netifs = {}
|
self._netifs = {}
|
||||||
self._netifslock = threading.Lock()
|
self._netifslock = threading.Lock()
|
||||||
if values is None:
|
|
||||||
values = session.mobility.getconfig(object_id, self.name, self.getdefaultvalues())[1]
|
if not values:
|
||||||
self.file = self.valueof("file", values)
|
values = self.default_values()
|
||||||
self.refresh_ms = int(self.valueof("refresh_ms", values))
|
self.session.mobility.set_configs(values, node_id=object_id, config_type=self.name)
|
||||||
self.loop = self.valueof("loop", values).lower() == "on"
|
|
||||||
self.autostart = self.valueof("autostart", values)
|
self.file = values["file"]
|
||||||
self.parsemap(self.valueof("map", values))
|
self.refresh_ms = int(values["refresh_ms"])
|
||||||
self.script_start = self.valueof("script_start", values)
|
self.loop = values["loop"].lower() == "on"
|
||||||
self.script_pause = self.valueof("script_pause", values)
|
self.autostart = values["autostart"]
|
||||||
self.script_stop = self.valueof("script_stop", values)
|
self.parsemap(values["map"])
|
||||||
|
self.script_start = values["script_start"]
|
||||||
|
self.script_pause = values["script_pause"]
|
||||||
|
self.script_stop = values["script_stop"]
|
||||||
logger.info("ns-2 scripted mobility configured for WLAN %d using file: %s", object_id, self.file)
|
logger.info("ns-2 scripted mobility configured for WLAN %d using file: %s", object_id, self.file)
|
||||||
self.readscriptfile()
|
self.readscriptfile()
|
||||||
self.copywaypoints()
|
self.copywaypoints()
|
||||||
self.setendtime()
|
self.setendtime()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def configure_mob(cls, session, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration messages for setting up a model.
|
|
||||||
Pass the MobilityManager object as the manager object.
|
|
||||||
|
|
||||||
:param core.session.Session session: current session calling function
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
"""
|
|
||||||
return cls.configure(session.mobility, config_data)
|
|
||||||
|
|
||||||
def readscriptfile(self):
|
def readscriptfile(self):
|
||||||
"""
|
"""
|
||||||
Read in mobility script from a file. This adds waypoints to a
|
Read in mobility script from a file. This adds waypoints to a
|
||||||
|
@ -1234,4 +1233,4 @@ class Ns2ScriptedMobility(WayPointMobility):
|
||||||
return
|
return
|
||||||
filename = self.findfile(filename)
|
filename = self.findfile(filename)
|
||||||
args = ["/bin/sh", filename, typestr]
|
args = ["/bin/sh", filename, typestr]
|
||||||
utils.check_cmd(args, cwd=self.session.sessiondir, env=self.session.get_environment())
|
utils.check_cmd(args, cwd=self.session.session_dir, env=self.session.get_environment())
|
||||||
|
|
|
@ -398,12 +398,12 @@ class WlanNode(LxBrNet):
|
||||||
elif model.config_type == RegisterTlvs.MOBILITY.value:
|
elif model.config_type == RegisterTlvs.MOBILITY.value:
|
||||||
self.mobility = model(session=self.session, object_id=self.objid, values=config)
|
self.mobility = model(session=self.session, object_id=self.objid, values=config)
|
||||||
|
|
||||||
def updatemodel(self, model_name, values):
|
def updatemodel(self, model_name, config):
|
||||||
"""
|
"""
|
||||||
Allow for model updates during runtime (similar to setmodel().)
|
Allow for model updates during runtime (similar to setmodel().)
|
||||||
|
|
||||||
:param model_name: model name to update
|
:param str model_name: model name to update
|
||||||
:param values: values to update model with
|
:param dict config: values to update model with
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
logger.info("updating model %s" % model_name)
|
logger.info("updating model %s" % model_name)
|
||||||
|
@ -412,14 +412,14 @@ class WlanNode(LxBrNet):
|
||||||
|
|
||||||
model = self.model
|
model = self.model
|
||||||
if model.config_type == RegisterTlvs.WIRELESS.value:
|
if model.config_type == RegisterTlvs.WIRELESS.value:
|
||||||
if not model.updateconfig(values):
|
if not model.updateconfig(config):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.model.position_callback:
|
if self.model.position_callback:
|
||||||
for netif in self.netifs():
|
for netif in self.netifs():
|
||||||
netif.poshook = self.model.position_callback
|
netif.poshook = self.model.position_callback
|
||||||
if netif.node is not None:
|
if netif.node is not None:
|
||||||
(x, y, z) = netif.node.position.get()
|
x, y, z = netif.node.position.get()
|
||||||
netif.poshook(netif, x, y, z)
|
netif.poshook(netif, x, y, z)
|
||||||
|
|
||||||
self.model.setlinkparams()
|
self.model.setlinkparams()
|
||||||
|
|
|
@ -118,12 +118,7 @@ class Sdt(object):
|
||||||
:return: True if enabled, False otherwise
|
:return: True if enabled, False otherwise
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
if not hasattr(self.session.options, "enablesdt"):
|
return self.session.options.get_config("enablesdt") == "1"
|
||||||
return False
|
|
||||||
enabled = self.session.options.enablesdt
|
|
||||||
if enabled in ("1", "true", 1, True):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def seturl(self):
|
def seturl(self):
|
||||||
"""
|
"""
|
||||||
|
@ -132,11 +127,8 @@ class Sdt(object):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
url = None
|
url = self.session.options.get_config("stdurl")
|
||||||
if hasattr(self.session.options, "sdturl"):
|
if not url:
|
||||||
if self.session.options.sdturl != "":
|
|
||||||
url = self.session.options.sdturl
|
|
||||||
if url is None or url == "":
|
|
||||||
url = self.DEFAULT_SDT_URL
|
url = self.DEFAULT_SDT_URL
|
||||||
self.url = urlparse(url)
|
self.url = urlparse(url)
|
||||||
self.address = (self.url.hostname, self.url.port)
|
self.address = (self.url.hostname, self.url.port)
|
||||||
|
|
|
@ -7,17 +7,11 @@ a list of available services to the GUI and for configuring individual
|
||||||
services.
|
services.
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
from itertools import repeat
|
|
||||||
|
|
||||||
from core import CoreCommandError
|
from core import CoreCommandError
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.conf import Configurable
|
|
||||||
from core.conf import ConfigurableManager
|
|
||||||
from core.data import ConfigData
|
|
||||||
from core.data import EventData
|
from core.data import EventData
|
||||||
from core.data import FileData
|
from core.data import FileData
|
||||||
from core.enumerations import ConfigDataTypes
|
|
||||||
from core.enumerations import ConfigFlags
|
|
||||||
from core.enumerations import EventTypes
|
from core.enumerations import EventTypes
|
||||||
from core.enumerations import MessageFlags
|
from core.enumerations import MessageFlags
|
||||||
from core.enumerations import RegisterTlvs
|
from core.enumerations import RegisterTlvs
|
||||||
|
@ -78,7 +72,7 @@ class ServiceManager(object):
|
||||||
cls.add(service)
|
cls.add(service)
|
||||||
|
|
||||||
|
|
||||||
class CoreServices(ConfigurableManager):
|
class CoreServices(object):
|
||||||
"""
|
"""
|
||||||
Class for interacting with a list of available startup services for
|
Class for interacting with a list of available startup services for
|
||||||
nodes. Mostly used to convert a CoreService into a Config API
|
nodes. Mostly used to convert a CoreService into a Config API
|
||||||
|
@ -88,7 +82,6 @@ class CoreServices(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
name = "services"
|
name = "services"
|
||||||
config_type = RegisterTlvs.UTILITY.value
|
config_type = RegisterTlvs.UTILITY.value
|
||||||
|
|
||||||
_invalid_custom_names = ("core", "api", "emane", "misc", "netns", "phys", "services")
|
_invalid_custom_names = ("core", "api", "emane", "misc", "netns", "phys", "services")
|
||||||
|
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
|
@ -98,7 +91,7 @@ class CoreServices(ConfigurableManager):
|
||||||
:param core.session.Session session: session this manager is tied to
|
:param core.session.Session session: session this manager is tied to
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
ConfigurableManager.__init__(self)
|
# ConfigurableManager.__init__(self)
|
||||||
self.session = session
|
self.session = session
|
||||||
# dict of default services tuples, key is node type
|
# dict of default services tuples, key is node type
|
||||||
self.defaultservices = {}
|
self.defaultservices = {}
|
||||||
|
@ -154,34 +147,31 @@ class CoreServices(ConfigurableManager):
|
||||||
return s
|
return s
|
||||||
return service
|
return service
|
||||||
|
|
||||||
def setcustomservice(self, object_id, service, values):
|
def setcustomservice(self, object_id, service, config):
|
||||||
"""
|
"""
|
||||||
Store service customizations in an instantiated service object
|
Store service customizations in an instantiated service object
|
||||||
using a list of values that came from a config message.
|
using a list of values that came from a config message.
|
||||||
|
|
||||||
:param int object_id: object id to set custom service for
|
:param int object_id: object id to set custom service for
|
||||||
:param class service: service to set
|
:param class service: service to set
|
||||||
:param list values: values to
|
:param dict config: values to
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
logger.debug("setting custom service(%s) for node(%s): %s", object_id, service, config)
|
||||||
if service._custom:
|
if service._custom:
|
||||||
s = service
|
s = service
|
||||||
else:
|
else:
|
||||||
# instantiate the class, for storing config customization
|
# instantiate the class, for storing config customization
|
||||||
s = service()
|
s = service()
|
||||||
# values are new key=value format; not all keys need to be present
|
|
||||||
# a missing key means go with the default
|
# set custom service configuration
|
||||||
if Configurable.haskeyvalues(values):
|
for name, value in config.iteritems():
|
||||||
for v in values:
|
s.setvalue(name, value)
|
||||||
key, value = v.split('=', 1)
|
|
||||||
s.setvalue(key, value)
|
|
||||||
# old-style config, list of values
|
|
||||||
else:
|
|
||||||
s.fromvaluelist(values)
|
|
||||||
|
|
||||||
# assume custom service already in dict
|
# assume custom service already in dict
|
||||||
if service._custom:
|
if service._custom:
|
||||||
return
|
return
|
||||||
|
|
||||||
# add the custom service to dict
|
# add the custom service to dict
|
||||||
if object_id in self.customservices:
|
if object_id in self.customservices:
|
||||||
self.customservices[object_id] += (s,)
|
self.customservices[object_id] += (s,)
|
||||||
|
@ -436,130 +426,6 @@ class CoreServices(ConfigurableManager):
|
||||||
status = "-1"
|
status = "-1"
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def configure_request(self, config_data):
|
|
||||||
"""
|
|
||||||
Receive configuration message for configuring services.
|
|
||||||
With a request flag set, a list of services has been requested.
|
|
||||||
When the opaque field is present, a specific service is being
|
|
||||||
configured or requested.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: response messages
|
|
||||||
:rtype: ConfigData
|
|
||||||
"""
|
|
||||||
node_id = config_data.node
|
|
||||||
session_id = config_data.session
|
|
||||||
opaque = config_data.opaque
|
|
||||||
|
|
||||||
logger.debug("configuration request: node(%s) session(%s) opaque(%s)", node_id, session_id, opaque)
|
|
||||||
|
|
||||||
# send back a list of available services
|
|
||||||
if opaque is None:
|
|
||||||
type_flag = ConfigFlags.NONE.value
|
|
||||||
data_types = tuple(repeat(ConfigDataTypes.BOOL.value, len(ServiceManager.services)))
|
|
||||||
values = "|".join(repeat('0', len(ServiceManager.services)))
|
|
||||||
names = map(lambda x: x._name, ServiceManager.services)
|
|
||||||
captions = "|".join(names)
|
|
||||||
possible_values = ""
|
|
||||||
for s in ServiceManager.services:
|
|
||||||
if s._custom_needed:
|
|
||||||
possible_values += '1'
|
|
||||||
possible_values += '|'
|
|
||||||
groups = self.buildgroups(ServiceManager.services)
|
|
||||||
# send back the properties for this service
|
|
||||||
else:
|
|
||||||
if node_id is None:
|
|
||||||
return None
|
|
||||||
node = self.session.get_object(node_id)
|
|
||||||
if node is None:
|
|
||||||
logger.warn("Request to configure service for unknown node %s", node_id)
|
|
||||||
return None
|
|
||||||
servicesstring = opaque.split(':')
|
|
||||||
services, unknown = self.servicesfromopaque(opaque, node.objid)
|
|
||||||
for u in unknown:
|
|
||||||
logger.warn("Request for unknown service '%s'" % u)
|
|
||||||
|
|
||||||
if len(services) < 1:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if len(servicesstring) == 3:
|
|
||||||
# a file request: e.g. "service:zebra:quagga.conf"
|
|
||||||
file_data = self.getservicefile(services, node, servicesstring[2])
|
|
||||||
self.session.broadcast_file(file_data)
|
|
||||||
|
|
||||||
# short circuit this request early to avoid returning response below
|
|
||||||
return None
|
|
||||||
|
|
||||||
# the first service in the list is the one being configured
|
|
||||||
svc = services[0]
|
|
||||||
# send back:
|
|
||||||
# dirs, configs, startindex, startup, shutdown, metadata, config
|
|
||||||
type_flag = ConfigFlags.UPDATE.value
|
|
||||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(svc.keys)))
|
|
||||||
values = svc.tovaluelist(node, services)
|
|
||||||
captions = None
|
|
||||||
possible_values = None
|
|
||||||
groups = None
|
|
||||||
|
|
||||||
return ConfigData(
|
|
||||||
message_type=0,
|
|
||||||
node=node_id,
|
|
||||||
object=self.name,
|
|
||||||
type=type_flag,
|
|
||||||
data_types=data_types,
|
|
||||||
data_values=values,
|
|
||||||
captions=captions,
|
|
||||||
possible_values=possible_values,
|
|
||||||
groups=groups,
|
|
||||||
session=session_id,
|
|
||||||
opaque=opaque
|
|
||||||
)
|
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Receive configuration message for configuring services.
|
|
||||||
With a request flag set, a list of services has been requested.
|
|
||||||
When the opaque field is present, a specific service is being
|
|
||||||
configured or requested.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
data_types = config_data.data_types
|
|
||||||
values = config_data.data_values
|
|
||||||
node_id = config_data.node
|
|
||||||
opaque = config_data.opaque
|
|
||||||
|
|
||||||
error_message = "services config message that I don't know how to handle"
|
|
||||||
if values is None:
|
|
||||||
logger.error(error_message)
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
values = values.split('|')
|
|
||||||
|
|
||||||
if opaque is None:
|
|
||||||
# store default services for a node type in self.defaultservices[]
|
|
||||||
if data_types is None or data_types[0] != ConfigDataTypes.STRING.value:
|
|
||||||
logger.info(error_message)
|
|
||||||
return None
|
|
||||||
key = values.pop(0)
|
|
||||||
self.defaultservices[key] = values
|
|
||||||
logger.debug("default services for type %s set to %s", key, values)
|
|
||||||
else:
|
|
||||||
# store service customized config in self.customservices[]
|
|
||||||
if node_id is None:
|
|
||||||
return None
|
|
||||||
services, unknown = self.servicesfromopaque(opaque, node_id)
|
|
||||||
for u in unknown:
|
|
||||||
logger.warn("Request for unknown service '%s'" % u)
|
|
||||||
|
|
||||||
if len(services) < 1:
|
|
||||||
return None
|
|
||||||
svc = services[0]
|
|
||||||
self.setcustomservice(node_id, svc, values)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def servicesfromopaque(self, opaque, object_id):
|
def servicesfromopaque(self, opaque, object_id):
|
||||||
"""
|
"""
|
||||||
Build a list of services from an opaque data string.
|
Build a list of services from an opaque data string.
|
||||||
|
|
|
@ -11,6 +11,7 @@ import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from itertools import repeat
|
||||||
|
|
||||||
import pwd
|
import pwd
|
||||||
|
|
||||||
|
@ -18,8 +19,10 @@ from core import constants
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.api import coreapi
|
from core.api import coreapi
|
||||||
from core.broker import CoreBroker
|
from core.broker import CoreBroker
|
||||||
from core.conf import Configurable
|
from core.conf import ConfigShim
|
||||||
from core.conf import ConfigurableManager
|
from core.conf import ConfigurableOptions
|
||||||
|
from core.conf import Configuration
|
||||||
|
from core.conf import NewConfigurableManager
|
||||||
from core.data import ConfigData
|
from core.data import ConfigData
|
||||||
from core.data import EventData
|
from core.data import EventData
|
||||||
from core.data import ExceptionData
|
from core.data import ExceptionData
|
||||||
|
@ -37,11 +40,10 @@ from core.misc import nodeutils
|
||||||
from core.misc import utils
|
from core.misc import utils
|
||||||
from core.misc.event import EventLoop
|
from core.misc.event import EventLoop
|
||||||
from core.misc.ipaddress import MacAddress
|
from core.misc.ipaddress import MacAddress
|
||||||
from core.mobility import BasicRangeModel
|
|
||||||
from core.mobility import MobilityManager
|
from core.mobility import MobilityManager
|
||||||
from core.mobility import Ns2ScriptedMobility
|
|
||||||
from core.netns import nodes
|
from core.netns import nodes
|
||||||
from core.sdt import Sdt
|
from core.sdt import Sdt
|
||||||
|
from core.service import CoreService
|
||||||
from core.service import CoreServices
|
from core.service import CoreServices
|
||||||
from core.xml.xmlsession import save_session_xml
|
from core.xml.xmlsession import save_session_xml
|
||||||
|
|
||||||
|
@ -81,10 +83,6 @@ class Session(object):
|
||||||
self.objects = {}
|
self.objects = {}
|
||||||
self._objects_lock = threading.Lock()
|
self._objects_lock = threading.Lock()
|
||||||
|
|
||||||
# dict of configurable objects
|
|
||||||
self.config_objects = {}
|
|
||||||
self._config_objects_lock = threading.Lock()
|
|
||||||
|
|
||||||
# TODO: should the default state be definition?
|
# TODO: should the default state be definition?
|
||||||
self.state = EventTypes.NONE.value
|
self.state = EventTypes.NONE.value
|
||||||
self._state_time = time.time()
|
self._state_time = time.time()
|
||||||
|
@ -106,60 +104,30 @@ class Session(object):
|
||||||
self.config_handlers = []
|
self.config_handlers = []
|
||||||
self.shutdown_handlers = []
|
self.shutdown_handlers = []
|
||||||
|
|
||||||
# setup broker
|
# initialize feature helpers
|
||||||
self.broker = CoreBroker(session=self)
|
self.broker = CoreBroker(session=self)
|
||||||
self.add_config_object(CoreBroker.name, CoreBroker.config_type, self.broker.configure)
|
|
||||||
|
|
||||||
# setup location
|
|
||||||
self.location = CoreLocation()
|
self.location = CoreLocation()
|
||||||
self.add_config_object(CoreLocation.name, CoreLocation.config_type, self.location.configure)
|
|
||||||
|
|
||||||
# setup mobiliy
|
|
||||||
self.mobility = MobilityManager(session=self)
|
self.mobility = MobilityManager(session=self)
|
||||||
self.add_config_object(MobilityManager.name, MobilityManager.config_type, self.mobility.configure)
|
|
||||||
self.add_config_object(BasicRangeModel.name, BasicRangeModel.config_type, BasicRangeModel.configure_mob)
|
|
||||||
self.add_config_object(Ns2ScriptedMobility.name, Ns2ScriptedMobility.config_type,
|
|
||||||
Ns2ScriptedMobility.configure_mob)
|
|
||||||
|
|
||||||
# setup services
|
|
||||||
self.services = CoreServices(session=self)
|
self.services = CoreServices(session=self)
|
||||||
self.add_config_object(CoreServices.name, CoreServices.config_type, self.services.configure)
|
|
||||||
|
|
||||||
# setup emane
|
|
||||||
self.emane = EmaneManager(session=self)
|
self.emane = EmaneManager(session=self)
|
||||||
self.add_config_object(EmaneManager.name, EmaneManager.config_type, self.emane.configure)
|
self.options = SessionConfig()
|
||||||
|
|
||||||
# setup sdt
|
|
||||||
self.sdt = Sdt(session=self)
|
|
||||||
|
|
||||||
# future parameters set by the GUI may go here
|
|
||||||
self.options = SessionConfig(session=self)
|
|
||||||
self.add_config_object(SessionConfig.name, SessionConfig.config_type, self.options.configure)
|
|
||||||
self.metadata = SessionMetaData()
|
self.metadata = SessionMetaData()
|
||||||
self.add_config_object(SessionMetaData.name, SessionMetaData.config_type, self.metadata.configure)
|
self.sdt = Sdt(session=self)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""
|
"""
|
||||||
Shutdown all emulation objects and remove the session directory.
|
Shutdown all emulation objects and remove the session directory.
|
||||||
"""
|
"""
|
||||||
|
# shutdown/cleanup feature helpers
|
||||||
# shutdown emane
|
|
||||||
self.emane.shutdown()
|
self.emane.shutdown()
|
||||||
|
|
||||||
# shutdown broker
|
|
||||||
self.broker.shutdown()
|
self.broker.shutdown()
|
||||||
|
|
||||||
# shutdown NRL's SDT3D
|
|
||||||
self.sdt.shutdown()
|
self.sdt.shutdown()
|
||||||
|
|
||||||
# delete all current objects
|
# delete all current objects
|
||||||
self.delete_objects()
|
self.delete_objects()
|
||||||
|
|
||||||
preserve = False
|
|
||||||
if hasattr(self.options, "preservedir") and self.options.preservedir == "1":
|
|
||||||
preserve = True
|
|
||||||
|
|
||||||
# remove this sessions working directory
|
# remove this sessions working directory
|
||||||
|
preserve = self.options.get_config("preservedir") == "1"
|
||||||
if not preserve:
|
if not preserve:
|
||||||
shutil.rmtree(self.session_dir, ignore_errors=True)
|
shutil.rmtree(self.session_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
@ -379,12 +347,7 @@ class Session(object):
|
||||||
except:
|
except:
|
||||||
message = "exception occured when running %s state hook: %s" % (coreapi.state_name(state), hook)
|
message = "exception occured when running %s state hook: %s" % (coreapi.state_name(state), hook)
|
||||||
logger.exception(message)
|
logger.exception(message)
|
||||||
self.exception(
|
self.exception(ExceptionLevels.ERROR, "Session.run_state_hooks", None, message)
|
||||||
ExceptionLevels.ERROR,
|
|
||||||
"Session.run_state_hooks",
|
|
||||||
None,
|
|
||||||
message
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_state_hook(self, state, hook):
|
def add_state_hook(self, state, hook):
|
||||||
"""
|
"""
|
||||||
|
@ -422,7 +385,7 @@ class Session(object):
|
||||||
if state == EventTypes.RUNTIME_STATE.value:
|
if state == EventTypes.RUNTIME_STATE.value:
|
||||||
self.emane.poststartup()
|
self.emane.poststartup()
|
||||||
xml_file_version = self.get_config_item("xmlfilever")
|
xml_file_version = self.get_config_item("xmlfilever")
|
||||||
if xml_file_version in ('1.0',):
|
if xml_file_version in ("1.0",):
|
||||||
xml_file_name = os.path.join(self.session_dir, "session-deployed.xml")
|
xml_file_name = os.path.join(self.session_dir, "session-deployed.xml")
|
||||||
save_session_xml(self, xml_file_name, xml_file_version)
|
save_session_xml(self, xml_file_name, xml_file_version)
|
||||||
|
|
||||||
|
@ -597,64 +560,6 @@ class Session(object):
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.exception("error writing nodes file")
|
logger.exception("error writing nodes file")
|
||||||
|
|
||||||
def add_config_object(self, name, object_type, callback):
|
|
||||||
"""
|
|
||||||
Objects can register configuration objects that are included in
|
|
||||||
the Register Message and may be configured via the Configure
|
|
||||||
Message. The callback is invoked when receiving a Configure Message.
|
|
||||||
|
|
||||||
:param str name: name of configuration object to add
|
|
||||||
:param int object_type: register tlv type
|
|
||||||
:param func callback: callback function for object
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
register_tlv = RegisterTlvs(object_type)
|
|
||||||
logger.debug("adding config object callback: %s - %s", name, register_tlv)
|
|
||||||
with self._config_objects_lock:
|
|
||||||
self.config_objects[name] = (object_type, callback)
|
|
||||||
|
|
||||||
def config_object(self, config_data):
|
|
||||||
"""
|
|
||||||
Invoke the callback for an object upon receipt of configuration data for that object.
|
|
||||||
A no-op if the object doesn't exist.
|
|
||||||
|
|
||||||
:param core.data.ConfigData config_data: configuration data to execute against
|
|
||||||
:return: responses to the configuration data
|
|
||||||
:rtype: list
|
|
||||||
"""
|
|
||||||
name = config_data.object
|
|
||||||
logger.info("session(%s) setting config(%s)", self.session_id, name)
|
|
||||||
for key, value in config_data.__dict__.iteritems():
|
|
||||||
logger.debug("%s = %s", key, value)
|
|
||||||
|
|
||||||
replies = []
|
|
||||||
|
|
||||||
if name == "all":
|
|
||||||
with self._config_objects_lock:
|
|
||||||
for name in self.config_objects:
|
|
||||||
config_type, callback = self.config_objects[name]
|
|
||||||
reply = callback(self, config_data)
|
|
||||||
|
|
||||||
if reply:
|
|
||||||
replies.append(reply)
|
|
||||||
|
|
||||||
return replies
|
|
||||||
|
|
||||||
if name in self.config_objects:
|
|
||||||
with self._config_objects_lock:
|
|
||||||
config_type, callback = self.config_objects[name]
|
|
||||||
|
|
||||||
reply = callback(self, config_data)
|
|
||||||
|
|
||||||
if reply:
|
|
||||||
replies.append(reply)
|
|
||||||
|
|
||||||
return replies
|
|
||||||
else:
|
|
||||||
logger.info("session object doesn't own model '%s', ignoring", name)
|
|
||||||
|
|
||||||
return replies
|
|
||||||
|
|
||||||
def dump_session(self):
|
def dump_session(self):
|
||||||
"""
|
"""
|
||||||
Log information about the session in its current state.
|
Log information about the session in its current state.
|
||||||
|
@ -742,10 +647,8 @@ class Session(object):
|
||||||
if self.emane.startup() == self.emane.NOT_READY:
|
if self.emane.startup() == self.emane.NOT_READY:
|
||||||
return
|
return
|
||||||
|
|
||||||
# startup broker
|
# start feature helpers
|
||||||
self.broker.startup()
|
self.broker.startup()
|
||||||
|
|
||||||
# startup mobility
|
|
||||||
self.mobility.startup()
|
self.mobility.startup()
|
||||||
|
|
||||||
# boot the services on each node
|
# boot the services on each node
|
||||||
|
@ -901,11 +804,25 @@ class Session(object):
|
||||||
:return: control net prefix list
|
:return: control net prefix list
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
p = getattr(self.options, "controlnet", self.config.get("controlnet"))
|
p = self.options.get_config("controlnet")
|
||||||
p0 = getattr(self.options, "controlnet0", self.config.get("controlnet0"))
|
if not p:
|
||||||
p1 = getattr(self.options, "controlnet1", self.config.get("controlnet1"))
|
p = self.config.get("controlnet")
|
||||||
p2 = getattr(self.options, "controlnet2", self.config.get("controlnet2"))
|
|
||||||
p3 = getattr(self.options, "controlnet3", self.config.get("controlnet3"))
|
p0 = self.options.get_config("controlnet0")
|
||||||
|
if not p0:
|
||||||
|
p0 = self.config.get("controlnet0")
|
||||||
|
|
||||||
|
p1 = self.options.get_config("controlnet1")
|
||||||
|
if not p1:
|
||||||
|
p1 = self.config.get("controlnet1")
|
||||||
|
|
||||||
|
p2 = self.options.get_config("controlnet2")
|
||||||
|
if not p2:
|
||||||
|
p2 = self.config.get("controlnet2")
|
||||||
|
|
||||||
|
p3 = self.options.get_config("controlnet3")
|
||||||
|
if not p3:
|
||||||
|
p3 = self.config.get("controlnet3")
|
||||||
|
|
||||||
if not p0 and p:
|
if not p0 and p:
|
||||||
p0 = p
|
p0 = p
|
||||||
|
@ -1000,7 +917,7 @@ class Session(object):
|
||||||
logger.warning("controlnet updown script not configured")
|
logger.warning("controlnet updown script not configured")
|
||||||
|
|
||||||
# check if session option set, overwrite if so
|
# check if session option set, overwrite if so
|
||||||
options_updown_script = getattr(self.options, "controlnet_updown_script", None)
|
options_updown_script = self.options.get_config("controlnet_updown_script")
|
||||||
if options_updown_script:
|
if options_updown_script:
|
||||||
updown_script = options_updown_script
|
updown_script = options_updown_script
|
||||||
|
|
||||||
|
@ -1194,6 +1111,7 @@ class Session(object):
|
||||||
node = self.get_object(node_id)
|
node = self.get_object(node_id)
|
||||||
node.cmd(data, wait=False)
|
node.cmd(data, wait=False)
|
||||||
|
|
||||||
|
# TODO: move to core handlers
|
||||||
def send_objects(self):
|
def send_objects(self):
|
||||||
"""
|
"""
|
||||||
Return API messages that describe the current session.
|
Return API messages that describe the current session.
|
||||||
|
@ -1222,36 +1140,48 @@ class Session(object):
|
||||||
logger.info(pprint.pformat(dict(link_data._asdict())))
|
logger.info(pprint.pformat(dict(link_data._asdict())))
|
||||||
self.broadcast_link(link_data)
|
self.broadcast_link(link_data)
|
||||||
|
|
||||||
# send model info
|
# send mobility model info
|
||||||
configs = self.mobility.getallconfigs()
|
for node_id in self.mobility.nodes():
|
||||||
configs += self.emane.getallconfigs()
|
node = self.get_object(node_id)
|
||||||
logger.info("sending model configs:")
|
for model_class, config in self.mobility.getmodels(node):
|
||||||
for node_number, cls, values in configs:
|
logger.info("mobility config: node(%s) class(%s) values(%s)", node_id, model_class, config)
|
||||||
logger.info("config: node(%s) class(%s) values(%s)", node_number, cls, values)
|
config_data = ConfigShim.config_data(0, node_id, ConfigFlags.UPDATE.value, model_class, config)
|
||||||
config_data = cls.config_data(
|
self.broadcast_config(config_data)
|
||||||
flags=0,
|
|
||||||
node_id=node_number,
|
# send emane model info
|
||||||
type_flags=ConfigFlags.UPDATE.value,
|
for node_id in self.emane.nodes():
|
||||||
values=values
|
if node_id not in self.objects:
|
||||||
)
|
continue
|
||||||
logger.info(pprint.pformat(dict(config_data._asdict())))
|
|
||||||
self.broadcast_config(config_data)
|
node = self.get_object(node_id)
|
||||||
|
for model_class, config in self.emane.getmodels(node):
|
||||||
|
logger.info("emane config: node(%s) class(%s) values(%s)", node_id, model_class, config)
|
||||||
|
config_data = ConfigShim.config_data(0, node_id, ConfigFlags.UPDATE.value, model_class, config)
|
||||||
|
self.broadcast_config(config_data)
|
||||||
|
|
||||||
# service customizations
|
# service customizations
|
||||||
service_configs = self.services.getallconfigs()
|
service_configs = self.services.getallconfigs()
|
||||||
for node_number, service in service_configs:
|
for node_id, service in service_configs:
|
||||||
opaque = "service:%s" % service._name
|
opaque = "service:%s" % service._name
|
||||||
|
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(CoreService.keys)))
|
||||||
|
node = self.get_object(node_id)
|
||||||
|
values = CoreService.tovaluelist(node, node.services)
|
||||||
config_data = ConfigData(
|
config_data = ConfigData(
|
||||||
node=node_number,
|
message_type=0,
|
||||||
|
node=node_id,
|
||||||
|
object=self.services.name,
|
||||||
|
type=ConfigFlags.UPDATE.value,
|
||||||
|
data_types=data_types,
|
||||||
|
data_values=values,
|
||||||
|
session=self.session_id,
|
||||||
opaque=opaque
|
opaque=opaque
|
||||||
)
|
)
|
||||||
config_response = self.services.configure_request(config_data)
|
self.broadcast_config(config_data)
|
||||||
self.broadcast_config(config_response)
|
|
||||||
|
|
||||||
for file_name, config_data in self.services.getallfiles(service):
|
for file_name, config_data in self.services.getallfiles(service):
|
||||||
file_data = FileData(
|
file_data = FileData(
|
||||||
message_type=MessageFlags.ADD.value,
|
message_type=MessageFlags.ADD.value,
|
||||||
node=node_number,
|
node=node_id,
|
||||||
name=str(file_name),
|
name=str(file_name),
|
||||||
type=opaque,
|
type=opaque,
|
||||||
data=str(config_data)
|
data=str(config_data)
|
||||||
|
@ -1271,91 +1201,62 @@ class Session(object):
|
||||||
)
|
)
|
||||||
self.broadcast_file(file_data)
|
self.broadcast_file(file_data)
|
||||||
|
|
||||||
config_data = ConfigData()
|
# send session configuration
|
||||||
|
session_config = self.options.get_configs()
|
||||||
|
config_data = ConfigShim.config_data(0, None, ConfigFlags.UPDATE.value, self.options, session_config)
|
||||||
|
self.broadcast_config(config_data)
|
||||||
|
|
||||||
# retrieve session configuration data
|
# send session metadata
|
||||||
options_config = self.options.configure_request(config_data, type_flags=ConfigFlags.UPDATE.value)
|
data_values = "|".join(["%s=%s" % item for item in self.metadata.get_configs().iteritems()])
|
||||||
self.broadcast_config(options_config)
|
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.metadata.get_configs())
|
||||||
|
config_data = ConfigData(
|
||||||
# retrieve session metadata
|
message_type=0,
|
||||||
metadata_config = self.metadata.configure_request(config_data, type_flags=ConfigFlags.UPDATE.value)
|
object=self.metadata.name,
|
||||||
self.broadcast_config(metadata_config)
|
type=ConfigFlags.NONE.value,
|
||||||
|
data_types=data_types,
|
||||||
|
data_values=data_values
|
||||||
|
)
|
||||||
|
self.broadcast_config(config_data)
|
||||||
|
|
||||||
logger.info("informed GUI about %d nodes and %d links", len(nodes_data), len(links_data))
|
logger.info("informed GUI about %d nodes and %d links", len(nodes_data), len(links_data))
|
||||||
|
|
||||||
|
|
||||||
class SessionConfig(ConfigurableManager, Configurable):
|
class SessionConfig(NewConfigurableManager, ConfigurableOptions):
|
||||||
"""
|
"""
|
||||||
Session configuration object.
|
Session configuration object.
|
||||||
"""
|
"""
|
||||||
name = "session"
|
name = "session"
|
||||||
config_type = RegisterTlvs.UTILITY.value
|
config_type = RegisterTlvs.UTILITY.value
|
||||||
config_matrix = [
|
|
||||||
("controlnet", ConfigDataTypes.STRING.value, "", "", "Control network"),
|
|
||||||
("controlnet_updown_script", ConfigDataTypes.STRING.value, "", "", "Control network script"),
|
|
||||||
("enablerj45", ConfigDataTypes.BOOL.value, "1", "On,Off", "Enable RJ45s"),
|
|
||||||
("preservedir", ConfigDataTypes.BOOL.value, "0", "On,Off", "Preserve session dir"),
|
|
||||||
("enablesdt", ConfigDataTypes.BOOL.value, "0", "On,Off", "Enable SDT3D output"),
|
|
||||||
("sdturl", ConfigDataTypes.STRING.value, Sdt.DEFAULT_SDT_URL, "", "SDT3D URL"),
|
|
||||||
]
|
|
||||||
config_groups = "Options:1-%d" % len(config_matrix)
|
|
||||||
|
|
||||||
def __init__(self, session):
|
@classmethod
|
||||||
"""
|
def configurations(cls):
|
||||||
Creates a SessionConfig instance.
|
return [
|
||||||
|
Configuration(_id="controlnet", _type=ConfigDataTypes.STRING, label="Control Network"),
|
||||||
|
Configuration(_id="controlnet0", _type=ConfigDataTypes.STRING, label="Control Network 0"),
|
||||||
|
Configuration(_id="controlnet1", _type=ConfigDataTypes.STRING, label="Control Network 1"),
|
||||||
|
Configuration(_id="controlnet2", _type=ConfigDataTypes.STRING, label="Control Network 2"),
|
||||||
|
Configuration(_id="controlnet3", _type=ConfigDataTypes.STRING, label="Control Network 3"),
|
||||||
|
Configuration(_id="controlnet_updown_script", _type=ConfigDataTypes.STRING, label="Control Network Script"),
|
||||||
|
Configuration(_id="enablerj45", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"],
|
||||||
|
label="Enable RJ45s"),
|
||||||
|
Configuration(_id="preservedir", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
|
||||||
|
label="Preserve session dir"),
|
||||||
|
Configuration(_id="enablesdt", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
|
||||||
|
label="Enable SDT3D output"),
|
||||||
|
Configuration(_id="sdturl", _type=ConfigDataTypes.STRING, default=Sdt.DEFAULT_SDT_URL, label="SDT3D URL")
|
||||||
|
]
|
||||||
|
|
||||||
:param core.session.Session session: session this manager is tied to
|
@classmethod
|
||||||
:return: nothing
|
def config_groups(cls):
|
||||||
"""
|
return "Options:1-%d" % len(cls.configurations())
|
||||||
ConfigurableManager.__init__(self)
|
|
||||||
self.session = session
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
def __init__(self):
|
||||||
"""
|
super(SessionConfig, self).__init__()
|
||||||
Reset the session configuration.
|
config = self.default_values()
|
||||||
|
self.set_configs(config)
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
defaults = self.getdefaultvalues()
|
|
||||||
for key in self.getnames():
|
|
||||||
# value may come from config file
|
|
||||||
value = self.session.get_config_item(key)
|
|
||||||
if value is None:
|
|
||||||
value = self.valueof(key, defaults)
|
|
||||||
value = self.offontobool(value)
|
|
||||||
setattr(self, key, value)
|
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration values.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
return self.configure_values_keyvalues(config_data, self, self.getnames())
|
|
||||||
|
|
||||||
def configure_request(self, config_data, type_flags=ConfigFlags.NONE.value):
|
|
||||||
"""
|
|
||||||
Handle a configuration request.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:param type_flags:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
node_id = config_data.node
|
|
||||||
values = []
|
|
||||||
|
|
||||||
for key in self.getnames():
|
|
||||||
value = getattr(self, key)
|
|
||||||
if value is None:
|
|
||||||
value = ""
|
|
||||||
values.append("%s" % value)
|
|
||||||
|
|
||||||
return self.config_data(0, node_id, type_flags, values)
|
|
||||||
|
|
||||||
|
|
||||||
class SessionMetaData(ConfigurableManager):
|
class SessionMetaData(NewConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Metadata is simply stored in a configs[] dict. Key=value pairs are
|
Metadata is simply stored in a configs[] dict. Key=value pairs are
|
||||||
passed in from configure messages destined to the "metadata" object.
|
passed in from configure messages destined to the "metadata" object.
|
||||||
|
@ -1363,92 +1264,3 @@ class SessionMetaData(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
name = "metadata"
|
name = "metadata"
|
||||||
config_type = RegisterTlvs.UTILITY.value
|
config_type = RegisterTlvs.UTILITY.value
|
||||||
|
|
||||||
def configure_values(self, config_data):
|
|
||||||
"""
|
|
||||||
Handle configuration values.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
values = config_data.data_values
|
|
||||||
if values is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
key_values = values.split('|')
|
|
||||||
for key_value in key_values:
|
|
||||||
try:
|
|
||||||
key, value = key_value.split('=', 1)
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError("invalid key in metdata: %s", key_value)
|
|
||||||
|
|
||||||
self.add_item(key, value)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def configure_request(self, config_data, type_flags=ConfigFlags.NONE.value):
|
|
||||||
"""
|
|
||||||
Handle a configuration request.
|
|
||||||
|
|
||||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
|
||||||
:param int type_flags: configuration request flag value
|
|
||||||
:return: configuration data
|
|
||||||
:rtype: ConfigData
|
|
||||||
"""
|
|
||||||
node_number = config_data.node
|
|
||||||
values_str = "|".join(map(lambda item: "%s=%s" % item, self.items()))
|
|
||||||
return self.config_data(0, node_number, type_flags, values_str)
|
|
||||||
|
|
||||||
def config_data(self, flags, node_id, type_flags, values_str):
|
|
||||||
"""
|
|
||||||
Retrieve configuration data object, leveraging provided data.
|
|
||||||
|
|
||||||
:param flags: configuration data flags
|
|
||||||
:param int node_id: node id
|
|
||||||
:param type_flags: type flags
|
|
||||||
:param values_str: values string
|
|
||||||
:return: configuration data
|
|
||||||
:rtype: ConfigData
|
|
||||||
"""
|
|
||||||
data_types = tuple(map(lambda (k, v): ConfigDataTypes.STRING.value, self.items()))
|
|
||||||
|
|
||||||
return ConfigData(
|
|
||||||
message_type=flags,
|
|
||||||
node=node_id,
|
|
||||||
object=self.name,
|
|
||||||
type=type_flags,
|
|
||||||
data_types=data_types,
|
|
||||||
data_values=values_str
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_item(self, key, value):
|
|
||||||
"""
|
|
||||||
Add configuration key/value pair.
|
|
||||||
|
|
||||||
:param key: configuration key
|
|
||||||
:param value: configuration value
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
self.configs[key] = value
|
|
||||||
|
|
||||||
def get_item(self, key):
|
|
||||||
"""
|
|
||||||
Retrieve configuration value.
|
|
||||||
|
|
||||||
:param key: key for configuration value to retrieve
|
|
||||||
:return: configuration value
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return self.configs[key]
|
|
||||||
except KeyError:
|
|
||||||
logger.exception("error retrieving item from configs: %s", key)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def items(self):
|
|
||||||
"""
|
|
||||||
Retrieve configuration items.
|
|
||||||
|
|
||||||
:return: configuration items iterator
|
|
||||||
"""
|
|
||||||
return self.configs.iteritems()
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
|
from core.conf import ConfigShim
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.service import ServiceManager
|
from core.service import ServiceManager
|
||||||
|
@ -369,6 +370,7 @@ class CoreDocumentParser0(object):
|
||||||
values.append("files=%s" % files)
|
values.append("files=%s" % files)
|
||||||
if not bool(service.getAttribute("custom")):
|
if not bool(service.getAttribute("custom")):
|
||||||
return True
|
return True
|
||||||
|
values = ConfigShim.str_to_dict(values)
|
||||||
self.session.services.setcustomservice(n.objid, svc, values)
|
self.session.services.setcustomservice(n.objid, svc, values)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from xml.dom.minidom import parse
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core import logger
|
from core import logger
|
||||||
|
from core.conf import ConfigShim
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.misc.ipaddress import MacAddress
|
from core.misc.ipaddress import MacAddress
|
||||||
|
@ -615,6 +616,7 @@ class CoreDocumentParser1(object):
|
||||||
values.append('cmddown=%s' % shutdown)
|
values.append('cmddown=%s' % shutdown)
|
||||||
if validate:
|
if validate:
|
||||||
values.append('cmdval=%s' % validate)
|
values.append('cmdval=%s' % validate)
|
||||||
|
|
||||||
filenames = []
|
filenames = []
|
||||||
files = []
|
files = []
|
||||||
for f in xmlutils.iter_children_with_name(service, 'file'):
|
for f in xmlutils.iter_children_with_name(service, 'file'):
|
||||||
|
@ -629,11 +631,15 @@ class CoreDocumentParser1(object):
|
||||||
data = None
|
data = None
|
||||||
typestr = 'service:%s:%s' % (name, filename)
|
typestr = 'service:%s:%s' % (name, filename)
|
||||||
files.append((typestr, filename, data))
|
files.append((typestr, filename, data))
|
||||||
|
|
||||||
if filenames:
|
if filenames:
|
||||||
values.append('files=%s' % filenames)
|
values.append('files=%s' % filenames)
|
||||||
|
|
||||||
custom = service.getAttribute('custom')
|
custom = service.getAttribute('custom')
|
||||||
if custom and custom.lower() == 'true':
|
if custom and custom.lower() == 'true':
|
||||||
|
values = ConfigShim.str_to_dict(values)
|
||||||
self.session.services.setcustomservice(node.objid, session_service, values)
|
self.session.services.setcustomservice(node.objid, session_service, values)
|
||||||
|
|
||||||
# NOTE: if a custom service is used, setservicefile() must be
|
# NOTE: if a custom service is used, setservicefile() must be
|
||||||
# called after the custom service exists
|
# called after the custom service exists
|
||||||
for typestr, filename, data in files:
|
for typestr, filename, data in files:
|
||||||
|
@ -812,7 +818,7 @@ class CoreDocumentParser1(object):
|
||||||
params = self.parse_parameter_children(options)
|
params = self.parse_parameter_children(options)
|
||||||
for name, value in params.iteritems():
|
for name, value in params.iteritems():
|
||||||
if name and value:
|
if name and value:
|
||||||
setattr(self.session.options, str(name), str(value))
|
self.session.options.set_config(str(name), str(value))
|
||||||
|
|
||||||
def parse_session_hooks(self, session_config):
|
def parse_session_hooks(self, session_config):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -217,13 +217,7 @@ class ScenarioPlan(XmlElement):
|
||||||
self.last_network_id = 0
|
self.last_network_id = 0
|
||||||
self.addNetworks()
|
self.addNetworks()
|
||||||
self.addDevices()
|
self.addDevices()
|
||||||
|
|
||||||
# XXX Do we need these?
|
|
||||||
# self.session.emane.setup() # not during runtime?
|
|
||||||
# self.addorigin()
|
|
||||||
|
|
||||||
self.addDefaultServices()
|
self.addDefaultServices()
|
||||||
|
|
||||||
self.addSessionConfiguration()
|
self.addSessionConfiguration()
|
||||||
|
|
||||||
def addNetworks(self):
|
def addNetworks(self):
|
||||||
|
@ -318,10 +312,12 @@ class ScenarioPlan(XmlElement):
|
||||||
|
|
||||||
# options
|
# options
|
||||||
options = self.createElement("options")
|
options = self.createElement("options")
|
||||||
defaults = self.coreSession.options.getdefaultvalues()
|
options_config = self.coreSession.options.get_configs()
|
||||||
for i, (k, v) in enumerate(self.coreSession.options.getkeyvaluelist()):
|
for _id, default_value in self.coreSession.options.default_values().iteritems():
|
||||||
if str(v) != str(defaults[i]):
|
value = options_config[_id]
|
||||||
XmlElement.add_parameter(self.document, options, k, v)
|
if value != default_value:
|
||||||
|
XmlElement.add_parameter(self.document, options, _id, value)
|
||||||
|
|
||||||
if options.hasChildNodes():
|
if options.hasChildNodes():
|
||||||
config.appendChild(options)
|
config.appendChild(options)
|
||||||
|
|
||||||
|
@ -340,7 +336,7 @@ class ScenarioPlan(XmlElement):
|
||||||
|
|
||||||
# metadata
|
# metadata
|
||||||
meta = self.createElement("metadata")
|
meta = self.createElement("metadata")
|
||||||
for k, v in self.coreSession.metadata.items():
|
for k, v in self.coreSession.metadata.get_configs().iteritems():
|
||||||
XmlElement.add_parameter(self.document, meta, k, v)
|
XmlElement.add_parameter(self.document, meta, k, v)
|
||||||
if meta.hasChildNodes():
|
if meta.hasChildNodes():
|
||||||
config.appendChild(meta)
|
config.appendChild(meta)
|
||||||
|
@ -482,6 +478,7 @@ class NetworkElement(NamedXmlElement):
|
||||||
modelconfigs = network_object.session.mobility.getmodels(network_object)
|
modelconfigs = network_object.session.mobility.getmodels(network_object)
|
||||||
modelconfigs += network_object.session.emane.getmodels(network_object)
|
modelconfigs += network_object.session.emane.getmodels(network_object)
|
||||||
chan = None
|
chan = None
|
||||||
|
|
||||||
for model, conf in modelconfigs:
|
for model, conf in modelconfigs:
|
||||||
# Handle mobility parameters below
|
# Handle mobility parameters below
|
||||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||||
|
@ -496,10 +493,9 @@ class NetworkElement(NamedXmlElement):
|
||||||
channel_domain="CORE")
|
channel_domain="CORE")
|
||||||
|
|
||||||
# Add wireless model parameters
|
# Add wireless model parameters
|
||||||
for i, key in enumerate(model.getnames()):
|
for key, value in conf.iteritems():
|
||||||
value = conf[i]
|
|
||||||
if value is not None:
|
if value is not None:
|
||||||
chan.addParameter(key, model.valueof(key, conf))
|
chan.addParameter(key, value)
|
||||||
|
|
||||||
for model, conf in modelconfigs:
|
for model, conf in modelconfigs:
|
||||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||||
|
@ -509,8 +505,8 @@ class NetworkElement(NamedXmlElement):
|
||||||
type_element = self.createElement("type")
|
type_element = self.createElement("type")
|
||||||
type_element.appendChild(self.createTextNode(model.name))
|
type_element.appendChild(self.createTextNode(model.name))
|
||||||
mobility.appendChild(type_element)
|
mobility.appendChild(type_element)
|
||||||
for i, key in enumerate(model.getnames()):
|
|
||||||
value = conf[i]
|
for key, value in conf.iteritems():
|
||||||
if value is not None:
|
if value is not None:
|
||||||
mobility.addParameter(key, value)
|
mobility.addParameter(key, value)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue