在NS中添加一个新协议的步骤
2009-05-25 21:31
225 查看
在NS中添加一个新协议的步骤
1、在ns-2.x目录下创建协议名(CTAgg)目录,此目录中包含CTAgg.h CTAgg.cc CTAgg_pkt.h CTAgg_rtable.h CTAgg_rtable.cc五个文件。
2、撰写CTAgg_pkt.h,对数据包类型进行声明(修改common/pakcet.h文件中的枚举类型packet_t和类p_info)。绑定包头到TCL接口。
TAgg_rtable.cc五个文件。
3、撰写CTAgg.h。
4、撰写CTAgg.cc。
5、撰写CTAgg_rtable.h。操作路由表函数的声明。
.h CTAgg.cc CTAgg_pk
6、撰写CTAgg_rtable.cc。操作路由表函数的实现。
7、跟踪支持,修改trace/cmu-trace.h和trace/cmu-trace.cc。
在CMUTrace类中实现void format_CTAgg(Packet *p, int offset)函数,需要加入#include 。
CTAgg)目录,此目录中包含CTAgg
8、修改TCL库,tcl/lib/ns-packet.tcl中的foreach prot{}
tcl/lib/ns-default.tcl中添加Agent/Protoname set accessible_var_ true
tcl/lib/ns-lib.tcl中的create-wireless-node函数中添加.h CTAgg.cc CTAgg_pk
Protoname {
set ragent [$self create-CTAgg-agent $node]
}t.h CTAgg_rtable.h C
tcl/lib/ns-lib.tcl中添加函数create-CTAgg-agent
9、修改队列优先级,修改queue/priqueue.cc中的recv()函数。
10、修改Makefile。
最近正在研究怎样把自己新写的协议添加到NS2中去,正好借鉴了一些朋友的文章,现在整理下来,以便以后参考,也希望能给广大博友一些方便。
step 1:
比如我们新建的协议名字就叫做protoname
,以ns2.27平台为例,我们在ns2.27目录下建立一个protoname目录。此目录包含protoname.h,protoname.cc,protoname_pkt.h,protoname_rtable.h,
protoname_rtable.cc
五个文件。
其中五个文件的具体功能和作用如下:
(1)protoname.h 定义必要的计时器和路由代理
(2)protoname.cc 执行计时器、路由代理和Tcl文件
(3)protoname_pkt.h 声明protoname路由协议需要在无线自组网节点交换的数据包
(4)protoname_rtable.h 声明我们自己的路由选择表
(5)protoname_rtable.cc 执行路由选择表
step 2:
相应文件的代码
(1)protoname.h
#ifndef __protoname_h__
#define __protoname_h__
// 下面包含一些需要的头文件
#include "protoname_pkt.h" //数据包报头
#include "protoname_rtable.h"
#include <agent.h> //代理基本类
#include <packet.h> //数据包类
#include <trace.h> //跟踪类,用于在跟踪文件里记录输出的仿真结果
#include <timer-handler.h> //计时器基本类,创建我们自定义的计时器
#include <random.h> //随机类,用于产生伪随机数
#include <classifier-port.h> //端口分类器类,用于淘汰向上层传输的数据包
#include <mobilenode.h>
#include "arp.h"
#include "ll.h"
#include "mac.h"
#include "ip.h"
#include "delay.h"
#define CURRENT_TIME Scheduler::instance().clock() //定义了一个用于得到当前仿真时间的宏
//通过一个调度类的实例完成
#define JITTER (Random::uniform()*0.5) //在0-0.5之间去随机数作为发送数据的延迟时间
class Protoname; // forward declaration
/* Timers */ //自定义计时器发送定时的控制包
class Protoname_PktTimer : public TimerHandler {
public:
Protoname_PktTimer(Protoname* agent) : TimerHandler() {
agent_ = agent;
}
protected:
Protoname* agent_;
virtual void expire(Event* e);
};
/* Agent */ //定义Protoname 类
class Protoname : public Agent {
/* Friends */
friend class Protoname_PktTimer;
/* Private members */ //封装了自身的地址、内状态、路由表、可变的Tcl
//以及一个负责指定输出数量的计数器
nsaddr_t ra_addr_;
//protoname_state state_;
protoname_rtable rtable_;
int accesible_var_; //用来读取Tcl代码或脚本语言
u_int8_t seq_num_;
protected:
MobileNode* node_;
PortClassifier* dmux_; // For passing packets up to agents.端口分类器
Trace* logtarget_; // For logging.跟踪器
Protoname_PktTimer pkt_timer_; // Timer for sending packets.自定义计时器
//内部属性
inline nsaddr_t& ra_addr() { return ra_addr_; }
//inline protoname_state& state() { return state_; }
inline int& accessible_var() { return accesible_var_; }
void forward_data(Packet*); //数据包被正确传输的目的地
void recv_protoname_pkt(Packet*);
void send_protoname_pkt();
void reset_protoname_pkt_timer();
public:
Protoname(nsaddr_t);
int command(int, const char*const*);
void recv(Packet*, Handler*);
//void mac_failed(Packet*);
};
#endif
2)protoname.cc
#include "protoname.h"
#include "protoname_pkt.h"
#include <random.h>
#include <cmu-trace.h>
#include <iostream>
int hdr_protoname_pkt::offset_;
static class ProtonameHeaderClass : public PacketHeaderClass {
public:
ProtonameHeaderClass() : PacketHeaderClass("PacketHeader/Protoname", sizeof(hdr_protoname_pkt)) {
bind_offset(&hdr_protoname_pkt::offset_);
}
} class_rtProtoProtoname_hdr;
static class ProtonameClass : public TclClass {
public:
ProtonameClass() : TclClass("Agent/Protoname") {}
TclObject* create(int argc, const char*const* argv) {
assert(argc == 5);
return (new Protoname((nsaddr_t) Address::instance().str2addr(argv[4])));
}
} class_rtProtoProtoname;
void
Protoname_PktTimer::expire(Event* e) {
agent_->send_protoname_pkt();
agent_->reset_protoname_pkt_timer();
}
Protoname::Protoname(nsaddr_t id) : Agent(PT_PROTONAME), pkt_timer_(this) {
bind_bool("accesible_var_", &accesible_var_);
ra_addr_ = id;
node_ = (MobileNode*)Node::get_node_by_address(id);
}
int
Protoname::command(int argc, const char*const* argv) {
if (argc == 2) {
if (strcasecmp(argv[1], "start") == 0) {
pkt_timer_.resched(0.0);
return TCL_OK;
}
else if (strcasecmp(argv[1], "print_rtable") == 0) {
if (logtarget_ != 0) {
sprintf(logtarget_->pt_->buffer(), "P %f _%d_ Routing Table", CURRENT_TIME, ra_addr());
logtarget_->pt_->dump();
rtable_.print(logtarget_);
}
else {
fprintf(stdout, "%f _%d_ If you want to print this routing table "
"you must create a trace file in your tcl script", CURRENT_TIME, ra_addr());
}
return TCL_OK;
}
}
else if (argc == 3) {
// Obtains corresponding dmux to carry packets to upper layers
if (strcmp(argv[1], "port-dmux") == 0) {
dmux_ = (PortClassifier*)TclObject::lookup(argv[2]);
if (dmux_ == 0) {
fprintf(stderr, "%s: %s lookup of %s failed/n", __FILE__, argv[1], argv[2]);
return TCL_ERROR;
}
return TCL_OK;
}
// Obtains corresponding tracer
else if (strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) {
logtarget_ = (Trace*)TclObject::lookup(argv[2]);
if (logtarget_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
// Pass the command to the base class
return Agent::command(argc, argv);
}
void
Protoname::recv(Packet* p, Handler* h) {
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
if (ih->saddr() == ra_addr()) {
// If there exists a loop, must drop the packet
if (ch->num_forwards() > 0) {
drop(p, DROP_RTR_ROUTE_LOOP);
return;
}
// else if this is a packet I am originating, must add IP header
else if (ch->num_forwards() == 0)
ch->size() += IP_HDR_LEN;
}
// If it is a protoname packet, must process it
if (ch->ptype() == PT_PROTONAME)
recv_protoname_pkt(p);
// Otherwise, must forward the packet (unless TTL has reached zero)
else {
ih->ttl_--;
if (ih->ttl_ == 0) {
drop(p, DROP_RTR_TTL);
return;
}
forward_data(p);
}
}
void
Protoname::recv_protoname_pkt(Packet* p) {
struct hdr_ip* ih = HDR_IP(p);
struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
// All routing messages are sent from and to port RT_PORT,
// so we check it.
assert(ih->sport() == RT_PORT);
assert(ih->dport() == RT_PORT);
/* ... processing of protoname packet ... */
// Release resources
Packet::free(p);
}
void
Protoname::send_protoname_pkt() {
Packet* p = allocpkt();
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
ph->pkt_src() = ra_addr();
ph->pkt_len() = 7;
ph->pkt_seq_num() = seq_num_++;
ch->ptype() = PT_PROTONAME;
ch->direction() = hdr_cmn::DOWN;
ch->size() = IP_HDR_LEN + ph->pkt_len();
ch->error() = 0;
ch->next_hop() = IP_BROADCAST;
ch->addr_type() = NS_AF_INET;
ih->saddr() = ra_addr();
ih->daddr() = IP_BROADCAST;
ih->sport() = RT_PORT;
ih->dport() = RT_PORT;
ih->ttl() = IP_DEF_TTL;
Scheduler::instance().schedule(target_, p, JITTER);
}
void
Protoname::reset_protoname_pkt_timer() {
pkt_timer_.resched((double)5.0);
}
void
Protoname::forward_data(Packet* p) {
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
if (ch->direction() == hdr_cmn::UP &&
((u_int32_t)ih->daddr() == IP_BROADCAST || ih->daddr() == ra_addr())) {
dmux_->recv(p, 0);
return;
}
else {
ch->direction() = hdr_cmn::DOWN;
ch->addr_type() = NS_AF_INET;
if ((u_int32_t)ih->daddr() == IP_BROADCAST)
ch->next_hop() = IP_BROADCAST;
else {
nsaddr_t next_hop = rtable_.lookup(ih->daddr());
if (next_hop == IP_BROADCAST) {
debug("%f: Agent %d can not forward a packet destined to %d/n",
CURRENT_TIME,
ra_addr(),
ih->daddr());
drop(p, DROP_RTR_NO_ROUTE);
return;
}
else
ch->next_hop() = next_hop;
}
Scheduler::instance().schedule(target_, p, 0.0);
}
}
(3)protoname_pkt.h
#ifndef __protoname_pkt_h__
#define __protoname_pkt_h__
#include <packet.h>
#define HDR_PROTONAME_PKT(p) hdr_protoname_pkt::access(p)
struct hdr_protoname_pkt {
nsaddr_t pkt_src_; // Node which originated this packet
u_int16_t pkt_len_; // Packet length (in bytes)
u_int8_t pkt_seq_num_; // Packet sequence number
inline nsaddr_t& pkt_src() { return pkt_src_; }
inline u_int16_t& pkt_len() { return pkt_len_; }
inline u_int8_t& pkt_seq_num() { return pkt_seq_num_; }
static int offset_;
inline static int& offset() { return offset_; }
inline static hdr_protoname_pkt* access(const Packet* p) {
return (hdr_protoname_pkt*)p->access(offset_);
}
};
#endif
(4)protoname_rtable.h
#ifndef __protoname_rtable_h__
#define __protoname_rtable_h__
#include <trace.h>
#include <map>
typedef std::map<nsaddr_t, nsaddr_t> rtable_t;
class protoname_rtable {
rtable_t rt_;
public:
protoname_rtable();
void print(Trace*);
void clear();
void rm_entry(nsaddr_t);
void add_entry(nsaddr_t, nsaddr_t);
nsaddr_t lookup(nsaddr_t);
u_int32_t size();
};
#endif
(5)protoname_rtable.cc
#include "protoname_rtable.h"
#include "ip.h"
protoname_rtable::protoname_rtable() { }
void
protoname_rtable::print(Trace* out) {
sprintf(out->pt_->buffer(), "P/tdest/tnext");
out->pt_->dump();
for (rtable_t::iterator it = rt_.begin(); it != rt_.end(); it++) {
sprintf(out->pt_->buffer(), "P/t%d/t%d", (*it).first, (*it).second);
out->pt_->dump();
}
}
void
protoname_rtable::clear() {
rt_.clear();
}
void
protoname_rtable::rm_entry(nsaddr_t dest) {
rt_.erase(dest);
}
void
protoname_rtable::add_entry(nsaddr_t dest, nsaddr_t next) {
rt_[dest] = next;
}
nsaddr_t
protoname_rtable::lookup(nsaddr_t dest) {
rtable_t::iterator it = rt_.find(dest);
if (it == rt_.end())
return IP_BROADCAST;
else
return (*it).second;
}
u_int32_t
protoname_rtable::size() {
return rt_.size();
}
step 3:
我们需要对ns2中的一些文件进行修改,来使这个协议在tcl中被调用,
需要修改的文件有以下几个,你可以在ns目录下找到它们:
Common/packet.h
Trace/cmu-trace.h
Trace/cmu-trace.cc
Tcl/lib/ns-packet.tcl
Tcl/lib/ns-default.tcl
Tcl/lib/ns-lib.tcl
Queue/priqueue.cc
Makefile
step4:
需要修改的具体内容(在需要修改的地方添加红色的字)
1.Common/packet.h
(两个需要修改的地方)
1: enum packet_t {
2: PT_TCP,
3: PT_UDP,
4: PT_CBR,
5: /* ... much more packet types ... */
6:
PT_PROTONAME,
7: PT_NTYPE // This MUST be the LAST one
8: };
=======================================
1: p_info() {
2: name_[PT_TCP]= "tcp";
3: name_[PT_UDP]= "udp";
4: name_[PT_CBR]= "cbr";
5: /* ... much more names ... */
6: name_[PT_PROTONAME]= "protoname";
7: }
2.Trace/cmu-trace.h
(一个)
1: class CMUTrace : public Trace {
2: /* ... definitions ... */
3: private:
4: /* ... */
5: void format_aodv(Packet *p, int offset);
6: void format_protoname(Packet *p, int offset);
7: };
3.Trace/cmu-trace.cc
(三个,先在最上面加头文件,在找一个合适的地方加函数)
1: #include <protoname/protoname_pkt.h>
2:
3: /* ... */
4:
5: void
6: CMUTrace::format_protoname(Packet *p, int offset)
7: {
8: struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
9:
10: if (pt_->tagged()) {
11: sprintf(pt_->buffer() + offset,
12: "-protoname:o %d -protoname:s %d -protoname:l %d ",
13: ph->pkt_src(),
14: ph->pkt_seq_num(),
15: ph->pkt_len());
16: }
17: else if (newtrace_) {
18: sprintf(pt_->buffer() + offset,
19: "-P protoname -Po %d -Ps %d -Pl %d ",
20: ph->pkt_src(),
21: ph->pkt_seq_num(),
22: ph->pkt_len());
23: }
24: else {
25: sprintf(pt_->buffer() + offset,
26: "[protoname %d %d %d] ",
27: ph->pkt_src(),
28: ph->pkt_seq_num(),
29: ph->pkt_len());
30: }
31: }
=========================================
1: void
2: CMUTrace::format(Packet* p, const char *why)
3: {
4: /* ... */
5: case PT_PING:
6: break;
7:
8: case PT_PROTONAME:
9: format_protoname(p, offset);
10: break;
11:
12: default:
13: /* ... */
14: }
4.Tcl/lib/ns-packet.tcl
(一个)
1: foreach prot {
2: Protoname
3: AODV
4: ARP
5: # ...
6: NV
7: } {
8: add-packet-header $prot
9: }
5.Tcl/lib/ns-default.tcl
(一个)
1: # ...
2: # Defaults defined for Protoname
3: Agent/Protoname set accessible_var_ true
6.Tcl/lib/ns-lib.tcl
(两个)
1: Simulator instproc create-wireless-node args {
2: # ...
3: switch -exact $routingAgent_ {
4: Protoname {
5: set ragent [$self create-protoname-agent $node]
6: }
7: # ...
8: }
9: # ...
10: }
=======================================
1: Simulator instproc create-protoname-agent { node } {
2: # Create Protoname routing agent
3: set ragent [new Agent/Protoname [$node node-addr]]
4: $self at 0.0 "$ragent start"
5: $node set ragent_ $ragent
6: return $ragent
7: }
7.Queue/priqueue.cc
(一个)
1: void
2: PriQueue::recv(Packet *p, Handler *h)
3: {
4: struct hdr_cmn *ch = HDR_CMN(p);
5:
6: if (Prefer_Routing_Protocols) {
7:
8: switch(ch->ptype()) {
9: case PT_DSR:
10: case PT_MESSAGE:
11: case PT_TORA:
12: case PT_AODV:
13: case PT_PROTONAME:
14: recvHighPriority(p, h);
15: break;
16:
17: default:
18: Queue::recv(p, h);
19: }
20: }
21: else {
22: Queue::recv(p, h);
23: }
24: }
8.Makefile
(一个)
1: OBJ_CC = /
2: tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o /
3: # ...
4: protoname/protoname.o protoname/protoname_rtable.o /
5: # ...
6: $(OBJ_STL)
step 5:
编译
在ns目录下输入下名命令进行编译:
$ make clean
$ touch common/packet.cc
$ make
到这里,我们添加新协议的过程就结束了。
step 6:
测试
协议写完了,要用一个tcl对它进行测试,下面这是个很简单的而且可用的例子
set ns [new Simulator]
$ns node-config -Routing protoname
set nf [open out.nam w]
$ns namtrace-all $nf
set nd [open out.tr w]
$ns trace-all $nd
proc finish {} {
global ns nf nd
$ns flush-trace
close $nf
close $nd
exec nam out.nam &
exit 0
}
for {set i 0} {$i < 7} {incr i} {set n($i) [$ns node] }
for {set i 0} {$i < 7} {incr i} {
$ns duplex-link $n($i) $n([expr ($i+1)%7]) 1Mb 10ms DropTail
}
set udp0 [new Agent/UDP]
$ns attach-agent $n(0) $udp0
set cbr0 [new Application/Traffic/CBR]
$cbr0 set packetSize_ 500
$cbr0 set interval_ 0.005
$cbr0 attach-agent $udp0
set null0 [new Agent/Null]
$ns attach-agent $n(3) $null0
$ns connect $udp0 $null0
$ns at 0.5 "$cbr0 start"
$ns rtmodel-at 1.0 down $n(1) $n(2)
$ns rtmodel-at 2.0 up $n(1) $n(2)
$ns at 4.5 "$cbr0 stop"
$ns at 5.0 "finish"
$ns run
1、在ns-2.x目录下创建协议名(CTAgg)目录,此目录中包含CTAgg.h CTAgg.cc CTAgg_pkt.h CTAgg_rtable.h CTAgg_rtable.cc五个文件。
2、撰写CTAgg_pkt.h,对数据包类型进行声明(修改common/pakcet.h文件中的枚举类型packet_t和类p_info)。绑定包头到TCL接口。
TAgg_rtable.cc五个文件。
3、撰写CTAgg.h。
4、撰写CTAgg.cc。
5、撰写CTAgg_rtable.h。操作路由表函数的声明。
.h CTAgg.cc CTAgg_pk
6、撰写CTAgg_rtable.cc。操作路由表函数的实现。
7、跟踪支持,修改trace/cmu-trace.h和trace/cmu-trace.cc。
在CMUTrace类中实现void format_CTAgg(Packet *p, int offset)函数,需要加入#include 。
CTAgg)目录,此目录中包含CTAgg
8、修改TCL库,tcl/lib/ns-packet.tcl中的foreach prot{}
tcl/lib/ns-default.tcl中添加Agent/Protoname set accessible_var_ true
tcl/lib/ns-lib.tcl中的create-wireless-node函数中添加.h CTAgg.cc CTAgg_pk
Protoname {
set ragent [$self create-CTAgg-agent $node]
}t.h CTAgg_rtable.h C
tcl/lib/ns-lib.tcl中添加函数create-CTAgg-agent
9、修改队列优先级,修改queue/priqueue.cc中的recv()函数。
10、修改Makefile。
最近正在研究怎样把自己新写的协议添加到NS2中去,正好借鉴了一些朋友的文章,现在整理下来,以便以后参考,也希望能给广大博友一些方便。
step 1:
比如我们新建的协议名字就叫做protoname
,以ns2.27平台为例,我们在ns2.27目录下建立一个protoname目录。此目录包含protoname.h,protoname.cc,protoname_pkt.h,protoname_rtable.h,
protoname_rtable.cc
五个文件。
其中五个文件的具体功能和作用如下:
(1)protoname.h 定义必要的计时器和路由代理
(2)protoname.cc 执行计时器、路由代理和Tcl文件
(3)protoname_pkt.h 声明protoname路由协议需要在无线自组网节点交换的数据包
(4)protoname_rtable.h 声明我们自己的路由选择表
(5)protoname_rtable.cc 执行路由选择表
step 2:
相应文件的代码
(1)protoname.h
#ifndef __protoname_h__
#define __protoname_h__
// 下面包含一些需要的头文件
#include "protoname_pkt.h" //数据包报头
#include "protoname_rtable.h"
#include <agent.h> //代理基本类
#include <packet.h> //数据包类
#include <trace.h> //跟踪类,用于在跟踪文件里记录输出的仿真结果
#include <timer-handler.h> //计时器基本类,创建我们自定义的计时器
#include <random.h> //随机类,用于产生伪随机数
#include <classifier-port.h> //端口分类器类,用于淘汰向上层传输的数据包
#include <mobilenode.h>
#include "arp.h"
#include "ll.h"
#include "mac.h"
#include "ip.h"
#include "delay.h"
#define CURRENT_TIME Scheduler::instance().clock() //定义了一个用于得到当前仿真时间的宏
//通过一个调度类的实例完成
#define JITTER (Random::uniform()*0.5) //在0-0.5之间去随机数作为发送数据的延迟时间
class Protoname; // forward declaration
/* Timers */ //自定义计时器发送定时的控制包
class Protoname_PktTimer : public TimerHandler {
public:
Protoname_PktTimer(Protoname* agent) : TimerHandler() {
agent_ = agent;
}
protected:
Protoname* agent_;
virtual void expire(Event* e);
};
/* Agent */ //定义Protoname 类
class Protoname : public Agent {
/* Friends */
friend class Protoname_PktTimer;
/* Private members */ //封装了自身的地址、内状态、路由表、可变的Tcl
//以及一个负责指定输出数量的计数器
nsaddr_t ra_addr_;
//protoname_state state_;
protoname_rtable rtable_;
int accesible_var_; //用来读取Tcl代码或脚本语言
u_int8_t seq_num_;
protected:
MobileNode* node_;
PortClassifier* dmux_; // For passing packets up to agents.端口分类器
Trace* logtarget_; // For logging.跟踪器
Protoname_PktTimer pkt_timer_; // Timer for sending packets.自定义计时器
//内部属性
inline nsaddr_t& ra_addr() { return ra_addr_; }
//inline protoname_state& state() { return state_; }
inline int& accessible_var() { return accesible_var_; }
void forward_data(Packet*); //数据包被正确传输的目的地
void recv_protoname_pkt(Packet*);
void send_protoname_pkt();
void reset_protoname_pkt_timer();
public:
Protoname(nsaddr_t);
int command(int, const char*const*);
void recv(Packet*, Handler*);
//void mac_failed(Packet*);
};
#endif
2)protoname.cc
#include "protoname.h"
#include "protoname_pkt.h"
#include <random.h>
#include <cmu-trace.h>
#include <iostream>
int hdr_protoname_pkt::offset_;
static class ProtonameHeaderClass : public PacketHeaderClass {
public:
ProtonameHeaderClass() : PacketHeaderClass("PacketHeader/Protoname", sizeof(hdr_protoname_pkt)) {
bind_offset(&hdr_protoname_pkt::offset_);
}
} class_rtProtoProtoname_hdr;
static class ProtonameClass : public TclClass {
public:
ProtonameClass() : TclClass("Agent/Protoname") {}
TclObject* create(int argc, const char*const* argv) {
assert(argc == 5);
return (new Protoname((nsaddr_t) Address::instance().str2addr(argv[4])));
}
} class_rtProtoProtoname;
void
Protoname_PktTimer::expire(Event* e) {
agent_->send_protoname_pkt();
agent_->reset_protoname_pkt_timer();
}
Protoname::Protoname(nsaddr_t id) : Agent(PT_PROTONAME), pkt_timer_(this) {
bind_bool("accesible_var_", &accesible_var_);
ra_addr_ = id;
node_ = (MobileNode*)Node::get_node_by_address(id);
}
int
Protoname::command(int argc, const char*const* argv) {
if (argc == 2) {
if (strcasecmp(argv[1], "start") == 0) {
pkt_timer_.resched(0.0);
return TCL_OK;
}
else if (strcasecmp(argv[1], "print_rtable") == 0) {
if (logtarget_ != 0) {
sprintf(logtarget_->pt_->buffer(), "P %f _%d_ Routing Table", CURRENT_TIME, ra_addr());
logtarget_->pt_->dump();
rtable_.print(logtarget_);
}
else {
fprintf(stdout, "%f _%d_ If you want to print this routing table "
"you must create a trace file in your tcl script", CURRENT_TIME, ra_addr());
}
return TCL_OK;
}
}
else if (argc == 3) {
// Obtains corresponding dmux to carry packets to upper layers
if (strcmp(argv[1], "port-dmux") == 0) {
dmux_ = (PortClassifier*)TclObject::lookup(argv[2]);
if (dmux_ == 0) {
fprintf(stderr, "%s: %s lookup of %s failed/n", __FILE__, argv[1], argv[2]);
return TCL_ERROR;
}
return TCL_OK;
}
// Obtains corresponding tracer
else if (strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) {
logtarget_ = (Trace*)TclObject::lookup(argv[2]);
if (logtarget_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
// Pass the command to the base class
return Agent::command(argc, argv);
}
void
Protoname::recv(Packet* p, Handler* h) {
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
if (ih->saddr() == ra_addr()) {
// If there exists a loop, must drop the packet
if (ch->num_forwards() > 0) {
drop(p, DROP_RTR_ROUTE_LOOP);
return;
}
// else if this is a packet I am originating, must add IP header
else if (ch->num_forwards() == 0)
ch->size() += IP_HDR_LEN;
}
// If it is a protoname packet, must process it
if (ch->ptype() == PT_PROTONAME)
recv_protoname_pkt(p);
// Otherwise, must forward the packet (unless TTL has reached zero)
else {
ih->ttl_--;
if (ih->ttl_ == 0) {
drop(p, DROP_RTR_TTL);
return;
}
forward_data(p);
}
}
void
Protoname::recv_protoname_pkt(Packet* p) {
struct hdr_ip* ih = HDR_IP(p);
struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
// All routing messages are sent from and to port RT_PORT,
// so we check it.
assert(ih->sport() == RT_PORT);
assert(ih->dport() == RT_PORT);
/* ... processing of protoname packet ... */
// Release resources
Packet::free(p);
}
void
Protoname::send_protoname_pkt() {
Packet* p = allocpkt();
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
ph->pkt_src() = ra_addr();
ph->pkt_len() = 7;
ph->pkt_seq_num() = seq_num_++;
ch->ptype() = PT_PROTONAME;
ch->direction() = hdr_cmn::DOWN;
ch->size() = IP_HDR_LEN + ph->pkt_len();
ch->error() = 0;
ch->next_hop() = IP_BROADCAST;
ch->addr_type() = NS_AF_INET;
ih->saddr() = ra_addr();
ih->daddr() = IP_BROADCAST;
ih->sport() = RT_PORT;
ih->dport() = RT_PORT;
ih->ttl() = IP_DEF_TTL;
Scheduler::instance().schedule(target_, p, JITTER);
}
void
Protoname::reset_protoname_pkt_timer() {
pkt_timer_.resched((double)5.0);
}
void
Protoname::forward_data(Packet* p) {
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_ip* ih = HDR_IP(p);
if (ch->direction() == hdr_cmn::UP &&
((u_int32_t)ih->daddr() == IP_BROADCAST || ih->daddr() == ra_addr())) {
dmux_->recv(p, 0);
return;
}
else {
ch->direction() = hdr_cmn::DOWN;
ch->addr_type() = NS_AF_INET;
if ((u_int32_t)ih->daddr() == IP_BROADCAST)
ch->next_hop() = IP_BROADCAST;
else {
nsaddr_t next_hop = rtable_.lookup(ih->daddr());
if (next_hop == IP_BROADCAST) {
debug("%f: Agent %d can not forward a packet destined to %d/n",
CURRENT_TIME,
ra_addr(),
ih->daddr());
drop(p, DROP_RTR_NO_ROUTE);
return;
}
else
ch->next_hop() = next_hop;
}
Scheduler::instance().schedule(target_, p, 0.0);
}
}
(3)protoname_pkt.h
#ifndef __protoname_pkt_h__
#define __protoname_pkt_h__
#include <packet.h>
#define HDR_PROTONAME_PKT(p) hdr_protoname_pkt::access(p)
struct hdr_protoname_pkt {
nsaddr_t pkt_src_; // Node which originated this packet
u_int16_t pkt_len_; // Packet length (in bytes)
u_int8_t pkt_seq_num_; // Packet sequence number
inline nsaddr_t& pkt_src() { return pkt_src_; }
inline u_int16_t& pkt_len() { return pkt_len_; }
inline u_int8_t& pkt_seq_num() { return pkt_seq_num_; }
static int offset_;
inline static int& offset() { return offset_; }
inline static hdr_protoname_pkt* access(const Packet* p) {
return (hdr_protoname_pkt*)p->access(offset_);
}
};
#endif
(4)protoname_rtable.h
#ifndef __protoname_rtable_h__
#define __protoname_rtable_h__
#include <trace.h>
#include <map>
typedef std::map<nsaddr_t, nsaddr_t> rtable_t;
class protoname_rtable {
rtable_t rt_;
public:
protoname_rtable();
void print(Trace*);
void clear();
void rm_entry(nsaddr_t);
void add_entry(nsaddr_t, nsaddr_t);
nsaddr_t lookup(nsaddr_t);
u_int32_t size();
};
#endif
(5)protoname_rtable.cc
#include "protoname_rtable.h"
#include "ip.h"
protoname_rtable::protoname_rtable() { }
void
protoname_rtable::print(Trace* out) {
sprintf(out->pt_->buffer(), "P/tdest/tnext");
out->pt_->dump();
for (rtable_t::iterator it = rt_.begin(); it != rt_.end(); it++) {
sprintf(out->pt_->buffer(), "P/t%d/t%d", (*it).first, (*it).second);
out->pt_->dump();
}
}
void
protoname_rtable::clear() {
rt_.clear();
}
void
protoname_rtable::rm_entry(nsaddr_t dest) {
rt_.erase(dest);
}
void
protoname_rtable::add_entry(nsaddr_t dest, nsaddr_t next) {
rt_[dest] = next;
}
nsaddr_t
protoname_rtable::lookup(nsaddr_t dest) {
rtable_t::iterator it = rt_.find(dest);
if (it == rt_.end())
return IP_BROADCAST;
else
return (*it).second;
}
u_int32_t
protoname_rtable::size() {
return rt_.size();
}
step 3:
我们需要对ns2中的一些文件进行修改,来使这个协议在tcl中被调用,
需要修改的文件有以下几个,你可以在ns目录下找到它们:
Common/packet.h
Trace/cmu-trace.h
Trace/cmu-trace.cc
Tcl/lib/ns-packet.tcl
Tcl/lib/ns-default.tcl
Tcl/lib/ns-lib.tcl
Queue/priqueue.cc
Makefile
step4:
需要修改的具体内容(在需要修改的地方添加红色的字)
1.Common/packet.h
(两个需要修改的地方)
1: enum packet_t {
2: PT_TCP,
3: PT_UDP,
4: PT_CBR,
5: /* ... much more packet types ... */
6:
PT_PROTONAME,
7: PT_NTYPE // This MUST be the LAST one
8: };
=======================================
1: p_info() {
2: name_[PT_TCP]= "tcp";
3: name_[PT_UDP]= "udp";
4: name_[PT_CBR]= "cbr";
5: /* ... much more names ... */
6: name_[PT_PROTONAME]= "protoname";
7: }
2.Trace/cmu-trace.h
(一个)
1: class CMUTrace : public Trace {
2: /* ... definitions ... */
3: private:
4: /* ... */
5: void format_aodv(Packet *p, int offset);
6: void format_protoname(Packet *p, int offset);
7: };
3.Trace/cmu-trace.cc
(三个,先在最上面加头文件,在找一个合适的地方加函数)
1: #include <protoname/protoname_pkt.h>
2:
3: /* ... */
4:
5: void
6: CMUTrace::format_protoname(Packet *p, int offset)
7: {
8: struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);
9:
10: if (pt_->tagged()) {
11: sprintf(pt_->buffer() + offset,
12: "-protoname:o %d -protoname:s %d -protoname:l %d ",
13: ph->pkt_src(),
14: ph->pkt_seq_num(),
15: ph->pkt_len());
16: }
17: else if (newtrace_) {
18: sprintf(pt_->buffer() + offset,
19: "-P protoname -Po %d -Ps %d -Pl %d ",
20: ph->pkt_src(),
21: ph->pkt_seq_num(),
22: ph->pkt_len());
23: }
24: else {
25: sprintf(pt_->buffer() + offset,
26: "[protoname %d %d %d] ",
27: ph->pkt_src(),
28: ph->pkt_seq_num(),
29: ph->pkt_len());
30: }
31: }
=========================================
1: void
2: CMUTrace::format(Packet* p, const char *why)
3: {
4: /* ... */
5: case PT_PING:
6: break;
7:
8: case PT_PROTONAME:
9: format_protoname(p, offset);
10: break;
11:
12: default:
13: /* ... */
14: }
4.Tcl/lib/ns-packet.tcl
(一个)
1: foreach prot {
2: Protoname
3: AODV
4: ARP
5: # ...
6: NV
7: } {
8: add-packet-header $prot
9: }
5.Tcl/lib/ns-default.tcl
(一个)
1: # ...
2: # Defaults defined for Protoname
3: Agent/Protoname set accessible_var_ true
6.Tcl/lib/ns-lib.tcl
(两个)
1: Simulator instproc create-wireless-node args {
2: # ...
3: switch -exact $routingAgent_ {
4: Protoname {
5: set ragent [$self create-protoname-agent $node]
6: }
7: # ...
8: }
9: # ...
10: }
=======================================
1: Simulator instproc create-protoname-agent { node } {
2: # Create Protoname routing agent
3: set ragent [new Agent/Protoname [$node node-addr]]
4: $self at 0.0 "$ragent start"
5: $node set ragent_ $ragent
6: return $ragent
7: }
7.Queue/priqueue.cc
(一个)
1: void
2: PriQueue::recv(Packet *p, Handler *h)
3: {
4: struct hdr_cmn *ch = HDR_CMN(p);
5:
6: if (Prefer_Routing_Protocols) {
7:
8: switch(ch->ptype()) {
9: case PT_DSR:
10: case PT_MESSAGE:
11: case PT_TORA:
12: case PT_AODV:
13: case PT_PROTONAME:
14: recvHighPriority(p, h);
15: break;
16:
17: default:
18: Queue::recv(p, h);
19: }
20: }
21: else {
22: Queue::recv(p, h);
23: }
24: }
8.Makefile
(一个)
1: OBJ_CC = /
2: tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o /
3: # ...
4: protoname/protoname.o protoname/protoname_rtable.o /
5: # ...
6: $(OBJ_STL)
step 5:
编译
在ns目录下输入下名命令进行编译:
$ make clean
$ touch common/packet.cc
$ make
到这里,我们添加新协议的过程就结束了。
step 6:
测试
协议写完了,要用一个tcl对它进行测试,下面这是个很简单的而且可用的例子
set ns [new Simulator]
$ns node-config -Routing protoname
set nf [open out.nam w]
$ns namtrace-all $nf
set nd [open out.tr w]
$ns trace-all $nd
proc finish {} {
global ns nf nd
$ns flush-trace
close $nf
close $nd
exec nam out.nam &
exit 0
}
for {set i 0} {$i < 7} {incr i} {set n($i) [$ns node] }
for {set i 0} {$i < 7} {incr i} {
$ns duplex-link $n($i) $n([expr ($i+1)%7]) 1Mb 10ms DropTail
}
set udp0 [new Agent/UDP]
$ns attach-agent $n(0) $udp0
set cbr0 [new Application/Traffic/CBR]
$cbr0 set packetSize_ 500
$cbr0 set interval_ 0.005
$cbr0 attach-agent $udp0
set null0 [new Agent/Null]
$ns attach-agent $n(3) $null0
$ns connect $udp0 $null0
$ns at 0.5 "$cbr0 start"
$ns rtmodel-at 1.0 down $n(1) $n(2)
$ns rtmodel-at 2.0 up $n(1) $n(2)
$ns at 4.5 "$cbr0 stop"
$ns at 5.0 "finish"
$ns run
相关文章推荐
- 在NS中添加自己编写新协议的步骤
- 如何在NS-2 AODV协议中添加一种新的数据包类型[转载]
- 为一个驱动添加Android中间层的步骤
- Linux netlink之添加一个简单协议
- NS2:添加一个新的自写协议的方法
- 如何在NS-2 AODV协议中添加一种新的数据包类型
- ns-2.31 下实现 mflood协议的添加
- 为一个驱动添加Android中间层的步骤
- 如何在NS-2中添加协议[转载]
- 为一个驱动添加Android中间层的步骤
- 为一个驱动添加Android中间层的步骤
- [翻译]NS下添加新协议
- [翻译]NS下添加新协议
- centos 7中添加一个新用户并授权的步骤详解
- Arcgis Engine 添加一个Symbol符号样式步骤
- 在NS2中添加一个新的协议
- mfc中添加一个自定义函数步骤
- 添加一个文档模板的步骤
- NS-2.35添加MFlood协议
- [翻译]NS下添加新协议