1、在NS2下添加路由协议,主要是参照已有的像AODV、DSDV等路由协议,当然如果不想添加可以直接在这两种协议上进行修改。总而言之,我们要抓住一点,我们所添加的协议是在一个节点上,只要我们在一个节点上添加成功了,那么其他的节点都是一样的,所以我们在编写协议的时候主要抓住节点的收和发以及转发这3个基本点去编写,无论协议有多复杂,还是离不开这3点。接收的时候有来自上层TCP/UDP传下来的,还有是从下层传上来的;
在ns2中添加协议,主要是包的添加,以及在哪些地方需要去进行注册以至于我们的新协议可以和已经有的AODV一样;
例如我们可以在节点配置的时候
node-config -adhcoRouting New_Protocol
......
.....
可以直接调用我们的新协议;
主要添加的文件为:
ns-2.35/tcl/lib/ns-default.tcl
这个tcl文件主要作用是当我们在c++中绑定了和otcl的变量以后,在它里面进行初始化
ns-2.35/tcl/lib/ns-packet.tcl
这个tcl文件中有如下的一个用来激活我们的包头,在此文件中添加我们的PacketHeader/NewHeader中的NewHeader来完成注册;
set protolist {
# Common:
Common
Flags
IP # IP
# Routing Protocols:
NV # NixVector classifier for stateless routing
rtProtoDV # distance vector routing protocol
rtProtoLS # link state routing protocol
SR # source routing, dsr/hdr_sr.cc
Src_rt # source routing, src_rtg/hdr_src.cc
# Routers:
LDP # mpls/ldp.cc
MPLS # MPLS, MultiProtocol Label Switching
问题:NewHeader注册这个和哪里对应?和在packet.h中定义的包的类型,名字时候需要一致?
其实这个注册的NewHeader是与下面的SimpleHeaderClass中的SIMPLE是对应一致的,因为它就是一个OTCL对象,方便我们在TCL代码中去加入或者删除不需要的包头
1、NewHeader这个注册的TCL包头和其他在Packet建立的类型没有任何关系,所以名字不一样也是可以的;
2、值得注意的是:
static class SimpleHeaderClass:public PacketHeaderClass{
public:
SimpleHeaderClass():PacketHeaderClass("PacketHeader/SIMPLE",sizeof(hdr_simple_pkt)){
bind_offset(&hdr_simple_pkt::offset_);
}
}class_rtProtoSimple_hdr;
我们必须而且只能在构造函数中绑定offset,这样由包头管理器可以定位到此包头的位置,在tcl中,我们也用NewHeader可以增加和删除包,如:
remove-packet-header AODV ARP
注册,定义是为了在TCL中使用更加方便
ns-2.35/tcl/lib/ns-agent.tcl
在这里面有一些agent的初始化以及过程的定义,我们可以在里面添加我们自己的过程;这个最终是要被source到ns-lib.tcl中的
ns-2.35/tcl/lib/ns-lib.tcl
当我们去添加无线路由协议的时候,我们要找到如下代码
Simulator instproc create-wireless-node args {
$self instvar routingAgent_ wiredRouting_ propInstance_ llType_ \
macType_ ifqType_ ifqlen_ phyType_ chan antType_ \
energyModel_ initialEnergy_ txPower_ rxPower_ \
idlePower_ sleepPower_ sleepTime_ transitionPower_ transitionTime_ \
topoInstance_ level1_ level2_ inerrProc_ outerrProc_ FECProc_ rtAgentFunction_
Simulator set IMEPFlag_ OFF
# create node instance
set node [eval $self create-node-instance $args]
# basestation address setting
if { [info exist wiredRouting_] && $wiredRouting_ == "ON" } {
$node base-station [AddrParams addr2id [$node node-addr]]
}
if {$rtAgentFunction_ != ""} {
set ragent [$self $rtAgentFunction_ $node]
} else {
switch -exact $routingAgent_ {
DSDV {
set ragent [$self create-dsdv-agent $node]
}
DSR {
$self at 0.0 "$node start-dsr"
}
AODV {
puts "aodv----------------------------------------"
set ragent [$self create-aodv-agent $node]
}
AOMDV {
set ragent [$self create-aomdv-agent $node]
}
MDART {
set ragent [$self create-mdart-agent $node]
}
PUMA {
set ragent [$self create-puma-agent $node]
}
TORA {
Simulator set IMEPFlag_ ON
set ragent [$self create-tora-agent $node]
}
DIFFUSION/RATE {
eval $node addr $args
set ragent [$self create-diffusion-rate-agent $node]
}
DIFFUSION/PROB {
eval $node addr $args
set ragent [$self create-diffusion-probability-agent $node]
}
Directed_Diffusion {
eval $node addr $args
set ragent [$self create-core-diffusion-rtg-agent $node]
}
FLOODING {
eval $node addr $args
set ragent [$self create-flooding-agent $node]
}
OMNIMCAST {
eval $node addr $args
set ragent [$self create-omnimcast-agent $node]
}
DumbAgent {
set ragent [$self create-dumb-agent $node]
}
ManualRtg {
set ragent [$self create-manual-rtg-agent $node]
}
Simple {
set ragent [$self create-simple-agent $node]
}
default {
eval $node addr $args
puts "Wrong node routing agent!"
exit
}
}
}
可以看到里面有AODV等等协议;可以按照上面的例子加入自己的协议;
Simulator instproc create-simple-agent { node} {
set ragent [new Agent/Simple [$node node-addr] ]
$self at 0.0 "$ragent start"
$node set ragent_ $ragent
return $ragent
}
加入自己的方法,按照已有的路由,不过其中的方法我们要在.cc中的command存在,否则报错。
ns-2.35/trace/cmu-trace.cc文件
加入自己的协议以后,我们更加关注的是trace文件以及输出格式,在此文件中实现了所有trace的格式
找到以下内容,我们可以添加自己的格式
void CMUTrace::format(Packet* p, const char *why)
{
hdr_cmn *ch = HDR_CMN(p);
int offset = 0;
/*
* Log the MAC Header
*/
<span style="color:#ff0000;">format_mac_common(p, why, offset);</span>
// cout<<ch->ptype()<<endl;
// cout<< packet_info.name(76)<<endl;
if (pt_->namchannel())
nam_format(p, offset);
offset = strlen(pt_->buffer());
//insert myself
switch(ch->ptype()) {
case PT_MAC:
case PT_SMAC:
break;
case PT_ARP:
format_arp(p, offset);
break;
default:
<span style="color:#ff0000;">format_ip(p, offset);</span>
offset = strlen(pt_->buffer());
switch(ch->ptype()) {
case PT_AODV:
format_aodv(p, offset);
break;
// AOMDV patch
case PT_AOMDV:
format_aomdv(p, offset);
break;
case PT_TORA:
format_tora(p, offset);
break;
case PT_IMEP:
format_imep(p, offset);
break;
case PT_DSR:
format_dsr(p, offset);
break;
case PT_MESSAGE:
case PT_UDP:
format_msg(p, offset);
break;
case PT_TCP:
case PT_ACK:
format_tcp(p, offset);
break;
case PT_SCTP:
/* Armando L. Caro Jr. <acaro@@cis,udel,edu> 6/5/2002
*/
format_sctp(p, offset);
break;
case PT_CBR:
format_rtp(p, offset);
break;
case PT_DIFF:
break;
case PT_GAF:
case PT_PING:
break;
case PT_SIMPLE:
format_simple(p,offset);
break;
default:
if(pktTrc_ && pktTrc_->format_unknow(p, offset, pt_, newtrace_))
break;
/*<zheng: del -- there are many more new packet types added, like PT_EXP (poisson traffic belongs to this type)>
fprintf(stderr, "%s - invalid packet type (%s).\n",
__PRETTY_FUNCTION__, packet_info.name(ch->ptype()));
exit(1);
</zheng: del>*/
break; //zheng: add
}
}
}
可以在代码中看到AODV和以及其他的包格式,我们也将自己的添加进去,然后编写自己的format函数,值得一提的是,从代码中我们会发现,在代码中以及为我们添加了
format_mac_common以及format_ip函数,所以我们自己添加的协议会出现在其后;形成这种类型
s 12.000000000 _0_ RTR --- 0 AODV 48 [0 0 0 0] ------- [0:255 -1:255 30 0] [0x2 1 2 [1 0] [0 6]] (REQUEST)
在这个包里我们进行包类别的定义以及名字的绑定;
static const packet_t PT_DCCP = 63;
static const packet_t PT_DCCP_REQ = 64;
static const packet_t PT_DCCP_RESP = 65;
static const packet_t PT_DCCP_ACK = 66;
static const packet_t PT_DCCP_DATA = 67;
static const packet_t PT_DCCP_DATAACK = 68;
static const packet_t PT_DCCP_CLOSE = 69;
static const packet_t PT_DCCP_CLOSEREQ = 70;
static const packet_t PT_DCCP_RESET = 71;
// M-DART packets
static const packet_t PT_MDART = 72;
static const packet_t PT_SIMPLE=73;
static const packet_t PT_LWB=74;
static const packet_t PT_TEST1=75;
static const packet_t PT_TEST2=76;
// insert new packet types here
static packet_t PT_NTYPE = 77; // This MUST be the LAST one
这里注意最后一个不为const常量
class p_info {
public:
p_info()
{
initName();
}
const char* name(packet_t p) const {
if ( p <= p_info::nPkt_ ) return name_[p];
return 0;
}
static bool data_packet(packet_t type) {
return ( (type) == PT_TCP || \
(type) == PT_TELNET || \
(type) == PT_CBR || \
(type) == PT_AUDIO || \
(type) == PT_VIDEO || \
(type) == PT_ACK || \
(type) == PT_SCTP || \
(type) == PT_SCTP_APP1 || \
(type) == PT_HDLC \
);
}
static packetClass classify(packet_t type) {
if (type == PT_DSR ||
type == PT_MESSAGE ||
type == PT_TORA ||
type == PT_PUMA ||
type == PT_AODV ||
type == PT_MDART ||
type == PT_SIMPLE)
return ROUTING;
if (type == PT_TCP ||
type == PT_TELNET ||
type == PT_CBR ||
type == PT_AUDIO ||
type == PT_VIDEO ||
type == PT_ACK ||
type == PT_SCTP ||
type == PT_SCTP_APP1 ||
type == PT_HDLC)
return DATApkt;
if (pc_)
return pc_->classify(type);
return UNCLASSIFIED;
}
static void addPacketClassifier(PacketClassifier *pc)
{
if(!pc)
return;
pc->setNext(pc_);
pc_ = pc;
}
static void initName()
{
if(nPkt_ >= PT_NTYPE+1)
return;
char **nameNew = new char*[PT_NTYPE+1];
for(unsigned int i = (unsigned int)PT_SMAC+1; i < nPkt_; i++)
{
nameNew[i] = name_[i];
}
if(!nPkt_)
delete [] name_;
name_ = nameNew;
nPkt_ = PT_NTYPE+1;
name_[PT_TEST1]="test1";
name_[PT_TEST2]="test2";
name_[PT_TCP]= "tcp";
name_[PT_UDP]= "udp";
name_[PT_CBR]= "cbr";
name_[PT_AUDIO]= "audio";
name_[PT_VIDEO]= "video";
name_[PT_ACK]= "ack";
name_[PT_START]= "start";
name_[PT_STOP]= "stop";
name_[PT_PRUNE]= "prune";
name_[PT_GRAFT]= "graft";
name_[PT_GRAFTACK]= "graftAck";
name_[PT_JOIN]= "join";
name_[PT_ASSERT]= "assert";
name_[PT_MESSAGE]= "message";
name_[PT_RTCP]= "rtcp";
name_[PT_RTP]= "rtp";
name_[PT_RTPROTO_DV]= "rtProtoDV";
name_[PT_CtrMcast_Encap]= "CtrMcast_Encap";
name_[PT_CtrMcast_Decap]= "CtrMcast_Decap";
name_[PT_SRM]= "SRM";
name_[PT_REQUEST]= "sa_req";
name_[PT_ACCEPT]= "sa_accept";
name_[PT_CONFIRM]= "sa_conf";
name_[PT_TEARDOWN]= "sa_teardown";
name_[PT_LIVE]= "live";
name_[PT_REJECT]= "sa_reject";
name_[PT_TELNET]= "telnet";
name_[PT_FTP]= "ftp";
name_[PT_PARETO]= "pareto";
name_[PT_EXP]= "exp";
name_[PT_INVAL]= "httpInval";
name_[PT_HTTP]= "http";
name_[PT_ENCAPSULATED]= "encap";
name_[PT_MFTP]= "mftp";
name_[PT_ARP]= "ARP";
name_[PT_MAC]= "MAC";
name_[PT_TORA]= "TORA";
name_[PT_DSR]= "DSR";
name_[PT_AODV]= "AODV";
name_[PT_MDART]= "MDART";
name_[PT_IMEP]= "IMEP";
加入对应的名字
经过以上添加,便可以类似AODV一样做为无线路由算法添加到ns2中
tips:
添加新的协议,其实有一个基本的死框架,我们按照框架写完后,再进行自己协议的编写。
死框架:
1、申明一个继承了Agent类的子类,实现其中的recv()方法,其他是自己实现的函数
2、利用TclClass进行C++与OTCL进行绑定
3、申明一个包类型
4、将包类型的C++与OTCL进行绑定,利用PacketHeaderClass 类来实现
5、注册包类型
以上5个步骤是一个死框架,其它我们需要的时候往里加即可;