UCB/LBNL/VINT Network Simulator - ns (version 2)

 

NS é um simulador de eventos discreto com o objetivo centrado em pesquisas em redes.Ele fornece um suporte substancial para simulações de  TCP, roteamento, e protocolos multicast.

O NS é um variante do REAL network simulator em 1989 e evolui consideravelmente nos ultimos anos. Seu desenvolvimento é um trabalho de cooperação com o VINT project.

Inicialização

Sua inicialização é através do comando 'ns <tclscript>', onde <tclscript> é o nome do script em tcl que define o cenário de simulação. É possivel também iniciar o ns sem nenhum argumento e adiconar os comandos Tcl no shell Tcl. Tudo no ns depende de um script Tcl. O script pode criar alguma saida na stdout, pode escrever um arquivo de trace ou pode inicializar o nam para visualização da simulação.

O NS utiliza um programa, o Nam como visualizador das simulações testadas.

Nam

Programa de Visualização da Simulação

Utiliza os arquivos .nam gerados pelos scripts do NS

TCL

A linguagem script OTcl é a ferramenta principal no uso do Ns.

Exemplos de Codigo TCL

set a 123             ;#Cria uma variavel com nome a e valor 123

nset b $a              ;#Copia o valor de b em a
nset c [expr $b+10]         ;#Calcula o valor entre os colchetes e armazena o resultado em c
nfor {set i 0} {$i < 3} {incr i} {puts $i};# For que imprime o valor de i

Exemplo de script de Simulação com dois nodos fixos

#Cria o objeto simulador

set ns [new Simulator]

 

#Cria o arquivo de trace para o nam

set nf [open out.nam w]

 

#Define que toda a simulação será registrada no out.nam

$ns namtrace-all $nf

 

#Define o procedimento de encerramento que fecha o simulador e abre o nam

proc finish {} {

global ns nf

$ns flush-trace

 

#Fecha o trace file

close $nf

 

#Executa nam com o trace file

exec nam out.nam &

 

exit 0

}

 

#Cria dois nodos. A definição da configuração do Nodo é a padrão

set n0 [$ns node]

set n1 [$ns node]

 

#Cria um link  duplex entre eles, com largura de banda de  1Megabit e delay de 10ms

$ns duplex-link $n0 $n1 1Mb 10ms DropTail

 

#Chama o procedimento finish apos 5 segundos de simulação

$ns at 5.0 "finish"

 

#Executa a simulação

$ns run

Figura 1 - Saida do Nam

Simulação de um Agente para a Comunicação dos nodos

#Cria um agente  CBR (Constant Bit Reate) e vincula ao nodo n0

set cbr0 [new Agent/CBR]

$ns attach-agent $n0 $cbr0

 

#Seta o tamanho do pacote e o intervalo de envio

$cbr0 set packetSize_ 500

$cbr0 set interval_ 0.005

 

#Cria um agente Null , para sincronização de tráfego e vincula ao nodo n1

set null0 [new Agent/Null]

$ns attach-agent $n1 $null0

 

#Conecta os agentes para estabelecer a comunicação 

$ns connect $cbr0 $null0

 

#Faz o schedule dos eventos do agente  CBR 

$ns at 0.5 "$cbr0 start"

$ns at 4.5 "$cbr0 stop"

Figura 2. Saida do Nam. Dois nodos comunicando

 

Modificando a Topologia

set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
set n3 [$ns node]

#Criar o link entre os 4 nodos

$ns duplex-link $n0 $n2 1Mb 10ms DropTail
$ns duplex-link $n1 $n2 1Mb 10ms DropTail
$ns duplex-link $n3 $n2 1Mb 10ms DropTail

# Setar a orientação entre eles


$ns duplex-link-op $n0 $n2 orient right-down 
$ns duplex-link-op $n1 $n2 orient right-up 
$ns duplex-link-op $n2 $n3 orient right 

 

 

Identificando os Pacotes

# Identificação do fluxo de pacotes
# O parametro 'fid_' significa 'flow id'. 
$cbr0 set fid_ 1
$cbr1 set fid_ 2

#Setando a cor dos pacotes
$ns color 1 Blue
$ns color 2 Red



# criando uma topologia maior

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
}

 

# Falha de conexão controlada. A conexão entre os nodos 1 e 2 é interrompida no 

# espaço de tempo de 1 a 2 segundos de simulação

$ns rtmodel-at 1.0 down $n(1) $n(2)
$ns rtmodel-at 2.0 up $n(1) $n(2)

 

