A Discrete-Event Network Simulator
Rastreamento

Construindo topologias

Construindo uma rede em barramento

Nesta seção, o conhecimento sobre dispositivos de rede e canais de comunicação são expandidos de forma a abordar um exemplo de uma rede em barramento. O ns-3 fornece um dispositivo de rede e canal que é chamado de CSMA (Carrier Sense Multiple Access).

O dispositivo CSMA modela uma rede simples no contexto da Ethernet. Uma rede Ethernet real utiliza CSMA/CD (Carrier Sense Multiple Access with Collision Detection) com recuo binário exponencial para lidar com o meio de transmissão compartilhado. O dispositivo e o canal CSMA do ns-3 modelam apenas um subconjunto deste.

Assim como foi visto nos assistentes ponto-a-ponto (objetos) na construção de topologias ponto-a-ponto, veremos assistentes (objetos) equivalentes da topologia CSMA nesta seção. O formato e o funcionamento destes assistentes serão bastante familiares para o leitor.

Um novo código exemplo é fornecido na pasta examples/tutorial. Este baseia-se no código first.cc e adiciona uma rede CSMA a simulação ponto-a-ponto já considerada. O leitor pode abrir o arquivo examples/tutorial/second.cc em seu editor favorito para acompanhar o restante desta seção. Embora seja redundante, o código será analisado em sua totalidade, examinando alguns de seus resultados.

Assim como no exemplo first.cc (e em todos os exemplos ns-3), o arquivo começa com uma linha de modo Emacs e algumas linhas do padrão GPL.

O código começa com o carregamento de módulos através da inclusão dos arquivos.

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

Algo que pode ser surpreendentemente útil é uma pequena arte ASCII que mostra um desenho da topologia da rede construída. Um “desenho” similar é encontrado na maioria dos exemplos no projeto.

Neste caso, é possível perceber que o exemplo ponto-a-ponto (a ligação entre os nós n0 e n1 abaixo) está sendo estendido, agregando uma rede em barramento ao lado direito. Observe que esta é a topologia de rede padrão, visto que o número de nós criados na LAN pode ser mudado. Se o atributo nCsma for configurado para um, haverá um total de dois nós na LAN (canal CSMA) — um nó obrigatório e um nó “extra”. Por padrão, existem três nós “extra”, como pode ser observado:

// Default Network Topology
//
//       10.1.1.0
// n0 -------------- n1   n2   n3   n4
//    point-to-point  |    |    |    |
//                    ================
//                      LAN 10.1.2.0

Em seguida, o namespace do ns-3 é usado e um componente de registro (log) é definido. Até aqui, tudo é exatamente como em first.cc, não há nada novo ainda.

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

O programa principal começa com um toque ligeiramente diferente. A variável ‘verbose’ é usada para determinar se os componentes de registro de UdpEchoClientApplication e UdpEchoServerApplication estarão habilitados. O valor padrão é verdadeiro (os componentes de registro estão ativados), mas é possível desligar durante os testes de regressão deste exemplo.

Você verá códigos familiares que lhe permitirão mudar o número de dispositivos na rede CSMA via linha de comando. Fizemos algo semelhante, quando permitimos que o número de pacotes enviados em uma sessão fosse alterado. A última linha garante que você tenha pelo menos um nó “extra”.

O código consiste em variações de APIs abordadas anteriormente neste tutorial.

bool verbose = true;
uint32_t nCsma = 3;

CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);

cmd.Parse (argc, argv);

if (verbose)
  {
    LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
    LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
  }

nCsma = nCsma == 0 ? 1 : nCsma;

O próximo passo é a criação de dois nós que iremos conectar através da ligação ponto-a-ponto. O NodeContainer é usado para fazer isto, assim como foi feito em first.cc.

NodeContainer p2pNodes;
p2pNodes.Create (2);

Em seguida, declaramos outro NodeContainer para manter os nós que serão parte da rede em barramento (CSMA). Primeiro, instanciamos somente o contêiner.

NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

Depois, na próxima linha de código, obtém-se o primeiro nó do contêiner ponto-a-ponto e o adiciona ao contêiner de nós que irão receber dispositivos CSMA. O nó em questão vai acabar com um dispositivo ponto-a-ponto e um dispositivo CSMA. Em seguida, criamos uma série de nós “extra” que compõem o restante da rede CSMA. Visto que já temos um nó na rede CSMA – aquele que terá tanto um dispositivo ponto-a-ponto quanto um dispositivo de rede CSMA, o número de nós “extras” representa o número desejado de nós na seção CSMA menos um.

Instanciamos um PointToPointHelper e definimos os atributos padrões de forma a criar uma transmissão de cinco megabits por segundo e dois milésimos de segundo de atraso para dispositivos criados utilizando este assistente.

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Em seguida, instanciamos um NetDeviceContainer para gerenciar os dispositivos ponto-a-ponto e então Instalamos os dispositivos nos nós ponto-a-ponto.

Mencionamos anteriormente que abordaríamos um assistente para dispositivos e canais CSMA, as próximas linhas o introduzem. O CsmaHelper funciona como o PointToPointHelper, mas cria e conecta dispositivos e canais CSMA. No caso de um par de dispositivos e canais CSMA, observe que a taxa de dados é especificada por um atributo do canal, ao invés de um atributo do dispositivo. Isto ocorre porque uma rede CSMA real não permite que se misture, por exemplo, dispositivos 10Base-T e 100Base-T em um mesmo meio. Primeiro definimos a taxa de dados a 100 megabits por segundo e, em seguida, definimos o atraso do canal como a velocidade da luz, 6560 nano-segundos (escolhido arbitrariamente como 1 nanossegundo por 30,48 centímetros sobre um segmento de 100 metros). Observe que você pode definir um atributo usando seu tipo de dados nativo.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

Assim como criamos um NetDeviceContainer para manter os dispositivos criados pelo PointToPointHelper, criamos um NetDeviceContainer para gerenciar os dispositivos criados pelo nosso CsmaHelper. Chamamos o método Install do CsmaHelper para instalar os dispositivos nos nós do csmaNodes NodeContainer.

