[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