# Seta o protocolo de roteamento alternativo

$ns rtproto DV

 

Implementação de Novos protocolos de roteamento

Para a implementação de novos protocolos de roteamento é necessário definir novas classes Agentes, que irão conter o código do novo protocolo, e a classe packet onde serão definidos os novos tipos de pacotes do protocolo.

Agentes

Os agentes representam pontos finais onde os pacotes da camada de rede são construídos ou consumidos, e são usados na implementação de varias camadas. A classe Agente tem uma implementação parcial em OTcl e parte em C++. A implementação em C++ encontra-se nos arquivos  ~ns/agente.cc e ~ns/agent.h e a parte em OTcl está em ~ns/tcl/lib/ns-agent.tcl

Estado do Agente

A Classe Agente em C++ inclui diversos campos que simulam um pacote antes de ser enviado. Estes campos são os seguintes:

 

Addr_  Endereço do Nodo de origem

Dst_     Para onde os pacotes estão sendo enviados

Size_   Tamanho do pacote em bytes

Type_  Tipo de pacote

Prio_    O campo IP de prioridade

Flags _  os flags do pacote

Defttl_ O valor default do ttl

 

Essas variáveis podem ser modificadas em qualquer classe derivada de agente.

 

Métodos

 

A classe Agente suporta a geração e recepção de pacotes. As seguintes funções são responsáveis pôr estas funções  e geralmente não são sobrescritas pelas classes derivadas:

 

Packet* allocpkt()      - Aloca um novo pacote e assinala seus campos. Esta função preenche os seguintes campos em um tipo de pacote normal: uid, ptype, size e os seguintes campos do cabeçalho IP: src,dst,plowid,prio,ttl.  E  também completa de zeros os seguintes Flags do cabeçalho: ecn,pri,usr1,usr2. Qualquer informação extra no pacote deve ser tratada nas funções derivadas de Agente.

 

Packet* allocpkt(int)  - Aloca um novo pacote com o data payload de n bytes e assinala seus campo.

 

As funções a seguir também são definidas na classe Agente, mas devem ser sobrescritas pelas classes que derivam Agente:

 

Void timeout(timeout number)  - Função de controle do timeout

Void recv(Packet*, Handler *)   - Função principal que controla a recepção de pacotes do Agente. Este Esta unção é o ponto de entrada na recepção de pacotes e é invocada pelos outros nodos quando enviam um pacote. Na maioria dos casos os Agentes não fazem uso do segundo argumento( este é o handler do pacote que está enviando o pacote)

 

Usando o OTcl

 

Os agentes são criados através do OTcl e o estado interno do agente pode ser modificado através da função set em TCL. É interessante notar que alguns campos que definem os estados do Agente em TCL só existem em OTCL e não é possível acessa-los a partir do C++.

 

Criação e manipulação dos agentes

 

O processo de criação de um Agente em TCL é o seguinte:

 

Set newtcp[new Agente/TCP]                ; Cria um novo agente ( e sua versão em C++)

$newtcp set window_   20                        ; Seta a janela do agente TCP para 20

$newtcp target $dest                      ; Seta o alvo do Agente, que é implementado na classe Connector

$newtcp set portID_ 1                              ; Existe apenas em TCL

 

 

Métodos em OTcl

 

Os métodos do Agente implementados em OTcl são os seguintes :

 

port                  -Identificador do porto do Agente

dst-port              - Identificador do porto destino

attach-source         - Cria e linka um Objeto Source a um Agente

 

Exemplo: Agentes TCP

 

A classe TCP representa um versão simplificada do Sender TCP. Ela envia dados para um Agente TCPSink e processa os ackknowledgments. Ele possui um objeto separado associado que representa a demanda da aplicação.

 

Criando o Agente

 

O seguinte código OTcl cria um agente TCP e seta seus estados:

 

set tcp [new Agente/TCP]      ;#Cria o agente de envio

$tcp set fid_ 2               ;# seta o flow ID do IP

set sink [new Agente/TCPSink] ;#Cria o agente de recepção

$ns attach-agent $ns0 $tcp    ;# coloca o sender no nodo $n0

$ns attach-agent $ns3 $sink   ;# coloca o receiver no nodo $n3

set ftp [new Application/FTP] ;# Cria um ftp como a aplicacao do alvo

$ftp attach-agent $tcp        ;# Associa o FTp com o sender TCP

$ns at 1.2 “$ftp start”       ;# Ajusta o FTP para iniciar no tempo 1.2 Seg da simulação

 

