带包头路由协议的创建过程(转帖)

本协议共创建五个文件: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

posted on 2013-05-06 15:36  原来...  阅读(385)  评论(0编辑  收藏  举报

导航