""" Defines Emane Models used within CORE. """ from core import emane from core import logger from core.misc import utils from core.mobility import WirelessModel from core.xml import xmlutils class EmaneModel(WirelessModel): """ EMANE models inherit from this parent class, which takes care of handling configuration messages based on the _confmatrix list of configurable parameters. Helper functions also live here. """ _prefix = { "y": 1e-24, # yocto "z": 1e-21, # zepto "a": 1e-18, # atto "f": 1e-15, # femto "p": 1e-12, # pico "n": 1e-9, # nano "u": 1e-6, # micro "m": 1e-3, # mili "c": 1e-2, # centi "d": 1e-1, # deci "k": 1e3, # kilo "M": 1e6, # mega "G": 1e9, # giga "T": 1e12, # tera "P": 1e15, # peta "E": 1e18, # exa "Z": 1e21, # zetta "Y": 1e24, # yotta } @classmethod def configure_emane(cls, session, config_data): """ Handle configuration messages for setting up a model. Pass the Emane object as the manager object. :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) @classmethod def emane074_fixup(cls, value, div=1.0): """ Helper for converting 0.8.1 and newer values to EMANE 0.7.4 compatible values. NOTE: This should be removed when support for 0.7.4 has been deprecated. """ if div == 0: return "0" if type(value) is not str: return str(value / div) if value.endswith(tuple(cls._prefix.keys())): suffix = value[-1] value = float(value[:-1]) * cls._prefix[suffix] return str(int(value / div)) def buildnemxmlfiles(self, e, ifc): """ Build the necessary nem, mac, and phy XMLs in the given path. """ raise NotImplementedError def buildplatformxmlnementry(self, doc, n, ifc): """ Build the NEM definition that goes into the platform.xml file. This returns an XML element that will be added to the element. This default method supports per-interface config (e.g. or per-EmaneNode config (e.g. . This can be overriden by a model for NEM flexibility; n is the EmaneNode. """ nem = doc.createElement("nem") nem.setAttribute("name", ifc.localname) # if this netif contains a non-standard (per-interface) config, # then we need to use a more specific xml file here nem.setAttribute("definition", self.nemxmlname(ifc)) return nem def buildplatformxmltransportentry(self, doc, n, ifc): """ Build the transport definition that goes into the platform.xml file. This returns an XML element that will added to the nem definition. This default method supports raw and virtual transport types, but may be overriden by a model to support the e.g. pluggable virtual transport. n is the EmaneNode. """ ttype = ifc.transport_type if not ttype: logger.info("warning: %s interface type unsupported!" % ifc.name) ttype = "raw" trans = doc.createElement("transport") trans.setAttribute("definition", n.transportxmlname(ttype)) if emane.VERSION < emane.EMANE092: trans.setAttribute("group", "1") param = doc.createElement("param") param.setAttribute("name", "device") if ttype == "raw": # raw RJ45 name e.g. "eth0" param.setAttribute("value", ifc.name) else: # virtual TAP name e.g. "n3.0.17" param.setAttribute("value", ifc.localname) if emane.VERSION > emane.EMANE091: param.setAttribute("value", ifc.name) trans.appendChild(param) return trans def basename(self, interface=None): """ Return the string that other names are based on. If a specific config is stored for a node"s interface, a unique filename is needed; otherwise the name of the EmaneNode is used. """ emane = self.session.emane name = "n%s" % self.object_id if interface is not None: nodenum = interface.node.objid # Adamson change - use getifcconfig() to get proper result # if emane.getconfig(nodenum, self._name, None)[1] is not None: if emane.getifcconfig(nodenum, self.name, None, interface) is not None: name = interface.localname.replace(".", "_") return "%s%s" % (name, self.name) def nemxmlname(self, interface=None): """ Return the string name for the NEM XML file, e.g. "n3rfpipenem.xml" """ append = "" if emane.VERSION > emane.EMANE091: if interface and interface.transport_type == "raw": append = "_raw" return "%snem%s.xml" % (self.basename(interface), append) def shimxmlname(self, ifc=None): """ Return the string name for the SHIM XML file, e.g. "commeffectshim.xml" """ return "%sshim.xml" % self.basename(ifc) def macxmlname(self, ifc=None): """ Return the string name for the MAC XML file, e.g. "n3rfpipemac.xml" """ return "%smac.xml" % self.basename(ifc) def phyxmlname(self, ifc=None): """ Return the string name for the PHY XML file, e.g. "n3rfpipephy.xml" """ return "%sphy.xml" % self.basename(ifc) def update(self, moved, moved_netifs): """ invoked from MobilityModel when nodes are moved; this causes EMANE location events to be generated for the nodes in the moved list, making EmaneModels compatible with Ns2ScriptedMobility """ try: wlan = self.session.get_object(self.object_id) wlan.setnempositions(moved_netifs) except KeyError: logger.exception("error during update") def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None, jitter=None, netif2=None): """ Invoked when a Link Message is received. Default is unimplemented. """ warntxt = "EMANE model %s does not support link " % self.name warntxt += "configuration, dropping Link Message" logger.warn(warntxt) @staticmethod def valuestrtoparamlist(dom, name, value): """ Helper to convert a parameter to a paramlist. Returns a an XML paramlist, or None if the value does not expand to multiple values. """ try: values = utils.make_tuple_fromstr(value, str) except SyntaxError: logger.exception("error in value string to param list") return None if not hasattr(values, "__iter__"): return None if len(values) < 2: return None return xmlutils.add_param_list_to_parent(dom, parent=None, name=name, values=values)