Agora temos os nossos nós, dispositivos e canais criados, mas não temos nenhuma pilha de protocolos presente. Assim como no exemplo first.cc, usaremos o InternetStackHelper para instalar estas pilhas.

InternetStackHelper stack;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);

Lembre-se que pegamos um dos nós do contêiner p2pNodes e o adicionamos ao contêiner csmaNodes. Assim, só precisamos instalar as pilhas nos nós p2pNodes restantes e todos os nós do contêiner csmaNodes para abranger todos os nós na simulação.

Assim como no exemplo first.cc, vamos usar o Ipv4AddressHelper para atribuir endereços IP para as interfaces de nossos dispositivos. Primeiro, usamos a rede 10.1.1.0 para criar os dois endereços necessários para os dispositivos ponto-a-ponto.

Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);

Lembre-se que salvamos as interfaces criadas em um contêiner para tornar mais fácil a obtenção de informações sobre o endereçamento para uso na criação dos aplicativos.

Precisamos agora atribuir endereços IP às interfaces dos dispositivo CSMA. A operação é a mesma realizada para o ponto-a-ponto, exceto que agora estamos realizando a operação em um contêiner que possui um número variável de dispositivos CSMA — lembre-se que fizemos o número de dispositivos CSMA serem passados na linha de comando. Os dispositivos CSMA serão associados com endereços IP da rede 10.1.2.0, como visto a seguir.

address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);

Agora a topologia já está construída, mas precisamos de aplicações. Esta seção é muito similar a seção de aplicações do exemplo first.cc, mas vamos instanciar o servidor em um dos nós que tem um dispositivo CSMA e o cliente em um nó que tem apenas um dispositivo ponto-a-ponto.

Primeiro, vamos configurar o servidor de eco. Criamos um UdpEchoServerHelper e fornecemos o atributo obrigatório do construtor que é o número da porta. Lembre-se que esta porta pode ser alterada posteriormente, utilizando o método SetAttribute.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

Lembre-se que o csmaNodes NodeContainer contém um dos nós criados para a rede ponto-a-ponto e os nCsma nós “extra”. O que queremos é o último dos nós “extra”. A entrada zero do contêiner csmaNodes será o nó ponto-a-ponto. O jeito fácil de pensar nisso é, ao criar um nó CSMA “extra”, este será o nó um do contêiner csmaNodes. Por indução, se criarmos nCsma nós “extra”, o último será o de índice nCsma. Isto ocorre no Get da primeira linha de código.

A aplicação cliente é criada exatamente como fizemos no exemplo first.cc. Novamente, fornecemos os atributos necessários no construtor do UdpEchoClientHelper (neste caso, o endereço e porta remotos). Dizemos ao cliente para enviar pacotes para o servidor. Instalamos o cliente no nó ponto-a-ponto mais à esquerda visto na ilustração da topologia.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

Visto que construímos uma inter-rede, precisamos de alguma forma de roteamento. O ns-3 fornece o que chamamos de roteamento global para simplificar essa tarefa. O roteamento global tira proveito do fato de que toda a inter-rede é acessível na simulação — ele realiza a disponibilização do roteamento sem a necessidade de configurar roteadores individualmente.

Basicamente, o que acontece é que cada nó se comporta como se fosse um roteador OSPF que se comunica instantaneamente e magicamente com todos os outros roteadores transparentemente. Cada nó gera anúncios de ligações e os comunica diretamente a um gerente de rota global. O gerente, por sua vez, utiliza esta informação para construir as tabelas de roteamento de cada nó. A configuração deste tipo de roteamento é realizada em uma linha:

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Em seguida, vamos habilitar o rastreamento pcap. A primeira linha de código para habilita o rastreamento pcap no assistente ponto-a-ponto. A segunda linha habilita o rastreamento pcap no assistente CSMA e há um parâmetro extra que ainda não havíamos usado.

pointToPoint.EnablePcapAll ("second");
csma.EnablePcap ("second", csmaDevices.Get (1), true);

A rede CSMA é uma rede multi-ponto-a-ponto. Isto significa que pode (e neste caso, de fato há) vários nós em um meio compartilhado. Cada um destes nós tem um dispositivo de rede associado. Existem duas alternativas para a coleta de informações de rastreamento em uma rede desse tipo. Uma maneira é criar um arquivo de rastreamento para cada dispositivo de rede e armazenar apenas os pacotes que são enviados ou recebidos por esse dispositivo. Outra maneira é escolher um dos dispositivos e colocá-lo em modo promíscuo. Esse dispositivo então “sniffs” a rede por todos os pacotes e os armazena em um único arquivo pcap. Isto é como o tcpdump funciona, por exemplo. O último parâmetro informa ao assistente CSMA se deve ou não capturar pacotes em modo promíscuo.

Neste exemplo, vamos selecionar um dos dispositivos CSMA e pedir para realizar uma captura promíscua na rede, emulando, assim, o que o tcpdump faria. Se você estivesse em uma máquina Linux faria algo como tcpdump -i eth0 para obter o rastreamento. Neste caso, especificamos o dispositivo usando csmaDevices.Get(1), que seleciona o primeiro dispositivo no contêiner. Configurando o último parâmetro para verdadeiro habilita a captura no modo promíscuo.

A última seção do código apenas executa e limpa a simulação como no exemplo first.cc.

  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}

Para executar este exemplo, copie o arquivo de second.cc para o diretório “scratch” e use o comando waf para compilar exatamente como você fez com first.cc. Se você estiver no diretório raiz do repositório, digite,

cp examples/tutorial/second.cc scratch/mysecond.cc
./waf

Atenção: Usamos o arquivo second.cc como um dos nossos testes de regressão para verificar se ele funciona exatamente como achamos que deve, a fim de fazer o seu tutorial uma experiência positiva. Isto significa que um executável chamado second já existe no projeto. Para evitar qualquer confusão sobre o que você está executando, renomeie para mysecond.cc como sugerido acima.

Se você está seguindo o tutorial religiosamente (você está? certo?), ainda vai ter a variável NS_LOG definida, então limpe a variável e execute o programa.