A instrução new Agetn/TCP resulta na criação do objeto C++TcpAgent. Seu construtor invoca primeiro o construtor da classe base Agente e depois efetua seus proprios bindings.

 

O Agente TcpAgent é inicializado nesse exemplo quando  o FTP recebe a diretiva start no tempo 1.2 Seg. A operação start é definida em ~ns/tcl/lib.ns-source.tcl

 Application/FTP instproc start{}{

                [$self agente] send –1

}

Neste caso a variavel agente está vinculada ao agente TCP e send –1 é analogo a enviar um arquivo extremamente grande. A chamada send faz com que o agente TCP comece a enviar pacotes. Neste caso a função output do Agente TCP efetua as seguintes chamadas:

 

Void TcpAgent::output(int seqno, int reason)

{

              &nbs p; Packet * p=  allocpkt();

Hdr_tcp * tcph = (hdr_tcp*) p->access(off_tcp);

Double now = Scheduler::instance().clock();

tcph->seqno = seqno;

tcph->ts() = now;

Connector::send(p,0);

...

}

Esta rotina primeiro aloca um novo pacote( com seus cabeçalhos e os cabeçalhos IP preenchidos) e depois preenche os campos especificos para o Agente. Para encontrar o cabeçalho TCP no pacote a variavel off_tcp_ deve estar apropriadamente inicializada. O método access da classe Packet retorna o respectivo cabeçalho, o qual é preenchido e o send da classe Conector é chamado para enviar o pacote. O operador de escopo :: do C++  foi utilizado para evitar chamr a funçào send do Agente.

 

No agente que está recebendo os pacotes a entrada é processada através das funções recv() e ack().

 

Criando um novo Agente

 

Para criar um novo Agente é necessário:

 

1.        Decidir quais as caracteristicas a serem derivadas e cria as definiçòes de classe apropriadas. O tipo mais simples de Agente do tipo datagrama não orientado a conexão é o que está definido na classe Agente/UDP. Geradores de trafego podem ser facilmentes conectados a agentes UDP. Para protocolos que desejam usar transporte orientado a conexão(como o TCP) podem usar diversos agentes TCP. Finalmete, se o um novo tipo de protocolo está sendo desenvolvido a melhor escolha é usar a classe Agente como classe base.

2.        Definir os métodos recv() e timetou().  O método recv é responsável pela recepçãp dos pacotes. Caso não seja definido será usado o da classe base( Se a classe Agentfor a classe base, a função recv utilizada será a da classe Connector). O método timeout() é usado para periodicamnete enviar pacotes de request

 

3.        Definir quaisquer timers necessários a classe.

 

4.        Definir as funções em OTcl . Para efetuar isto é necessário estabelecer um mapeamento entre o nome da classe em OTcl e  o objeto que está sendo criado em C++ quando esta classe é instanciada em OTcl.  Por exemplo:

 

Static class ECHOClass : public TclClass{

Public:

ECHOClass(): TclClass(Ägent/ECHO”){}

TclObject* create(int argc, const char*const argv){

         ;        Retunr(new ECHO_Agent());

}
} class_echo;

    Neste exemplo um objeto “class_echo”é criado. Seu construtor coloca o nome “Agente/ECHO” no espaço para o OTcl.  A definição do método create() especifica como o objeto sombra em C++ é criado quando o interpretador em OTcl é instruido para criar um objeto da classe “Agent/ECHO”.

    Após serem criados os objetos, as variáveis em C++ são linkadas as correspondetes em OTcl, de forma que qualquer acesso nessas variáveis em OTcl pode alterar o valor da variavel em C++. Pôr exemplo:


ECHO_Agent::ECHO_Agent(): Agente(PT_ECHO)

{

                bind(“packetSize_”,&size);

                bindtime(“interval_”, &interval_);

}

 

Após a criação dos objetos e o link das variáveis, é possível acessar as funções em C++ a partir do OTcl. Isto é feito através da função command. Exemplo:

 

Int ECHO_Agent::command(int argc, const char*const* argv)

{

         & nbsp;      if(argc==2)

{

         & nbsp;         if(strcmp(argv[1],”start”)==0)

                       timeout(0);

                       return(TCL_OK);

}

         & nbsp;      return(Agent::command(argc,argv));

}

 

5.        O método start em OTcl é interpretado pela função command que idenfica a chamada e a executa. Neste caso ele chama o método timeout que irá inciar a transmissão de pacotes. Caso a função não esteja implementada neste Agente a string é passada para a classe base.

