samples/ns-2/simple.tcl.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Wed, 21 Feb 2007 17:06:19 +0100
changeset 317 b5959aa4a02f
parent 310 03f09f4d1a8d
child 318 7069232166d3
permissions -rw-r--r--
fix queue tracing

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * 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
 *
 * ns-2 simple.tcl script (ported from ns-2)
 * Originally authored by Steve McCanne, 12/19/1996
 */

// Port of ns-2/tcl/ex/simple.tcl to ns-3
// Corresponding ns-2 otcl commands are commented out above the 
// replacement ns-3 code, to highlight the change in design

#include <iostream>
#include <string>

#include "ns3/debug.h"
#include "ns3/simulator.h"
#include "ns3/nstime.h"
#include "ns3/internet-node.h"
#include "ns3/serial-channel.h"
#include "ns3/mac-address.h"
#include "ns3/ipv4-address.h"
#include "ns3/arp-ipv4-interface.h"
#include "ns3/ipv4.h"
#include "ns3/udp-socket.h"
#include "ns3/ipv4-route.h"
#include "ns3/drop-tail.h"
#include "ns3/trace-writer.h"

using namespace ns3;

class Tracer : public TraceWriter{
public:
  Tracer ()
  {
  };

  Tracer (std::string const &filename) 
  {
    Open(filename);
  };

  Tracer (char const *filename) : m_tracer(filename)
  {
    Open(filename);
  };

  ~Tracer () {};

  void Log (const char *s, const Packet &p)
  {
    m_filestr << s << &p << std::endl;
  }

protected:
  TraceWriter m_tracer;
};


static void
GenerateTraffic (UdpSocket *socket, uint32_t size)
{
  std::cout << "Node: " << socket->GetNode()->GetId () << " at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
  socket->SendDummy (size);
  if (size > 50)
    {
      Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
    }
}

static void
UdpSocketPrinter (UdpSocket *socket, uint32_t size, Ipv4Address from, uint16_t fromPort)
{
  std::cout << "Node: " << socket->GetNode()->GetId () << " at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
}

static void
PrintTraffic (UdpSocket *socket)
{
  socket->SetDummyRxCallback (MakeCallback (&UdpSocketPrinter));
}

#if 0
static void
PrintRoutingTable (InternetNode *a, std::string name)
{
  Ipv4 *ipv4 = a->GetIpv4 ();
  std::cout << "interfaces node="<<name<<std::endl;
  for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
    {
      Ipv4Interface *interface = ipv4->GetInterface (i);
      std::cout << "interface addr="<<interface->GetAddress () 
                << ", netmask="<<interface->GetNetworkMask ()
                << std::endl;
    }

  std::cout << "routing table:" << std::endl;
  for (uint32_t i = 0; i < ipv4->GetNRoutes (); i++)
    {
      Ipv4Route *route = ipv4->GetRoute (i);
      std::cout << (*route) << std::endl;
    }
  std::cout << "node end" << std::endl;
}
#endif

  static SerialChannel * 