export NS_LOG=
./waf --run scratch/mysecond

Uma vez que configuramos aplicações UDP de eco para rastrear, assim como fizemos em first.cc, você verá uma saída semelhante quando executar o código.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.415s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.2.4

Lembre-se que a primeira mensagem, “Sent 1024 bytes to 10.1.2.4,” é o cliente UDP enviando um pacote de eco para o servidor. Neste caso, o servidor está em uma rede diferente (10.1.2.0). A segunda mensagem, “Received 1024 bytes from 10.1.1.1,” é do servidor de eco, gerado quando ele recebe o pacote de eco. A mensagem final, “Received 1024 bytes from 10.1.2.4,” é do cliente de eco, indicando que ele recebeu seu eco de volta.

Se você olhar no diretório raiz, encontrará três arquivos de rastreamento:

second-0-0.pcap  second-1-0.pcap  second-2-0.pcap

Vamos gastar um tempo para ver a nomeação desses arquivos. Todos eles têm a mesma forma, <nome>-<nó>-<dispositivo>.pcap. Por exemplo, o primeiro arquivo na listagem é second-0-0.pcap `` que é o rastreamento pcap do zero, dispositivo zero. Este é o dispositivo na rede ponto-a-ponto no zero. O arquivo ``second-1-0.pcap é o rastreamento pcap para o dispositivo zero no nó um, também um dispositivo ponto-a-ponto. O arquivo second-2-0.pcap é o rastreamento pcap para o dispositivo zero no nó dois.

Se remetermos para a ilustração da topologia no início da seção, vai ver que o nó zero é o nó mais à esquerda da ligação ponto-a-ponto e o nó um é o nó que tem tanto um dispositivo ponto-a-ponto quanto um CSMA. Observamos que o nó dois é o primeiro nó “extra” na rede CSMA e seu dispositivo zero foi selecionado como o dispositivo para capturar pacotes de modo promíscuo.

Agora, vamos seguir o pacote de eco através das redes. Primeiro, faça um tcpdump do arquivo de rastreamento para o nó ponto-a-ponto mais à esquerda — nó zero.

tcpdump -nn -tt -r second-0-0.pcap

Teremos o conteúdo do arquivo pcap:

reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

A primeira linha do despejo (dump) indica que o tipo da ligação é PPP (ponto-a-ponto). Você então vê o pacote de eco deixando o nó zero através do dispositivo associado com o endereço IP 10.1.1.1, destinado para o endereço IP 10.1.2.4 (o nó CSMA mais à direita). Este pacote vai passar pela ligação ponto-a-ponto e será recebido pelo dispositivo ponto-a-ponto no nó um. Vamos dar uma olhada:

tcpdump -nn -tt -r second-1-0.pcap

Observamos agora a saída de rastreamento pcap do outro lado da ligação ponto-a-ponto:

reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Aqui vemos que o tipo de ligação também é PPP. Vemos nesta interface o pacote do endereço IP 10.1.1.1 (que foi enviado a 2,000000 segundos) endereçado ao IP 10.1.2.4. Agora, internamente a este nó, o pacote será enviado para a interface CSMA e devemos vê-lo saindo nesse dispositivo a caminho de seu destino final.

Lembre-se que selecionamos o nó 2 como o “sniffer” promíscuo para a rede CSMA, por isso, vamos analisar o arquivo second-2-0.pcap.

tcpdump -nn -tt -r second-2-0.pcap

Temos agora o despejo do nó dois, dispositivo zero:

reading from file second-2-0.pcap, link-type EN10MB (Ethernet)
2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1
2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06
2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4
2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03
2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Observamos que o tipo de ligação agora é “Ethernet”. Algo novo apareceu. A rede em barramento necessicita do ARP, o “Address Resolution Protocol”. O nó um sabe que precisa enviar o pacote para o endereço IP 10.1.2.4, mas não sabe o endereço MAC do nó correspondente. Ele transmite na rede CSMA (ff:ff:ff:ff:ff:ff) pedindo ao dispositivo que tem o endereço IP 10.1.2.4. Neste caso, o nó mais à direita responde dizendo que está no endereço MAC 00:00:00:00:00:06. Note que o nó dois não está diretamente envolvido nesta troca, mas está capturando todo o tráfego da rede.

Esta troca é vista nas seguintes linhas,

2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1
2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06

Em seguida, o nó um, dispositivo um, envia o pacote de eco UDP para o servidor no endereço IP 10.1.2.4.

2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024

O servidor recebe a solicitação de eco e tenta enviar de volta para a origem. O servidor sabe que este endereço está em outra rede que chega através do endereço IP 10.1.2.1. Isto porque inicializamos o roteamento global. Entretanto, o nó servidor de eco não sabe o endereço MAC do primeiro nó CSMA, por isso tem que solicitar via ARP assim como o primeiro nó CSMA teve que fazer.

2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4
2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03

O servidor então envia o eco de volta ao nó de encaminhamento.

2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Analisando o nó mais à direita da ligação ponto-a-ponto,

tcpdump -nn -tt -r second-1-0.pcap

Observamos o pacote que ecoou vindo de volta para a lingação ponto-a-ponto na última linha do despejo.

reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Finalmente, analisando o nó que originou o eco,

tcpdump -nn -tt -r second-0-0.pcap

vericamos que o pacote eco chega de volta na fonte em 2,007602 segundos

reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Finalmente, lembre-se que adicionamos a habilidade de controlar o número de dispositivos CSMA na simulação por meio da linha de comando. Você pode alterar esse argumento da mesma forma como quando alteramos o número de pacotes de eco no exemplo first.cc. Tente executar o programa com o número de dispositivos “extra” em quatro:

./waf --run "scratch/mysecond --nCsma=4"

Você deve ver agora:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
Sent 1024 bytes to 10.1.2.5
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.2.5

Observe que o servidor de eco foi agora transferido para o último dos nós CSMA, que é 10.1.2.5 em vez de o caso padrão, 10.1.2.4.

