本协议共创建五个文件:protoname.h,protoname.cc,protoname_pkt.h,proto_rtable.h,proto_rtable.cc
第一步:建立协议的数据包头。
1.1 在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_; //生成数据包的源节点
u_int16_t pkt_len_; //数据包的长度(以字节为单位)
u_int8_t pkt_seq_num_; //数据的序列号
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_;}
// Header access methods
static int offset_; // required by PacketHeaderManager
inline static int& offset() { return offset_; }
inline static hdr_protoname_pkt* access(const Packet* p) {
return (hdr_protoname_pkt*) p->access(offset_);
}
};
#endif
1.2 在protoname.cc中,将数据包头绑定到Tcl接口,
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;
第二步:在protoname.h中,声明Protoname类和其它类。
#ifndef __protoname_h__
#define __protoname_h__
#include "protoname_pkt.h" // protoname/protoname_pkt.h定义了我们的数据包头
#include "protoname_rtable.h"
#include <agent.h> // common/agent.h定义了Agent基类
#include <packet.h> // common/packet.h定义了Packet类
#include <trace.h> // trace/trace.h定义了Trace类,用来将模拟结果输入到trace文件中去。
#include <timer-handler.h> // common/timer-handler.h定义了TimerHandler基类,我们利用它创建客观定时器
#include <random.h> // tools/random.h定义了Random类,用来生成伪随机数
#include <classifier/classifier-port.h> //classifier/classifier-port.h 定义了ProtClassifier类,用来传送数据包至上层
#define CURRENT_TIME Scheduler::instance().clock()
#define JITTER (Random::uniform()*0.5)
typedef u_int8_t protoname_state;
class Protoname; //前向声明
class Protoname_PktTimer : public TimerHandler { //声明全局定时器类
public:
Protoname_PktTimer(Protoname* agent) : TimerHandler() {
agent_=agent;
}
protected:
Protoname* agent_;
virtual void expire (Event* e);
};
class Protoname : public Agent { //声明Protoname类
friend class Protoname_PktTimer;
nsaddr_t ra_addr_;
protoname_state state_;
protoname_rtable rtable_;
int accessible_var_;
u_int8_t seq_num_;
protected:
PortClassifier* dmux_; //用来向上传递数据包给代理。
Trace* logtarget_; //For logging
Protoname_PktTimer pkt_timer_; //发送数据包的定时器
inline nsaddr_t& ra_addr() {return ra_addr_;}
inline protoname_state& state() {return state_;}
inline int& accessible_var() {return accessible_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*);
};
#endif
第三步:在protoname.cc中将Protoname类绑定到OTcl。
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;
第四步:在protoname.cc中绑定变量,提供C++的变量给OTcl访问。
Protoname::Protoname (nsaddr_t id): Agent(PT_PROTONAME),pkt_timer_(this) { //在构造函数中进行绑定
bind_bool("accessible_var_",&accessible_var_);
ra_addr_=id;
}
第五步:在protoname.cc中实现全局定时器类的函数。 //根据具体协议可选
void Protoname_PktTimer::expire (Event* e) {
agent_->send_protoname_pkt();
agent_->reset_protoname_pkt_timer();
}
第六步:在protoname.cc中,提供C++的控制命令给OTcl,
int
Protoname::command(int argc, const char*const* argv) {
if(argc == 2) { //此函数是我们的代理从Agent类继承的。
if(strncasecmp(argv[1], "start",2) == 0) {
pkt_timer_.resched(0.0);
return TCL_OK;
}
if(strncasecmp(argv[1], "print_rtable",2) == 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) {
if(strcmp(argv[1], "port-dumx")==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;
}
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;
}
}
return Agent::command(argc, argv);
}
第七步:在protoname.cc中,对接收到的数据进行处理。
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(ch->num_forwards()>0) {
drop(p,DROP_RTR_ROUTE_LOOP);
return;
}
else if (ch->num_forwards()==0) {
ch->size() +=IP_HDR_LEN;
}
}
if (ch->ptype() == PT_PROTONAME)
recv_protoname_pkt(p);
else {
ih->ttl_--;
if (ih->ttl_ == 0) {
drop(p,DROP_RTR_TTL);
return;
}
forward_data(p);
}
}
在NS-2中对数据包进行声明。
a、 在common/packet.h的枚举类型enum packet_t中添加PT_PTOTONAME
b、 在common/packet.h的p_info类中添加name_[PT_PTOTONAME]="Protoname"
修改Tcl库:
a、增加包头,在tcl/lib/ns-packet.tcl中的foreach prot{}中添加Protoname
b、在tcl/lib/ns-default.tcl添加协议变量的缺省值
Agent/Protoname set accessible_var_ true
c、由于此协议要添加一个创建节点的过程,在tcl/lib/ns-lib.tcl中的Simulator instproc create-wireless-node args {}添加
Protoname { set ragent [$self create-protoname-agent $node]}
在tcl/lib/ns-lib.tcl中添加
Simulator instproc create-protoname-agent { node } {
set ragent [new Agent/Protoname [$node node-addr]]
$self at 0.0 "$ragent start"
$node set ragent_ $ragent
return $ragent
}
第八步,在protoname.cc中,实现与协议相关的函数。
此协议中需实现的函数包括recv_protoname_pkt(),send_protoname_pkt(),reset_protoname_pkt_timer(),forward_data()。
第九步,建立协议的路由表。在protoname_rtable.h中声明protname_rtable类,在protoname_rtalbe.cc中实现。
在Makefile中添加:
protoname/protoname.o protoname/protoname_rtable.o \
最后./configure
make clean
make depend
make