6.        Escrever o código em OTcl especifico para acessar o agente

 

Pacote

 

    Os procedimentos e definições de classes sobre os pacotes estão em  ~ns/tcl/lib/nsd-lib.tcl , ~ns/tcl/lib/ns-packet.tcl e ~ns/packet.h 

    Os objetos na classe Packet são as unidades fundamentais de troca ente os objetos durante a simulação. A classe pacote provê informações sobre como linkar o pacote na lista de pacotes, como referir aos buffers que contém os cabeçalhos do pacote, e como são definidos. Novos protocolos podem definir seus próprios cabeçalhos ou extender

os já existentes.

    Novos pacotes são introduzidos no simulador, pela definição da estrutura em C++ dos campos necessários, definindo uma classe estatica que provê o link em OTcl, e então modificar algumas partes do código de inicialização , assinalando o offset em bytes de cada pacote, informando onde o novo cabeçalho é colocado em relação aos outros campos.

    No desenvolvimento de um novo protocolo, normalmente sempre é necessário especificar um novo tipo de cabeçalho no protocolo. 

 

Adicionando um Novo tipo de Cabeçalho

 

Os passos para criar um novo tipo de pacote são os seguintes:

 

  1. Criar uma nova estrutura e definir os campos

  2. Definir as funções membros para os campos  necessários

  3. Criar uma classe estatica para efetuar a linkagem em OTcl( definir PacketHeader/NovoCabeçalho)

  4. Editar ~ns/tcl/bin/ns-packet.tcl para habilitar o novo formato do pacote 

 

 

Classes de Pacotes

Existem em C++, 4 tipos de classes relevantes para o  uso de pacotes e cabeçalhos de pacotes em geral: Packet,packet_info, PacketHeader e PacketHeaderManager.  A classe Packet define um tipo para todos os pacotes na simulação, em sua subclasse Event que estes pacotes podem ser escalonados. A classe packet_info armazena todas as representações textuais para os nomes dos pacotes. A classe Packet Header provê a classe base para qualquer cabeçalho de pacote configurado. A classe PacketHeaderManager define a classe usada para manipular e coletar os cabeçalhos correntemente configurados. 

 

 

Criando um novo Protocolo no NS

ns_ping.h

#ifndef ns_ping_h
#define ns_ping_h

#include "agent.h"
#include "tclcl.h"
#include "packet.h"
#include "address.h"
#include "ip.h"

/* Definição do Cabeçalho do Pacote*/
struct hdr_ping {
char ret;
double send_time;
};

/* Definição da classe do agente*/
class PingAgent : public Agent {
public:
PingAgent();
int command(int argc, const char*const* argv);
void recv(Packet*, Handler*);
protected:
int off_ping_;
};

Codigo da Classe Ping

static class PingHeaderClass : public PacketHeaderClass {
public:
PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping", 
sizeof(hdr_ping)) {}
} class_pinghdr;


static class PingClass : public TclClass {
public:
PingClass() : TclClass("Agent/Ping") {}
TclObject* create(int, const char*const*) {
return (new PingAgent());
}
} class_ping;

 

Vinculação das variaveis do Objeto em TCL com o objeto em C++

PingAgent::PingAgent() : Agent(PT_PING)
{
bind("packetSize_", &size_);
bind("off_ping_", &off_ping_);
}

A função command

int PingAgent::command(int argc, const char*const* argv)
{
if (argc == 2) {


    if (strcmp(argv[1], "send") == 0) {
           // Criate um novo pacote

            Packet* pkt = allocpkt();
            // Acessa o cabeçalho ping do novo pacote

           hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_);
            // Seta o campothe  field para 0, para o nodo receptor gerar a resposta

            hdr->ret = 0;
           // Armazena o current time no campo 'send_time' 


            hdr->send_time = Scheduler::instance().clock();
          // Envia o pacote

            send(pkt, 0);
        // return TCL_OK indicando o sucesso do envio

        return (TCL_OK);
}
}
// Se o comando não é implementado por esta classe, ele é enviado para a classe mãe que o tratara

return (Agent::command(argc, argv));
}

 

Mudanças necessárias no NS para novo tipo de pacote

Packet.h:

enum packet_t {
PT_TCP,
PT_UDP,
......
// inserir novos tipos de pacotes aqui

PT_TFRC,
PT_TFRC_ACK,
PT_PING, // packet protocol ID for our ping-agent
PT_NTYPE // This MUST be the LAST one
};

 