É possível que você não se satisfaça com um arquivo de rastreamento gerado por um espectador na rede CSMA. Você pode querer obter o rastreamento de um único dispositivo e pode não estar interessado em qualquer outro tráfego na rede. Você pode fazer isso facilmente.

Vamos dar uma olhada em scratch/mysecond.cc e adicionar o código permitindo-nos ser mais específicos. Os assistentes do ns-3 fornecem métodos que recebem um número de nó e um número de dispositivo como parâmetros. Substitua as chamadas EnablePcap pelas seguites:

pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false);

Sabemos que queremos criar um arquivo pcap com o nome base “second” e sabemos também que o dispositivo de interesse em ambos os casos vai ser o zero, então estes parâmetros não são interessantes.

A fim de obter o número do nó, você tem duas opções: primeiro, os nós são numerados de forma crescente a partir de zero na ordem em que você os cria. Uma maneira de obter um número de nó é descobrir este número “manualmente” através da ordem de criação. Se olharmos na ilustração da topologia da rede no início do arquivo, perceberemos que foi o que fizemos. Isto pode ser visto porque o último nó CSMA vai ser o de número nCsma + 1. Esta abordagem pode tornar-se muito difícil em simulações maiores.

Uma maneira alternativa, que usamos aqui, é perceber que os NodeContainers contêm ponteiros para objetos Node do ns-3. O objeto Node tem um método chamado GetId que retornará o ID do nó, que é o número do nó que buscamos. Vamos dar uma olhada por Node no Doxygen e localizar esse método, que está mais abaixo no código do núcleo do que vimos até agora. Às vezes você tem que procurar diligentemente por coisas úteis.

Consulte a documentação em Doxygen para a sua distribuição do ns (lembre-se que você pode encontrá-la no site do projeto). Você pode chegar a documentação sobre o objeto Node procurando pela guia “Classes”, até encontrar ns3::Node na “Class List”. Selecione ns3::Node e você será levado a documentação para a classe Node. Se você ir até o método GetId e selecioná-lo, será levado a documentação detalhada do método. Usar o método getId pode tornar muito mais fácil determinar os números dos nós em topologias complexas.

Vamos limpar os arquivos de rastreamento antigos do diretório raiz para evitar confusão sobre o que está acontecendo,

rm *.pcap
rm *.tr

Se você compilar o novo código e executar a simulação com nCsma em 100,

./waf --run "scratch/mysecond --nCsma=100"

você vai observar a seguinte saída:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
Sent 1024 bytes to 10.1.2.101
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.2.101

Observe que o servidor de eco está agora em 10.1.2.101, que corresponde a ter 100 nós CSMA “extras” com o servidor de eco no último. Se você listar os arquivos pcap no diretório principal, você verá,

second-0-0.pcap  second-100-0.pcap  second-101-0.pcap

O arquivo de rastreamento second-0-0.pcap é o dispositivo ponto-a-ponto “mais à esquerda” que é a origem do pacote de eco. O arquivo second-101-0.pcap corresponde ao dispositivo CSMA mais à direita que é onde o servidor de eco reside. O leitor deve ter notado que o parâmetro final na chamada para ativar o rastreamento no nó servidor era falso. Isto significa que o rastreamento nesse nó estava em modo não-promíscuo.

Para ilustrar a diferença entre o rastreamento promíscuo e o não promíscuo, também solicitamos um rastreamento não-promíscuo para o nó vizinho ao último. Dê uma olhada no tcpdump para second-100-0.pcap.

tcpdump -nn -tt -r second-100-0.pcap

Agora observamos que o nó 100 é realmente um espectador na troca de eco. Os únicos pacotes que ele recebe são os pedidos ARP que são transmitidos para a rede CSMA inteira (em broadcast).

reading from file second-100-0.pcap, link-type EN10MB (Ethernet)
2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1
2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101

Agora, dê uma olhada no tcpdump para second-101-0.pcap.

tcpdump -nn -tt -r second-101-0.pcap

Observamos que o nó 101 é realmente o participante na troca de eco.

reading from file second-101-0.pcap, link-type EN10MB (Ethernet)
2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1
2.003696 arp reply 10.1.2.101 is-at 00:00:00:00:00:67
2.003801 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, length 1024
2.003801 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101
2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03
2.003822 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, length 1024

Modelos, atributos e a sua realidade

Este é um local conveniente para fazer uma pequena excursão e fazer uma observação importante. Pode ou não ser óbvio para o leitor, mas sempre que alguém está usando uma simulação, é importante entender exatamente o que está sendo modelado e o que não está. É tentador, por exemplo, pensar nos dispositivos e canais CSMA utilizados na seção anterior como se fossem dispositivos Ethernet reais, e esperar um resultado que vai refletir diretamente o que aconteceria em uma Ethernet real. Este não é o caso.

Um modelo é, por definição, uma abstração da realidade. Em última análise, é responsabilidade do autor do código da simulação determinar a chamada “faixa de precisão” e “domínio de aplicabilidade” da simulação como um todo e, portanto, suas partes constituintes.

Em alguns casos, como no Csma, pode ser bastante fácil de determinar o que é não modelado. Ao ler a descrição do fonte (csma.h) você descobrirá que não há detecção de colisão e poderá decidir sobre quão aplicável a sua utilização será em sua simulação ou quais ressalvas pode querer incluir em seus resultados. Em outros casos, pode ser razoavelmente fácil configurar comportamentos que podem não existir em qualquer equipamento real que possa ser comprado por aí. Vale a pena gastar algum tempo investigando tais casos e quão facilmente pode-se desviar para fora dos limites da realidade em suas simulações.

Como você viu, o ns-3 fornece atributos que um usuário pode facilmente configurar para mudar o comportamento do modelo. Considere dois dos atributos do CsmaNetDevice: Mtu e EncapsulationMode. O atributo Mtu indica a unidade máxima de transmissão para o dispositivo. Este é o tamanho máximo do Protocol Data Unit (PDU) que o dispositivo pode enviar.