AddDuplexLink(
  InternetNode* a, 
  const Ipv4Address& addra,
  const MacAddress& macaddra, 
  InternetNode* b, 
  const Ipv4Address& addrb,
  const MacAddress& macaddrb, 
  const Ipv4Mask& netmask,
  // const Rate& rate, 
  // const Time& delay,
  TraceContainer &traceContainer,
  std::string &name) 
{
    std::string qName;
    SerialChannel* channel = new SerialChannel();

    qName = name + "::Queue A";
    DropTailQueue* dtqa = new DropTailQueue(qName);
    dtqa->RegisterTraces (traceContainer);

    SerialNetDevice* neta = new SerialNetDevice(a, macaddra);
    neta->AddQueue(dtqa);
    Ipv4Interface *interfA = new ArpIpv4Interface (a, neta);
    uint32_t indexA = a->GetIpv4 ()->AddInterface (interfA);
    channel->Attach (neta);
    neta->Attach (channel);

    interfA->SetAddress (addra);
    interfA->SetNetworkMask (netmask);
    interfA->SetUp ();

    qName = name + "::Queue B";
    DropTailQueue* dtqb = new DropTailQueue(qName);
    dtqb->RegisterTraces (traceContainer);

    SerialNetDevice* netb = new SerialNetDevice(b, macaddrb);
    netb->AddQueue(dtqb);
    Ipv4Interface *interfB = new ArpIpv4Interface (b, netb);
    uint32_t indexB = b->GetIpv4 ()->AddInterface (interfB);
    channel->Attach (netb);
    netb->Attach (channel);

    interfB->SetAddress (addrb);
    interfB->SetNetworkMask (netmask);
    interfB->SetUp ();

    a->GetIpv4 ()->AddHostRouteTo (addrb, indexA);
    b->GetIpv4 ()->AddHostRouteTo (addra, indexB);

    NS_DEBUG_UNCOND("Adding interface " << indexA << " to node " << a->GetId())
    NS_DEBUG_UNCOND("Adding interface " << indexB << " to node " << b->GetId())

    //PrintRoutingTable (a, "a");
    //PrintRoutingTable (b, "b");

    return channel;
}