class p_info {
public:
p_info() {
name_[PT_TCP]= "tcp";
name_[PT_UDP]= "udp";
...........
name_[PT_TFRC]= "tcpFriend";
name_[PT_TFRC_ACK]= "tcpFriendCtl";

name_[PT_PING]="Ping";

name_[PT_NTYPE]= "undefined";
}
.....
}

e executar ' make depend'

No arquivo 'tcl/lib/ns-default.tcl', setar o tamanho do Pacote:

Agent/Ping set packetSize_ 64

No arquivo 'tcl/lib/ns-packet.tcl' incluir o novo tipo de pacote :

{ SRMEXT off_srm_ext_}
{ Ping off_ping_ }} {
set cl PacketHeader/[lindex $pair 0]

E no Makefile incluir 

sessionhelper.o delaymodel.o srm-ssm.o \
srm-topo.o \
ping.o \
$(LIB_DIR)int.Vec.o $(LIB_DIR)int.RVec.o \
$(LIB_DIR)dmalloc_support.o \

 

Para usar o ping no Script :

Agent/Ping instproc recv {from rtt} {
$self instvar node_
puts "node [$node_ id] received ping answer from \
$from with round-trip-time $rtt ms."
}

 Exemplo de script de Simulação com três nodos moveis

#Define Global Variables

# =========================================================
# Define options
#=========================================================
set val(chan) Channel/WirelessChannel ;    # Tipo de canal

set val(prop) Propagation/TwoRayGround ; # Modelo de Propagação do Sinal

set val(ant) Antenna/OmniAntenna ;# Tipo de Antena
set val(ll) LL ;# Tipo da camada de Link

set val(ifq) Queue/DropTail/PriQueue ;# Tipo da fila de pacotes

set val(ifqlen) 50 ;# max packet in ifq
set val(netif) Phy/WirelessPhy ;# Tipo de Interface de rede

set val(mac) Mac/802_11 ;# MAC type
set val(rp) DSDV ;#  Tipo de roteamento ad-hoc 

set val(nn) 2 ;# number of mobilenodes

 

set ns_  [new Simulator] ; cria uma instancia do simulador ns 

set topo [new Topography] ; cria a topology e 

 $topo load_flatgrid 670 670   ; define a area em  670x670 

#Define standard ns/nam trace

set tracefd  [open demo.tr w]

$ns_ trace-all $tracefd

set namtrace [open demo.nam w]

$ns_ namtrace-all-wireless $namtrace 670 670     

#Create  “God”

set god_ [create-god 3]

# God é usado para armazenar um array com o menor numero de hops entre dois nodos

$ns_ at 899.00 “$god_ setdist 2 3 1”

 

#Definição de um nodo movel

$ns_ node-config 

        -adhocRouting DSDV or DSR or TORA #

      -llType LL \

     -macType Mac/802_11\

     -ifqLen 50 \

     -ifqType Queue/DropTail/PriQueue \

     -antType Antenna/OmniAntenna \

     -propType Propagation/TwoRayGround \

     -phyType Phy/WirelessPhy \

     -channelType Channel/WirelessChannel \

     -topoInstance $topo

     -agentTrace ON \

     -routerTrace OFF \

     -macTrace OFF

 

#define o modelo de energia do nodo

$ns_ node-config -energyModel EnergyModel

                        -initialEnergy 100.0

         -txPower 0.6

  -rxPower 0.2

 

#Cria um nodo móvel e coloca -o no canal

set node [$ns_ node]

$node random-motion 0 ;# disable random motion

# Loop para criar 3 nodos

for {set i < 0} {$i<3} {incr i} {

    set node_($i) [$ns_ node]

}

#Define a posicao inicial do nodo no nam

$ns_  at 200.0 “$ns_ nam-end-wireless 200.00”

$ns_ at 200.00 “$ns_ halt

#Start your simulation

$ns_  run

Links

NS

Programa de Simulação , Network Simulator

                http://www.isi.edu/nsnam/ns/index.html

Tutorial 

            http://www-mash.cs.berkeley.edu/ns/tutorial/index.html

Mainling Lists

          http://www.isi.edu/ns/ns-lists.html

Debugação

          http://www.isi.edu/ns/ns-debugging.html

 

Simulações Ad Hoc

How To de Implementação de um Protocolo Ad Hoc (LAR)- Autor : Andre Mota - andmota@dcc.ufmg.br

 

TCL

Tutoriais

Tutorial de OTcl

Tutorial sobre Tcl/tk

Manual Tcl 8.0 / tk8.0