O valor padrão para o MTU é 1500 bytes na CsmaNetDevice. Este padrão corresponde a um número encontrado na RFC 894, “Um padrão para a transmissão de datagramas IP sobre redes Ethernet”. O número é derivado do tamanho máximo do pacote para redes 10Base5 (full-spec Ethernet) – 1518 bytes. Se você subtrair a sobrecarga de encapsulamento DIX para pacotes Ethernet (18 bytes), você vai acabar com o tamanho máximo possível de dados (MTU) de 1500 bytes. Pode-se também encontrar que o MTU para redes IEEE 802.3 é 1492 bytes. Isto é porque o encapsulamento LLC/SNAP acrescenta oito bytes extra de sobrecarga para o pacote. Em ambos os casos, o hardware subjacente pode enviar apenas 1518 bytes, mas o tamanho dos dados é diferente.

A fim de definir o modo de encapsulamento, o CsmaNetDevice fornece um atributo chamado EncapsulationMode que pode assumir os valores Dix ou Llc. Estes correspondem ao enquadramento Ethernet e LLC/SNAP, respectivamente.

Se deixarmos o Mtu com 1500 bytes e mudarmos o encapsulamento para Llc, o resultado será uma rede que encapsula PDUs de 1500 bytes com enquadramento LLC/SNAP, resultando em pacotes de 1526 bytes, o que seria ilegal em muitas redes, pois elas podem transmitir um máximo de 1518 bytes por pacote. Isto resultaria em uma simulação que, de maneira sutil, não refletiria a realidade que você possa estar esperando.

Só para complicar o cenário, existem quadros jumbo (1500 < MTU <= 9000 bytes) e quadros super-jumbo (MTU > 9000 bytes) que não são oficialmente especificados pela IEEE, mas estão disponíveis em alguns equipamentos de redes de alta velocidade (Gigabit) e NICs. Alguém poderia deixar o encapsulamento em Dix, e definir o atributo Mtu em um dispositivo CsmaNetDevice para 64000 bytes – mesmo que o atributo CsmaChannel DataRate associado esteja fixado em 10 megabits por segundo. Isto modelaria um equipamento Ethernet 10Base5, dos anos 80, suportando quadros super-jumbo. Isto é certamente algo que nunca foi feito, nem é provável que alguma vez seja feito, mas é bastante fácil de configurar.

No exemplo anterior, usamos a linha de comando para criar uma simulação que tinha 100 nós CSMA. Poderíamos ter facilmente criado uma simulação com 500 nós. Se fossemos de fato modelar uma rede com conectores de pressão (vampire-taps) 10Base5, o comprimento máximo do cabo Ethernet é 500 metros, com um espaçamento mínimo entre conectores de 2,5 metros. Isso significa que só poderia haver 200 máquinas em uma rede real. Poderíamos facilmente construir uma rede ilegal desta maneira também. Isto pode ou não resultar em uma simulação significativa dependendo do que você está tentando modelar.

Situações similares podem ocorrer em muitos momentos no ns-3, assim como em qualquer simulador. Por exemplo, você pode posicionar os nós de tal forma que ocupem o mesmo espaço ao mesmo tempo ou você pode ser capaz de configurar amplificadores ou níveis de ruído que violam as leis básicas da física.

O ns-3 geralmente favorece a flexibilidade, e muitos modelos permitirão a configuração de atributos sem impor qualquer consistência ou especificação especial subjacente.

Em resumo, o importante é que o ns-3 vai fornecer uma base super flexível para experimentações. Depende de você entender o que está requisitando ao sistema e se certificar de que as simulações tem algum significado e alguma ligação com a sua realidade.

Construindo uma rede sem fio

Nesta seção, vamos expandir ainda mais nosso conhecimento sobre dispositivos e canais do ns-3 para cobrir um exemplo de uma rede sem fio. O ns-3 fornece um conjunto de modelos 802.11 que tentam fornecer uma implementação precisa a nível MAC da especificação 802.11 e uma implementação “não-tão-lenta” a nível PHY da especificação 802.11a.

Assim como vimos assistentes de topologia (objetos) ponto-a-ponto e CSMA quando da construção destes modelos, veremos assistentes Wifi similares nesta seção. O formato e o funcionamento destes assistentes devem parecer bastante familiar ao leitor.

Fornecemos um exemplo no diretório examples/tutorial. Este arquivo baseia-se no código presente em second.cc e adiciona uma rede Wifi a ele. Vá em frente e abra examples/tutorial/third.cc em seu editor favorito. Você já deve ter visto código ns-3 suficiente para entender a maior parte do que está acontecendo neste exemplo, existem algumas coisas novas, mas vamos passar por todo o código e examinar alguns dos resultados.

Assim como no exemplo second.cc (e em todos os exemplos ns-3), o arquivo começa com uma linha de modo emacs e algumas linhas do padrão GPL.

Dê uma olhada na arte ASCII (reproduzida abaixo) que mostra topologia de rede construída no exemplo. Você pode ver que estamos ampliando ainda mais nosso exemplo agregando uma rede sem fio do lado esquerdo. Observe que esta é uma topologia de rede padrão, pois você pode variar o número de nós criados nas redes com fio e sem fio. Assim como no exemplo second.cc, se você mudar nCsma, ele lhe dará um número “extra” de nós CSMA. Da mesma forma, você pode definir nWifi para controlar quantos nós (estações) STA serão criados na simulação. Sempre haverá um nó AP (access point) na rede sem fio. Por padrão, existem três nós “extra” no CSMA e três nós sem fio STA.

O código começa pelo carregamento de módulos através da inclusão dos arquivos, assim como no exemplo second.cc. Há algumas novas inclusões correspondentes ao módulo Wifi e ao módulo de mobilidade que discutiremos a seguir.

#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"

A ilustração da topologia da rede é a seguinte:

// Default Network Topology
//
//   Wifi 10.1.3.0
//                 AP
//  *    *    *    *
//  |    |    |    |    10.1.1.0
// n5   n6   n7   n0 -------------- n1   n2   n3   n4
//                   point-to-point  |    |    |    |
//                                   ================
//                                     LAN 10.1.2.0

