Monday, October 18, 2010

MAC Interface in ns-2

General Architecture of a mobile node in ns-2:



the relationship of MAC could be found in ns-mobilenode.tcl. The source code:
........
#
# The following setups up link layer, mac layer, network interface
# and physical layer structures for the mobile node.
#
Node/MobileNode instproc add-interface { channel pmodel lltype mactype \
  qtype qlen iftype anttype topo inerrproc outerrproc fecproc} {
 $self instvar arptable_ nifs_ netif_ mac_ ifq_ ll_ imep_ inerr_ outerr_ fec_
 
  .......    
    #
 # Link Layer
 #
 $ll arptable $arptable_
 $ll mac $mac
 $ll down-target $ifq

 if {$imepflag == "ON" } {
  $imep recvtarget [$self entry]
  $imep sendtarget $ll
  $ll up-target $imep

        } else {
  $ll up-target [$self entry]
 }
 #
 # Interface Queue
 #
 $ifq target $mac
 $ifq set limit_ $qlen
 if {$imepflag != ""} {
  set drpT [$self mobility-trace Drop "IFQ"]
 } else {
  set drpT [cmu-trace Drop "IFQ" $self]
        }
 $ifq drop-target $drpT
 if { $namfp != "" } {
  $drpT namattach $namfp
 }
         
        # Mac Layer
 #
 $mac netif $netif
 $mac up-target $ll

 if {$outerr == "" && $fec == ""} {
  $mac down-target $netif
 } elseif {$outerr != "" && $fec == ""} {
  $mac down-target $outerr
  $outerr target $netif
 } elseif {$outerr == "" && $fec != ""} {
  $mac down-target $fec
  $fec down-target $netif
 } else {
  $mac down-target $fec
  $fec down-target $outerr
  $err target $netif
 }
Actually, from top to down path, the structure is  ll  --->  ifq ----> mac ---> netif . for packets going up, it is netif ---> mac --->ll. Thus, ifq is only used for down path of . however, a scheduler is also only useful to handle outgoing packets. Thus, if we want to implement a scheduler, we have to use something to replace this "ifq" and remake the interface in tcl script.

Why List-based improvement in ns-2.27 cause problems?

Since in ns-2.27, a "list-based improvement" is used to control the number of nodes receiving packet copies. prevX_ and nextX_ are added in MobileNode class to form a list. Before a packet is sendup, this list is sorted in ascending order. Then with the getAffectedNodes(), some nodes are picked based on (x,y) coordinates to receive the copy of the packet. This design is in WirelessChannel:sendUp() call.
This design has a serious bug: no consideration of the case that multiple interfaces might be colocated in the same node. In this case, The node's prevX_ and nextX_ will be updated multiple times if you want to create multiple PHY interfaces to utilize multiple channels. As a result, the prevX_ of each !Mobilenode will be set to point to itself!!!!
There are no quick fix for this. I have to rollback code to ns-2.26 to avoid segmentation fault.
Therefore, to have multiple radio interfaces in a node, this has to be disabled.

Ricean Fading based probabilistic Link Error

OAR ns extensions for Fading:

The error-part is extended from another online patch from CMU and Rice Univ.

Cite from OAR site:
"Although the CMU implementation results in an accurate simulation of the wireless channel for each individual flow, the fading components of channels for different flows are identical, a scenario not encountered in practice. This arises due to the fact that the index into the pre-computed channel table (used to look-up the components of fading envelope) is chosen based on the simulator's time instant, which is identical for all flows. To more realistically model the wireless channel for multiple users we modified the implementation such that channel lookup indexes are a function of the flow and time."

How to use

Three files:
  • prop_ricean.cc
  • prop_ricean.h
  • rice_table.txt
A table has to be created in a file to store all fading components.
File rice_table.txt maintains the table used by Ricean Fading Model.

Original Description from CMU package
III. USAGE
  There is a sample script in the simscript directory.  You will need
  this and the file "rice_table.txt".

  You should be able to run the sample script "rjp-sample.tcl".  This
  is just a slightly modified version of the example script
  wireless-mitf.tcl which is in the NS distribution.

  Parameters for the Ricean Fading:  The fading model is used to
modulate the output of a large-scale fading model. In this case, it
uses TwoRayGround as the large-scale model. 
  
  For the Ricean Fading model:

  MaxVelocity   :  This parameter determines the doppler spectrum.
      The value of this parameter is the maximum speed of any objects in the
      environment (could be nodes).  It is NOT the speed of the
      nodes themselves.

  RiceanK  : The Ricean K factor

  LoadRiceFile :  The file containing a table of in-phase and
   quadrature-phase ricean components.  This has to do with the
   computation of the fading enveloped and doesn't have to be changed. 
   Just load the provided file "rice_table.txt"  in the simscript directory.
 

  The provided script uses the NORT routing as the routing protocol
  (it is a NULL routing protocol).
  This is not provided with the NS distribution.  You can add nort.cc
  and nort.h to a directory called nort/ in your NS source directory,
  add nort/nort.o  to Makefile.in, run configure and then make to
  include support for this.

I did some minor changes, and the three files can be downloaded here:

The files prop_ricean.* should be put in the directory of ./mobile of ns source tree and the ricean_table.txt should be put in the same directory with simulation tcl-script.

Some lines in Tcl to enable this new propagation model:

set val(prop)           Propagation/Ricean          ;# radio-propagation model

set prop_inst [$ns_ set propInstance_]

$prop_inst MaxVelocity  2.5;
$prop_inst RiceanK        6;
$prop_inst LoadRiceFile  "rice_table.txt";

Reference Links:

1. Rice OAR software (http://www.ece.rice.edu/networks/software/OAR/OAR.html)
2. CMU Additions to the NS network simulator to handle Ricean and Rayleigh fading     http://www.ece.cmu.edu/wireless/downloads.html

"init" function of OTCL

The constructor function of a class (object) is: Init


The init instproc is used to initialize a freshly allocated object that is a direct or indirect instance of the class Object. It is normally called by the system (perhaps from more specialized init instprocs) as part of object creation, but may be called by the user.
init interprets its arguments as pairs of option keys and option values. Each option key should be the name of a valid method for the object, preceded by a dash. The method should take one argument. For each option key and option value pair, init calls the method on the object, with the option value as its argument. It returns the empty string.
To customize object creation, write an init instproc for a class, not an alloc proc. If the option key and option value creation syntax is still desired, then call the Object init instproc by using next. This is discussed in the create instproc in OTcl Classes.
% Class Bagel
Bagel
% foreach i {1 2 3 4} {                    
  Bagel instproc $i {v} {puts $v}
}
% Bagel abagel
abagel
% abagel init -1 one -2 two -3 three -4 four!
one
two
three
four!
init is conceptually equivalent to the following.
Object instproc init {args} {                   
  if {[llength $args]%2 != 0} then {            
    error {uneven number of arguments}          
  }                                             
  while {$args != {}} {                         
    set key [lindex $args 0]                    
    if {[string match {-*} $key]} then {        
      set key [string range $key 1 end]         
    }                                           
    set val [lindex $args 1]                    
    if {[catch {$self $key $val} msg]!=0} then {
      set opt [list $self $key $val]            
      error "$msg during $opt"                
    }                                           
    set args [lrange $args 2 end]               
  }                                             
  return {}                                     
}

Demystify TwoRayGround propagation model

In this model, the shadowing fading factor is not considered. Therefore, for a unique distance, the Pr is a determinstic value. Usually, tworayground has two formulas:
  • when d is less than the crossing distance: Free Space model is used.
  • when d is larger than the crossing distance: the follownig formula is applied:
Pr =   PtGtGrht2hr2 / (Ld4)
Based on the default settings in ns-2, we can derive a relationship between Pr and distance
Default parameter in ns-2:
  • Pt = 0.28183815
  • L = 1
  • Antenna Gain : 1
  • Antanna height 1.5m
DistancePr
15m2.81838e-5
20m8.91754e-6
22m6.0908e-6
30m1.7615e-6
60m1.1009e-7
120m6.8808e-9
200m8.9175e-10
210m7.3365e-10
220m6.908e-10
230m5.0986e-10
240m4.3005e-10
250m3.6526e-10
300m1.7615e-10
350m9.5081e-11
400m5.5735e-11
450m3.4795e-11
500m2.2829e-11
550m1.5592e-11
600m1.1009e-11
650m7.993e-12
700m5.9425e-12
750m4.5094e-12

Cross-distnace Effect

In reality, path loss index is only 2 in near distance. Therefore, for near-distance (<25m) , the above formula does not apply. When distance is less than ~25 meter, the Friss model will be used. Check tworayground.cc for detail

Friday, October 8, 2010

Introduction to packet headers and addresses in ns-2

Headers & Addresses in ns-2


 Notice that by default, all packet headers are included.A diagram:

Common-header:
Access method:
 struct hdr_cmn {
        enum dir_t { DOWN= -1, NONE= 0, UP= 1 };
        packet_t ptype_;        // packet type (see above)
        int     size_;          // simulated packet size
        int     uid_;           // unique id
        int     error_;         // error flag
        int     errbitcnt_;     // # of corrupted bits jahn
        int     fecsize_;
        double  ts_;            // timestamp: for q-delay measurement
        int     iface_;         // receiving interface (label)
        dir_t   direction_;     // direction: 0=none, 1=up, -1=down
        // source routing
        char src_rt_valid;

        //Monarch extn begins
        nsaddr_t prev_hop_;     // IP addr of forwarding hop
        nsaddr_t next_hop_;     // next hop for this packet
        int      addr_type_;    // type of next_hop_ addr
        nsaddr_t last_hop_;     // for tracing on multi-user channels

        // called if pkt can't obtain media or isn't ack'd. not called if
        // droped by a queue
        FailureCallback xmit_failure_;
        void *xmit_failure_data_;

        /*
         * MONARCH wants to know if the MAC layer is passing this back because
         * it could not get the RTS through or because it did not receive
         * an ACK.
         */
        int     xmit_reason_;

#define XMIT_REASON_RTS 0x01
#define XMIT_REASON_ACK 0x02

        // filled in by GOD on first transmission, used for trace analysis
        int num_forwards_;      // how many times this pkt was forwarded
        int opt_num_forwards_;   // optimal #forwards
        // Monarch extn ends;

        // tx time for this packet in sec
        double txtime_;
        inline double& txtime() { return(txtime_); }

        static int offset_;     // offset for this header
        inline static int& offset() { return offset_; }
        inline static hdr_cmn* access(const Packet* p) {
                return (hdr_cmn*) p->access(offset_);
        }

       .....
}

hdr_cmn *ch= hdr_cmn::access(pkt); //common header
 What's in common header (refer to  ./common/packet.h)
  • ch->ptype()   :   protocl type. e.g. PT_DSR shows this is a signaling message for DSR protocol, not a normal DATA packet
  • ch->size();
  • ch->direction() : Up or Down
  • ch->uid()
  • ch->iface():  Interface
  • ch->next_hop():    next hop for this packet. IP address in format nsaddr_t*. So, it is amazing to see some codes like, ch->next_hop=MAC_BRPADCST . MAC_BROADCST is defined as #define MAC_BROADCAST ((u_int32_t) 0xffffffff) and nsaddr_t is also deined as int32_t in config.h (typedef int32_t nsaddr_t;   ). Basically, ns2 use 32bit addressing support.


MAC Ethernet Address in 802.11 MAC Header:
Access method:
 struct hdr_mac802_11 {
        struct frame_control    dh_fc;                                       // 2 byte
        u_int16_t               dh_duration;                                 // 2
        u_char                  dh_da[ETHER_ADDR_LEN];                       // 6
        u_char                  dh_sa[ETHER_ADDR_LEN];                       // 6
        u_char                  dh_bssid[ETHER_ADDR_LEN];                    // 6
        u_int16_t               dh_scontrol;                                 // 2
        u_char                  dh_body[0]; // XXX Non-ANSI                  // 1   //not allocate, the address of ....};
 .....

 u_int32_t src,dst;

 struct hdr_mac802_11 *dh = HDR_MAC802_11(p);

//method to get a 32bit general descriptor of address
 dst = ETHER_ADDR(dh->dh_ra);
 src = ETHER_ADDR(dh->dh_ta);

//method to set ....
      int src, dst;
      STORE4BYTE(&dst, (dh->dh_ra));
      STORE4BYTE(&src, (dh->dh_ta));

Ethernet Address is specified in mac.h as (#define ETHER_ADDR_LEN 6 ). Thus, dh_ra and dh_ta are both six-unsinged-character array. Also, there is another defintion for this operation:  #define ETHER_ADDR(x)     (GET4BYTE(x)), so only the last 4 bytes are reassembled for a 32-bit address.
How MAC address is set? The addr() function is defined in the Class MAC, and the index_ is corresponding internal member ( type is integer).

static int MacIndex = 0;

Mac::Mac() :
        BiConnector(), abstract_(0), netif_(0), tap_(0), ll_(0), channel_(0), callback_(0),
        hRes_(this), hSend_(this), state_(MAC_IDLE), pktRx_(0), pktTx_(0)
{
        index_ = MacIndex++;
        bind_bw("bandwidth_", &bandwidth_);
        bind_time("delay_", &delay_);
        bind_bool("abstract_", &abstract_);
}

class Mac : public BiConnector {
public:
   ....  
   inline int addr() { return index_; }
protected:
   ....
   int index_;             // MAC address
   ....

} 

//alos, the  mac-802.11 use index as its mac address to form MAC frames: (see in mac-802_11.cc)
....
STORE4BYTE(&index_, (rf->rf_ta));



Space Sharing in MAC-802.11 header


As in packet.h

#define HDR_MAC802_11(p) ((hdr_mac802_11 *)hdr_mac::access(p))
There is no define of access function of struct hdr_mac802_11. The problem is that, we acccess the header use the struct mac_hdr, and then convert it to a 802.11 header. Thus, the frame space and frame format should have some realtion:
See.

size of mac header is 36 bytes, but size of mac-802.11 header in ns-2 is only 24 bytes.



IP Addr in IP header
Access Method: (refer to ./common/ip.h )

 struct hdr_ip {
        /* common to IPv{4,6} */
        ns_addr_t       src_;
        ns_addr_t       dst_;
        int             ttl_;

        /* Monarch extn */
//      u_int16_t       sport_;
//      u_int16_t       dport_;

        /* IPv6 */
        int             fid_;   /* flow id */
        int             prio_;

        static int offset_;
        inline static int& offset() { return offset_; }
        inline static hdr_ip* access(const Packet* p) {
                return (hdr_ip*) p->access(offset_);
        }

    /* per-field member acces functions */
        ns_addr_t& src() { return (src_); }
        nsaddr_t& saddr() { return (src_.addr_); }
        int32_t& sport() { return src_.port_;}

        ns_addr_t& dst() { return (dst_); }
        nsaddr_t& daddr() { return (dst_.addr_); }
        int32_t& dport() { return dst_.port_;}
        int& ttl() { return (ttl_); }
        /* ipv6 fields */
        int& flowid() { return (fid_); }
        int& prio() { return (prio_); }
};

......

struct ns_addr_t {
        int32_t addr_;
        int32_t port_;
#ifdef __cplusplus p.dest = ID((Address::instance().get_nodeaddr(iph->daddr())),::IP);
  p.src = ID((
        ns_addr_t& operator= (const ns_addr_t& n) {
                addr_ = n.addr_;
                port_ = n.port_;
                return (*this);
        }
        int operator== (const ns_addr_t& n) {
                return ((addr_ == n.addr_) && (port_ == n.port_));
        } p.dest = ID((Address::instance().get_nodeaddr(iph->daddr())),::IP);
  p.src = ID((
#endif // __cplusplus
};


hdr_ip *iph =  hdr_ip::access(packet);

//method to set address
  iph->saddr() = Address::instance().create_ipaddr(p.src.addr, RT_PORT); p.dest = ID((Address::instance().get_nodeaddr(iph->daddr())),::IP);
  p.src = ID((
  iph->sport() = RT_PORT;
  iph->daddr() = Address::instance().create_ipaddr(p.dest.addr, RT_PORT);
  iph->dport() = RT_PORT;
  iph->ttl() = 255;
// method to read address ??
   iph->saddr()
   iph->daddr()
   p.dest = ID((Address::instance().get_nodeaddr(iph->daddr())),::IP);
   p.src = ID((Address::instance().get_nodeaddr(iph->saddr())),::IP);
As seen, ns_addr_t is different from nsaddr_t, it has ip address and port infomation. Just 32 bit is suitable for ip address.

Very Important! All things above IP ( Routing, TCP are) are implemented as Agent. Any agent's message must include an IP header.
The class Agent has functions like addr() and daddr() to get the address of IP header.
 class Agent : public Connector {
 public:
    ....
        inline nsaddr_t& addr() { return here_.addr_; }
        inline nsaddr_t& port() { return here_.port_; }
        inline nsaddr_t& daddr() { return dst_.addr_; }
        inline nsaddr_t& dport() { return dst_.port_; }
  protected:
        ...
        ns_addr_t here_;                // address of this agent
        ns_addr_t dst_;                 // destination address for pkt flow
        ...
}


int
Agent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
{
        if (delay_bind(varName, localName, "agent_addr_", (int*)&(here_.addr_), tracer)) return TCL_OK;
        if (delay_bind(varName, localName, "agent_port_", (int*)&(here_.port_), tracer)) return TCL_OK;
        if (delay_bind(varName, localName, "dst_addr_", (int*)&(dst_.addr_), tracer)) return TCL_OK;
        if (delay_bind(varName, localName, "dst_port_", (int*)&(dst_.port_), tracer)) return TCL_OK;

......

Class Hierarchy :  TclObject --->  NSObject ----> Agent


DSR's SR (Source Route) Header
the SR has a path informaton from source to a destination, an SR should have following basic information for a baseline version of DSR protocol:
  • a path of IP or other addressses
  • a type to show this is route-request, route-reply or route-error
  • an ID to distinguish duplicate requests.
struct sr_addr {
        int addr_type;          /* same as hdr_cmn in packet.h */ 
        nsaddr_t addr;

        /*
         * Metrics that I want to collect at each node
         */
        double  Pt_;
};

struct route_request {
        int     req_valid_;     /* request header is valid? */
        int     req_id_;        /* unique request identifier */
        int     req_ttl_;       /* max propagation */
};

struct route_reply {
        int     rep_valid_;     /* reply header is valid? */
        int     rep_rtlen_;     /* # hops in route reply */
        struct sr_addr  rep_addrs_[MAX_SR_LEN];
};

struct route_error {
        int     err_valid_;     /* error header is valid? */
        int     err_count_;     /* number of route errors */
        struct link_down err_links_[MAX_ROUTE_ERRORS];
};

......
class hdr_sr {
private:
        int valid_;             /* is this header actually in the packet?
                                   and initialized? */
        int salvaged_;  /* packet has been salvaged? */

        int num_addrs_;
        int cur_addr_;
        struct sr_addr addrs_[MAX_SR_LEN];

        struct route_request    sr_request_;
        struct route_reply      sr_reply_;
        struct route_error      sr_error_;
...

         inline struct sr_addr* addrs() { return addrs_; }
...
}

//Constructor of Path, convert a SR header into a PATH object
Path::Path(struct hdr_sr *srh)
{ /* make a path from the bits of an NS source route header */
        path = new ID[MAX_SR_LEN];

        if (! srh->valid()) {
                len = 0;
                cur_index = 0;
                return;
        }

        len = srh->num_addrs();
        cur_index = srh->cur_addr();

        assert(len <= MAX_SR_LEN);

        for (int i = 0 ; i < len ; i++)
                path[i] = ID(srh->addrs()[i]);  //note : both type and addr are copied
}


hdr_sr *srh =  hdr_sr::access(packet);
SRPacket p(packet, srh);
p.dest = ID((Address::instance().get_nodeaddr(iph->daddr())),::IP);
p.src = ID((Address::instance().get_nodeaddr(iph->saddr())),::IP);


To get and set SR header, first we need to turn things into a packet of type SRPacket, in this class, route[n] is use to access ID[n], for each ID[n], use   inline nsaddr_t getNSAddr_t() to get this addr;
Normally, all SR-related operation are use "ID" not direct 32bit integer to refer.
How the address get set at the very beginning of the DSR Agent, use those :
SRNodeNew instproc init args {
 ...... 
 $dsr_agent_ addr $address_
 ......

}

Analyze ns-2 trace file

Ns-2 has two options to generate traces with different fomats. Basically, you could use
$ns use-newtrace
to generate the new trace and the detailed explanation could be found in Ns Manual. A very good reference about the trace is the ns-2 wiki page. See: http://nsnam.isi.edu/nsnam/index.php/NS-2_Trace_Formats

By default, old trace format is used. The source code ./trace/cmu-trace.cc needs to be read to understand it completely. For instance, the function format_ip will explain the trace of IP part.
void
CMUTrace::format_ip(Packet *p, int offset)
{
        struct hdr_cmn *ch = HDR_CMN(p);
        struct hdr_ip *ih = HDR_IP(p);

        // hack the IP address to convert pkt format to hostid format
        // for now until port ids are removed from IP address. -Padma.
        int src = Address::instance().get_nodeaddr(ih->saddr());
        int dst = Address::instance().get_nodeaddr(ih->daddr());

    ............

}

void
CMUTrace::format_mac(Packet *p, int offset)
{

else {
                sprintf(pt_->buffer() + offset,
                        " [%x %x %x %x] ",
                        //*((u_int16_t*) &mh->dh_fc),
                        mh->dh_duration,

                        ETHER_ADDR(mh->dh_ra),
                        ETHER_ADDR(mh->dh_ta),


                        GET_ETHER_TYPE(mh->dh_body));
        }
......

}


A typical trace for a CBR traffic is:

s 20.000000000 _0_ AGT  --- 6 cbr 512 [0 0 0 0] ------- [0:0 1:0 32 0] [0] 0 0
r 20.000000000 _0_ RTR  --- 6 cbr 512 [0 0 0 0] ------- [0:0 1:0 32 0] [0] 0 0
s 20.000000000 _0_ RTR  --- 6 cbr 532 [0 0 0 0] ------- [0:0 1:0 32 1] [0] 0 0
s 20.000275000 _0_ MAC  --- 6 cbr 584 [13a 1 0 800] ------- [0:0 1:0 32 1] [0] 0 0
r 20.004947063 _1_ MAC  --- 6 cbr 532 [13a 1 0 800] ------- [0:0 1:0 32 1] [0] 1 0
s 20.004957063 _1_ MAC  --- 0 ACK 38 [0 0 0 0]
r 20.004972063 _1_ AGT  --- 6 cbr 532 [13a 1 0 800] ------- [0:0 1:0 32 1] [0] 1 0
r 20.005261125 _0_ MAC  --- 0 ACK 38 [0 0 0 0]

An AWK script example to analyze the trace and calculate throughput
 
For a topology involve 4 flows with distinguishing source and destination nodes, this following awk script gets throughout data and put in wu.dat file
BEGIN {counter1 = 0; counter2 = 0; counter3 = 0; counter4 = 0;}
$1~/r/ && $2>50 && $2< 100  && /_12_/ && /AGT/  {   counter1 += ($8- 20)
                        size = $8 - 20 }
$1~/r/ && $2>50 && $2 <100 && /_13_/ && /AGT/  {   counter2 += ($8- 20)
                        size = $8 - 20 }
$1~/r/ && $2>50 && $2<100 && /_14_/ && /AGT/  {   counter3 += ($8- 20)
                        size = $8 - 20 }
$1~/r/ && $2>50 && $2<100 && /_15_/ && /AGT/  {   counter4 += ($8- 20)
                        size = $8 - 20 } throughout

END {
      print (size , counter1*8/(50), counter2*8/50, counter3*8/(50), counter4*8/50,
                  (counter1+counter2+counter3+counter4)*8/50 )  >> "wu.dat"}

To analyze the throughout or delay in a finite time duration, we need extract sending and receiving time from the trace file

$2>100 && $2 < 150 && (/_6_/ || /_2_/)  &&  /AGT/    {  print $1, $2, $6  > "dst2.tr" }
$2>100 && $2 <150 && (/_0_/ || /_9_/)  &&  /AGT/    {   print $1, $2, $6  > "dst9.tr" }
$2>100 && $2 <150 && (/_12_/ || /_3_/)  &&  /AGT/    {   print $1, $2, $6  > "dst3.tr" }
$2>100 && $2 <150 && (/_10_/ || /_4_/)  &&  /AGT/    {   print $1, $2, $6  > "dst4.tr" }
$2>100 && $2 <150 && (/_11_/ || /_8_/)  &&  /AGT/    {   print $1, $2, $6  > "dst8.tr" }

The respective new trace files such as "dst2.tr" will keep the sending or receiving time, "s'" or "r" label and, node's MAC address. From those data, we could use a program to calculate the average throughputor mean value of end-to-end delay of the flow.

The C source file (delay.c) to calculate delay is given as below:



#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  FILE *fin, *fout, *fout2;
  int pkt_index[1000]; 
  double pkt_send_time[1000];
  int head;
  //int tail;
  /* make sure it is large enough to hold all temprary data! */
  int i,j,num;
  double tm, tm_delay, total_delay, avg_delay, var_delay;
  int idx;
  char type;
  int flag;
  int num_sent;
  
  head = 0;
  for ( i=0; i<1000; i++)
  {
     pkt_index[i]  = -1;
     pkt_send_time[i] = 0.0f;
  }
  
  fin = fopen(argv[1], "r");
  fout = fopen (argv[2], "w");
  fout2 = fopen ( argv[3],"a");
  
  if(fin==NULL) {
    printf("Error: can't open file.\n");
    return 1;
  }
  else {
    printf("File opened successfully.\n");

    i = 0 ;  
    num  = 0;  
    num_sent = 0;
    while(!feof(fin)) 
    { 
      /* loop through and store the numbers into the array */
      fscanf(fin, "%c %lf %d \n", &type,&tm, &idx);
      //printf( "%f\n", tm);
      
  if ( type == 's' )
  {
   //addentry(idx, tm);
   pkt_index[head] = idx;
   pkt_send_time[head] = tm;
   head++;
   if ( head == 1000 ) head = 0;
   num_sent++;
     
     
  }
  else if ( type == 'r' )
  {
   flag = 0;
   for ( j=0; j< 1000; j++)
   {
    
    if (  pkt_index[j] == idx )
    {
    //printf("match,%f, %f\n!" ,tm, pkt_send_time[j]);
    tm_delay =  tm - pkt_send_time[j];
    flag = 1;
    break;
    } 
   }
   //addentry to output
   if ( flag == 1)
   {
   fprintf( fout,"%d %lf \n", idx, tm_delay ); 
   total_delay += tm_delay;    
   num++;
   }
  }
      i++;
    }
    avg_delay = total_delay / num ;
    fprintf(fout2,"Number of entries read: %d\n", i);
    fprintf(fout2,"Number of entries sent: %d\n", num_sent);
    fprintf(fout2,"Number of entries received:  %d\n", num);
    fprintf(fout2,"average delay of entries :  %lf\n", avg_delay);
    
    fclose(fin);
    fclose(fout);
  
    
    //finally, calcualte variance
    fout = fopen ( argv[2], "r") ;
    if ( fout == NULL ) return -1;
    var_delay = 0;
    while (!feof(fout))
    {
       fscanf(fout, "%d %lf\n", &idx ,&tm);
       var_delay += ( tm - avg_delay  ) * (tm - avg_delay);    
    }
    var_delay /= num;     
    fprintf(fout2, "variance of  delay is :  %lf\n", var_delay);
    fclose (fout);
    fclose (fout2);
    
    return 0;
  }
} 

To use this C code:
$ gcc delay.c -o delaycal
$ ./delaycal dst2.tr wu0.dat wu1.dat

NS-2 Tutorials

Ns-2 is a widely used tool to simulate the behavior of wired and wireless networks. Useful information about ns-2 can be found at:

Thursday, October 7, 2010

Traffic Pattern Generation

cbrgen


Random traffic connections of TCP and CBR can be setup between mobilenodes using a traffic-scenario generator script. This traffic generator script is available under ~ns/indep-utils/cmu-scen-gen and is called cbrgen.tcl. It can be used to create CBR and TCP traffics connections between wireless mobilenodes. In order to create a traffic-connection file, we need to define the type of traffic connection (CBR or TCP), the number of nodes and maximum number of connections to be setup between them, a random seed and incase of CBR connections, a rate whose inverse value is used to compute the interval time between the CBR pkts. So the command line looks like the following:

ns cbrgen.tcl [-type cbr|tcp] [-nn nodes] [-seed seed] [-mc connections][-rate rate] >output.tcl

The start times for the TCP/CBR connections are randomly generated with a maximum value set at 180.0s, thus the simulation time is at least 180 seconds. And the number of nodes has no relationship to the maximum number of connections (mc), we can have 10 nodes, also 10 connections as one node could have multiple simultaneous connections to other nodes. The parameter "rate" means how many packets per second, thus, for CBR traffic, the packet intervel is the reversal of this parameter. And for TCP traffic, we don't have to specify rate, ftp connections are going to be used. the default packet size is 512B. Actully, we can change all this in the "output.tcl" file.Note that there is no guarantee that the number of connections are created and the actual nodes involved as source and sink. A typical generated CBR traffic file looks like:
#
# 2 connecting to 3 at time 82.557023746220864
#
set udp_(0) [new Agent/UDP]
$ns_ attach-agent $node_(2) $udp_(0)
set null_(0) [new Agent/Null]
$ns_ attach-agent $node_(3) $null_(0)
set cbr_(0) [new Application/Traffic/CBR]
$cbr_(0) set packetSize_ 512
$cbr_(0) set interval_ 0.25
$cbr_(0) set random_ 1
$cbr_(0) set maxpkts_ 10000
$cbr_(0) attach-agent $udp_(0)
$ns_ connect $udp_(0) $null_(0)
$ns_ at 82.557023746220864 "$cbr_(0) start"
......
# 
#Total sources/connections: 4/6
#
The last lines shows how many actual connections are created and how many nodes are used for the source.

Node Movement and Topology Generation

To simulate a mobility scenario, the nodes' positions at every time instant need to be determined.


Instead of specifying and controlling each nodes' position and movement pattern, we may use a CMU tool "setdest" to generate large number of nodes and there movements. The tool use a random waypoint model.
Setdest
Setdest tool is used to generate the positions of nodes and their moving speed and moving directions.
The syntax is:

 setdest -v 1 -n $numnodes -p $pt -M $maxspeed -t $simtime -x $maxx -y $maxy
for example: 

    setdest -v 1 -n 50 -p 0 -M 20 -t 900 -x 1500 -y 300
will generate a 1500*300 topology with 50 nodes random distributed labeled by a XY(Z) coordinates.  

(Note that, there is a bug in the README file, which gives a wrong option for specifying the speed, we should use "-M" instead of "-s" ).
In the output, you can find that: after the initial positions are given, the nodes are specified with their movement destination and speed. Then, the initial distance (hop counts) information are counted by a GOD. 
Currently, the god object is used only to store an array of the shortest number of hops required to reach from one node to an other. The god object does not calculate this on the fly during simulation runs, since it can be quite time consuming. The information is loaded into the god object from the movement pattern file (this file)..
Then, the nodes are going to move during this 900-second simulation scenario. During this, the distance (hop-counts) information is going to change, thus, the following lines are going to show this recent change. Note that the distance is calculated based on a nominal radio range as "250" meters. The god information should not be available to any of the node. Thus, for a routing protocol, it has to discover the distance by itself with some mechanism.
It's possible that a node reaches its destination before the simulation timer ends. Thus, it needs to re-specify a new direction and speed for it. Also, the average pause time is a parameter to allow a node stop to move in a destination before moving again.
Finally, there are some statistics about this movement file? During the simulation, some nodes get isolated from all other nodes which results one count of "destination unreachable". Also, all route changes and link changes are calculated.
# nodes: 50, pause: 0.00, max speed: 20.00, max x: 1500.00, max y: 300.00
#
$node_(0) set X_ 1472.239335818631
$node_(0) set Y_ 218.102475038104
$node_(0) set Z_ 0.000000000000
$node_(1) set X_ 266.329091949493
$node_(1) set Y_ 188.988756134562
$node_(1) set Z_ 0.000000000000
.....
$ns_ at 0.000000000000 "$node_(0) setdest 298.258250355189 34.553480936942 5.763540789209"
$ns_ at 0.000000000000 "$node_(1) setdest 783.793876303622 280.181784294036 16.832727003192"
$ns_ at 0.000000000000 "$node_(2) setdest 978.836090908830 151.467060345492 19.354908025316"
$ns_ at 0.000000000000 "$node_(3) setdest 376.126888262665 139.747808400435 11.497476206039"
$ns_ at 0.000000000000 "$node_(4) setdest 370.541780738321 185.032792269909 8.002013555825"
$ns_ at 0.000000000000 "$node_(5) setdest 1463.652810766312 132.618506062927 17.607998988233"
$ns_ at 0.000000000000 "$node_(6) setdest 1020.046295404814 40.982731716802 15.434148765705"
......
$god_ set-dist 0 1 6
$god_ set-dist 0 2 1
$god_ set-dist 0 3 4
$god_ set-dist 0 4 2
$god_ set-dist 0 5 4
$god_ set-dist 0 6 8
$god_ set-dist 0 7 6
......
$ns_ at 0.141920608238 "$god_ set-dist 17 24 2"
$ns_ at 0.165720133690 "$god_ set-dist 3 15 1" 
$ns_ at 0.263269271549 "$god_ set-dist 1 46 2" 
$ns_ at 0.263269271549 "$god_ set-dist 7 46 2" 
$ns_ at 0.263269271549 "$god_ set-dist 12 46 1"
$ns_ at 0.263269271549 "$god_ set-dist 25 46 3"
$ns_ at 0.263269271549 "$god_ set-dist 46 47 3"
$ns_ at 0.314230786054 "$god_ set-dist 5 42 5" 
......
$ns_ at 12.602131706040 "$god_ set-dist 16 36 2"
$ns_ at 12.623221733243 "$node_(12) setdest 424.679916546080 186.581540202946 5.803287072825"
$ns_ at 12.682532746855 "$god_ set-dist 18 40 3"
.....
$ns_ at 899.907548331028 "$god_ set-dist 32 40 1"
$ns_ at 899.932142983319 "$god_ set-dist 22 40 1"
$ns_ at 899.991403308054 "$god_ set-dist 3 29 1"
#
# Destination Unreachables: 429
#
# Route Changes: 72037
#
# Link Changes: 11892
#
# Node | Route Changes | Link Changes
# 0 | 2709 | 433
# 1 | 3098 | 467
# 2 | 2651 | 496
# 3 | 3398 | 642Setdest
# 4 | 3036 | 548
# 5 | 2755 | 252
# 6 | 3471 | 601
for generate scenarios in a patch, we could use following shell scripts.
#!/bin/csh
unset noclobber
set outdir = wzb-scen

set maxspeed = 1
set numnodes = 50
set maxx = 1500
set maxy = 300
set simtime = 900

foreach pt (5 10 15 20 25 30 40 50)
foreach scen ( 1 2 3 4 5)
echo scen $scen : setdest -n $numnodes -p $pt -M $maxspeed -t $simtime \
      -x $maxx -y $maxy
time ./setdest -n $numnodes -p $pt -M $maxspeed -t $simtime \
      -x $maxx -y $maxy \
      >$outdir/scen-${maxx}x${maxy}-${numnodes}-${pt}-${maxspeed}-${scen}
echo
end
end

Simulating wireless link errors

To attach the error model, add following codes to a TCL simulation script


..........
proc UniformErr {} {
                set err [new ErrorModel]
                $err unit packet
                $err set rate_ 0.05
                return $err
        }
        # $err rate_ 0.5  "invalid command ErrModel::Command does not support"
        # the other valid method is " set err [new ErrorModel/Uniform 0.05 pkt] "
        # the parameter rate ( 0 or 0.9) is a threshold that all packets all going through and 90% packets are
        # going to be drop

     proc TwoStateMarkovErr {} {

                set tmp0 [new ErrorModel/Uniform 0 pkt]
                set tmp1 [new ErrorModel/Uniform .7 pkt]

                 # Array of states (error models)
                set m_states [list $tmp0 $tmp1]
                 # Durations for each of the states, tmp, tmp1 and tmp2, respectively
                set m_periods [list 0.1 .075 ]
        # Transition state model matrix
        set m_transmx { {0.9   0.1 }
                        {0.7   0.3 } }
        set m_trunit byte
        # Use time-based transition
        set m_sttype time
        set m_nstates 2
        set m_nstart [lindex $m_states 0]

        set em [new ErrorModel/MultiState $m_states $m_periods $m_transmx \
                $m_trunit $m_sttype $m_nstates $m_nstart]
        return $em
    }

      $ns_ node-config -adhocRouting $val(rp) \
                         -llType $val(ll) \
                         -macType $val(mac) \
                         -ifqType $val(ifq) \
                         -ifqLen $val(ifqlen) \
                         -antType $val(ant) \
                         -propType $val(prop) \
                         -phyType $val(netif) \
                         -channel  $chan1 \
                         -topoInstance $topo \
                         -agentTrace ON \
                         -routerTrace OFF\
                         -macTrace ON \
                         -movementTrace OFF \
                         -IncomingErrProc TwoStateMarkovErr
                         #\
                         #-OutcomingErrProc TwoStateMarkovErr

#The other way to configure error
#        $ns_ node-config --IncomingErrProc $opt(err)

Network Simulator 2 script for a complex scenario


#This is an example for DSDV routing with 50 nodes in a 670*670 m2 area
#
# Note that all options listed in the beginning of the file could be initialized 
# with command line arguments by using "getopt $argc $argv"
# ======================================================================
# Default Script Options
# ======================================================================
set opt(chan)  Channel/WirelessChannel
set opt(prop)  Propagation/TwoRayGround
#set opt(netif)  NetIf/SharedMedia
set opt(netif)  Phy/WirelessPhy
#set opt(mac)  Mac/802_11
set opt(mac)  Mac/802_11
set opt(ifq)  Queue/DropTail/PriQueue
set opt(ll)  LL
set opt(ant)            Antenna/OmniAntenna

set opt(x)  670 ;# X dimension of the topography
set opt(y)  670  ;# Y dimension of the topography
set opt(cp)  "../mobility/scene/cbr-50-10-4-512"
set opt(sc)  "../mobility/scene/scen-670x670-50-600-20-0"

set opt(ifqlen)  50  ;# max packet in ifq
set opt(nn)  50  ;# number of nodes
set opt(seed)  0.0
set opt(stop)  1000.0  ;# simulation time
set opt(tr)  out.tr  ;# trace file
set opt(rp)             dsdv            ;# routing protocol script
set opt(lm)             "off"           ;# log movement

# ======================================================================

#set AgentTrace   ON
#set RouterTrace  ON
#set MacTrace   OFF     #useless code, the only way to toggle Mac trace on is to use node-config

LL set mindelay_  50us
LL set delay_   25us
LL set bandwidth_  0 ;# not used
LL set off_prune_  0 ;# not used
LL set off_CtrMcast_  0 ;# not used

Agent/Null set sport_  0
Agent/Null set dport_  0

Agent/CBR set sport_  0
Agent/CBR set dport_  0

Agent/TCPSink set sport_ 0
Agent/TCPSink set dport_ 0

Agent/TCP set sport_  0
Agent/TCP set dport_  0
Agent/TCP set packetSize_ 1460

Queue/DropTail/PriQueue set Prefer_Routing_Protocols    1

# unity gain, omni-directional antennas
# set up the antennas to be centered in the node and 1.5 meters above it
Antenna/OmniAntenna set X_ 0
Antenna/OmniAntenna set Y_ 0
Antenna/OmniAntenna set Z_ 1.5
Antenna/OmniAntenna set Gt_ 1.0
Antenna/OmniAntenna set Gr_ 1.0

# Initialize the SharedMedia interface with parameters to make
# it work like the 914MHz Lucent WaveLAN DSSS radio interface
Phy/WirelessPhy set CPThresh_ 10.0
Phy/WirelessPhy set CSThresh_ 1.559e-11
Phy/WirelessPhy set RXThresh_ 3.652e-10
Phy/WirelessPhy set Rb_ 2*1e6
Phy/WirelessPhy set Pt_ 0.2818
Phy/WirelessPhy set freq_ 914e+6 
Phy/WirelessPhy set L_ 1.0

# ======================================================================

proc usage { argv0 }  {
 puts "Usage: $argv0"
 puts "\tmandatory arguments:"
 puts "\t\t\[-x MAXX\] \[-y MAXY\]"
 puts "\toptional arguments:"
 puts "\t\t\[-cp conn pattern\] \[-sc scenario\] \[-nn nodes\]"
 puts "\t\t\[-seed seed\] \[-stop sec\] \[-tr tracefile\]\n"
}


proc getopt {argc argv} {
 global opt
 lappend optlist cp nn seed sc stop tr x y

 for {set i 0} {$i < $argc} {incr i} {
  set arg [lindex $argv $i]
  if {[string range $arg 0 0] != "-"} continue

  set name [string range $arg 1 end]
  set opt($name) [lindex $argv [expr $i+1]]
 }
}

proc cmu-trace { ttype atype node } {
 global ns_ tracefd

 if { $tracefd == "" } {
  return ""
 }
 set T [new CMUTrace/$ttype $atype]
 $T target [$ns_ set nullAgent_]
 $T attach $tracefd
        $T set src_ [$node id]

        $T node $node

 return $T
}




proc log-movement {} {
    global logtimer ns_ ns

    set ns $ns_
    source ../mobility/timer.tcl
    Class LogTimer -superclass Timer
    LogTimer instproc timeout {} {
 global opt node_;
 for {set i 0} {$i < $opt(nn)} {incr i} {
     $node_($i) log-movement
 }
 $self sched 0.1
    }

    set logtimer [new LogTimer]
    $logtimer sched 0.1
}

# ======================================================================
# Main Program
# ======================================================================
getopt $argc $argv

#
# Source External TCL Scripts
#
#source ../lib/ns-mobilenode.tcl

#if { $opt(rp) != "" } {
 #source ../mobility/$opt(rp).tcl
 #} elseif { [catch { set env(NS_PROTO_SCRIPT) } ] == 1 } {
 #puts "\nenvironment variable NS_PROTO_SCRIPT not set!\n"
 #exit
#} else {
 #puts "\n*** using script $env(NS_PROTO_SCRIPT)\n\n";
        #source $env(NS_PROTO_SCRIPT)
#}
#source ../lib/ns-cmutrace.tcl
source ../lib/ns-bsnode.tcl
source ../mobility/com.tcl

# do the get opt again incase the routing protocol file added some more
# options to look for
getopt $argc $argv

if { $opt(x) == 0 || $opt(y) == 0 } {
 usage $argv0
 exit 1
}

if {$opt(seed) > 0} {
 puts "Seeding Random number generator with $opt(seed)\n"
 ns-random $opt(seed)
}

#
# Initialize Global Variables
#
set ns_  [new Simulator]
set chan [new $opt(chan)]
set prop [new $opt(prop)]
set topo [new Topography]
set tracefd [open $opt(tr) w]

$topo load_flatgrid $opt(x) $opt(y)

$prop topography $topo

#
# Create God
#
create-god $opt(nn)


#
# log the mobile nodes movements if desired
#
if { $opt(lm) == "on" } {
    log-movement
}

 $ns_ node-config -macTrace ON


#
#  Create the specified number of nodes $opt(nn) and "attach" them
#  the channel.
#  Each routing protocol script is expected to have defined a proc
#  create-mobile-node that builds a mobile node and inserts it into the
#  array global $node_($i)
#

if { [string compare $opt(rp) "dsr"] == 0} { 
 for {set i 0} {$i < $opt(nn) } {incr i} {
  dsr-create-mobile-node $i
 }
} elseif { [string compare $opt(rp) "dsdv"] == 0} { 
 for {set i 0} {$i < $opt(nn) } {incr i} {
  dsdv-create-mobile-node $i
 }
}



#
# Source the Connection and Movement scripts
#
if { $opt(cp) == "" } {
 puts "*** NOTE: no connection pattern specified."
        set opt(cp) "none"
} else {
 puts "Loading connection pattern..."
 source $opt(cp)
}


#
# Tell all the nodes when the simulation ends
#
for {set i 0} {$i < $opt(nn) } {incr i} {
    $ns_ at $opt(stop).000000001 "$node_($i) reset";
}
$ns_ at $opt(stop).00000001 "puts \"NS EXITING...\" ; $ns_ halt"


if { $opt(sc) == "" } {
 puts "*** NOTE: no scenario file specified."
        set opt(sc) "none"
} else {
 puts "Loading scenario file..."
 source $opt(sc)
 puts "Load complete..."
}

puts $tracefd "M 0.0 nn $opt(nn) x $opt(x) y $opt(y) rp $opt(rp)"
puts $tracefd "M 0.0 sc $opt(sc) cp $opt(cp) seed $opt(seed)"
puts $tracefd "M 0.0 prop $opt(prop) ant $opt(ant)"

puts "Starting Simulation..."
$ns_ run

A simple example for wireless simulation scenario


#This script creates a 4x4 grid topology and run 4 CBR traffic flows over four pair of#nodes in this grid.
# ===================================================
# Author: ZHIBIN WU 06/19/2003
# ==================================================



set cbr_size 500
set cbr_interval 0.002
set num_row 4
set time_duration 100

set val(chan) Channel/WirelessChannel ;# channel type
set val(prop) Propagation/TwoRayGround ;# radio-propagation model
set val(netif) Phy/WirelessPhy ;# network interface type
set val(mac) Mac/802_11 ;# MAC type
set val(ifq) Queue/DropTail/PriQueue ;# interface queue type
set val(ll) LL ;# link layer type
set val(ant) Antenna/OmniAntenna ;# antenna model
set val(ifqlen) 50 ;# max packet in ifq
set val(rp) DSDV ;# routing protocol
# 
# Initialize ns
#
set ns_ [new Simulator]
set tracefd [open simple.tr w]
$ns_ trace-all $tracefd

# set up topography object
set topo       [new Topography]
$topo load_flatgrid 1000 1000

create-god [expr $num_row * $num_row ]

$ns_ node-config -adhocRouting $val(rp) -llType $val(ll) \
     -macType $val(mac)  -ifqType $val(ifq) \
     -ifqLen $val(ifqlen) -antType $val(ant) \
     -propType $val(prop) -phyType $val(netif) \
     -channel  [new $val(chan)] -topoInstance $topo \
     -agentTrace ON -routerTrace OFF\
     -macTrace ON \
     -movementTrace OFF
 
for {set i 0} {$i < [expr $num_row*$num_row]} {incr i} {
    set node_($i) [$ns_ node]
}
set k 0;
while {$k < $num_row } {
    for {set i 0} {$i < $num_row } {incr i} {
 set m [expr $i+$k*$num_row];
 $node_($m) set X_ [expr $i*240];
 $node_($m) set Y_ [expr $k*240+20.0];
 $node_($m) set Z_ 0.0
    }
    incr k;
}; 
for {set i 0} {$i < $num_row } {incr i} {
    set udp_($i) [new Agent/UDP]
    set null_($i) [new Agent/Null]
} 
  $ns_ attach-agent $node_(0) $udp_(0)
  $ns_ attach-agent $node_(7) $udp_(1)
  $ns_ attach-agent $node_(2) $udp_(2)
  $ns_ attach-agent $node_(7) $udp_(3)
  $ns_ attach-agent $node_(6) $null_(0)
  $ns_ attach-agent $node_(1) $null_(1)
  $ns_ attach-agent $node_(8) $null_(2)
  $ns_ attach-agent $node_(15) $null_(3)
for {set i 0} {$i < $num_row } {incr i} {
     $ns_ connect $udp_($i) $null_($i)
}
for {set i 0} {$i < $num_row } {incr i} {
    set cbr_($i) [new Application/Traffic/CBR]
$cbr_($i) set packetSize_ $cbr_size
$cbr_($i) set interval_ 0.5
$cbr_($i) attach-agent $udp_($i)
} 
$ns_ at 11.0234 "$cbr_(0) start"
$ns_ at 10.4578 "$cbr_(1) start" 
$ns_ at 12.7184 "$cbr_(2) start"
$ns_ at 12.2456 "$cbr_(3) start" 
# Tell nodes when the simulation ends
#
for {set i 0} {$i < [expr $num_row*$num_row] } {incr i} {
    $ns_ at [expr $time_duration +10.0] "$node_($i) reset";
}
$ns_ at [expr $time_duration +10.0] "finish"
$ns_ at [expr $time_duration +10.01] "puts \"NS Exiting...\"; $ns_ halt"

proc finish {} {
global ns_ tracefd
$ns_ flush-trace
close $tracefd
}

puts "Starting Simulation..."
$ns_ run 

Debugging ns-2

Enable gdb debugging
./configure --enable-debug
make clean
make
 
Note: After you have done that, the Makefile is initialized again and loose all your changes to Makefile if your did some.


When ns-2 crashes, here are some possible places to check for any causes of errors:
  1. Scheduler: Event UID not valid!. This is probably associated with timers. If a timer has been called to start again before it expires...
  2. Segmentation fault. A pointer goes to a wrong place. A pointer is out of bound. Or null pointer value.
  3. No obvious cause of fault. Program stopped in a place that no obvious coding errors can be found. Try "make clean + make". Sometimes, if *.h file is changed, the cross-included header files needs to be re-compiled into the final program.
Refer to another article: http://wmlab.csie.ncu.edu.tw/~youngway/MTdata/archives/000104.html

Install ns 2.28 in Debian with gcc 4.0 or above

A usual problem is TK8.4.5 compile failure. This is because of lack of  X11 development libraries. Do apt-get install libx11-dev,libxt-dev
For gcc 4.0.3, ns-2.28 source codes are violating programming regulations. So, some files have to be manually modified to let "make" succeed.
Generally, the declaration of  "class A" has to be put before a reference appears in another class definition. For example,
class B
{

   A*  aa;
....
}

Also, declaration as
static const double ALPHA_ = 0.4;
in a header file, is illegal, because initialization of a static variable in header file would lead to multiple initializations occurred in all files including this header file.

So, it must be changed as :
static const double ALPHA_ // in header file
const double XCPQueue::ALPHA_ = 0.4; // in cpp file
A list of paths are given as below: (copying from ns-mail list)

diff -ru ns-allinone-2.28.orig/nam-1.11/agent.h ns-allinone-2.28/nam-1.11/agent.h
--- ns-allinone-2.28.orig/nam-1.11/agent.h 2001-06-15 21:53:10.000000000 -0400
+++ ns-allinone-2.28/nam-1.11/agent.h 2005-06-13 18:10:05.000000000 -0400
@@ -70,7 +70,7 @@
 inline double width() {return width_;}
 inline double height() {return height_;}
 virtual void findClosestCornertoPoint(double x, double y, 
- double &corner_x, double &corner_y) const = NULL; 
+ double &corner_x, double &corner_y) const = 0; 
 virtual void place(double x, double y);
 void label(const char* name, int anchor);
 void color(const char* name);
diff -ru ns-allinone-2.28.orig/ns-2.28/diffusion3/lib/nr/nr.hh ns-allinone-2.28/ns-2.28/diffusion3/lib/nr/nr.hh
--- ns-allinone-2.28.orig/ns-2.28/diffusion3/lib/nr/nr.hh 2005-01-19 13:23:21.000000000 -0500
+++ ns-allinone-2.28/ns-2.28/diffusion3/lib/nr/nr.hh 2005-06-13 18:11:03.000000000 -0400
@@ -43,7 +43,8 @@
 typedef signed int int32_t;
 #endif
 typedef signed short int16_t;
-#if defined (sparc)
+// #if defined (sparc)
+#if defined (__SVR4) && defined (__sun)
 typedef char int8_t;
 #else
 // Conflicts with system declaration of int8_t in Solaris
diff -ru ns-allinone-2.28.orig/ns-2.28/xcp/xcpq.cc ns-allinone-2.28/ns-2.28/xcp/xcpq.cc
--- ns-allinone-2.28.orig/ns-2.28/xcp/xcpq.cc 2005-02-03 13:29:20.000000000 -0500
+++ ns-allinone-2.28/ns-2.28/xcp/xcpq.cc 2005-06-13 18:10:30.000000000 -0400
@@ -33,6 +33,15 @@
 } class_droptail_xcpq;
 
 
+const double XCPQueue::ALPHA_ = 0.4;
+const double XCPQueue::BETA_ = 0.226;
+const double XCPQueue::GAMMA_ = 0.1;
+const double XCPQueue::XCP_MAX_INTERVAL= 1.0;
+const double XCPQueue::XCP_MIN_INTERVAL= .001;
+
+const double XCPQueue::BWIDTH = 0.01;
+
+
 XCPQueue::XCPQueue(): queue_timer_(NULL), 
 estimation_control_timer_(NULL),
 rtt_timer_(NULL), effective_rtt_(0.0),
diff -ru ns-allinone-2.28.orig/ns-2.28/xcp/xcpq.h ns-allinone-2.28/ns-2.28/xcp/xcpq.h
--- ns-allinone-2.28.orig/ns-2.28/xcp/xcpq.h 2005-02-03 13:29:20.000000000 -0500
+++ ns-allinone-2.28/ns-2.28/xcp/xcpq.h 2005-06-13 18:10:36.000000000 -0400
@@ -113,11 +113,11 @@
 XCPTimer* rtt_timer_;
 double link_capacity_bps_;
 
- static const double ALPHA_ = 0.4;
- static const double BETA_ = 0.226;
- static const double GAMMA_ = 0.1;
- static const double XCP_MAX_INTERVAL= 1.0;
- static const double XCP_MIN_INTERVAL= .001;
+ static const double ALPHA_ ;
+ static const double BETA_ ;
+ static const double GAMMA_ ;
+ static const double XCP_MAX_INTERVAL;
+ static const double XCP_MIN_INTERVAL;
 
 double Te_; // control interval
 double Tq_; 
@@ -141,7 +141,7 @@
 double b_[BSIZE];
 double t_[BSIZE];
 int maxb_;alter
- static const double BWIDTH = 0.01;
+ static const double BWIDTH;
 int min_queue_ci_;
 int max_queue_ci_;
 

Solution for another problem when install ns-2.28 in Debian
./configure: line 7068: ` OSF*)' tcl8.3.2 configuration failed! Exiting .

The problem is that there are superfluous "'" characters in unix/configure:
grep in unix/configure for /etc/.relid and change it 
from 
 system=MP-RAS-`awk '{print }' /etc/.relid'`
to
 system=MP-RAS-`awk '{print }' /etc/.relid`

There are more occurrences of that line in tcl, tk and 
octcl with the same problem.

For gcc 4.1.1 or above, there is a lot of coding violations. The best way is to still use gcc-4.0 to compile, change Makefile:

CC      = gcc-4.0
CPP     = g++-4.0

Install ns-2.27 in Red Hat Linux

Follow the following steps to install ns-2.27 in Red Hat Linux distribution
  1. tar -xzf *
  2. ./install
  3. Change .bash_profile and add some environment variables. put /home/zhibinwu/ns-allinone-2.27/bin:/home/zhibinwu/ns-allinone-2.27/tcl8.4.5/unix:/home/zhibinwu/ns-allinone-2.27/tk8.4.5/unix into your PATH environment; so that you'll be able to run itm/tclsh/wish/xgraph.
    IMPORTANT NOTICES:
    (1) You MUST put /home/zhibinwu/ns-allinone-2.27/otcl-1.8, /home/zhibinwu/ns-allinone-2.27/lib into your LD_LIBRARY_PATH environment variable.
     If it complains about X libraries, add path to your X libraries into LD_LIBRARY_PATH.
     If you are using csh, you can set it like:
     setenv LD_LIBRARY_PATH .... If you are using sh, you can set it like:
     export LD_LIBRARY_PATH=....
    
    (2) You MUST put /home/zhibinwu/ns-allinone-2.27/tcl8.4.5/library into your TCL_LIBRARY environmental variable. Otherwise ns/nam will complain during startup.
    
    (3) [OPTIONAL] To save disk space, you can now delete directories tcl8.4.5
     and tk8.4.5. They are now installed under /home/zhibinwu/ns-allinone-2.27/{bin,include,lib}
    so , finally the bash_profile is like this:
    PATH=$PATH:$HOME/bin:/home/zhibinwu/ns2/ns-allinone-2.27/bin:/home/zhibinwu/ns2/ns-allinone-2.27/tcl8.4.5/unix:/home/zhibinwu/ns2/ns-allinone-2.27/tk8.4.5/unix
    
    export LD_LIBRARY_PATH=/home/zhibinwu/ns2/ns-allinone-2.27/otcl-1.8:home/zhibinwu/ns2/ns-allinone-2.27/lib
    
    export TCL_LIBRARY=/home/zhibinwu/ns2/ns-allinone-2.27/tcl8.4.5/library
    
  4. cd ns-2.27; ./validate

Note: The ns installation needs x-develop package. Otherwise, it will fail to build TCL TK.

Installation: A possible problem with CPP_NAMESPACE 
ns-2.27/indep-utils/cmu-scen-gen/setdest/Makefile,
 ns-2.27/indep-utils/webtrace-conv/nlanr/Makefile, and
 ns-2.27/indep-utils/webtrace-conv/dec/Makefile,
 needed to be modified in order to fix a bug in ISI's distribution. The bug
 caused a compile-time error that looked like this:

 g++ -c -Dstand_alone -DSTL_NAMESPACE=@STL_NAMESPACE@ -o setdest.o setdest.cc
 In file included from ../../../config.h:54,
 from setdest.h:5,
 from setdest.cc:57:
 ../../../autoconf.h:85: Error: namespace `CPP_NAMESPACE' undeclared
 setdest.cc:71:1: warning: "INFINITY" redefined
 In file included from /usr/include/math.h:40,
 from setdest.cc:43:
 /usr/include/bits/mathdef.h:35:1: warning: this is the location of the previous definition
 make[1]: *** [setdest.o] Error 1
 make[1]: Leaving directory `/home/iandow/netsim/ns-allinone-2.27/ns-2.27/indep-utils/cmu-scen-gen/setdest'
 make[1]: Entering directory `/home/iandow/netsim/ns-allinone-2.27/ns-2.27/indep-utils/webtrace-conv/dec'

 To fix the bug, edit ns-2.27/indep-utils/cmu-scen-gen/setdest/Makefile and 
 change this line:
 DEFINE = -Dstand_alone -DSTL_NAMESPACE=@STL_NAMESPACE@
 to this line:
 DEFINE = -Dstand_alone -DSTL_NAMESPACE=@STL_NAMESPACE@ -DCPP_NAMESPACE=std

 In the other two makefiles, append -DCPP_NAMESPACE=std to CFLAGS.


REFERENCES:

[1] The Network Simulator - ns-2, http://www.isi.edu/nsnam/ns/
[2] NS news database, http://www.isi.edu/nsnam/htdig/search.html