src/devices/p2p/p2p-topology.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Thu, 10 May 2007 18:33:52 +0200
changeset 567 6fb98941c36f
parent 561 23ee8e81c379
child 568 e1660959ecbb
permissions -rw-r--r--
remove leaks and rework the Ptr class to work with a new refcount mechanism

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
//
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation;
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Author: George F. Riley<riley@ece.gatech.edu>
//

//
// Topology helper for ns3.
// George F. Riley, Georgia Tech, Spring 2007

#include <algorithm>
#include "ns3/assert.h"

#include "ns3/nstime.h"

#include "ns3/internet-node.h"
#include "ns3/ipv4-address.h"
#include "ns3/drop-tail.h"
#include "ns3/i-ipv4.h"

#include "p2p-channel.h"
#include "p2p-net-device.h"
#include "p2p-topology.h"

namespace ns3 {

PointToPointChannel *
PointToPointTopology::AddPointToPointLink(
  Ptr<Node> n1,
  Ptr<Node> n2,
  const DataRate& bps,
  const Time& delay)
{
  PointToPointChannel* channel = new PointToPointChannel(bps, delay);
  channel->Ref ();

  PointToPointNetDevice* net1 = new PointToPointNetDevice(n1);
  net1->Ref ();

  net1->AddQueue(Queue::Default().Copy());
  n1->AddDevice (net1);
  net1->Attach (channel);
  net1->Unref ();
  
  PointToPointNetDevice* net2 = new PointToPointNetDevice(n2);
  net2->Ref ();

  net2->AddQueue(Queue::Default().Copy());
  n2->AddDevice (net2);
  net2->Attach (channel);
  net2->Unref ();

  return channel;
}

bool
PointToPointTopology::AddIpv4Addresses(
  const PointToPointChannel *chan,
  Ptr<Node> n1, const Ipv4Address& addr1,
  Ptr<Node> n2, const Ipv4Address& addr2)
{

  // Duplex link is assumed to be subnetted as a /30
  // May run this unnumbered in the future?
  Ipv4Mask netmask("255.255.255.252");
  NS_ASSERT (netmask.IsMatch(addr1,addr2));

  // The PointToPoint channel is used to find the relevant NetDevices
  NS_ASSERT (chan->GetNDevices () == 2);
  NetDevice* nd1 = chan->GetDevice (0);
  NetDevice* nd2 = chan->GetDevice (1);
  // Make sure that nd1 belongs to n1 and nd2 to n2
  if ( (nd1->GetNode ()->GetId () == n2->GetId () ) && 
       (nd2->GetNode ()->GetId () == n1->GetId () ) )
    {
      std::swap(nd1, nd2);
    }
  NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ());
  NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ());
  
  IIpv4 *ip1 = n1->QueryInterface<IIpv4> (IIpv4::iid);
  uint32_t index1 = ip1->AddInterface (nd1);

  ip1->SetAddress (index1, addr1);
  ip1->SetNetworkMask (index1, netmask);
  ip1->SetUp (index1);

  IIpv4 *ip2 = n2->QueryInterface<IIpv4> (IIpv4::iid);
  uint32_t index2 = ip2->AddInterface (nd2);

  ip2->SetAddress (index2, addr2);
  ip2->SetNetworkMask (index2, netmask);
  ip2->SetUp (index2);
  
  ip1->AddHostRouteTo (addr2, index1);
  ip2->AddHostRouteTo (addr1, index2);
  
  ip1->Unref ();
  ip2->Unref ();
  
  return true;
}

#ifdef NOTYET