Observamos que estamos acrescentando um novo dispositivo de rede ao nó à esquerda da ligação ponto-a-ponto que se torna o ponto de acesso da rede sem fios. Alguns nós STA sem fio são criados para preencher a nova rede 10.1.3.0, como mostrado no lado esquerdo da ilustração.

Após a ilustração, o namespace ns-3 é usado e um componente de registro é definido.

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");

O programa principal começa exatamente como em second.cc, adicionando parâmetros de linha de comando para habilitar ou desabilitar componentes de registro e para alterar o número de dispositivos criados.

bool verbose = true;
uint32_t nCsma = 3;
uint32_t nWifi = 3;

CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);

cmd.Parse (argc,argv);

if (verbose)
  {
    LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
    LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
  }

Assim como em todos os exemplos anteriores, o próximo passo é a criação de dois nós que irão se ligar através da ligação ponto-a-ponto.

NodeContainer p2pNodes;
p2pNodes.Create (2);

Em seguida, instanciamos um PointToPointHelper e definimos os atributos padrões para criar uma transmissão de cinco megabits por segundo e dois milésimos de segundo de atraso para dispositivos que utilizam este assistente. Então instalamos os dispositivos nos nós e o canal entre eles.

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Em seguida, declaramos outro NodeContainer para manter os nós que serão parte da rede em barramento (CSMA).

NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

A próxima linha de código obtém o primeiro nó do contêiner ponto-a-ponto e o adiciona ao contêiner de nós que irão receber dispositivos CSMA. O nó em questão vai acabar com um dispositivo ponto-a-ponto e um dispositivo CSMA. Em seguida, criamos uma série de nós “extra” que compõem o restante da rede CSMA.

Em seguida, instanciamos um CsmaHelper e definimos seus atributos assim como fizemos no exemplo anterior. Criamos um NetDeviceContainer para gerenciar os dispositivos CSMA criados e então instalamos dispositivos CSMA nos nós selecionados.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

Em seguida, vamos criar os nós que farão parte da rede Wifi. Vamos criar alguns nós “estações”, conforme especificado na linha de comando, e iremos usar o nó “mais à esquerda” da rede ponto-a-ponto como o nó para o ponto de acesso.

NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);

A próxima parte do código constrói os dispositivos Wifi e o canal de interligação entre esses nós. Primeiro, vamos configurar os assistentes PHY e de canal:

YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();

Para simplificar, este código usa a configuração padrão da camada PHY e modelos de canais que estão documentados na API doxygen para os métodos YansWifiChannelHelper::Default e YansWifiPhyHelper::Default. Uma vez que esses objetos são instanciados, criamos um objeto de canal e associamos ele ao nosso gerente de objetos da camada PHY para nos certificarmos de que todos os objetos da camada PHY criados pelo YansWifiPhyHelper compartilham o mesmo canal subjacente, isto é, eles compartilham o mesmo meio físico sem fio e podem comunicar-se e interferir:

phy.SetChannel (channel.Create ());

Uma vez que o assistente PHY está configurado, podemos nos concentrar na camada MAC. Aqui escolhemos trabalhar com MACs não-Qos, por isso usamos um objeto NqosWifiMacHelper para definir os parâmetros MAC.

WifiHelper wifi = WifiHelper::Default ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");

NqosWifiMacHelper mac = NqosWifiMacHelper::Default ();

O método SetRemoteStationManager diz ao assistente o tipo de algoritmo de controle de taxa a usar. Aqui, ele está pedindo ao assistente para usar o algoritmo AARF — os detalhes estão disponíveis no Doxygen.

Em seguida, configuramos o tipo de MAC, o SSID da rede de infraestrutura, e nos certificamos que as estações não realizam sondagem ativa (active probing):

Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
  "Ssid", SsidValue (ssid),
  "ActiveProbing", BooleanValue (false));

Este código primeiro cria um objeto de um identificador de conjunto de serviços (SSID 802.11) que será utilizado para definir o valor do atributo “Ssid” da implementação da camada MAC. O tipo particular da camada MAC que será criado pelo assistente é especificado como sendo do tipo “ns3::StaWifiMac”. O uso do assistente NqosWifiMacHelper irá garantir que o atributo “QosSupported” para os objetos MAC criados será falso. A combinação destas duas configurações implica que a instância MAC criada em seguida será uma estação (STA) não-QoS e não-AP, em uma infraestrutura BSS (por exemplo, uma BSS com um AP). Finalmente, o atributo “ActiveProbing” é definido como falso. Isto significa que as solicitações de sondagem não serão enviados pelos MACs criados por este assistente.

Depois que todos os parâmetros específicos das estações estão completamente configurados, tanto na camada MAC como na PHY, podemos invocar o nosso método já familiar Instalar para criar os dispositivos Wifi destas estações:

NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);

Já configuramos o Wifi para todos nós STA e agora precisamos configurar o AP. Começamos esse processo mudando o atributo padrão NqosWifiMacHelper para refletir os requisitos do AP.

mac.SetType ("ns3::ApWifiMac",
  "Ssid", SsidValue (ssid)));

Neste caso, o NqosWifiMacHelper vai criar camadas MAC do “ns3::ApWifiMac”, este último especificando que uma instância MAC configurado como um AP deve ser criado, com o tipo de assistente implicando que o atributo “QosSupported” deve ser definido como falso - desativando o suporte a Qos do tipo 802.11e/WMM nos APs criados.

As próximas linhas criam um AP que compartilha os mesmos atributos a nível PHY com as estações:

NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);

Agora, vamos adicionar modelos de mobilidade. Queremos que os nós STA sejam móveis, vagando dentro de uma caixa delimitadora, e queremos fazer o nó AP estacionário. Usamos o MobilityHelper para facilitar a execução desta tarefa. Primeiro, instanciamos um objeto MobilityHelper e definimos alguns atributos controlando a funcionalidade de “alocação de posição”.

MobilityHelper mobility;

mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
  "MinX", DoubleValue (0.0),
  "MinY", DoubleValue (0.0),
  "DeltaX", DoubleValue (5.0),
  "DeltaY", DoubleValue (10.0),
  "GridWidth", UintegerValue (3),
  "LayoutType", StringValue ("RowFirst"));