int main (int argc, char *argv[])
{
    // set ns [new Simulator]
    // ** not needed, Simulator is static object 

    // set n0 [$ns node]
    // set n1 [$ns node]
    // set n2 [$ns node]
    // set n3 [$ns node]

    // ** Here, some kind of factory or topology object will instantiates 
    // ** four identical nodes; for now, we just explicitly create them
    InternetNode *n0 = new InternetNode();
    InternetNode *n1 = new InternetNode();
    InternetNode *n2 = new InternetNode();
    InternetNode *n3 = new InternetNode();

    TraceContainer traceContainer;

    n0->SetName(std::string("Node 0"));
    n1->SetName(std::string("Node 1"));
    n2->SetName(std::string("Node 2"));
    n3->SetName(std::string("Node 3"));
 
    // set f [open out.tr w]
    // $ns trace-all $f 
    // set nf [open out.nam w]
    // $ns namtrace-all $nf
    // ** tracing configuration occurs later **
    
    // $ns duplex-link $n0 $n2 5Mb 2ms DropTail
    // $ns duplex-link $n1 $n2 5Mb 2ms DropTail
    // $ns duplex-link $n2 $n3 1.5Mb 10ms DropTail
    // ** part of topology creation object? **
    std::string channelName;

    channelName = "Channel 1";
    SerialChannel* ch1 = AddDuplexLink (
      n0, Ipv4Address("10.1.1.1"), MacAddress("00:00:00:00:00:01"), 
      n2, Ipv4Address("10.1.1.2"), MacAddress("00:00:00:00:00:02"), 
      Ipv4Mask("255.255.255.0"), 
      traceContainer, channelName);

    channelName = "Channel 2";
    SerialChannel* ch2 = AddDuplexLink (
      n1, Ipv4Address("10.1.2.1"), MacAddress("00:00:00:00:00:03"), 
      n2, Ipv4Address("10.1.2.2"), MacAddress("00:00:00:00:00:04"), 
      Ipv4Mask("255.255.255.0"), 
      traceContainer, channelName);

    channelName = "Channel 3";
    SerialChannel* ch3 = AddDuplexLink (
      n2, Ipv4Address("10.1.3.1"), MacAddress("00:00:00:00:00:05"), 
      n3, Ipv4Address("10.1.3.2"), MacAddress("00:00:00:00:00:06"), 
      Ipv4Mask("255.255.255.0"), 
      traceContainer, channelName);

    // $ns duplex-link-op $n0 $n2 orient right-up
    // $ns duplex-link-op $n1 $n2 orient right-down
    // $ns duplex-link-op $n2 $n3 orient right
    // $ns duplex-link-op $n2 $n3 queuePos 0.5
    // ** nam commands-- not supported **

    // set udp0 [new Agent/UDP]
    // $ns attach-agent $n0 $udp0
    UdpSocket *source0 = new UdpSocket (n0);

    // set cbr0 [new Application/Traffic/CBR]
    // $cbr0 attach-agent $udp0

    // set udp1 [new Agent/UDP]
    // $ns attach-agent $n3 $udp1
    UdpSocket *source3 = new UdpSocket (n3);

    // $udp1 set class_ 1
    // ** class_ is for nam **

    // set cbr1 [new Application/Traffic/CBR]
    // $cbr1 attach-agent $udp1
    // 
    // set null0 [new Agent/Null]
    // $ns attach-agent $n3 $null0
    UdpSocket *sink3 = new UdpSocket(n3);
    sink3->Bind (80);
   
    // set null1 [new Agent/Null]
    // $ns attach-agent $n1 $null1
    UdpSocket *sink1 = new UdpSocket(n1);
    sink1->Bind (80);

    // $ns connect $udp0 $null0
    source0->SetDefaultDestination (Ipv4Address ("10.1.3.2"), 80);
    // $ns connect $udp1 $null1
    source3->SetDefaultDestination (Ipv4Address ("10.1.2.1"), 80);

    // Here, finish off packet routing configuration
    n0->GetIpv4()->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
    n3->GetIpv4()->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);

    //PrintRoutingTable (n0, "n0");
    //PrintRoutingTable (n1, "n1");
    //PrintRoutingTable (n2, "n2");
    //PrintRoutingTable (n3, "n3");

    // $ns at 1.0 "$cbr0 start"
    // $ns at 1.1 "$cbr1 start"

    Tracer tracer("serial-net-test.log");

    char buffer[80];

    for (int i = 1; i <= 3; ++i) {
      for (int j = 0; j < 2; ++j) {
        sprintf(buffer, "Channel %d::Queue %c::Queue::Enque", i, 'A' + j);
        
        NS_DEBUG_UNCOND("tracing event " << buffer)

        traceContainer.SetCallback (buffer,
          MakeCallback (&Tracer::Log, &tracer));

        sprintf(buffer, "Channel %d::Queue %c::Queue::Deque", i, 'A' + j);

        NS_DEBUG_UNCOND("tracing event " << buffer)

        traceContainer.SetCallback (buffer,
          MakeCallback (&Tracer::Log, &tracer));

        sprintf(buffer, "Channel %d::Queue %c::Queue::Drop", i, 'A' + j);

        NS_DEBUG_UNCOND("tracing event " << buffer)

        traceContainer.SetCallback (buffer,
          MakeCallback (&Tracer::Log, &tracer));
      }
    }

    GenerateTraffic (source0, 100);
    PrintTraffic (sink3);

    GenerateTraffic (source3, 100);
    PrintTraffic (sink1);
    // 
    // set tcp [new Agent/TCP]
    // $tcp set class_ 2
    // set sink [new Agent/TCPSink]
    // $ns attach-agent $n0 $tcp
    // $ns attach-agent $n3 $sink
    // $ns connect $tcp $sink
    // set ftp [new Application/FTP]
    // $ftp attach-agent $tcp
    // $ns at 1.2 "$ftp start"
    // 
    // $ns at 1.35 "$ns detach-agent $n0 $tcp ; $ns detach-agent $n3 $sink"
    // ** TCP may not be in this snapshot **
    // 
    // puts [$cbr0 set packetSize_]
    // puts [$cbr0 set interval_]
    // 
    // $ns at 3.0 "finish"
    Simulator::StopAt (Seconds(3.0));
    // 
    // proc finish {} {
    //         global ns f nf
    //         $ns flush-trace
    //         close $f
    //         close $nf
    //         
    //         puts "running nam..."
    //         exec nam out.nam &
    //         exit 0
    // }
    // ** this finish proc not needed? **
    // 
    // $ns run
    Simulator::Run ();
    
    // The below deletes will be managed by future topology objects
    // or containers or smart pointers
    delete n0;
    delete n1;
    delete n2;
    delete n3;
    delete ch1;
    delete ch2;
    delete ch3;
    delete source3;
    delete source0;
    delete sink3;
    delete sink1;

    Simulator::Destroy ();
}