First of all, I install ns2.34 on Ubuntu 11.04. If you don`t know how to do it, just follow this page, http://itantenna.blogspot.com/2012/01/install-ns234-on-ubuntu-1004.html
Here, I just give the program which I modified. If you want to check the details, please download this document, http://personales.unican.es/aguerocr/files/ucMultiIfacesSupport.pdf. Please notice that I am not following this tutorial wholly.
Before we modify the original NS2 program, we`d better make a backup copy of it.(This is very important) OK, the first file we need to modify is "ns-lib.tcl". We will define four procedures,
-------------------------------------/tcl/lib/ns-lib.tcl-----------------------------------------------------------
Simulator instproc change−numifs {newnumifs} {
$self instvar numifs_
set numifs_ $newnumifs
}
Simulator instproc add−channel {indexch ch} {
$self instvar chan
set chan($indexch) $ch
}
Simulator instproc get−numifs { } {
$self instvar numifs
if [ info exists numifs ] {
return $numifs }else{
return ””
}
}
Simulator instproc ifNum {val} {$self set numifs $val}
Then changes the "node-config" procedure like this,
Simulator instproc node−config args {
......
set args [eval $self init−vars $args]
$self instvar addressType_ routingAgent_ propType_ macTrace_ \
routerTrace_ agentTrace_ movementTrace_ channelType_ channel_ numifs_ \
chan_ topoInstance_ propInstance_ mobileIP_ rxPower_ \
# change wrt Mike ’ s code
txPower_ idlePower_ satNodeType_ eotTrace_
......
# Single channel, single interface
warn ”Please use −channel as shown in tcl/ex/
wireless−mitf.tcl”
if {![ info exists chan]} {
set chan [new $channelType_ ]
}
} elseif {[info exists channel_ ]} {
# Multiple channel, multiple interfaces
if {[ info exists numifs_ ]} {
set chan(0) $channel_ } else {
set chan $channel_
}
if [ info exists topoInstance_ ] {
$propInstance_ topography $topoInstance_
}
......
Simulator instproc create−wireless−node args {
$self instvar routingAgent_ wiredRouting_ propInstance_ llType_ \
macType_ ifqType_ ifqlen_ phyType_ chan_ antType_ energyModel_ \
initialEnergy_ txPower_ rxPower_ idlePower_ \
topoInstance_ level1_ level2_ inerrProc_ outerrProc_ FECProc_ numifs_
Simulator set IMEPFlag_ OFF
......
# Adding Interface
if {[info exist numifs_] } {
for {set i 0} {$i < $numifs_} {incr i} {
# Add one interface per channel
$node add−interface $chan( $i ) $propInstance_ $llType_ $macType_ \
$ifqType_ $ifqlen_ $phyType_ $antType_ $topoInstance_ \
$inerrProc_ $outerrProc_ $FECProc_
}
} else {
$node add−interface $chan $propInstance_ $llType_ $macType_ \
$ifqType_ $ifqlen_ $phyType_ $antType_ $topoInstance_ \
$inerrProc_ $outerrProc_ $FECProc_
}
# Attach agent
if {$routingAgent_ != ”DSR”} {
$node attach $ragent [Node set rtagent_ port_ ]
}
......
-------------------------------------/tcl/lib/ns-mobilenode.tcl-----------------------------------------------------------
......
Node/MobileNode instproc add−target { agent port } {
$self instvar dmux_ imep_ toraDebug_
set ns [ Simulator instance ]
set newapi [ $ns imep−support ]
$agent set sport_ $port
# We get the number of interfaces from the simulator object
set numIfsSimulator [ $ns get−numifs ]
# special processing for TORA/IMEP node
set toraonly [string first ”TORA” [$agent info class]]
......
#
# Special processing for ZBR
# set zbronly [string first ”ZBR” [$agent info class]]
# if {$zbronly != −1 } {
# $agent if−queue [ $self set ifq_(0) ] ;
# ifq between LL and MAC
#
if { $port == [Node set rtagent_ port_ ] } {
# Special processing when multiple interfaces are supported
if {$numIfsSimulator != ””} {
for {set i 0} {$i < [$self set nifs_]} {incr i} {
$agent if−queue $i [$self set ifq_($i)]
}
}
# Ad hoc routing agent setup needs special handling
$self add−target−rtagent $agent $port
return
}
......
Node/MobileNode instproc add−target−rtagent { agent port } {
$self instvar imep_ toraDebug_
set ns [ Simulator instance ]
set newapi [ $ns imep−support ]
set namfp [$ns get−nam−traceall]
set dmux_ [ $self demux]
set classifier_ [ $self entry]
# We see whether we have multiple interfaces in the simulation
set numIfsSimulator [ $ns get−numifs ]
# let the routing agent know about the port dmux
$agent port−dmux $dmux_
......
# second tracer to see the actual
# types of tora packets before imep packs them
if { [info exists toraDebug_] && $toraDebug_ == ”ON”} {
set sndT2 [ $self mobility−trace Send ”TRP”]
$sndT2 target $imep_(0)
$agent target $sndT2
}
$sndT target [$self set ll_(0)]
} else { ;# noIMEP
i f {$numIfsSimulator != ””} {
for {set i 0} {$i < [$self set nifs_ ]} {incr i} {
set sndT [cmu−trace Send ”RTR” $self ]
$agent target $i $sndT
$sndT target [$self set ll_($i)]
}
} else {
$agent target $sndT
$sndT target [$self set ll_(0)]
}
}
......
$imep_(0) sendtarget [ $self set ll_(0) ]
} else { ;# noIMEP
if {$numIfsSimulator != ””} {
for {set i 0} {$i< [$self set nifs_] } {incr i} {
$agent target $i [$self set ll_($i)]
}
} else {
$agent target [$self set ll_(0)]
}
}
#
# Recv Target
#
if {$newapi == ”ON” } {
[$self set ll_(0)] up−target $imep_(0)
$classifier_ defaulttarget $agent
......
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_
set ns [ Simulator instance ]
set imepflag [ $ns imep−support ]
set t $nifs_
incr nifs_
...
set inerr $inerr_($t)
set outerr $outerr_($t)
set fec $fec_($t)
# We also create one ARP table per interface
set arptable_($t) [new ARPTable $self $mac]
set arptable $arptable_($t)
if {$imepflag != ””} {
set drpT [ $self mobility−trace Drop ”IFQ”]
} else {
set drpT [cmu−trace Drop ”IFQ” $self ]
}
$arptable drop−target $drpT
if { $namfp != ”” } { $drpT namattach $namfp
}
#
# Link Layer
#
$ l l arptable $arptable
$ll mac $mac
$ll down−target $ifq
......
Node/MobileNode instproc init args {
...
$self instvar nifs_ arptable_ X_ Y_ Z_ nodetype_
set X 0.0
set Y 0.0
set Z 0.0
# set arptable ”” ;# no ARP table yet
set nifs 0 ;# number of network interfaces
......
Node/MobileNode instproc reset {} {
$self instvar arptable_ nifs_ netif_ mac_ ifq_ ll_ imep_
for {set i 0} {$i < $nifs_} {incr i} {
$netif_($i) reset
$mac_($i) reset
$ll_($i) reset
$ifq_($i) reset
if { [info exists opt(imep)] && $opt(imep) == ”ON” } {
$imep_( $i ) reset
}
if { $arptable_($i) != ”” } {
$arptable _( $i ) reset
}
}
}
-------------------------------------/common/mobilenode.h-----------------------------------------------------------
...
# define MAX_CHANNELS 20
...
/∗ For list−keeper ∗/
MobileNode∗ nextX_[MAX_CHANNELS] ;
MobileNode∗ prevX_[MAX_CHANNELS] ;
...
void start(void);
void getLoc(double ∗x, double ∗y, double ∗z);
inline void getVelo(double ∗dx, double ∗dy, double ∗dz) {
∗dx= dX_ ∗ speed_; ∗dy= dY_ ∗ speed_; ∗dz= 0.0;
}
...
-------------------------------------/common/mobilenode.cc-----------------------------------------------------------
void MobileNode::getLoc(double ∗x, double ∗y, double ∗z)
{
update position ()
∗x = X_;
∗y = Y_;
∗z = Z_;
}
-------------------------------------/mac/channel.cc-----------------------------------------------------------
Replace ALL the nextX_ and prevX_ by the following arrays in this program.
nextX_[this−>index()]
prevX_[this−>index()]
And modify this part,
affectedNodes = getAffectedNodes(mtnode, distCST_ + /∗ safety ∗/ 5, &numAffectedNodes ) ;
for (i=0; i < numAffectedNodes; i++) {
rnode = affectedNodes [ i ] ;
if (rnode == tnode)
continue ;
newp = p−>copy();
propdelay = get_pdelay(tnode, rnode);
rifp = (rnode−>ifhead()).lh_first;
for(; rifp; rifp = rifp−>nextnode()){
if(rifp−>channel() == this) {
s.schedule(rifp , newp, propdelay);
}
}
}
delete []affectedNodes ;
-------------------------------------/mac/mac-802_11.cc-----------------------------------------------------------
......
if(tx_active_ && hdr−>error() == 0) {
hdr−>error () = 1;
}
hdr−>iface() = addr();
if(rx_state_ == MAC_IDLE){
......
For routing part, I use the AODV protocol as an example here.
-------------------------------------/aodv/aodv.h-----------------------------------------------------------
......
# define MinHelloInterval (0.75 * HELLO_INTERVAL)
# define MAX_IF 11
......
/*
* Route Table Management
*/
void rt_update(aodv_rt_entry *rt, u_int32_t seqnum, u_int16_t metric, nsaddr_t nexthop, double expire_time, u_int8_t interface);
......
int nIfaces ;
NsObject ∗targetlist[MAX_IF];
PriQueue ∗ifqueuelist [MAX_IF];
......
-------------------------------------/aodv/aodv.cc-----------------------------------------------------------
......
int
AODV::command(int argc, const char*const* argv) {
......
else if(argc == 3) {
......
}
else if(argc == 4) {
if (strcmp(argv[1] ,”if−queue”) == 0) {
PriQueue ∗ ifq = (PriQueue ∗) TclObject::lookup(argv[3]);
int temp_ = atoi(argv[2]);
if(temp_ == nIfaces) {
nIfaces++;
}
ifqueuelist [temp_] = ifq ;
if (ifqueuelist[temp_]) {
return TCL_OK;
}else{
return TCL_ERROR;
}
}
if (strcmp(argv[1] ,”target”) == 0) {
int temp_ = atoi(argv[2]);
if(temp_ == nIfaces) {
nIfaces++;
}
targetlist[temp_] = (NsObject ∗) TclObject::lookup(argv[3]);
if(targetlist[temp_]) {
return TCL_OK;
} else {
return TCL_ERROR;
}
}
}
return Agent::command(argc, argv);
} // Be careful, there are many brackets here!
/*
Constructor
*/
AODV::AODV(nsaddr_t id) : Agent(PT_AODV), btimer(this), htimer(this), ntimer(this), rtimer(this), lrtimer(this), rqueue() {
index = id;
seqno = 2;
bid = 1;
LIST_INIT(&nbhead);
LIST_INIT(&bihead);
logtarget = 0;
ifqueue = 0;
nIfaces = 0;
}
......
void
AODV::rt_update(aodv_rt_entry *rt, u_int32_t seqnum, u_int16_t metric,
nsaddr_t nexthop, double expire_time, u_int8_t interface) {
rt->rt_seqno = seqnum;
rt->rt_hops = metric;
rt->rt_flags = RTF_UP;
rt->rt_nexthop = nexthop;
rt->rt_expire = expire_time;
rt->rt_interface = interface;
}
......
void
AODV::recvRequest(Packet *p) {
struct hdr_ip *ih = HDR_IP(p);
struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);
aodv_rt_entry *rt;
struct hdr_cmn *ch = HDR_CMN(p);
u_int8_t Iface;
...
}
......
if ( (rq->rq_src_seqno > rt0->rt_seqno ) || ((rq->rq_src_seqno == rt0->rt_seqno) && (rq->rq_hop_count < rt0->rt_hops)) ) {
// If we have a fresher seq no. or lesser #hops for the
// same seq no., update the rt entry. Else don't bother.
if(nIfaces){
Iface = ch ->iface()-((Mac *) ifqueuelist[0]->target())->addr();
} else {
Iface = -1;
}
rt_update(rt0, rq->rq_src_seqno, rq->rq_hop_count, ih->saddr(),
max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE)), Iface );
if (rt0->rt_req_timeout > 0.0) {
// Reset the soft state and
// Set expiry time to CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT
// This is because route is used in the forward direction,
// but only sources get benefited by this change
rt0->rt_req_cnt = 0;
rt0->rt_req_timeout = 0.0;
rt0->rt_req_last_ttl = rq->rq_hop_count;
rt0->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;
}
...
}
......
void
AODV::recvReply(Packet *p) {
//struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
aodv_rt_entry *rt;
char suppress_reply = 0;
double delay = 0.0;
#ifdef DEBUG
fprintf(stderr, "%d - %s: received a REPLY\n", index, __FUNCTION__);
#endif // DEBUG
struct hdr_cmn *ch = HDR_CMN(p);
u_int8_t Iface;
...
if(nIfaces){
Iface = ch ->iface()-((Mac *) ifqueuelist[0]->target())->addr();
} else {
Iface = -1;
}
rt_update(rt, rp->rp_dst_seqno, rp->rp_hop_count,
rp->rp_src, CURRENT_TIME + rp->rp_lifetime, Iface);
// reset the soft state
rt->rt_req_cnt = 0;
rt->rt_req_timeout = 0.0;
rt->rt_req_last_ttl = rp->rp_hop_count;
...
}
......
void
AODV::forward(aodv_rt_entry *rt, Packet *p, double delay) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
if(ih->ttl_ == 0) {
#ifdef DEBUG
fprintf(stderr, "%s: calling drop()\n", __PRETTY_FUNCTION__);
#endif // DEBUG
drop(p, DROP_RTR_TTL);
return;
}
if (ch->ptype() != PT_AODV && ch->direction() == hdr_cmn::UP &&
((u_int32_t)ih->daddr() == IP_BROADCAST)
|| (ih->daddr() == here_.addr_)) {
dmux_->recv(p,0);
return;
}
if (rt) {
assert(rt->rt_flags == RTF_UP);
rt->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;
ch->next_hop_ = rt->rt_nexthop;
ch->addr_type() = NS_AF_INET;
ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction
}
else { // if it is a broadcast packet
// assert(ch->ptype() == PT_AODV); // maybe a diff pkt type like gaf
assert(ih->daddr() == (nsaddr_t) IP_BROADCAST);
ch->addr_type() = NS_AF_NONE;
ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction
}
if (ih->daddr() == (nsaddr_t) IP_BROADCAST) {
// If it is a broadcast packet
assert(rt == 0);
if (ch->ptype() == PT_AODV) {
/*
* Jitter the sending of AODV broadcast packets by 10ms
*/
if(nIfaces) {
for(int i=0; i
Packet *p_copy = p->copy();
Scheduler::instance().schedule(targetlist[i], p_copy, 0.01*Random::uniform());
}
Packet::free(p);
} else {
Scheduler::instance().schedule(target_, p, 0.01*Random::uniform()); // No jitter
}
} else {
if(nIfaces) {
for(int i=0; i
Packet *p_copy = p->copy();
Scheduler::instance().schedule(targetlist[i], p_copy, 0);
}
Packet::free(p);
} else {
Scheduler::instance().schedule(target_, p, 0); // No jitter
}
}
}
else { // Not a broadcast packet
if(delay > 0.0) {
if(nIfaces) {
Scheduler::instance().schedule(targetlist[rt->rt_interface], p, delay);
} else {
Scheduler::instance().schedule(target_, p, delay);
}
}
else {
// Not a broadcast packet, no delay, send immediately
if(nIfaces) {
Scheduler::instance().schedule(targetlist[rt->rt_interface], p, 0.);
} else {
Scheduler::instance().schedule(target_, p, 0.);
}
}
}
} // Be careful, many brackets here!
......
void
AODV::sendReply(nsaddr_t ipdst, u_int32_t hop_count, nsaddr_t rpdst,
u_int32_t rpseq, u_int32_t lifetime, double timestamp) {
Packet *p = Packet::alloc();
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
aodv_rt_entry *rt = rtable.rt_lookup(ipdst);
#ifdef DEBUG
fprintf(stderr, "sending Reply from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
assert(rt);
rp->rp_type = AODVTYPE_RREP;
//rp->rp_flags = 0x00;
rp->rp_hop_count = hop_count;
rp->rp_dst = rpdst;
rp->rp_dst_seqno = rpseq;
rp->rp_src = index;
rp->rp_lifetime = lifetime;
rp->rp_timestamp = timestamp;
// ch->uid() = 0;
ch->ptype() = PT_AODV;
ch->size() = IP_HDR_LEN + rp->size();
ch->iface() = -2;
ch->error() = 0;
ch->addr_type() = NS_AF_INET;
ch->next_hop_ = rt->rt_nexthop;
ch->prev_hop_ = index; // AODV hack
ch->direction() = hdr_cmn::DOWN;
ih->saddr() = index;
ih->daddr() = ipdst;
ih->sport() = RT_PORT;
ih->dport() = RT_PORT;
ih->ttl_ = NETWORK_DIAMETER;
if(nIfaces) {
Scheduler::instance().schedule(targetlist[rt->rt_interface], p, 0.);
} else {
Scheduler::instance().schedule(target_, p, 0.);
}
}
void
AODV::sendError(Packet *p, bool jitter) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
struct hdr_aodv_error *re = HDR_AODV_ERROR(p);
#ifdef ERROR
fprintf(stderr, "sending Error from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
re->re_type = AODVTYPE_RERR;
//re->reserved[0] = 0x00; re->reserved[1] = 0x00;
// DestCount and list of unreachable destinations are already filled
// ch->uid() = 0;
ch->ptype() = PT_AODV;
ch->size() = IP_HDR_LEN + re->size();
ch->iface() = -2;
ch->error() = 0;
ch->addr_type() = NS_AF_NONE;
ch->next_hop_ = 0;
ch->prev_hop_ = index; // AODV hack
ch->direction() = hdr_cmn::DOWN; //important: change the packet's direction
ih->saddr() = index;
ih->daddr() = IP_BROADCAST;
ih->sport() = RT_PORT;
ih->dport() = RT_PORT;
ih->ttl_ = 1;
// Do we need any jitter? Yes
if (jitter) {
if(nIfaces) {
for(int i=0; i
Packet *p_copy = p->copy();
Scheduler::instance().schedule(targetlist[i], p_copy, 0.01*Random::uniform());
}
Packet::free(p);
} else {
Scheduler::instance().schedule(target_, p, 0.01*Random::uniform());
}
}
else {
if(nIfaces) {
for(int i=0; i
Packet *p_copy = p->copy();
Scheduler::instance().schedule(targetlist[i], p_copy, 0.0);
}
Packet::free(p);
}
else {
Scheduler::instance().schedule(target_, p, 0.0);
}
}
}
void
AODV::sendHello() {
Packet *p = Packet::alloc();
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
struct hdr_aodv_reply *rh = HDR_AODV_REPLY(p);
#ifdef DEBUG
fprintf(stderr, "sending Hello from %d at %.2f\n", index, Scheduler::instance().clock());
#endif // DEBUG
rh->rp_type = AODVTYPE_HELLO;
//rh->rp_flags = 0x00;
rh->rp_hop_count = 1;
rh->rp_dst = index;
rh->rp_dst_seqno = seqno;
rh->rp_lifetime = (1 + ALLOWED_HELLO_LOSS) * HELLO_INTERVAL;
// ch->uid() = 0;
ch->ptype() = PT_AODV;
ch->size() = IP_HDR_LEN + rh->size();
ch->iface() = -2;
ch->error() = 0;
ch->addr_type() = NS_AF_NONE;
ch->prev_hop_ = index; // AODV hack
ih->saddr() = index;
ih->daddr() = IP_BROADCAST;
ih->sport() = RT_PORT;
ih->dport() = RT_PORT;
ih->ttl_ = 1;
if(nIfaces) {
for(int i=0; i
Packet *p_copy = p->copy();
Scheduler::instance().schedule(targetlist[i], p_copy, 0.0);
}
Packet::free(p);
}
else {
Scheduler::instance().schedule(target_, p, 0.0);
}
}