Este código diz ao assistente de mobilidade para usar uma grade bidimensional para distribuir os nós STA. Sinta-se à vontade para explorar a classe ns3::GridPositionAllocator no Doxygen para ver exatamente o que está sendo feito.

Arranjamos os nós em uma grade inicial, mas agora precisamos dizer-lhes como se mover. Escolhemos o modelo RandomWalk2dMobilityModel em que os nós se movem em uma direção aleatória a uma velocidade aleatória dentro de um delimitador quadrado.

mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
  "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));

Agora dizemos ao MobilityHelper para instalar os modelos de mobilidade nos nós STA.

mobility.Install (wifiStaNodes);

Queremos que o ponto de acesso permaneça em uma posição fixa durante a simulação. Conseguimos isto definindo o modelo de mobilidade para este nó como ns3::ConstantPositionMobilityModel:

mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (wifiApNode);

Agora temos os nossos nós, dispositivos e canais e modelos de mobilidade escolhidos para os nós Wifi, mas não temos pilhas de protocolo. Assim como já fizemos muitas vezes, usaremos o InternetStackHelper para instalar estas pilhas.

InternetStackHelper stack;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);

Assim como no exemplo second.cc, vamos usar o Ipv4AddressHelper para atribuir endereços IP para as interfaces de nossos dispositivos. Primeiro, usamos a rede 10.1.1.0 para criar os dois endereços necessários para os dois dispositivos ponto-a-ponto. Então, usamos rede 10.1.2.0 para atribuir endereços à rede CSMA e, por último, atribuir endereços da rede 10.1.3.0 para ambos os dispositivos STA e o ponto de acesso na rede sem fio.

Ipv4AddressHelper address;

address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);

address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);

address.SetBase ("10.1.3.0", "255.255.255.0");
address.Assign (staDevices);
address.Assign (apDevices);

Vamos colocar o servidor de eco no nó “mais à direita” na ilustração no início do arquivo.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

E colocamos o cliente de eco no último nó STA criado, apontando-o para o servidor na rede CSMA.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps =
  echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

Uma vez que construímos uma inter-rede aqui, precisamos ativar o roteamento inter-redes, assim como fizemos no exemplo second.cc.

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Algo que pode surpreender alguns usuários é o fato de que a simulação que acabamos de criar nunca vai parar “naturalmente”. Isto acontece porque pedimos para o ponto de acesso gerar beacons. Ele irá gerar beacons para sempre, e isso irá resultar em eventos sendo escalonados no futuro indefinidamente, por isso devemos dizer para o simulador parar, ainda que hajam eventos de geração de beacons agendados. A seguinte linha de código informa ao simulador para parar, para que não simulemos beacons para sempre e entremos no que é essencialmente um laço sem fim.

Simulator::Stop (Seconds (10.0));

Criamos rastreamento suficiente para cobrir todas as três redes:

pointToPoint.EnablePcapAll ("third");
phy.EnablePcap ("third", apDevices.Get (0));
csma.EnablePcap ("third", csmaDevices.Get (0), true);

Estas três linhas de código irão iniciar o rastreamento do pcap em ambos os nós ponto-a-ponto que funcionam como nosso backbone, irão iniciar um modo promíscuo (monitor) de rastreamento na rede Wifi e na rede CSMA. Isto vai permitir ver todo o tráfego com um número mínimo de arquivos de rastreamento.

Finalmente, executamos a simulação, limpamos e, em seguida, saimos do programa.

  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}

Para executar este exemplo, você deve copiar o arquivo third.cc para o diretório scratch e usar o Waf para compilar exatamente como com o exemplo second.cc. Se você está no diretório raiz do repositório você deverá digitar,

cp examples/tutorial/third.cc scratch/mythird.cc
./waf
./waf --run scratch/mythird

Novamente, uma vez que configuramos aplicações de eco UDP, assim como fizemos no arquivo second.cc, você verá uma saída similar.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.3.3
Received 1024 bytes from 10.1.2.4

Lembre-se que a primeira mensagem, Sent 1024 bytes to 10.1.2.4,” é o cliente de eco UDP enviando um pacote para o servidor. Neste caso, o cliente está na rede wireless (10.1.3.0). A segunda mensagem, “Received 1024 bytes from 10.1.3.3,” é do servidor de eco UDP, gerado quando este recebe o pacote de eco. A mensagem final, “Received 1024 bytes from 10.1.2.4,” é do cliente de eco, indicando que este recebeu o seu eco de volta do servidor.

No diretório raiz, encontraremos quatro arquivos de rastreamento desta simulação, dois do nó zero e dois do nó um:

third-0-0.pcap  third-0-1.pcap  third-1-0.pcap  third-1-1.pcap

O arquivo “third-0-0.pcap” corresponde ao dispositivo ponto-a-ponto no nó zero – o lado esquerdo do backbone. O arquivo “third-1-0.pcap” corresponde ao dispositivo ponto-a-ponto no nó um – o lado direito do backbone. O arquivo “third-0-1.pcap” corresponde o rastreamento em modo promíscuo (modo monitor) da rede Wifi e o arquivo “third-1 1.pcap” ao rastreamento em modo promíscuo da rede CSMA. Você consegue verificar isto inspecionando o código?

Como o cliente de eco está na rede Wifi, vamos começar por aí. Vamos dar uma olhada para a saída de rastreamento no modo promíscuo (modo monitor) capturada nessa rede.

tcpdump -nn -tt -r third-0-1.pcap

Você deverá ver alguns conteúdos ‘’wifi’’ que não tinham antes:

reading from file third-0-1.pcap, link-type IEEE802_11 (802.11)
0.000025 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000263 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000279 Acknowledgment RA:00:00:00:00:00:09
0.000552 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000568 Acknowledgment RA:00:00:00:00:00:07
0.000664 Assoc Response AID(0) :: Succesful
0.001001 Assoc Response AID(0) :: Succesful
0.001145 Acknowledgment RA:00:00:00:00:00:0a
0.001233 Assoc Response AID(0) :: Succesful
0.001377 Acknowledgment RA:00:00:00:00:00:0a
0.001597 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001613 Acknowledgment RA:00:00:00:00:00:08
0.001691 Assoc Response AID(0) :: Succesful
0.001835 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS

