[Ns-developers] Bug report: Config::Set may fail to set the attribute by using Names::Add

Dizhi Zhou dizhi.zhou at gmail.com
Thu Jun 15 07:33:25 PDT 2017


*/*Description*/*
Consider the following example script:
   // create a node
  NodeContainer nodes;
  nodes.Create (1);

   // install a P2P netdevice to the node
  PointToPointHelper pointToPoint;
  NetDeviceContainer devices;
  devices = pointToPoint.Install (nodes);

  // Add internet stack
  InternetStackHelper stack;
  stack.Install (nodes);

  // Define alias strings to represent the node and the netdevice
  Names::Add ("client", nodes.Get (0));
  Names::Add ("client/device", nodes.Get (0)->GetDevice (0));

  // Set DataRate attribute using such alias strings
  Config::Set ("/Names/client/device/$ns3::PointToPointNetDevice/DataRate",
StringValue ("2.5Mbps"));

The Config::Set doesn't work. The DataRate attribute is still equal to its
original default value (i,e, 32768bps).

However, the Config::Set works when we InternetStackHelper::Install() is
called after Names::Add and Config::Set.

*/* Root cause analysis */*
In Config::Set call stack, it calls Names::Find () to get the object
pointer of a string.
Resolver::DoResolve ()
{
  ...
  Ptr<Object> namedObject = *Names::Find<Object>* (root, item);
  ...
}

I print the namedObject name and item in both two cases
// Case 1: use InternetStackHelper::Install() *after* Config::Set and
Names::Add
item == client,  but namedObject == Node // expected results

// Case 2: use InternetStackHelper::Install() *before* Config::Set and
Names::Add
item == client,  but namedObject == Ipv4L3Protocol

In Case 2, Config::Set fails since it's unable find PointToPointNetDevice
from Ipv4L3Protocol.

Why Names::Find returns Ipv4L3Protocol instead of Node?
template <typename T>
/* static */
Ptr<T>
Names::Find (Ptr<Object> context, std::string name)
{
  Ptr<Object> obj = FindInternal (context, name);
  if (obj)
    {
      return *obj->GetObject<T> ();*
    }
...
}

In our example, T== Object, name == "client", obj == Node. . However,
obj->GetObject<T> returns object Ipv4L3Protocol, instead of object Node!!

Why?
template <typename T>
Ptr<T>
Object::GetObject () const
{
  // This is an optimization: if the cast works (which is likely),
  // things will be pretty fast.
  T *result = dynamic_cast<T *> (m_aggregates->buffer[0]);
  if (result != 0)
    {
      return Ptr<T> (result);
    }
  // if the cast does not work, we try to do a full type check.
  Ptr<Object> found = DoGetObject (T::GetTypeId ());
  if (found != 0)
    {
      return Ptr<T> (static_cast<T *> (PeekPointer (found)));
    }
  return 0;
}

GetObject() always do a dynamic_cast on the first object in the aggregate
list. In our case, Since T == Object in Case 2, such dynamic_cast always
successes. Therefore, Names::Find<Object>(root, item) can only return the
first object in the root's aggregation list.

In my example, before using InternetStackHelper::Instal(), the only object
in the Node aggregation list is the Node itself. After calling this
function, however, Ipv4L3Protocol becomes the first object in that list,
which causes the Config::Set failure.


*/*Solution*/*
For all Names::Find functions, use GetObject (TypeId), instead of
GetObject()

Names::Find (Ptr<Object> context, std::string name)
{
  Ptr<Object> obj = FindInternal (context, name);
  if (obj)
    {
      return *obj->GetObject<**obj->GetInstanceTypeId ()> ();*
    }
...
}

GetObject (TypeId) function will find the specified object from the
aggregate object list.

template <typename T>
Ptr<T>
Object::GetObject (TypeId tid) const
{
  Ptr<Object> found = DoGetObject (tid);
  if (found != 0)
    {
      return Ptr<T> (static_cast<T *> (PeekPointer (found)));
    }
  return 0;
}

I only test this solution in such example script. I may do a fully test and
add some test examples in this summer during my spare time.


Regards,
Dizhi



More information about the Ns-developers mailing list