// Get the net device connecting node n1 to n2.  For topologies where
// there are possibly multiple devices connecting n1 and n2 (for example
// wireless with two devices on different channels) this will return
// the first one found.
PointToPointNetDevice* PointToPointTopology::GetNetDevice(Ptr<Node> n1, Ptr<Node> n2)
{
  // First get the NetDeviceList capability from node 1
  NetDeviceList* ndl1 = n1->GetNetDeviceList();
  if (!ndl1) return 0; // No devices, return nil
  // Get the list of devices
  const NetDeviceList::NetDevices_t& dlist = ndl1->GetAll();
  for (NetDeviceList::NetDevices_t::const_iterator i = dlist.Begin();
       i != dlist.End(); ++i)
    { // Check each device
      NetDevice* nd = *i; // next device
      Channel* c = nd->GetChannel();
      if (!c) continue; // No channel
      if (c->NodeIsPeer(n2)) return nd; // found it
    }
  return 0; // None found
}
  
// Get the channel connecting node n1 to node n2
PointToPointChannel* PointToPointTopology::GetChannel(
  Ptr<Node> n1, 
  Ptr<Node> n2
)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, so no channel
  return nd->GetChannel();
}

Queue* PointToPointTopology::GetQueue(Ptr<Node> n1, Ptr<Node> n2)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, so in queue
  return nd->GetQueue();
}

Queue* PointToPointTopology::SetQueue(Ptr<Node> n1, Ptr<Node> n2, const Queue& q)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, can't set queue
  // Add the specified queue to the netdevice
  return nd->SetQueue(q);
}

#endif

#ifdef GFR
P2PChannel* Topology::AddDuplexLink(Ptr<Node> n1, const IPAddr& ip1, 
                                    Ptr<Node> n2, const IPAddr& ip2,
                                    const Rate& rate, const Time& delay)
{
  // First get the NetDeviceList capability from each node
  NetDeviceList* ndl1 = n1->GetNetDeviceList();
  NetDeviceList* ndl2 = n2->GetNetDeviceList();
  if (!ndl1 || !ndl2) return nil;  // Both ends must have NetDeviceList
  // Get the net devices
  P2PNetDevice* nd1 = ndl1->Add(P2PNetDevice(n1, rate, nil));
  P2PNetDevice* nd2 = ndl2->Add(P2PNetDevice(n1, rate, nd1->GetChannel()));
  // Not implemented yet.  Add appropriate layer 2 protocol for
  // the net devices.
  // Get the L3 proto for node 1 and configure it with this device
  L3Demux*    l3demux1 = n1->GetL3Demux();
  L3Protocol* l3proto1 = nil;
  // If the node 1 l3 demux exists, find the coresponding l3 protocol
  if (l3demux1) l3proto1 = l3demux1->Lookup(ip1.L3Proto());
  // If the l3 protocol exists, configure this net device.  Use a mask
  // of all ones, since there is only one device on the remote end
  // of this link
  if (l3proto1) l3proto1->AddNetDevice(nd1, ip1, ip1.GetMask(ip1.Size()*8));
  // Same for node 2
  L3Demux*    l3demux2 = n2->GetL3Demux();
  L3Protocol* l3proto2 = nil;
  // If the node 2 l3 demux exists, find the coresponding l3 protocol
  if (l3demux2) l3proto2 = l3demux2->Lookup(ip2.L3Proto());
  if (l3proto2) l3proto2->AddNetDevice(nd2, ip2, ip2.GetMask(ip2.Size()*8));
  return dynamic_cast<P2PChannel*>(nd1->GetChannel());  // Always succeeds
}

// Get the channel connecting node n1 to node n2
Channel* Topology::GetChannel(Ptr<Node> n1, Ptr<Node> n2)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, so no channel
  return nd->GetChannel();
}

Queue* Topology::GetQueue(Ptr<Node> n1, Ptr<Node> n2)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, so in queue
  return nd->GetQueue();
}

Queue* Topology::SetQueue(Ptr<Node> n1, Ptr<Node> n2, const Queue& q)
{
  NetDevice* nd = GetNetDevice(n1, n2);
  if (!nd) return 0; // No net device, can't set queue
  // Add the specified queue to the netdevice
  return nd->SetQueue(q);
}

#endif

} // namespace ns3