Observamos que o tipo de ligação agora é 802.11, como esperado. Você provavelmente vai entender o que está acontecendo e encontrar o pacote de pedido de eco e a resposta nesta saída de rastreamento. Vamos deixar como um exercício a análise completa da saída.

Agora, analisando o arquivo pcap do lado direito da ligação ponto-a-ponto,

tcpdump -nn -tt -r third-0-0.pcap

Novamente, temos algumas saídas familiares:

reading from file third-0-0.pcap, link-type PPP (PPP)
2.002160 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.009767 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Este é o pacote de eco indo da esquerda para a direita (do Wifi para o CSMA) e de volta através da ligação ponto-a-ponto.

Agora, analisando o arquivo pcap do lado direito da ligação ponto-a-ponto,

tcpdump -nn -tt -r third-1-0.pcap

Novamente, temos algumas saídas familiares:

reading from file third-1-0.pcap, link-type PPP (PPP)
2.005846 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.006081 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Este é o pacote de eco indo da esquerda para a direita (do Wifi para o CSMA) e depois voltando através do ligação ponto-a-ponto com tempos um pouco diferentes, como esperado.

O servidor de eco está na rede CSMA, vamos olhar para a saída de rastreamento promíscua:

tcpdump -nn -tt -r third-1-1.pcap

Temos algumas saídas familiares:

reading from file third-1-1.pcap, link-type EN10MB (Ethernet)
2.005846 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.005870 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.005870 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.005975 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.005975 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.006081 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Isto deve ser de fácil entendimento. Se esqueceu, volte e olhe para a discussão em second.cc. Este exemplo segue a mesma seqüência.

Passamos algum tempo com a criação de modelos de mobilidade para a rede sem fio e por isso seria uma vergonha encerrar sem mostrar que os nós STA estão realmente se movendo durante a simulação. Vamos fazer isto ligando o MobilityModel à fonte de rastreamento. Isto é apenas uma visão geral da seção que detalha o rastreamento, mas é um ótimo lugar para um exemplo.

Como mencionado na seção “Aperfeiçoando”, o sistema de rastreamento é dividido em origem de rastreamento e destino de rastreamento, com funções para conectar um ao outro. Vamos usar a mudança de curso padrão do modelo de mobilidade para originar os eventos de rastreamento. Vamos precisar escrever um destino de rastreamento para se conectar a origem que irá exibir algumas informações importantes. Apesar de sua reputação como difícil, é de fato muito simples. Antes do programa principal do código scratch/mythird.cc, adicione a seguinte função:

void
CourseChange (std::string context, Ptr<const MobilityModel> model)
{
  Vector position = model->GetPosition ();
  NS_LOG_UNCOND (context <<
    " x = " << position.x << ", y = " << position.y);
}

Este código obtém as informações de posição do modelo de mobilidade e registra a posição x e y do nó. Vamos criar o código para que esta função seja chamada toda vez que o nó com o cliente de eco mude de posição. Fazemos isto usando a função Config::Connect. Adicione as seguintes linhas de código no código antes da chamada Simulator::Run.

std::ostringstream oss;
oss <<
  "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
  "/$ns3::MobilityModel/CourseChange";

Config::Connect (oss.str (), MakeCallback (&CourseChange));

O que fazemos aqui é criar uma string contendo o caminho do namespace de rastreamento do evento ao qual se deseja conectar. Primeiro, temos que descobrir qual nó que queremos usando o método GetId como descrito anteriormente. No caso de usar o número padrão do CSMA e dos nós de rede sem fio, este acaba sendo o nó sete e o caminho do namespace de rastreamento para o modelo de mobilidade seria:

/NodeList/7/$ns3::MobilityModel/CourseChange

Com base na discussão na seção de rastreamento, você pode inferir que este caminho referencia o sétimo nó na lista NodeList global. Ele especifica o que é chamado de um objeto agregado do tipo ns3::MobilityModel. O prefixo cifrão implica que o MobilityModel é agregado ao nó sete. O último componente do caminho significa que estamos ligando ao evento “CourseChange” desse modelo.

Fazemos uma conexão entre a origem de rastreamento no nó sete com o nosso destino de rastreamento chamando Config::Connect e passando o caminho do namespace como parâmetro. Feito isto, cada evento de mudança de curso no nó sete será capturado em nosso destino de rastreamento, que por sua vez irá imprimir a nova posição.

Se você executar a simulação, verá as mudanças de curso assim que elas ocorrerem.

Build finished successfully (00:00:01)
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.41539, y = -0.811313
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.46199, y = -1.11303
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.52738, y = -1.46869
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.67099, y = -1.98503
/NodeList/7/$ns3::MobilityModel/CourseChange x = 5.6835, y = -2.14268
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.70932, y = -1.91689
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.3.3
Received 1024 bytes from 10.1.2.4
/NodeList/7/$ns3::MobilityModel/CourseChange x = 5.53175, y = -2.48576
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.58021, y = -2.17821
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.18915, y = -1.25785
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.7572, y = -0.434856
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.62404, y = 0.556238
/NodeList/7/$ns3::MobilityModel/CourseChange x = 4.74127, y = 1.54934
/NodeList/7/$ns3::MobilityModel/CourseChange x = 5.73934, y = 1.48729
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.18521, y = 0.59219
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.58121, y = 1.51044
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42888, y = 1.70014
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.40519, y = 1.91654
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.51981, y = 1.45166
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.34588, y = 2.01523
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.81046, y = 2.90077
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.89186, y = 3.29596
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.46617, y = 2.47732
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.05492, y = 1.56579
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.00393, y = 1.25054
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.00968, y = 1.35768
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.33503, y = 2.30328
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.18682, y = 3.29223
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.96865, y = 2.66873

Tabela de Conteúdo

Tópico anterior

Aprofundando Conhecimentos

Próximo tópico

Rastreamento

Esta Página