7 class NS3Wrapper(object):
8 def __init__(self, homedir = None):
9 super(NS3Wrapper, self).__init__()
11 self._uuid = self.make_uuid()
12 self._homedir = homedir or os.path.join("/tmp", self._uuid)
13 self._simulation_thread = None
14 self._condition = None
19 # holds reference to all ns-3 objects in the simulation
20 self._resources = dict()
22 # create home dir (where all simulation related files will end up)
23 home = os.path.normpath(self.homedir)
24 if not os.path.exists(home):
25 os.makedirs(home, 0755)
28 loglevel = os.environ.get("NS3LOGLEVEL", "debug")
29 self._logger = logging.getLogger("ns3wrapper.%s" % self.uuid)
30 self._logger.setLevel(getattr(logging, loglevel.upper()))
31 hdlr = logging.FileHandler(os.path.join(self.homedir, "ns3wrapper.log"))
32 formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
33 hdlr.setFormatter(formatter)
34 self._logger.addHandler(hdlr)
36 # Load ns-3 shared libraries and import modules
37 self._load_ns3_module()
56 return "uuid%s" % uuid.uuid4()
58 def singleton(self, clazzname):
59 uuid = "uuid%s"%clazzname
61 if not uuid in self._resources:
62 if not hasattr(self.ns3, clazzname):
63 msg = "Type %s not supported" % (typeid)
64 self.logger.error(msg)
66 clazz = getattr(self.ns3, clazzname)
67 typeid = "ns3::%s" % clazzname
68 self._resources[uuid] = (clazz, typeid)
72 def get_trace(self, trace, offset = None, nbytes = None ):
76 return self._started and not self._stopped
78 def get_resource(self, uuid):
79 (resource, typeid) = self._resources.get(uuid)
82 def get_typeid(self, uuid):
83 (resource, typeid) = self._resources.get(uuid)
86 def create(self, clazzname, *args):
87 if not hasattr(self.ns3, clazzname):
88 msg = "Type %s not supported" % (clazzname)
89 self.logger.error(msg)
91 clazz = getattr(self.ns3, clazzname)
92 #typeid = clazz.GetInstanceTypeId().GetName()
93 typeid = "ns3::%s" % clazzname
95 realargs = [self.get_resource(arg) if \
96 str(arg).startswith("uuid") else arg for arg in args]
98 resource = clazz(*realargs)
100 uuid = self.make_uuid()
101 self._resources[uuid] = (resource, typeid)
104 def set(self, uuid, name, value):
105 resource = self.get_resource(uuid)
107 if hasattr(resource, name):
108 setattr(resource, name, value)
110 self._set_ns3_attr(uuid, name, value)
112 def get(self, name, uuid = None):
113 resource = self.get_resource(uuid)
116 if hasattr(resource, name):
117 value = getattr(resource, name)
119 value = self._get_ns3_attr(uuid, name)
123 def invoke(self, uuid, operation, *args):
124 resource = self.get_resource(uuid)
125 typeid = self.get_typeid(uuid)
126 method = getattr(resource, operation)
128 realargs = [self.get_resource(arg) if \
129 str(arg).startswith("uuid") else arg for arg in args]
131 result = method(*realargs)
136 uuid = self.make_uuid()
137 self._resources[uuid] = (result, typeid)
142 self._condition = threading.Condition()
143 self._simulator_thread = threading.Thread(
144 target = self._simulator_run,
145 args = [self._condition])
146 self._simulator_thread.setDaemon(True)
147 self._simulator_thread.start()
150 def stop(self, time = None):
155 self.ns3.Simulator.Stop()
157 self.ns3.Simulator.Stop(self.ns3.Time(time))
162 if not self.ns3.Simulator.IsFinished():
165 # TODO!!!! SHOULD WAIT UNTIL THE THREAD FINISHES
166 if self._simulator_thread:
167 self._simulator_thread.join()
169 self.ns3.Simulator.Destroy()
171 self._resources.clear()
177 def _simulator_run(self, condition):
179 self.ns3.Simulator.Run()
180 # Signal condition on simulation end to notify waiting threads
182 condition.notifyAll()
185 def _schedule_event(self, condition, func, *args):
186 """ Schedules event on running simulation, and wait until
189 def execute_event(contextId, condition, has_event_occurred, func, *args):
194 has_event_occurred[0] = True
195 # notify condition indicating attribute was set
197 condition.notifyAll()
200 # contextId is defined as general context
201 contextId = long(0xffffffff)
203 # delay 0 means that the event is expected to execute inmediately
204 delay = self.ns3.Seconds(0)
206 # flag to indicate that the event occured
207 # because bool is an inmutable object in python, in order to create a
208 # bool flag, a list is used as wrapper
209 has_event_occurred = [False]
212 if not self.ns3.Simulator.IsFinished():
213 self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event,
214 condition, has_event_occurred, func, *args)
215 while not has_event_occurred[0] and not self.ns3.Simulator.IsFinished():
220 def _set_ns3_attr(self, uuid, name, value):
221 resource = self.get_resource(uuid)
222 ns3_value = self._to_ns3_value(uuid, name, value)
224 def set_attr(resource, name, ns3_value):
225 resource.SetAttribute(name, ns3_value)
228 # schedule the event in the Simulator
229 self._schedule_event(self._condition, set_attr, resource,
232 set_attr(resource, name, ns3_value)
234 def _get_ns3_attr(self, uuid, name):
235 resource = self.get_resource(uuid)
236 ns3_value = self._create_ns3_value(uuid, name)
238 def get_attr(resource, name, ns3_value):
239 resource.GetAttribute(name, ns3_value)
242 # schedule the event in the Simulator
243 self._schedule_event(self._condition, get_attr, resource,
246 get_attr(resource, name, ns3_value)
248 return self._from_ns3_value(uuid, name, ns3_value)
250 def _create_ns3_value(self, uuid, name):
251 typeid = get_typeid(uuid)
252 TypeId = self.ns3.TypeId()
253 tid = TypeId.LookupByName(typeid)
254 info = TypeId.AttributeInformation()
255 if not tid.LookupAttributeByName(name, info):
256 msg = "TypeId %s has no attribute %s" % (typeid, name)
257 self.logger.error(msg)
259 checker = info.checker
260 ns3_value = checker.Create()
263 def _from_ns3_value(self, uuid, name, ns3_value):
264 typeid = get_typeid(uuid)
265 TypeId = self.ns3.TypeId()
266 tid = TypeId.LookupByName(typeid)
267 info = TypeId.AttributeInformation()
268 if not tid.LookupAttributeByName(name, info):
269 msg = "TypeId %s has no attribute %s" % (typeid, name)
270 self.logger.error(msg)
272 checker = info.checker
273 value = ns3_value.SerializeToString(checker)
275 type_name = checker.GetValueTypeName()
276 if type_name in ["ns3::UintegerValue", "ns3::IntegerValue"]:
278 if type_name == "ns3::DoubleValue":
280 if type_name == "ns3::BooleanValue":
281 return value == "true"
285 def _to_ns3_value(self, uuid, name, value):
286 typeid = get_typeid(uuid)
287 TypeId = self.ns3.TypeId()
288 typeid = TypeId.LookupByName(typeid)
289 info = TypeId.AttributeInformation()
290 if not tid.LookupAttributeByName(name, info):
291 msg = "TypeId %s has no attribute %s" % (typeid, name)
292 self.logger.error(msg)
294 str_value = str(value)
295 if isinstance(value, bool):
296 str_value = str_value.lower()
298 checker = info.checker
299 ns3_value = checker.Create()
300 ns3_value.DeserializeFromString(str_value, checker)
303 def _load_ns3_module(self):
312 bindings = os.environ.get("NS3BINDINGS")
313 libdir = os.environ.get("NS3LIBRARIES")
315 # Load the ns-3 modules shared libraries
317 files = os.listdir(libdir)
318 regex = re.compile("(.*\.so)$")
319 libs = [m.group(1) for filename in files for m in [regex.search(filename)] if m]
324 libfile = os.path.join(libdir, lib)
326 ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
331 # if did not load any libraries in the last iteration break
332 # to prevent infinit loop
333 if len(libscp) == len(libs):
334 raise RuntimeError("Imposible to load shared libraries %s" % str(libs))
337 # import the python bindings for the ns-3 modules
339 sys.path.append(bindings)
341 # create a module to add all ns3 classes
342 ns3mod = imp.new_module("ns3")
343 sys.modules["ns3"] = ns3mod
345 # retrieve all ns3 classes and add them to the ns3 module
347 for importer, modname, ispkg in pkgutil.iter_modules(ns.__path__):
348 fullmodname = "ns.%s" % modname
349 module = __import__(fullmodname, globals(), locals(), ['*'])
351 # netanim.Config singleton overrides ns3::Config
352 if modname in ['netanim']:
355 for sattr in dir(module):
356 if not sattr.startswith("_"):
357 attr = getattr(module, sattr)
358 setattr(ns3mod, sattr, attr)