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.
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.
|
Programa de Visualização da Simulação |
|
|
Utiliza os arquivos .nam gerados pelos scripts do NS |

A linguagem script OTcl é a ferramenta principal no uso do Ns.
set a 123 ;#Cria uma variavel com nome a e valor 123
#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
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

# 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

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.
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
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.
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) |
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++.
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
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 |
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.
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().
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
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.
Os passos para criar um novo tipo de pacote são os seguintes:
Criar uma nova estrutura e definir os campos
Definir as funções membros para os campos necessários
Criar uma classe estatica para efetuar a linkagem em OTcl( definir PacketHeader/NovoCabeçalho)
Editar ~ns/tcl/bin/ns-packet.tcl para habilitar o novo formato do pacote
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.
#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_;
};
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;
PingAgent::PingAgent() : Agent(PT_PING)
{
bind("packetSize_", &size_);
bind("off_ping_", &off_ping_);
}
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));
}
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
|
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
|
How To de Implementação de um Protocolo Ad Hoc (LAR)- Autor : Andre Mota - andmota@dcc.ufmg.br |
TCL
|
Tutoriais
|