Este é o Howto de implementação do LAR no NS(Autor: André Mota).

 

Observações:

Este Howto foi criado durante a implementação do LAR e contem trechos que não estão na documentação oficial, ou seja foram testados experimentalmente e podem mudar.
Por enquanto todos os nodos estão se comunicando apenas por flooding. O algoritmo em si ainda não foi implementado, mas esta carcaça pode ser usada para implementar outros algoritmos.
Os arquivos referentes ao ns serão referenciados como ns/*, e os arquivos do código do LAR serão referenciados como lar/*.
 Sempre que for necessário indicar a inclusão de uma linha de código em um arquivo existente, a linha a ser inserida será indicada por setas ( -> ), e o resto do código será indicada para contexto.
 

1. No arquivo ns/packet.h:


Na enumeração:

enum packet_t {
   PT_TCP,
   PT_UDP,
   PT_CBR,
   ...
-> PT_LAR, <-

   PT_NTYPE // This MUST be the LAST one
};

Inclua linha indicada, para definir um novo tipo de pacote.
E logo abaixo:

class p_info {
 public:
   p_info() {
   name_[PT_TCP]= "tcp";
   name_[PT_UDP]= "udp";
   name_[PT_CBR]= "cbr";
   ...
   -> name_[PT_LAR]="LAR"; <-

   name_[PT_NTYPE]= "undefined";
 
 
 

2. No arquivo ns/tcl/lib/ns-packet.tcl, inclua a linha indicada


foreach pair {
   { Common off_cmn_ }
   { Mac off_mac_ }
   { Mac802_11 off_mac802_11_ }
   ...
   { Ping off_ping_}
-> { LAR off_lar_} <-
   } {
   ...
 

Estas duas modificações são necessárias para o NS reconhecer o formato
do pacote do LAR.
 
 

3. Reconhecimento do LAR como um protocolo de roteamento adhoc.

Para isto, e' necessário modificar o arquivo ns/tcl/lib/ns-lib.tcl. As modificações são:
 

3.1 Na função


Simulator instproc create-wireless-node { args } {
   ...
   switch -exact $routingAgent_ {
      ...
   -> LAR {
   -> set ragent [$self create-lar-agent $node]
   -> }
      ...
   }
 

3.2 Inclua a funcao


-> Simulator instproc create-lar-agent { node } {
->
-> # Create a dsdv routing agent for this node
->
-> set ragent [new Agent/LAR]
->
-> ## setup address (supports hier-addr) for lar agent
-> ## and mobilenode
-> set addr [$node node-addr]
->
-> $ragent addr $addr
-> $ragent node $node
->
-> if [Simulator set mobile_ip_] {
-> $ragent port-dmux [$node set dmux_]
-> }
-> $node addr $addr
-> $node set ragent_ $ragent
->
-> #delay till after add interface
->
-> $self at 0.0 "$ragent start-lar" ;# start updates
->
-> return $ragent
-> }
 

4. Inclusão do código do LAR no NS.


Para isto, inclua no arquivo ns/Makefile:

OBJ_CC = \
   random.o rng.o ranvar.o misc.o timer-handler.o \
   scheduler.o object.o \
   packet.o ip.o route.o connector.o ttl.o \
   ...
-> /home/ns/lar/lar.o /home/ns/lar/lar_routing_table.o <-

Onde está ultima linha contem os arquivos objetos do código.

Obs: O Makefile do ns ira automaticamente compilar os arquivos
fontes indicados acima. Digamos que no Makefile esteja:
OBJ_CC = teste1.o ...

O Makefile ira' tentar compilar o arquivo teste1.cc para
gerar o arquivo objeto teste1.o.
 
 

5. Código Principal

Finalmente, deve-se criar os arquivos contendo a implementação do LAR. Estes arquivos se chamarão lar.cc e lar.h. A principio, teremos os arquivos auxiliares lar_routing.table.cc e .h.
Vamos descrever agora o código destes arquivos.

lar_routing_table.cc implementa uma tabela de roteamento com procura por funcao HASH, e com os campos de endereco, rota e distancia.
Ja' em lar.cc e lar.h o bicho pega. E' aqui que esta' quase todo o código do algoritmo de roteamento. Vamos descrever então estes arquivos.
 

5.1 lar.cc

5.1.1

A classe estática LarHeaderClass registra o pacote do LAR do NS, e define o tamanho Maximo de seu cabeçalho:

static class LarHeaderClass : public PacketHeaderClass {
public:
LarHeaderClass() : PacketHeaderClass("PacketHeader/LAR",
MAX3(sizeof(hdr_lar_route_request),
sizeof(hdr_lar_route_response),
sizeof(hdr_lar_data)) ) {}
} class_larhdr;
 

5.1.2

A classe estática LarClass registra o LAR como um agente do NS, vinculando o com sua versão em OTCL

static class LarClass : public TclClass {
public:
  LarClass() : TclClass("Agent/LAR") {}
  TclObject* create(int, const char*const*) {
    return (new LarAgent());
  }
} class_lar;
 

5.1.3

Agora, devemos criar uma nova classe, LarAgent, derivada de Agent:
Seu construtor será:

LarAgent::LarAgent() : Agent(PT_LAR), ll_queue (0), seqno_ (0),
  myaddr_ (0), subnet_ (0), node_ (0), port_dmux_(0),
  periodic_callback_ (0), be_random_ (1),
  use_mac_ (0), verbose_ (1), trace_wst_ (0), lasttup_ (-10)
{
  bind("off_lar_", &off_lar_);
}

A função bind associa a propriedade da classe off_lar_, com a variavel em OTcl off_lar_.
 

5.1.4

O método
int LarAgent::command(int argc, const char*const* argv);

e' necessário para que a nova classe possa aceitar comandas do OTcl.
 

5.1.5

O método void LarAgent::recv(Packet* pkt, Handler *)

e' talvez um dos mais importantes.
Ele recebe, tanto da camada superior, quanto da camada inferior, os pacotes destinados ao novo e originados do nodo.
O roteamento em si' e' realizado aqui. Baseado nas informações do cabeçalho, este método deve decidir
se vai retransmitir ou nao o pacote.
 

5.1.6


A função

static void mac_callback (Packet * p, void *arg);

e' chamada quando ha' um erro de transmissão detectada pela camada de enlace.
Para ativar a função callback devemos definir no cabeçalho padrão de cada pacote que iremos enviar:

cmh->xmit_failure_ = mac_callback;
cmh->xmit_failure_data_ = this;

A primeira linha define a função mac_callback como a função a ser chamada na ocorrência de erro.
A segunda linha passa como argumento a instancia da classe LarAgent, ou seja, o nodo que originou o pacote.
Desta forma, quando a função mac_callback e' chamada e' possível saber que nodo originou o pacote.
 
 

5.2 lar.h

 

5.2.1

Neste arquivo definimos os formatos dos pacotes utilizados. Esta definição e' feita como uma estrutura:
struct hdr_lar {...};
struct hdr_lar_route_request {...};
struct hdr_lar_route_response {...};
struct hdr_lar_data {...};
 

5.2.2

A classe LarAgent e' definida aqui:
class LarAgent : public Agent {
 public:
  LarAgent();
  int command(int argc, const char*const* argv);
  void recv(Packet*, Handler*);
 protected:
  int off_lar_;

  // update old_rte in routing table to to new_rte
  Trace *tracetarget;       // Trace Target
  PriQueue *ll_queue;       // link level output queue
  int seqno_;               // Sequence number to advertise with...
  int myaddr_;              // My address...

  // Extensions for mixed type simulations using wired and wireless
  // nodes
  char *subnet_;            // My subnet
  MobileNode *node_;        // My node
  // for debugging
  char *address;
  NsObject *port_dmux_;    // my port dmux

  Event *periodic_callback_;           // notify for periodic update

  // Randomness/MAC/logging parameters
  int be_random_;
  int use_mac_;
  int verbose_;
  int trace_wst_;

  // last time a periodic update was sent...
  double lasttup_;  // time of last triggered update
  double next_tup;  // time of next triggered update
  //  Event *trigupd_scheduled; // event marking a scheduled triggered update
  ...
  void startUp(void);

};

  Observe que vários métodos e propriedades são obrigatórios para que o agente funcione corretamente como um protocolo de roteamento adhoc.
 
 

6. Considerações importantes

 

6.1 Para transmitir um pacote:

  Scheduler & s = Scheduler::instance ();
  hdr_ip *iph = (hdr_ip*)pkt->access(off_ip_);
  hdr_cmn *cmh = (hdr_cmn *)pkt->access(off_cmn_);
  hdr_lar_route_response *larrh = (hdr_lar_route_response *)pkt->access(off_lar_);
  ...
  cmh->next_hop_ = larrh->dest.nodes[larrh->d_size - 1];

  ou

  cmh->next_hop_ = IP_BROADCAST;
  ...
  cmh->addr_type_ = NS_AF_INET;
  cmh->xmit_failure_ = mac_callback;
  cmh->xmit_failure_data_ = this;
  cmh->direction() = hdr_cmn::DOWN;
  assert (!cmh->xmit_failure_ || cmh->xmit_failure_ == mac_callback);
 
  s.schedule(target_, pkt, 0.0 /*Random::uniform(0.01)*/);
 

  Lembre-se que nem o cabeçalho IP nem o cabeçalho do LAR foram preenchidos. Este código apenas ressalta alguns pontos importantes.
  A ultima linha realiza a transmissão do pacote. O ultimo argumento especifica em daqui a quanto tempo o pacote devera' ser transmitido.
  0.0 indica imediatamente. Em alguns casos, como flooding, isto poderá causar colisões sistemáticas. Então, a função Random::uniform(faixa), ou alguma outra, devera ser usada para definir um tempo aleatório de espera.
  cmh->next_hop_  define qual nodo será o destinatário imediato (não final) do pacote. IP_BROADCAST indica, obviamente, que todos dentro do alcance receberão o pacote.

  Outro ponto importante e' a definição:   cmh->direction() = hdr_cmn::DOWN;
  Para  assegurar a transmissão correta. Isto não consta na documentação oficial

6.2 Para descartar um pacote


   drop(pkt, _xulambs); // Onde _xulambs é a constante indicando a razão porque o pacote foi descartado

 

Com isso concluímos que o porquinho foi pro mar!