SIMULATOR_UUID = "singleton::Simulator"
CONFIG_UUID = "singleton::Config"
GLOBAL_VALUE_UUID = "singleton::GlobalValue"
+IPV4_GLOBAL_ROUTING_HELPER_UUID = "singleton::Ipv4GlobalRoutingHelper"
-def load_ns3_module():
+def load_ns3_libraries():
import ctypes
import re
- bindings = os.environ.get("NS3BINDINGS")
libdir = os.environ.get("NS3LIBRARIES")
# Load the ns-3 modules shared libraries
# to prevent infinit loop
if initial_size == len(libs):
raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
- initial_size = list(libs)
+ initial_size = len(libs)
+
+def load_ns3_module():
+ load_ns3_libraries()
# import the python bindings for the ns-3 modules
+ bindings = os.environ.get("NS3BINDINGS")
if bindings:
sys.path.append(bindings)
return ns3mod
class NS3Wrapper(object):
- def __init__(self, loglevel = logging.INFO):
+ def __init__(self, loglevel = logging.INFO, enable_dump = False):
super(NS3Wrapper, self).__init__()
# Thread used to run the simulation
self._simulation_thread = None
# Collection of allowed ns3 classes
self._allowed_types = None
+ # Object to dump instructions to reproduce and debug experiment
+ from ns3wrapper_debug import NS3WrapperDebuger
+ self._debuger = NS3WrapperDebuger(enabled = enable_dump)
+
+ @property
+ def debuger(self):
+ return self._debuger
+
@property
def ns3(self):
if not self._ns3:
@property
def is_running(self):
- return self._started and self.ns3.Simulator.IsFinished()
+ return self._started and not self.ns3.Simulator.IsFinished()
+
+ @property
+ def is_finished(self):
+ return self.ns3.Simulator.IsFinished()
def make_uuid(self):
return "uuid%s" % uuid.uuid4()
return self._objects.get(uuid)
def factory(self, type_name, **kwargs):
+ """ This method should be used to construct ns-3 objects
+ that have a TypeId and related introspection information """
+
if type_name not in self.allowed_types:
msg = "Type %s not supported" % (type_name)
self.logger.error(msg)
-
+
+ uuid = self.make_uuid()
+
+ ### DEBUG
+ self.logger.debug("FACTORY %s( %s )" % (type_name, str(kwargs)))
+
+ self.debuger.dump_factory(uuid, type_name, kwargs)
+ ########
+
factory = self.ns3.ObjectFactory()
factory.SetTypeId(type_name)
obj = factory.Create()
- uuid = self.make_uuid()
self._objects[uuid] = obj
+ ### DEBUG
+ self.logger.debug("RET FACTORY ( uuid %s ) %s = %s( %s )" % (
+ str(uuid), str(obj), type_name, str(kwargs)))
+ ########
+
return uuid
def create(self, clazzname, *args):
+ """ This method should be used to construct ns-3 objects that
+ do not have a TypeId (e.g. Values) """
+
if not hasattr(self.ns3, clazzname):
msg = "Type %s not supported" % (clazzname)
self.logger.error(msg)
-
+
+ uuid = self.make_uuid()
+
+ ### DEBUG
+ self.logger.debug("CREATE %s( %s )" % (clazzname, str(args)))
+
+ self.debuger.dump_create(uuid, clazzname, args)
+ ########
+
clazz = getattr(self.ns3, clazzname)
# arguments starting with 'uuid' identify ns-3 C++
obj = clazz(*realargs)
- uuid = self.make_uuid()
self._objects[uuid] = obj
+ ### DEBUG
+ self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid),
+ str(obj), clazzname, str(args)))
+ ########
+
return uuid
def invoke(self, uuid, operation, *args, **kwargs):
- if operation == "isAppRunning":
- return self._is_app_running(uuid)
-
- if uuid.startswith(SINGLETON):
- obj = self._singleton(uuid)
+ ### DEBUG
+ self.logger.debug("INVOKE %s -> %s( %s, %s ) " % (
+ uuid, operation, str(args), str(kwargs)))
+ ########
+
+ result = None
+ newuuid = None
+
+ if operation == "isRunning":
+ result = self.is_running
+ elif operation == "isFinished":
+ result = self.is_finished
+ elif operation == "isAppRunning":
+ result = self._is_app_running(uuid)
+ elif operation == "addStaticRoute":
+ ### DEBUG
+ self.debuger.dump_add_static_route(uuid, args)
+ ########
+
+ result = self._add_static_route(uuid, *args)
else:
- obj = self.get_object(uuid)
-
- method = getattr(obj, operation)
+ newuuid = self.make_uuid()
- # arguments starting with 'uuid' identify ns-3 C++
- # objects and must be replaced by the actual object
- realargs = self.replace_args(args)
- realkwargs = self.replace_kwargs(kwargs)
+ ### DEBUG
+ self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs)
+ ########
+
+ if uuid.startswith(SINGLETON):
+ obj = self._singleton(uuid)
+ else:
+ obj = self.get_object(uuid)
+
+ method = getattr(obj, operation)
+
+ # arguments starting with 'uuid' identify ns-3 C++
+ # objects and must be replaced by the actual object
+ realargs = self.replace_args(args)
+ realkwargs = self.replace_kwargs(kwargs)
- result = method(*realargs, **realkwargs)
+ result = method(*realargs, **realkwargs)
- if result is None or \
- isinstance(result, bool):
- return result
-
- newuuid = self.make_uuid()
- self._objects[newuuid] = result
+ # If the result is an object (not a base value),
+ # then keep track of the object a return the object
+ # reference (newuuid)
+ if not (result is None or type(result) in [
+ bool, float, long, str, int]):
+ self._objects[newuuid] = result
+ result = newuuid
- return newuuid
+ ### DEBUG
+ self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % (
+ "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid,
+ operation, str(args), str(kwargs)))
+ ########
+
+ return result
def _set_attr(self, obj, name, ns3_value):
obj.SetAttribute(name, ns3_value)
def set(self, uuid, name, value):
+ ### DEBUG
+ self.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
+
+ self.debuger.dump_set(uuid, name, value)
+ ########
+
obj = self.get_object(uuid)
type_name = obj.GetInstanceTypeId().GetName()
ns3_value = self._attr_from_string_to_ns3_value(type_name, name, value)
if not event_executed[0]:
self._set_attr(obj, name, ns3_value)
+ ### DEBUG
+ self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name,
+ str(value)))
+ ########
+
return value
def _get_attr(self, obj, name, ns3_value):
obj.GetAttribute(name, ns3_value)
def get(self, uuid, name):
+ ### DEBUG
+ self.logger.debug("GET %s %s" % (uuid, name))
+
+ self.debuger.dump_get(uuid, name)
+ ########
+
obj = self.get_object(uuid)
type_name = obj.GetInstanceTypeId().GetName()
ns3_value = self._create_attr_ns3_value(type_name, name)
if not event_executed[0]:
self._get_attr(obj, name, ns3_value)
- return self._attr_from_ns3_value_to_string(type_name, name, ns3_value)
+ result = self._attr_from_ns3_value_to_string(type_name, name, ns3_value)
+
+ ### DEBUG
+ self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name))
+ ########
+
+ return result
def start(self):
+ ### DEBUG
+ self.debuger.dump_start()
+ ########
+
# Launch the simulator thread and Start the
# simulator in that thread
self._condition = threading.Condition()
self._simulator_thread.start()
self._started = True
+ ### DEBUG
+ self.logger.debug("START")
+ ########
+
def stop(self, time = None):
+ ### DEBUG
+ self.debuger.dump_stop(time=time)
+ ########
+
if time is None:
self.ns3.Simulator.Stop()
else:
self.ns3.Simulator.Stop(self.ns3.Time(time))
+ ### DEBUG
+ self.logger.debug("STOP time=%s" % str(time))
+ ########
+
def shutdown(self):
+ ### DEBUG
+ self.debuger.dump_shutdown()
+ ########
+
while not self.ns3.Simulator.IsFinished():
#self.logger.debug("Waiting for simulation to finish")
time.sleep(0.5)
sys.stdout.flush()
sys.stderr.flush()
+ ### DEBUG
+ self.logger.debug("SHUTDOWN")
+ ########
+
def _simulator_run(self, condition):
# Run simulation
self.ns3.Simulator.Run()
if now.IsZero():
return False
- stop_value = self.get(uuid, "StopTime")
- stop_time = self.ns3.Time(stop_value)
-
- start_value = self.get(uuid, "StartTime")
- start_time = self.ns3.Time(start_value)
-
- self.logger.debug("NOW %s" % now.GetSeconds())
- self.logger.debug("START TIME %s" % start_value)
- self.logger.debug("STOP TIME %s" % stop_value)
+ app = self.get_object(uuid)
+ stop_time_value = self.ns3.TimeValue()
+ app.GetAttribute("StopTime", stop_time_value)
+ stop_time = stop_time_value.Get()
+ start_time_value = self.ns3.TimeValue()
+ app.GetAttribute("StartTime", start_time_value)
+ start_time = start_time_value.Get()
+
if now.Compare(start_time) >= 0 and now.Compare(stop_time) < 0:
return True
return False
+ def _add_static_route(self, ipv4_uuid, network, prefix, nexthop):
+ ipv4 = self.get_object(ipv4_uuid)
+
+ list_routing = ipv4.GetRoutingProtocol()
+ (static_routing, priority) = list_routing.GetRoutingProtocol(0)
+
+ ifindex = self._find_ifindex(ipv4, nexthop)
+ if ifindex == -1:
+ return False
+
+ nexthop = self.ns3.Ipv4Address(nexthop)
+
+ if network in ["0.0.0.0", "0", None]:
+ # Default route: 0.0.0.0/0
+ static_routing.SetDefaultRoute(nexthop, ifindex)
+ else:
+ mask = self.ns3.Ipv4Mask("/%s" % prefix)
+ network = self.ns3.Ipv4Address(network)
+
+ if prefix == 32:
+ # Host route: x.y.z.w/32
+ static_routing.AddHostRouteTo(network, nexthop, ifindex)
+ else:
+ # Network route: x.y.z.w/n
+ static_routing.AddNetworkRouteTo(network, mask, nexthop,
+ ifindex)
+ return True
+
+ def _find_ifindex(self, ipv4, nexthop):
+ ifindex = -1
+
+ nexthop = self.ns3.Ipv4Address(nexthop)
+
+ # For all the interfaces registered with the ipv4 object, find
+ # the one that matches the network of the nexthop
+ nifaces = ipv4.GetNInterfaces()
+ for ifidx in xrange(nifaces):
+ iface = ipv4.GetInterface(ifidx)
+ naddress = iface.GetNAddresses()
+ for addridx in xrange(naddress):
+ ifaddr = iface.GetAddress(addridx)
+ ifmask = ifaddr.GetMask()
+
+ ifindex = ipv4.GetInterfaceForPrefix(nexthop, ifmask)
+
+ if ifindex == ifidx:
+ return ifindex
+ return ifindex
+