[Ns-developers] [ns3] topology API

craigdo@ee.washington.edu craigdo at ee.washington.edu
Thu Jan 17 12:53:39 PST 2008


Okay, since nobody wants any preliminaries, I'll just present a framework
approach to the current problem.

First, at the client level, you would see something like the following in
simple.cc:

//
// inherit from the basic wireless cluster framework that does the 
// grunt work (technically, implements the frozen spots).  We're 
// going to override the pieces of the framework that we want to
// modify.  Here, we want to control how the net device is put 
// together and what applications are run on the nodes.
//
class MyWirelessClusterFramework : public WirelessClusterFramework
{
public:
  MyWirelessClusterFramework ();
  virtual ~MyWirelessClusterFramework ();

protected:
  virtual Ptr<NetDevice> CreateNetDevice (Ptr<Node> n, Ptr<Channel> ch);
  virtual void CreateApplications (Ptr<Node> n);
}

//
// Here's the method that's used to create the net devices.  Using
// inversion of control, it's brought up from the "bowels of the system"
// into the client space so we can control what happens directly.
//
// This is the case where Mathieu wanted to create another kind of rate
// control object that took different construction parameters.
//
// Using this approach, they're right here in front of the client's face
// to change however she wants.  There would be a default implementation
// of this method that would use the default rate control object so if 
// you don't want to change that, you don't have to re-implement this 
// method.
//
  Ptr<NetDevice>
MyWirelessClusterFramework::CreateNetDevice (Ptr<Node> n, Ptr<Channel> ch)
{
  Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> (n);

  Ptr<CraigsWierdRateControl> rate =
    CreateObject<CraigsWierdRateControl> (param1, param2, param3);

  nd->SetRateControl (rate);

  return nd;
}

//
// Here's the method that's used to create the applications.  Using
// inversion of control, it's brought up from the "bowels of the system"
// into the client space so we can control what happens directly.
//
// The default method would create no applications or possibly if you 
// almost always want something there, it could create it by default.
// You could add to the default set here as well (as is illustrated)
//
  void
MyWirelessClusterFramework::CreateApplications (Ptr<Node> n)
{
  WirelessClusterFramework::CreateApplications (n);
  Ptr<OnOffApplication> app = CreateObject<OnOffApplication> (n);
  return;
}

//
// Now the client uses the framework simply by asking it to Build some
// number of nodes.  She gets back a TopologySet that includes a channel
// and contains all of the nodes "connected" to the channel.
//
int
main (int argc, char *argv[])
{
  MyWirelessClusterFramework fw;
  Ptr<TopologySet> topo = fw.Build (100);
//
// Run IP address assigner, router, etc.
//
  Simulator::Run ();
  Simulator::Destroy ();
}

Now the framework code is implemented in some other file somewhere.  I would
expect that there are a number of frameworks for different basic topologies,
but here's how they might look for this problem.

There's a base class that has a frozen spot called Build that runs the for
loop and has hot spots for the creation functions that will likely be
changed ...

class TopologyFramework : public Object
{
public:
  TopologyFramework ();
  virtual ~TopologyFramework ();

  Ptr<TopologySet> Build (unit32_t n);  // frozen spot

protected:
  virtual Ptr<Channel> CreateChannel (void) = 0;
  virtual Ptr<Node> CreateNode (void) = 0;
  virtual Ptr<NetDevice> CreateNetDevice (Ptr<Node> n, Ptr<Channel> ch) = 0;
  virtual void CreateApplications (Ptr<Node> n) = 0;
};

The frozen spot code just creates a channel and connects up a bunch of
nodes, net devices and applications.  This code calls into the hot spots
wich can be refined by a client to do the dirty work.  Presumably this won't
change (much).

  Ptr<TopologySet>
TopologyFramework::Build (uint32_t n)
{
  Ptr<TopologySet> topo = Create<TopologySet> ();

  Ptr<Channel> ch = CreateChannel ();
  topo->SetChannel (ch);

  for (uint32_t i = 0; i < n; ++i)
    {
      Ptr<Node> n = CreateNode ();
      Ptr<NetDevice> nd = CreateNetDevice (n, ch);
	 CreateApplications (n);
      topo->AddNode (n);
      ch->AddNode (n);
    }
}

It's nice to have a default version that does useful work without having to
override/redefine anything, so there should be another class that looks
something like the following:

This would create a generic wireless cluster with the standard rate control
algorithm Mathieu spoke of.

class WirelessClusterFramework : public TopologyFramework
{
public:
  WirelessClusterFramework ();
  virtual ~VirtualClusterFramework ();

protected:
  virtual Ptr<Channel> CreateChannel (void);
  virtual Ptr<Node> CreateNode (void);
  virtual Ptr<NetDevice> CreateNetDevice (Ptr<Node> n, Ptr<Channel> ch);
  virtual Ptr<NetDevice> CreateApplications (Ptr<Node> n);
};

  Ptr<Channel>
WirelessClusterFramework::CreateChannel (void)
{
  return Create<WifiChannel>;
}

  Ptr<Node>
WirelessClusterFramework::CreateNode (void)
{
  Ptr<Node> n = CreateObject<Node>;
  n->AddIpStack ();
  n->AddUdpStack ();
  n->AddTcpStack ();
}

  Ptr<NetDevice>
WirelessClusterFramework::CreateNetDevice (Ptr<Node> n, Ptr<Channel> ch)
{
  Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> (n);
  Ptr<RateControl> rate = CreateObject<RateControl> ();

  nd->SetRateControl (rate);

  return nd;
}

So, there is really no need to implement any Parameters plumbing through the
system if we just take to heart what Mathieu said about exposing the control
flow to the user.

I think this is quite easy to understand and is more flexible than trying to
plumb Parameters down into the system.  Like Mathieu said, expose the area
on which you want to tweak directly to the user, don't force him to try and
execute his wishes by "remote control" by describing it via data.

Thoughts?

-- Craig




More information about the Ns-developers mailing list