Netkit2

De MediaWiki do Campus São José
Ir para: navegação, pesquisa

Índice

AVISO: ATUALIZAÇÃO MANUAL PARA VERSÃO 2.x

O netkit2 possui um bug que o impede se atualizar. Para corrigi-lo, deve-se atualizá-lo manualmente com este procedimento:

  1. Abrir um terminal
  2. Baixar o programa do Netkit2 com este comando:
    wget http://tele.sj.ifsc.edu.br/~msobral/netkit2/bin/netkit2
    
  3. Copiá-lo para o diretório do Netkit2:
    cp netkit2 ${NETKIT2_HOME}/bin/
    
  4. Executar o netkit2 para completar a atualização

Introdução

Netkit2 é um ambiente para experimentos com redes de computadores desenvolvido pela Área de Telecomunicações do IFSC (Câmpus São José), e que se inspirou no Netkit, uma ferramenta semelhante (mas mais simplificada) desenvolvida pela Universidade de Roma, na Itália. Com ele torna-se possível realizar experimentos sobre configuração básica de rede, roteamento, criação de infraestrutura WAN com MPLS, além de dispor de diversos serviços de rede (DNS, WWW, LDAP, e outros). Ele se compõe de máquinas virtuais Linux (implementadas com kernel Linux UML – User Mode Linux), que funcionam como roteadores ou computadores, e hubs Ethernet virtuais (UML switch) para interligar as máquinas virtuais. Para todos os efeitos, cada máquina virtual funciona como se fosse um computador real, possuindo uma ou mais interfaces de rede. Com esses recursos é possível criar redes de configurações arbitrárias para estudar protocolos de comunicação e serviços de rede.


O Netkit aqui descrito possui muitas diferenças em relação ao Netkit original, dentre elas:

  • A definição de tipos de equipamentos a serem usados no experimento, tais como roteadores, switches, e computadores de uso geral: cada máquina virtual pode assim ser especializada para facilitar sua configuração.
  • A possibilidade de definir diversos parâmetros de configuração de rede (ex: endereços de interfaces, rotas, VLANs, ...) diretamente no arquivo de configuração de um experimento.
  • A possibilidade de criar enlaces ponto-a-ponto via links seriais virtuais, que podem ter configurados suas taxas de bits, taxas de erro (BER) e atraso de propagação.
  • Uma interface gráfica para a execução de experimentos. Esse aplicativo concentra as telas de terminal das máquinas virtuais e provê diversas funções auxiliares para ajudar na realização dos experimentos. A figura abaixo mostra um exemplo dessa interface em ação:
Netkit-vlsm1.png


A segunda versão do Netkit apresentada neste artigo, chamada daqui em diante de Netkit2, é fruto de uma ampla reescrita da versão anterior. As principais modificações nesta segunda versão são:

  • Completa reescrita do interpretador do arquivo de configuração de experimento: o novo interpretador analisa mais criteriosamente a sintaxe da configuração de um experimento, e informa detalhadamente erros de sintaxe encontrados. Além disso, algumas modificações na sintaxe de configurações foram realizadas para torná-las mais consistentes.
  • Completa reescrita do software que inicia e controla as máquinas virtuais UML: na versão anterior isso ainda era realizado com os scripts do Netkit original, os quais possuíam limitações (ex: apenas uma interface tap por experimento, impossibilidade de execução de mais de um experimento no mesmo computador, entre outras).
  • Uso de um novo kernel e sistema de arquivos: na versão anterior usava-se o kernel 2.6.27 e sistema de arquivos Debian 6 do Netkit original. Agora usa-se um kernel 3.9 e sistema de arquivos Ubuntu 12.04.
  • Desenvolvimento de uma interface clara entre a execução de experimentos e sua visualização: apesar de aparentemente a nova versão ter a mesma interface de usuário da versão anterior, houve uma separação clara entre execução e visualização. Com isso, pode-se usar a API desenvolvida para criar facilmente novas interfaces de usuário.


As próximas seções explicam como instalar o Netkit, e como criar e executar experimentos.

Sistemas Operacionais compatíveis

Sistema operacional Compatível Incompatível
Debian 6 Squeeze X
Debian 7 Wheezy X
Ios MAC X
Versões do Ubuntu inferiores a 13.10 X
Ubuntu 14.04 Trusty Tahr LTS X
Ubuntu 15.04 Vivid Vervet X
Windows, qualquer versão X

OBS: A versão utilizada nos laboratórios é o Ubuntu 12.04 LTS

Instalação

A instalação pode ser feita de forma automática ou manual. Em ambos os casos, é necessário haver 1,5 GB livre em seu disco.

O Netkit foi criado para rodar em sistemas operacionais de 32 bits. Mas ele pode ser usado também em sistemas de 64 bits. Nesse caso, devem-se instalar os seguintes pacotes de software (instale-os com apt-get):

sudo apt-get install libc6-i386

Tanto para sistemas de 32 ou 64 bits, são necessários os seguintes pacotes de software para o correto funcionamento do Netkit:

sudo apt-get install graphviz python-vte bridge-utils uml-utilities

Após instalado, o Netkit pode ser atualizado executando-se netkit2 e usando o menu General->Update.

Instalação automática (recomendada)

OBS: o instalador assume que a instalação será feita em um sistema operacional Ubuntu 10.04 ou superior, 
e que o usuário use o shell Bash (/bin/bash).


Obtenha o instalador do Netkit e salve-o no disco de seu computador. Execute-o da seguinte forma em uma janela de terminal:

python netkit2-installer

O instalador será iniciado e apresentará a seguinte tela:

Netkit-installer.png

Normalmente deve-se usar a opção Install from Network, que faz o download do arquivo de instalação e o instala. Note que esse arquivo de instalação possui pouco mais de 270 MB, e pode demorar para ser copiado pela rede. A opção Install from File pode ser usada se o arquivo de instalação já estiver em seu disco.


O instalador realiza automaticamente os procedimentos descritos na seção Instalação manual.

Instalação manual

Para instalar o Netkit, deve-se obter o arquivo compactado netkit2.tar.bz2 (330 MB):


O Netkit foi completamente modificado em relação à distribuição original do projeto para possibilitar uma sintaxe mais rica para a configuração de experimentos. A nova sintaxe é orientada a componentes de rede, tais como computadores, gateways, switches e roteadores, gerando máquinas virtuais previamente configuradas de acordo com seu papel na rede. Outra melhoria foi a possibilidade de criar enlaces ponto-a-ponto entre máquinas virtuais usando interfaces seriais. Esses enlaces emulam a comunicação via portas seriais, e neles é possível usar um protocolo de enlace ponto-a-ponto (ex: PPP).

Você precisa de um computador com Linux, para onde deve copiar os arquivos acima. Não é necessário ter privilégio de superusuário para instalar o Netkit, tampouco para executá-lo. Aliás, NÃO EXECUTE O NETKIT COMO SUPERUSUÁRIO !!!

Após copiar o arquivo netkit2.tar.bz2 para seu computador, descompacte-o dentro de um subdiretório à sua escolha. Em seguida edite o arquivo ~/.profile (que contém a configuração do seu shell), e acrescente as seguintes definições de variáveis de ambiente:

export NETKIT2_HOME=/home/aluno/netkit2
export PATH=$NETKIT2_HOME/bin:$PATH

Obs: no exemplo acima foi assumido que o Netkit foi instalado em /home/aluno/netkit2 (quer dizer, você descompactou os arquivos dentro de /home/aluno/netkit2). Caso tenha instalado em outro diretório você deve corrigir a definição da variável de ambiente NETKIT2_HOME.

Ajustes finais

Alguns ajustes precisam ser feitos manualmente. Em particular, deve-se editar o arquivo sudoers para que o netkit2 tenha permissão de executar alguns comandos. Use o programa visudo para adicionar o comando ${NETKIT2_HOME}/bin/tap.py ao sudoers (substitua ${NETKIT2_HOME} pelo diretório onde o Netkit2 foi instalado). Por exemplo, se ${NETKIT2_HOME} for /home/aluno/netkit2, use o programa visudo para adicionar a seguinte linha (pode ser ao final da tela):

aluno   ALL=(root) NOPASSWD: SETENV: /home/aluno/netkit2/bin/tap.py


OBS: No Ubuntu 14.04 LTS, recomenda-se desabilitar o menu global da interface Unity. Nesse caso, use o aplicativo dconf-editor para adicionar netkit2 a com -> canonical -> unity-gtk-module -> blacklist (maiores detalhes). A tela do dconf-editor após a modificação está exemplificada a seguir.


Dconf-nk2.png

Testando a instalação

Para estrear seu Netkit você pode baixar o arquivo teste.conf, que descreve um experimento. Para rodá-lo siga estes passos:

  1. Execute . ~/.profile . Isto será necessário somente desta vez, pois das próximas vezes que iniciar o computador as configurações de ambiente do Netkit2 serão automaticamente carregadas.
  2. Execute netkit2. Deve aparecer a tela abaixo:

    Screenshot-gnome-netkit.png

  3. Na tela do netkit2 clique em File->Load and Run. Em seguida escolha o arquivo de configuração de experimento teste.conf.
  4. Após selecionar o arquivo de configuração, o experimento é automaticamente iniciado. A tela do netkit2 mostra o terminal (contendo um shell) de uma das máquinas virtuais. Para selecionar outra máquina virtual basta clicar no botão corresponde (logo abaixo da tela do terminal, como se pode ver abaixo).

    Netkit2-1.png

  5. Clique em File->Graph para visualizar um diagrama da topologia da rede em execução.

    Netkit2-2.png

O experimento de exemplo contém a seguinte rede:

Netkit2-lab1.png

Experimente a comunicação entre os computadores dessa rede, usando o comando ping. Investigue também que interfaces de rede existem em cada um deles, usando o comando ifconfig. Veja que rotas estáticas foram definidas usando o comando netstat -rn. Finalmente, para visualizar o tráfego experimente selecionar o ítem de menu Wireshark->any e em seguida fazer ping entre os computadores.

O menu do netkit2

Os ítens de menu do netkit2 tem as seguintes funções:

Menu File:

  • Load Only: carrega um arquivo de configuração de experimento, mas não o executa. Se um experimento já tiver sido carregado e estiver em execução, primeiro ele será terminado.
    • Drag and Drop (arrastar e soltar): pode-se carregar um experimento usando a função de arrastar e soltar. Pode-se arrastar um link para uma URL (ex: a partir de um navegador web), ou um arquivo da área de trabalho ou gerenciador de arquivos. Isso funciona somente se nenhum experimento estiver em execução.
  • Load and Run: carrega um arquivo de configuração de experimento e o executa imediatamente. Se um experimento já tiver sido carregado e estiver em execução, primeiro ele será terminado.
  • Export: exporta um projeto do Netkit, o qual contém o arquivo de configuração (extensão .conf) e arquivos preservados das máquinas virtuais. Ver maiores detalhes na seção sobre Projetos do Netkit.
  • Import from folder: importa um projeto do Netkit contido em um subdiretório. Ver maiores detalhes na seção sobre Projetos do Netkit.
  • Import from file: importa um projeto do Netkit contido em um arquivo compactado. Ver maiores detalhes na seção sobre Projetos do Netkit.
  • Edit: abre o editor de texto gedit para poder editar a configuração do experimento.
  • Graph: mostra/esconde um diagrama da topologia da rede
  • Clear: para o experimento e mostra a tela inicial do netkit2
  • Quit: termina o experimento e encerra o netkit2.


Menu Network:

  • Start ou Restart:
    • Start: inicia um experimento cujo arquivo de configuração foi carregado mais ainda não executado (i.e. usando File->Load Only). Se o arquivo de configuração tiver sido modificado desde o instante em que foi carregado, será novamente lido antes de ser executado.
    • Restart: reinicia um experimento que já esteja em execução, recarregando seu arquivo de configuração caso tenha sido modificado.
  • Stop: termina um experimento, parando todas suas máquinas virtuais.
  • Reload: recarrega o arquivo de configuração do experimento corrente, caso tenha sido modificado. Se o experimento estiver em execução, termina-o primeiro.

Menu Wireshark:

  • Cada ítem deste menu mostra o nome de uma interface de rede da máquina virtual selecionada. O ítem any representa todas as interfaces de rede. Ao selecionar um desses ítens, um processo de captura de pacotes é acionado na máquina virtual selecionada. Em seguida é executado o Wireshark para visualizar o tráfego coletado.


Menu General:

  • Help: abre uma página de ajuda do Netkit.
  • About: mostra uma tela com informações gerais sobre o netkit2.
  • Update: atualiza para a nova versão do netkit2.
  • Package Install Mode: ativa o modo de instalação de software, em que uma única máquina virtual é executada e com acesso em modo leitura-escrita ao sistema de arquivos. Softwares e modificações feitas em arquivos nesse modo de execução serão permanentes.
  • Restart netkit2: reinicia o netkit2 (neccessário após a atualização de versão).
  • Preferences: possibilita modificar algumas opções de execução de experimentos, tais como diretório de trabalho (default: diretório atual), quantidade de máquinas virtuais que podem ser iniciadas simultaneamente, e quantidade de memória alocada a cada máquina virtual.


A próxima seção descreve em detalhes como configurar um experimento do Netkit.

Softwares disponíveis nas máquinas virtuais

A imagem do sistema operacional das máquinas virtuais se baseia no Ubuntu 12.04. Nele foram instalados diversos softwares para a realização de experimentos de rede.


Lista de softwares de rede instalados
Pacote de software Descrição
apache2 + php5 servidor web Apache + PHP5
iptables / ebtables filtro de pacotes IPv4 / filtro de quadros ethernet
asterisk um PBX por software
bind9 servidor DNS
bmon monitor de uso de banda e estimador de taxa de bits
bwm-ng outro monitor de uso de banda e estimador de taxa de bits
cacti / cacti-spine gerador de gráficos de utilização de recursos do sistema e da rede
cbm mostra o tráfego atual em todas as interfaces de rede
clamav um antivirus útil para uso com MTA
cluster-glue ferramentas para criação de clusters (parte do projeto Linux-HA)
curl utilitário para transferir URL
dhcp3-server servidor DHCP
dig utilitário para consultas DNS
dovecot servidor IMAP e POP3
drbd espelhamento de discos através de uma rede (usado em clusters)
ejabberd servidor Jabber / XMPP
freeradius servidor Radius
gpg ferramenta para encriptação e assinatura digital
heartbeat monitor de recursos para clusters (parte do projeto Linux-HA)
hping3 ferramenta que envia pacotes TCP/IP (quase) arbitrários para hosts
htop visualizador de processos interativo
ifstat mostra estatísticas de interfaces de rede
iftop mostra o uso de banda em interfaces de rede
iperf realiza testes de vazão da rede
ipsec-tools utilitários para manipular parâmetros IPSec
iproute utilitário para manipular a tabela de rotas
iptraf monitor de tráfego em interfaces de rede
lynx um navegador web em modo texto
mailman um gerenciador de listas de email
monkey um servidor web minimalista
mtr ferramenta para diagnóstico de rede
mysql servidor Mysql e utilitários
nagios monitor de sistema e rede
ncftp um cliente FTP
ndisc6 utilitário que implementa ICMPv6 Neighbor Discovery
netdiag conjunto de utilitários para monitoramento de rede (trafshow,strobe,netwatch,statnet,tcpspray,tcpblast)
nethogs mostra o uso da banda por processo
netperf um benchmark para desempenho de rede
ngrep um grep de rede - captura pacotes de acordo com expressões regulares
nload mostra o uso da rede atual
nmap ferramenta para exploração da rede e varredura de portas
ntop mostra o uso da rede via web
openldap servidor OpenLDAP
opennhrp um daemon para implantar DMVPN
pktstat mostra a taxa de bits de diferentes tipos de pacotes por uma interface
openssh cliente e servidor SSH
openvpn cria VPNs baseadas em OpenSSL
pjsip ferramenta para testes de comunicação multimedia (audio e video com SIP, RTP e outros protocolos)
postfix MTA Postfix
proftpd servidor FTP
quagga conjunto de protocolos de roteamento
racoon daemon para gerenciar chaves IKE, usado em IPSec
radvd daemon para divulgação de roteador em redes IPv6
rdnssd daemon para descoberta de servidor DNS em redes IPv6
resource-agents interface para recursos em clusters (parte do projeto Linux-HA)
rsync ferramenta para cópia de arquivos através da rede
samba servidor de arquivos e impressoras com protocolos da rede Windows
shorewall / shorewall6 firewall para IPv4 / IPv6
sipp ferramenta para gerar tráfego de testes para SIP
snmpd agente SNMP e ferramentas correlatas
speedometer mede e mostra a taxa de bits em uma interface
squid servidor proxy e cache para web
stunnel cria túneis SSL
subversion sistema de controle de versão para desenvolvimento colaborativo
tc utilitário para manipular o traffic shaper
tcpd TCP-wrappers: controle de acesso a serviços de rede baseados em TCP
tcpdump captura e análise de tráfego na rede
tcptrack monitora conexões TCP
tshark captura e análise de tráfego na rede
vsftpd servidor FTP com ênfase em segurança
webalizer analisador de logs de servidores web e proxy
wu-ftpd servidor FTP clássico
xl2tpd um cliente/daemon para L2TP

Criação de experimentos

Para criar um experimento do Netkit, deve-se escrever um arquivo de configuração com extensão .conf (sugestão: Lab.conf). Esse arquivo deve conter a configuração da rede do seu experimento. Nele devem-se identificar os atributos globais do experimento, as máquinas virtuais que compõem a rede, seus tipos e como se conectam suas interfaces de rede. O tipo de máquina virtual diz respeito ao seu papel na rede, que pode ser:

  • generic: uma máquina virtual comum, e que pode representar um computador sem nada de especial.
  • gateway: possui as capacidades de generic, e adiciona a função de gateway. Isto é, esse tipo de máquina virtual encaminha datagramas IP entre suas interfaces de rede.
  • pppoe: especializa gateway para adicionar a capacidade de estabelecer enlaces PPPoE (i.e. criar um AC PPPoE).
  • mpls: estende o tipo pppoe, possibilitando criar um switch MPLS rudimentar. Com ele se podem criar LSP (circuitos-virtuais) estáticos e túneis.
  • router: estende o tipo mpls de forma a operar como um roteador. Usa o programa Quagga que implementa os protocolos de roteamento RIP, OSPF e BGP. Apresenta uma interface semelhante ao terminal de um roteador Cisco.
  • switch: estende o tipo generic para criar um switch Ethernet com suporte a VLANs IEEE 802.1q, enlaces agregados IEEE 802.1ax, protocolo STP segundo a norma IEEE 802.1d e controle de acesso IEEE 802.1x.
  • pbx: estende o tipo gateway para criar um PBX IP baseado em Asterisk.


O diagrama abaixo mostra a hierarquia dos tipos de componentes de rede por ora definidos:

Netkit2-tipos.png

Máquinas genéricas (computadores simples)

Máquinas genéricas são computadores que possuem uma ou mais interfaces de rede. No Netkit eles foram definidos para representar computadores de usuários ou servidores.

No exemplo abaixo duas máquinas genéricas, pc1 e pc2, têm suas interfaces ethernet eth0 conectadas à mesma rede local.

# Primeiro devem-se definir os tipos de maquinas virtuais do experimento. 
# Um computador Linux genérico é do tipo "generic":
# nome_vm[type]=generic

pc1[type]=generic
pc2[type]=generic

# Em seguida podem-se definir as interfaces de rede Ethernet: 
# nome_vm[nome_interface]=nome_rede_local:ip=IP/MASCARA

pc1[eth0]=lan0:ip=192.168.0.1/24
pc2[eth0]=lan0:ip=192.168.0.2/24

A rede resultante é:

Netkit-lab1.png

Para ver esse experimento em ação, copie o conteúdo acima para um arquivo (ex: Lab.conf). Em seguida execute o netkit2 e clique o botão Load para carregar esse arquivo de configuração. Assim que tiver concluído o início do experimento, você deve poder acessar as máquinas virtuais pc1 e pc2. Ambas possuem suas interfaces de rede eth0 configuradas com os endereços IP informados em Lab.conf. A figura abaixo mostra a tela do netkit2 com as máquinas virtuais:

Screenshot-gnome-netkit-4.png

Quando uma máquina virtual é iniciada, suas interfaces de rede precisam ser configuradas. Além disso, outros comandos podem ser necessários para prepará-la para o experimento, tais como criação de rotas estáticas ou inicialização de serviços de rede. Esses comandos adicionais podem ser adicionados ao arquivo nome_vm.startup (ex: para a máquina virtual pc1 o arquivo deve se chamar pc1.startup). No entanto, algumas opções de configuração mais comuns (como endereços IP de interfaces) podem ser feitas diretamente no arquivo de configuração Lab.conf. Assim, o próprio netkit2 configura automaticamente as máquinas virtuais quando inicia um experimento. Se houver necessidade de editar manualmente os arquivos nome_vm.startup, adicione seus comandos depois da linha:

/hostlab/nome_vm-auto.sh

Interligando interfaces de rede

No exemplo anterior, os dois computadores tiveram suas interfaces de rede interligadas. No Netkit o link entre interfaces é especificado por um nome_ de_link, que pode ser uma palavra qualquer a seu critério. Destacando a interligação das interfaces do exemplo anterior, nota-se que o nome do link é lan0:

pc1[eth0]=lan0:ip=192.168.0.1/24
pc2[eth0]=lan0:ip=192.168.0.2/24

Assim, todas as interfaces que estiverem associadas ao mesmo nome de link pertencerão ao mesmo enlace. Inclusive é possível conectar mais de duas interfaces ethernet, que assim se comunicarão como se houvesse um hub a interligá-las.

Observe que nome_de_link pode ser qualquer coisa. O Netkit não o interpreta nem o associa a qualquer nome de máquina virtual. Ele serve somente para informar as interfaces de rede que devem estar interligadas.

Interfaces podem ser declaradas para iniciarem desativadas. Para obter esse efeito, basta acrescentar o atributo down à interface, como neste exemplo:

pc1[eth0]=lan0:ip=192.168.0.1/24

# interface eth0 de pc2 inicia desativada
pc2[eth0]=lan0:ip=192.168.0.2/24:down
Usando DHCP

Interfaces de rede do tipo ethernet também podem ser configuradas usando DHCP. Para isso, deve-se definir o parâmetro IP da interface de rede da seguinte forma:

pc[type]=generic
pc[eth0]=link:ip=dhcp

Para que o DHCP funcione, deve existir ao menos um servidor DHCP dentro do mesmo domínio de broadcast ethernet. Isso se faz definindo o atributo dhcp de uma máquina virtual, como mostrado abaixo:

servidor[type]=generic

servidor[eth0]=link:ip=10.0.0.1/24

servidor[dhcp]=eth0:range=10.0.0.10,10.0.0.20:default-lease=7200:gateway=10.0.0.254

servidor[default_gateway]=10.0.0.254

O primeiro parâmetro na definição do atributo dhcp, como exemplificado acima, diz respeito à interface de rede onde serão atendidas requisições vindas de clientes DHCP. Mais de uma interface de rede pode ser servida, bastando definir novamente o atributo dhcp para cada interface. Os demais parâmetros seguem explicados na tabela abaixo:

Parâmetro Descrição Exemplo
range A faixa de endereços IP a ser concedida aos clientes. Deve ser definida com um par de endereços IP separados por vírgula range=10.0.0.10,10.0.0.20
gateway O endereço IP do gateway default da subrede a ser informado aos clientes. Se for omitido, o endereço IP da interface de rede que recebeu a requisição do cliente será informado como gateway default. gateway=10.0.0.254
default-lease A duração da concessão de um endereço para um cliente (em segundos). Se for omitido, será usado o valor de 600 segundos. default-lease=600
max-lease A duração máxima da concessão de um endereço para um cliente (em segundos). Se for omitido, será usado o valor de 3600 segundos. max-lease=3600
Limitação de banda nas interfaces de rede

A taxa de bits máxima em cada interface de rede pode ser limitada por meio do atributo rate. Esse atributo tem como argumento um valor inteiro, que corresponde à taxa em kbps (kilobits por segundo) permitida na interface.

# interface eth0 de pc1 tem taxa limitada a 256 kbps
pc1[eth0]=lan1:ip=192.168.0.1/24:rate=256

# interface eth0 de pc2 tem taxa limitada a 512 kbps
pc2[eth0]=lan1:ip=192.168.0.1/24:rate=512

IPv6

Endereços IPv6 podem ser atribuídos às interfaces de rede de forma similar a endereços IPv4, porém usando-se o atributo ipv6:

pc1[eth0]=lan0:ipv6=aa::1/64
pc2[eth0]=lan0:ipv6=aa::2/64

As regras para escrever endereços IPv6 compactos são válidas para o atributo ipv6. Assim, endereços como ::1/80, aa:bb::6/64, aa:bb:ccdd:1234:33:8899:1122:6677/80 são possíveis de serem usados.


Endereços IPv6 são automaticamente habilitados nas interfaces. Mesmo que não seja configurado explicitamente, cada interface terá seu endereço IPv6 em escopo local. Par desativar completamente o uso de IPv6 em uma interface, deve-se usar o atributo noipv6:

pc1[eth0]=lan0:ip=10.0.0.1/24:noipv6


Nesse exemplo, a interface eth0 de pc1 possui um endereço IPv4, porém endereços IPv6 estão desativados.

Rotas estáticas

Rotas estáticas para redes IPv4 ou IPv6 podem ser adicionadas a qualquer máquina virtual usando o atributo route:

pc1[route]=192.168.0.0/24:gateway=192.168.10.10
pc1[route]=172.18.0.0/16:gateway=192.168.10.1
pc1[route]=default:gateway=192.168.10.2

# Rotas IPv6 ... note o uso de default6 para a rota default IPv6
pc1[route]=default6:gateway=a:b::1
pc1[route]=cc:ab::/64:gateway=a:b::1

No exemplo acima foram adicionadas três rotas estáticas IPv4 ao computador pc1. A primeira tem como destino a rede 192.168.0.0/24, que deve ser alcançada via gateway 192.168.10.10. A segunda aponta a rede 172.18.0.0/16 e usa o gateway 192.168.10.1. A terceira é a rota default. No caso de rotas IPv6, note que deve-se usar a palavra-chave default6 para a rota default.

Autoconfiguração de endereços e descoberta automática de gateway IPv6 com radvd

No caso de redes IPv6, é possível usar o serviço radvd para a descoberta automática de gateway da rede. Esse serviço possibilita também a configuração automática de endereço IPv6 das interfaces dos computadores de uma rede, como resumido no manual do radvd:

radvd is the router advertisement daemon for IPv6. It listens to router solicitations and sends router advertisements 
as described in "Neighbor Discovery   for   IP   Version   6  (IPv6)"  (RFC  4861).   With  these  advertisements 
hosts can automatically configure  their  addresses  and some  other  parameters. They also can choose a default 
router based on these advertisements.

Para usar o radvd, deve-se ativá-lo no gateway da rede para cada interface de rede onde se desejam fazer os anúncios:

# radvd somente pode ser ativado em gateways (isso inclui router e outros tipo descendentes de gateway)
r1[type]=gateway

r1[eth0]=link1:ipv6=a:b::1/64
r1[eth1]=link2:ipv6=d:e::fe/64

# ativa o radvd na interface eth0. Os atributos ''min_interval'', ''max_interval'' e ''rdnss'' são opcionais.
r1[radvd]=eth0:min_interval=3:max_interval=10:rdnss=a:b::1

A configuração criada automaticamente para o radvd é simplificada. O exemplo acima geraria o seguinte arquivo de configuração /etc/radvd.conf:

interface eth0 {
  AdvSendAdvert on;
  MinRtrAdvInterval 3;
  MaxRtrAdvInterval 10;
  prefix a:b:0:0:0:0:0:0/64 {
  AdvOnLink on;
  AdvAutonomous on;
  };
  RDNSS a:b::1 {};
};


Do lado do cliente, nada é necessário fazer para que sua interface seja automaticamente configurada. Porém caso se queria a descoberta do servidor DNS na rede IPv6, deve-se ativar o serviço rdnssd, como no exemplo a seguir:

# declara uma interface no link denominado "lan". Note que não se declara a configuração
# do endereço IPv6
pc[eth0]=lan

# ativa o serviço rdnssd no host "pc"
pc[services]=rdnssd


OBS: para que o serviço rdnssd descubra o servidor DNS, o anúncio de servidores DNS deve ser ativado no serviço radvd do gateway da rede.

Rotas estáticas via interfaces PPP

No caso de interfaces PPP, rotas estáticas devem obrigatoriamente ser especificadas da seguinte forma:

pc1[route]=192.168.0.0/24:dev=ppp0

# Ou no caso de rota IPv6
pc1[route]=aa:bb::/64:dev=ppp0

A diferença está no fato de que se deve indicar a interface de saída da rota ao invés do gateway.

Rotas default (rota padrão)

A rota default é um caso especial, e por ser bastante comum existe um atributo específico para sua definição:

pc1[default_gateway]=192.168.0.254

# Ou no caso de IPv6
pc1[default_gateway]=aa:bb::1

No exemplo acima, o computador pc1 definiu que seu roteador default deve ser 192.168.0.254. Essa forma curta de definir a rota default funciona somente para rotas que passam por gateways. No caso de rotas por interfaces, deve-se adicioná-las com o atributo route.

OBS: no caso de interfaces PPP, não se pode especificar uma rota default com a sintaxe acima. Para essas interfaces, deve-se usar a sintaxe para rotas estáticas em geral:

pc1[route]=0.0.0.0/0:dev=ppp0

# Ou no caso de IPv6
pc1[route]=::/0:dev=ppp0

... ou:

pc1[route]=default:dev=ppp0

# No caso de IPv6
pc1[route]=default6:dev=ppp0

Enlaces ponto-a-ponto (via portas seriais)

No caso de uma rede em que máquinas virtuais se comunicam via portas seriais efetuando enlaces ponto-a-ponto, uma sintaxe ligeiramente diferente deve ser usada em Lab.conf:

pc1[type]=generic
pc2[type]=generic

pc1[ppp0]=link0:ip=10.0.0.1/30
pc2[ppp0]=link0:ip=10.0.0.2/30

A diferença está no nome da interface, que deve ser ppp0. Múltiplas interfaces ponto-a-ponto podem existir em cada máquina virtual. Ao iniciarem, as máquinas virtuais terão suas interfaces seriais interligadas. Essas interfaces dentro do Linux são identificadas por /dev/ttyS0, /dev/ttyS1, /dev/ttyS3, e assim por diante (similar a COM1, COM2, COM3, ... do Windows). Assim, dentro das máquinas virtuais podem-se criar enlaces PPP usando-se essas interfaces seriais. No exemplo acima, como foi definido o IP de cada interface ponto-a-ponto, o protocolo PPP será automaticamente ativado quando as máquinas virtuais iniciarem.


Interfaces PPP podem ter endereços IPv4 e IPv6 (ambos ou apenas um deles).


A emulação do enlace via portas seriais pode também simular propriedades de enlaces reais, tais como taxa de bits, atraso de propagação e taxa de erros de bit (BER). No exemplo anterior essas propriedades não foram especificadas, então a taxa de bits ficou limitada pelo computador, e o atraso de propapagação e BER foram nulos. Caso se deseje definir uma ou mais dessas propriedades, devem-se usar as opções rate, delay e ber na configuração do enlace ponto-a-ponto, como mostrado abaixo:

# rate: definida em bits por segundo (bps)
# delay: dado em milissegundos (ms)
# ber: valor entre 0 e 1
pc1[ppp0]=link0:ip=10.0.0.1/30:rate=64000:delay=100:ber=0.000001
pc2[ppp0]=link0:ip=10.0.0.2/30:rate=64000:delay=100:ber=0.000001

Nesse exemplo, o enlace link0 tem taxa de 64000 bps, atraso de propagação de 100 ms e BER de . Observe que uma ou mais dessas propriedades pode ser omitida, e que basta defini-las em uma das pontas do enlace.


OBS: para poder usar o wireshark em uma interface PPP, ela deve ter ativada a opção debug:

# A interface ppp0 de pc1 pode ter seu tráfego analisado com wireshark
pc1[ppp0]=link0:ip=10.0.0.1/30:debug=1

# a ppp0 de pc2 não ...
pc2[ppp0]=link0:ip=10.0.0.2/30
Usando a porta serial da máquina real

Pode-se vincular uma interface serial de uma máquina virtual a uma porta serial da máquina real. Com isso, é possível estabelecer enlaces PPP entre máquinas virtuais que estão em diferentes computadores. Esses computadores devem ter suas interfaces seriais RS-232 interligadas por um cabo serial cross. Essa vinculação é feita quando se escreve o nome de uma interface serial da máquina real no lugar do link, ao se declarar uma interface PPP:

pc1[type]=generic

# A interface ppp0 de pc1 está vinculada à interface ttyS0 da máquina real
pc1[ppp0]=ttyS0:ip=10.0.0.1/30

OBS: as interfaces seriais são chamadas de ttyS0 (equivalente a COM1 do DOS/Windows), ttyS1 (equivalente a COM2), e assim por diante.

Iniciando serviços de rede automaticamente

Serviços de rede, tais como os oferecidos pelos servidores SSH, Apache2 e outros, podem ser iniciados automaticamente usando-se o atributo services:

pc[services]=apache2:ssh

Os serviços a serem iniciados devem estar separados por :.

Observe que as configurações desses serviços poderão precisar ser ajustadas, dependendo de como se deseja que eles operem.

Arquivos de projeto do Netkit: preservando modificações feitas nas máquinas virtuais

No arquivo de configuração do Netkit (ex: Lab.conf) devem-se listar os diretorios e/ou arquivos a serem preservados em cada vm (pode haver vm sem o que preservar). Assim, ao iniciar a rede cada máquina virtual pode recuperar os arquivos preservados, e ao terminar os salva automaticamente. Por exemplo:

pc1[type]=generic
pc2[type]=generic

pc1[eth0]=link0:ip=192.168.0.1/24
pc2[eth0]=link0:ip=192.168.0.2/24

pc1[preserve]=/etc:/usr/local/etc

... vai preservar os diretorios /etc e /usr/local/etc de pc1, porém em pc2 nada será preservado. Os diretorios e arquivos a serem preservados devem estar separados por ":". Quanto mais específicos forem os diretórios listados, menor será a quantidade de arquivos a serem preservados.

Para facilitar a cópia da configuração de uma rede virtual, a qual inclui esses arquivos preservados, existem os ítens "Export" e "Import" no menu "File". Ao clicar em "Export", pode-se salvar em um subdiretório qualquer todo um projeto do Netit, o qual é chamado de "Netkit Project File". O nome desses arquivo de projeto é obtido do arquivo de configuração da rede, porém com extensão ".netkit". Ao clicar em "Import" pode-se escolher um projeto salvo previamente, tendo como efeito a restauração dos arquivos preservados das máquinas virtuais e a carga automática do arquivo de configuração. Com isso pode-se copiar o arquivo de projeto entre diferentes computadores, tornando possível reproduzir fielmente uma rede virtual criada e configurada previamente.

IMPORTANTE: somente deve-se exportar o arquivo de projeto APÓS terminar a execução da rede virtual.

Gateways (computadores que interligam subredes)

Neste outro exemplo (contido neste arquivo), o computador pc2 funciona como gateway entre os computadores pc1 e pc3.

pc1[type]=generic
pc2[type]=gateway
pc3[type]=generic
pc1[default_gateway]=192.168.0.2
pc3[default_gateway]=192.168.1.2

pc1[eth0]=lan0:ip=192.168.0.1/24
pc2[eth0]=lan0:ip=192.168.0.2/24
pc2[eth1]=lan1:ip=192.168.1.2/24
pc3[eth0]=lan1:ip=192.168.1.3/24

A rede resultante é:

Netkit-lab2.png

NAT

NAT pode ser ativado em máquinas virtuais do tipo gateway. Em sua configuração deve-se informar qual a interface de saída onde será feito o NAT:

pc2[type]=gateway

pc2[nat]=eth1

Assim, todos datagramas que sairem pela interface eth1 do gateway pc2 terão seus endereços IP de origem substituídos pelo endereço IP dessa interface.

Uplink para a rede real

O Netkit possibilita que se criem links para a rede real, e com isto as máquinas virtuais podem acessar a rede externa e mesmo a Internet. No entanto, o contrário é um pouco mais difícil (se bem que não impossível) devido a forma como o acesso à rede real foi implementado. O link para a rede real funciona como um enlace ponto-a-ponto ethernet entre uma máquina virtual e a máquina real (o sistema hospedeiro), como pode ser visto neste exemplo:

Netkit-uplink.png


pc1[type]=generic
pc2[type]=gateway

pc1[default_gateway]=192.168.0.2
pc2[default_gateway]=10.0.0.2

pc1[eth0]=link1:ip=192.168.0.1/24
pc2[eth0]=link1:ip=192.168.0.2/24
pc2[eth1]=uplink:ip=10.0.0.1/30

A criação do link para rede externa deve ser feita com o link especial uplink. Ele deve ter um endereço IP que será usado somente para criar o link entre a máquina virtual e o sistema hospedeiro. O IP no sistema hospedeiro é sempre o último endereço possível dentro da subrede especificada (no exemplo, seria o IP 10.0.0.2).

pc2[eth1]=uplink:ip=10.0.0.1/30

Se outras máquinas virtuais precisarem acessar a rede externa, devem ter rotas configuradas para usarem o gateway onde foi feito o uplink. Além disso, será necessário ativar o NAT nesse gateway.

Por fim, a criaçao do uplink implica executar alguns comandos como root no sistema hospedeiro. Assim, ao ativar a rede o Netkit irá usar o sudo para executar esses comandos. Por isso é possível que a sua senha seja solicitada durante a inicialização da rede virtual.

Uplink em modo bridge

Às vezes uma interface de uma máquina virtual precisa ser exposta na rede real, como se ela pertencesse ao sistema hospedeiro. Neste caso, deve-se criar uma bridge entre a interface da máquina virtual e uma interface real do sistema hospedeiro (de forma semelhante ao que faz o Virtualbox e outros tipos de máquinas virtuais). Uma bridge é um mecanismo existente no Linux para interligar interfaces ethernet em nível de enlace, como se elas formassem um switch. O procedimento para criar uma bridge integrada a uma interface do tipo uplink do Netkit é um tanto trabalhoso, e por isso esse processo foi automatizado.

A criação de um uplink em modo bridge deve ser feita usando o parâmetro bridge ao se declarar uma interface de rede, como mostrado abaixo:

pc[eth0]=uplink:bridge=eth0:ip=192.168.1.100/24

Neste exemplo, será criada uma bridge entre a interface eth0 da máquina virtual pc e a interface eth0 do sistema hospedeiro. Como com isso a interface da máquina virtual estará exposta na rede real, seu endereço IP pode pertencer à subrede da rede real. Se esse endereço IP for de alguma outra subrede, a máquina virtual não conseguirá se comunicar com as máquinas reais, tampouco acessar a Internet. Mas isso pode ser desejável se a intenção for interligar redes virtuais que estejam sendo executadas em diferentes computadores.

Outra possibilidade é configurar a interface com DHCP:

pc[eth0]=uplink:bridge=eth0:ip=dhcp

Desta forma, a interface obterá um endereço IP (além de rota default e servidor DNS) do servidor DHCP da rede real.

Por fim, é possível definir uma interface sem endereço IP:

pc[eth0]=uplink:bridge=eth0

PBX IP (Asterisk)

O Netkit possui um tipo de máquina virtual especial para funcionar como um PBX Asterisk. As diferenças entre esse tipo de máquina e gateway é a quantidade de memória a ela reservada (64 MB) e a instalação automática do software Asterisk. Todos os arquivos do Asterisk estão dentro de /usr/local/asterisk. Abaixo há um exemplo de uma rede com um PBX:

Pbx-netkit.png
Uma pequena rede com um PBX IP

A configuração dessa rede está mostrada a seguir:

global[compact]=True
#
pbx[type]=pbx
pc1[type]=generic
pc2[type]=generic
#
pbx[eth0]=link1:ip=192.168.1.254/24
pbx[eth1]=link2:ip=192.168.2.254/24
pc1[eth0]=link1:ip=192.168.1.1/24
pc2[eth0]=link2:ip=192.168.2.1/24

pc1[default_gateway]=192.168.1.254
pc2[default_gateway]=192.168.2.254
pbx[preserve]=/usr/local/asterisk/etc

O Asterisk instalado no PBX tem somente canais SIP e IAX2, porém isso é suficiente para realizar muitos experimentos sobre VoIP. Note que na configuração do experimento mostrada acima incluiu-se uma opção para preservar os arquivos contidos em /usr/local/asterisk/etc. Isso é fortemente recomendado, para que as configurações feitas nos canais SIP e IAX2, além do plano de discagem, não sejam perdidos ao se encerrar a execução da rede. Porém para que esses arquivos sejam realmente preservados, deve-se exportar o experimento logo após parar a rede, conforme explicado na seção sobre preservação de arquivos.

OBS: o Asterisk não é iniciado automaticamente. Para iniciá-lo execute:

/usr/local/asterisk/sbin/asterisk

... ou declare-o no arquivo de configuração do Netkit como um serviço a ser iniciado:

pbx[services]=asterisk

...e para monitorá-lo (abrir seu console):

/usr/local/asterisk/sbin/rasterisk -vvv

Realizando chamadas VoIP no Netkit

Um experimento sobre VoIP implica serem feitas chamadas para se testarem as configurações do PBX e para estudar o funcionamento dos protocolos envolvidos. Porém o uso de softphones dentro do Netkit é impraticável, visto que as máquinas virtuais não foram feitas para terem acesso ao microfone e alto-falante (tampouco apresentam ambiente gráfico, o que limita os softphones que poderiam ser usados). Como o objetivo do Netkit é ajudar a criar redes virtuais e realizar experimentos com aplicações que usem essas redes, seria suficiente simular chamadas VoIP para estudar a sinalização e o transporte das streams de audio. Desta forma, no Netkit foram instalados os softwares siprtp e pjsua, que fazem parte do projeto PJSIP (um conjunto de programas de teste e avaliação de desempenho para infraestruturas VoIP baseadas em SIP), e também o software sipp.

  • siprtp: esse programa possibilita fazer chamadas com áudio sintetizado, no entanto possui algumas restrições para ser usado com o Asterisk.
  • pjsua: esse programa é mais completo, sendo capaz de realizar chamadas muito próximas do real. Ele é até capaz de gerar o audio a partir de arquivos de som. Ao contrário do siprtp, o pjsua é capaz de se registrar no Asterisk.
  • sipp: mais um programa capaz de fazer muitos testes de conformidade e capacidade em chamadas SIP.
Usando o siprtp

O programa siprtp funciona em modo cliente-servidor: em um computador executa-se o programa em modo servidor (aguardando chamadas), e no outro executa-se em modo cliente (iniciando chamadas). As chamadas podem ser feitas diretamente ou com a intermediação de um ou mais PBX IP. O exemplo abaixo mostra os comandos necessários para se fazer uma chamada direta entre cliente e servidor:

Servidor Cliente
siprtp -i IP_do_servidor siprtp -i IP_do_cliente sip:0@IP_do_servidor

Chamadas que usam PBX como intermediários podem também ser realizadas, porém há alguns cuidados a tomar para que funcionem a contento:

  • siprtp não faz registro SIP no PBX, portanto a configuração dos canais SIP no PBX deve informar os endereços IP dos computadores onde estão tanto cliente quanto servidor. No Asterisk isso se faz com o parâmetro host de um canal SIP, definido no arquivo sip.conf:
    [1234]
    type=friend
    username=1234
    host=IP_do_computador_onde_roda_o_siprtp
    #secret=ultrasecreta ; não precisa de senha ...
    insecure=port,invite
    context=default
    allow=alaw
    allow=ulaw
    qualify=yes
    
  • siprtp não aceita RE-INVITE, portanto deve-se desativar essa funcionalidade no Asterisk. Na seção [general] do arquivo sip.conf deve-se incluir esta opção:
    directmedia=no
    
  • O cliente deve especificar o canal SIP e o endereço IP do PBX ao fazer uma chamada. Por exemplo, para fazer uma chamada para o canal 1234 deve-se executar o seguinte:
    siprtp -i IP_do_cliente sip:1234@IP_do_PBX
    
Usando o pjsua

O pjsua possui muitas funcionalidades que o tornam um agente SIP quase completo (faltaria ao menos suportar re-invite). Para usá-lo existem muitas opções de linha de comando, conforme descrito em seu manual. Aqui se demonstra como fazer uma chamada com dois pjsua registrados em um PBX Asterisk.

  1. Inicie o Asterisk no PBX, executando este comando:
    asterisk
    rasterisk -vvv
    
    Obs: "rasterisk -vvv" serve somente para que você possa monitorar o funcionamento do Asterisk
  2. Em cada máquina virtual fone pode ser criado um arquivo /root/pjsua.cfg, que contém configurações usuais para rodar o pjsua (ver exemplo mais à frente). Desta forma, evita-se ter que digitá-las sempre que se iniciar o programa. Deve-se executar o pjsua da seguinte forma para que use esse arquivo de configuração:
    pjsua --config-file=/root/pjsua.cfg
    
  3. O arquivo de configuração tenta registrar automaticamente o pjsua no Asterisk. A conta SIP pre-configurada para fins de demonstração é sip:100@ifsc.edu.br (mude-a de acordo com o seu experimento).
  4. Ao rodar o pjsua, confira no PBX se ele foi devidamente registrado. Assim, execute o seguinte no prompt do rasterisk desse PBX:
    sip show peers
    
    O resultado deve ser parecido com este (neste exemplo, foram ativados dois pjsua), em que se nota o Status OK para as contas SIP:

    Rasterisk1.png

  5. A tela do pjsua mostra um menu com os comandos que podem ser usados, como mostrado na seguinte figura:

    Pjsua1.png

  6. Para fazer uma chamada, use o comando m. Ao digitá-lo e teclar ENTER, será pedida a URL do contato a ser chamado:

    Pjsua2.png

  7. Uma vez tendo a chamada estabelecida, pode-se usar o comando dq para monitorar a qualidade da comunicação:

    Pjsua3.png

  8. Para encerrar a chamada, use o comando ha.
Ajustes na configuração do pjsua

O arquivo de configuração pjsua.cfg que foi fornecido contém configuração de demonstração. Ao fazer as suas modificações nas configurações dos PBX para realizar o trabalho, será necessário também ajustar esse arquivo. Abaixo segue o conteúdo do pjsua.cfg que está em fone1 (os números das linhas são apenas informativos, e não fazem parte do pjsua.cfg):

#
# User agent:
#
--auto-answer 200
--max-calls 4
--registrar sip:192.168.1.100
--proxy sip:192.168.1.100;lr
--realm *
# Abaixo devem ser especificados os dados da conta SIP
--id sip:100@ifsc.edu.br
--username 100
--password 100

#
# Logging options:
#
--log-level 3
--app-log-level 4

#
# Network settings:
#
--local-port 5060

#
# Media settings:
#
--null-audio
--snd-auto-close 1
--rtp-port 4000

#
# SIP extensions:
#
--use-timer 1

# Desativa deteccao de silencio
--no-vad

O que pode ser necessário modificar são os dados da conta SIP a ser usada pelo pjsua. Isso é especificado nas linhas 10, 11 e 12.

Usando o sipp

A documentação do SIPp mostra vários exemplos e detalha como se podem criar os cenários de teste. Existe também um pequeno manual que pode ser lido com este comando:

man sipp

Switches

Switches são implementados usando funcionalidades existentes no Linux. Assim, uma máquina virtual devidamente configurada pode se comportar como um switch. As funcionalidades possibilitam fazer experiências com VLANs IEEE 802.1q, agregação de enlaces IEEE 802.1AX, e mesmo com STP IEEE 802.1d.

Um switch com 4 portas pode ser criado da seguinte forma:

nome[type]=switch

nome[eth0]=port0
nome[eth1]=port1
nome[eth2]=port2
nome[eth3]=port3

Sendo:

  • nome: nome da maquina virtual

O exemplo com um switch (ver a biblioteca de exemplos mais abaixo) mostra como criar uma pequena LAN com switch. Note que a máquina virtual que será o switch (chamada aqui convenientemente de switch) deve declarar suas interfaces normalmente, além de definir que elas operam em modo bridge (i.e. como um switch):

switch[type]=switch
pc1[type]=generic
pc2[type]=generic
pc3[type]=generic
pc4[type]=generic

switch[eth0]=port0
switch[eth1]=port1
switch[eth2]=port2
switch[eth3]=port3

pc1[eth0]=port0:ip=192.168.0.1/24
pc2[eth0]=port1:ip=192.168.0.2/24
pc3[eth0]=port2:ip=192.168.0.3/24
pc4[eth0]=port3:ip=192.168.0.4/24


VLANs

Um switch pode ter também suas portas em diferentes vlans. Assim, no exemplo abaixo cria-se um switch com 4 portas, porém com 2 portas na vlan 5 e duas na vlan 10 (todas em modo untagged):

nome[type]=switch

nome[eth0]=port0:vlan_untagged=5
nome[eth1]=port1:vlan_untagged=10
nome[eth2]=port2:vlan_untagged=10
nome[eth3]=port3:vlan_untagged=5

Sendo:

  • nome: nome da maquina virtual
  • vlan_untagged: especifica o número de uma VLAN em modo untagged a que pertence a interface de rede em questão.

A configuração acima vai criar uma bridge para cada conjunto de interfaces que estão na mesma VLAN. Nesse exemplo as interfaces operam todas em modo untagged, mas se for necessário que operem em modo tagged deve-se fazer da seguinte forma:

nome[type]=switch

nome[eth0]=port0:vlan_tagged=10,20
nome[eth1]=port1:vlan_untagged=10
nome[eth2]=port2:vlan_untagged=10
nome[eth3]=port3:vlan_untagged=5
nome[eth4]=port4
nome[eth5]=port5

No exemplo acima, a interface eth0 estará nas VLANs 10 e 20 em modo tagged. No caso de interfaces em que não se especificam as vlans, como eth4 e eth5, o switch assume implicitamente que estão na vlan 1 e em modo untagged.

Com base nos exemplos acima, a sintaxe para definir as VLANs em uma interface de rede de uma máquina virtual deve ser:

nome_vm[nome_iface]=nome_link:vlan_untagged=num_vid:vlan_tagged=num_vid1,num_vid2,...

... sendo que tanto vlan_untagged quanto vlan_tagged podem ser omitidos, mas não podem ser usados ao mesmo tempo.

Um outro exemplo (também encontrado na biblioteca de exemplos) mostra um switch com duas VLANs, e o computador pc4 atuando como gateway entre as VLANs. O gateway usa duas interfaces virtuais, e assim a porta do switch em que ele está conectado deve operar em modo tagged:

switch[type]=switch
pc1[type]=generic
pc2[type]=generic
pc3[type]=generic
pc4[type]=gateway
pc5[type]=generic
pc6[type]=generic
pc7[type]=generic

switch[eth0]=port0:vlan_untagged=5
switch[eth1]=port1:vlan_untagged=5
switch[eth2]=port2:vlan_untagged=5
switch[eth3]=port3:vlan_tagged=5,10
switch[eth4]=port4:vlan_untagged=10
switch[eth5]=port5:vlan_untagged=10
switch[eth6]=port6:vlan_untagged=10

pc1[eth0]=port0:ip=192.168.0.1/24
pc2[eth0]=port1:ip=192.168.0.2/24
pc3[eth0]=port2:ip=192.168.0.3/24
pc4[eth0]=port3:vlan_tagged=(5,ip=192.168.0.4/24),(10,ip=192.168.1.4/24)
pc5[eth0]=port4:ip=192.168.1.5/24
pc6[eth0]=port5:ip=192.168.1.6/24
pc7[eth0]=port6:ip=192.168.1.7/24

Esse exemplo mostra que podem-se definir diretamente os endereços IP das interfaces de rede virtuais. Isso é útil para o caso de se definirem interfaces virtuais em máquinas virtuais do tipo generic, gateway e router (não tem sentido usar isso em switch). No entanto, a sintaxe nesse caso é ligeiramente diferente, pois deve-se colocar entre parênteses o número da vlan e o IP da interface, como destacado abaixo:

pc4[eth0]=port3:vlan_tagged=(5,ip=192.168.0.4/24),(10,ip=192.168.1.4/24)

STP (Spanning Tree Protocol)

Switches reais usualmente possuem suporte a STP (Spanning Tree Protocol) para possibilitar haver enlaces redundantes em uma rede local. No Netkit podem-se criar redes em que se usa o STP, que deve ser ativado no switches. Um exemplo de rede em que o STP se torna necessário é mostrada na figura abaixo:

LAN-anel-stp.png

Para criar essa rede no Netkit pode-se usar a seguinte configuração:

sw1[type]=switch
sw2[type]=switch
sw3[type]=switch
pc1[type]=generic
pc2[type]=generic
pc3[type]=generic
 
# Ativação do STP nos switches
sw1[stp]=on:bridge_priority=1024
sw2[stp]=on:bridge_priority=128
sw3[stp]=on:bridge_priority=500

sw1[eth0]=sw1-sw2
sw1[eth1]=sw1-port1
sw1[eth2]=sw1-sw3
 
sw2[eth0]=sw1-sw2
sw2[eth1]=sw2-port1
sw2[eth2]=sw2-sw3
 
sw3[eth0]=sw1-sw3
sw3[eth1]=sw3-port1
sw3[eth2]=sw2-sw3
 
pc1[eth0]=sw1-port1:ip=192.168.0.1/24
pc2[eth0]=sw2-port1:ip=192.168.0.2/24
pc3[eth0]=sw3-port1:ip=192.168.0.3/24

A configuração do STP se faz pelo atributo especial stp a ser especificado para cada switch. A opção on ativa o STP, e bridge_priority define a prioridade do switch no escopo do STP.

Como os switches podem ser configurados com múltiplas vlans, o STP deve ser ativado apropriadamente. Isso significa que cada vlan deve ter o STP rodando de forma independente. A configuração do Netkit para especificar o STP para cada vlan segue abaixo:

sw1[type]=switch

# Ativação do STP nos switches
sw1[stp]=on:bridge_priority=1024:vlan=5
sw1[stp]=on:bridge_priority=512:vlan=10

Nesse exemplo, o switch sw1 tem o STP ativado na vlans 5 e 10. Os parâmetros do STP inclusive podem ser diferentes em cada vlan, já que ele opera em cada uma de forma independente (i.e. o STP em uma vlan não interfere com o STP em outra vlan). Vlans em que o stp não foi explicitamente ativado usarão a configuração default do stp, a qual é definida omitindo-se informação sobre vlan:

# Configuração default do STP em um switch ... vale para todas as vlans em que 
# o stp não foi configurado individualmente.
sw1[stp]=on

# A configuração default pode conter quaisquer opções do stp, menos vlan:
sw2[stp]=on:bridge_priority=2000

Um último detalhe sobre o STP diz respeito ao custo e prioridade de cada porta do switch. No STP usado em switches reais, o custo de uma porta é dado pela sua velocidade. Assim, portas mais velozes têm custo menor que portas mais lentas, como por exemplo portas 1 Gbps comparadas a 100 Mbps. No Netkit não existe essa diferenciação entre as interfaces ethernet por serem emuladas, mas pode-se especificar manualmente o custo de cada interface a ser usado pelo STP. A configuração necessária deve ser colocada em cada porta da seguinte forma:

sw1[type]=switch

# Ativação do STP nos switches
sw1[stp]=on:bridge_priority=1024

sw1[eth0]=port0:stp_cost=10
sw1[eth1]=port1:stp_cost=100

Assim, nesse exemplo a interface eth0 do switch sw1 tem custo STP 10, e a interface eth1 tem custo 100. Os custos de interfaces de acordo com a norma IEEE 802.1d pode ser visto na seguinte tabela:

Stp-custos.png


A lista completa de opções que podem ser usadas na configuração do STP no Netkit segue abaixo:

# STP no switch:
# bridge_priority: prioridade do switch no STP
# hello_time: intervalo entre envios de BPDU
# max_age: tempo máximo que o STP pode ficar sem receber uma atualização de BPDU de outro switch
# forward_delay: atraso para enviar uma BPDU notificando uma mudança de configuração do STP
# on: ativa o STP
# off: inicia com STP desativado

sw1[stp]=on:vlan=10:bridge_priority=100:hello_time=2:max_age=10:forward_delay=1

# Porta do switch: pode ter as opções stp_cost (custo da porta) e stp_prio (prioridade da porta)
sw1[eth0]=port0:stp_cost=10:stp_prio=1

Controle de acesso IEEE 802.1x

O controle de acesso IEEE 802.1x possibilita liberar ou bloquear portas de switches mediante a identificação de usuários válidos. Para usá-lo no Netkit deve-se fazer o seguinte:

  1. Nos switches ativa-se a autenticação com IEEE 802.1x, fornecendo-se uma lista de usuários e respectivas senhas. Além disso, identificam-se quais portas dos switches que exigirão que usuários se autentiquem (portas autenticadoras).
    sw[type]=switch
    
    # Podem-se definir quantos usuários e senhas forem desejados.
    sw[8021x]=1:users=usuario1/senha1,usuario2/senha2
    
    # A interface eth0 do switch é uma porta autenticadora, mas a interface eth1 não.
    sw[eth0]=port0:8021x_authenticator=1
    sw[eth1]=port1
    
  2. Nos computadores que se conectarão aos switches deve-se informar o usuário e senha para fins de autenticação.
    pc[type]=generic
    
    pc[eth0]=port0:8021x_user=usuario1/senha1:ip=10.0.0.1/24
    

Juntando os dois exemplos acima, pode-se definir uma pequena rede para fins de demonstração do controle de acesso:

sw[type]=switch
pc1[type]=generic
pc2[type]=generic

# Podem-se definir quantos usuários e senhas forem desejados.
sw[8021x]=1:users=usuario1/senha1,usuario2/senha2

# A interface eth0 do switch é uma porta autenticadora, mas a interface eth1 não.
sw[eth0]=port0:8021x_authenticator=1
sw[eth1]=port1

pc1[eth0]=port0:8021x_user=usuario1/senha1:ip=10.0.0.1/24
pc2[eth0]=port1:ip=10.0.0.2/24

Ao executar a rede acima, deve-se conseguir fazer um ping entre pc1 e pc2. Se quiser testar com maiores detalhes o controle de acesso e vê-lo em ação, experimente fazer o seguinte:

  1. No pc2 deixe o ping em execução (ping 10.0.0.1)
  2. No pc1 execute o utilitário wpa_cli. Esse programa permite controlar o supplicant, que vem a ser o programa responsável por realizar a autenticação com IEEE 8021x. Ao iniciar o wpa_cli mostra um prompt (>), onde se podem executar comandos de consulta ou modificacão do supplicant.
    1. Execute status, e veja as informações sobre a autenticação mantidas pelo supplicant.
    2. Execute logoff, e em seguida observe como estão as resposta do ping no pc2. As respostas devem etr parado ...
    3. Execute logon, e novamente observe o ping no pc2. Após alguns segundos as respostas devem voltar a ser recebidas.
Definindo um IP de gerenciamento

Um switch pode possuir um endereço IP para fins de gerenciamento. No momento, isso é usado somente para que um switch consiga rodar um servidor Radius e atender pedidos de acesso vindos de outros switches. O IP de gerenciamento precisa estar vinculado a uma das VLANs do switch:

sw[management_ip]=192.168.0.10/24:vlan=5

No exemplo acima, o switch sw possui o IP de gerenciamento 192.168.0.10, que está vinculado a VLAN 5. Apenas um IP por switch hpode ser definido.

Como o tipo switch especializa o tipo generic, é possível definir rotas em um switch que possui um IP de gerenciamento. Isso pode ser feito da mesma forma que em máquinas virtuais genéricas (i.e. usando os atributos default_gateway ou route).

Usando um servidor Radius

Em uma infraestrutura de controle de acesso IEEE 8021.X, usualmente o servidor de autenticação reside em um equipamento em separado. Desta forma, os autenticadores (switches e access points) podem efetuar a autenticação usando uma base de usuários comum. Apesar do padrão IEEE 8021.X não definir como deve ser implementado o servidor de autenticação, os fabricantes de equipamentos adotaram o serviço Radius para assumir esse papel. Com isso, para implantar o servidor de autenticação deve-se instalar um servidor Radius em algum equipamento, e fazer com que os autenticadores o utilizem para para autenticar os acessos.

No Netkit a implantação de um servidor Radius foi simplificada e integrada à configuração do controle de acesso descrita no início desta seção. Por questão de simplicidade, o servidor Radius deve ser implantado em um switch. assim, a configuração de um switch que deve operar como servidor Radius é:

sw2[8021x]=1:users=u1/p1,u2/p2:radius_clients=10.0.0.10,10.0.0.254

O parâmetro users lista os usuários e senhas autenticados pelo Radius, e radius_clients lista os endereços IP dos clientes Radius (que são os demais switches). Em ambos os casos, as informações devem ser escritas como listas separadas por vírgulas.

Os clientes Radius precisam definir que servidor Radius irão utilizar. A configuração de um switch que é cliente Radius poderia ser esta:

sw[8021x]=1:radius_server=10.0.0.5

Note que os clientes Radius devem ser capazes de alcançarem o servidor Radius. Quer dizer, se clientes e servidor Radius estiverem em subredes IP diferentes, devem existir rotas para que eles possam se comunicar.

Um exemplo de uma rede com dois switches, sendo um deles um servidor Radius, está mostrada a seguir:

pc1[type]=generic
pc2[type]=generic
sw[type]=switch
sw2[type]=switch

sw[8021x]=1:radius_server=10.0.0.5
sw2[8021x]=1:users=aluno/teste:radius_clients=10.0.0.10

sw[management_ip]=10.0.0.10/24:vlan=1
sw2[management_ip]=10.0.0.5/24:vlan=1

pc1[eth0]=sw-port0:ip=10.0.0.1/24:8021x_user=aluno\teste
pc2[eth0]=sw-port1:ip=10.0.0.2/24:8021x_user=aluno\teste
sw[eth0]=sw-port0:8021x_authenticator=1
sw[eth1]=sw-port1:8021x_authenticator=1
sw[eth2]=sw-port2

sw2[eth0]=sw-port2
Ex-radius.png
Usando múltiplas VLANs
  • isto ainda não funciona ...

Quando um switch que é autenticador IEEE 802.1x possui múltiplas VLANs,

Usando freeradius

Agregação de enlace (bonding)

O Linux possui suporte a agregação de enlaces, em que se agrupam interfaces ethernet de forma a parecerem uma única interface (chamado de Linux Channel Bonding). A interface agregada tem prefixo bond, e assim deve ser identificada como bond0, bond1 e assim por diante. Para criar um enlace agregado no Netkit basta declarar em um switch uma interface desse tipo. A sintaxe da declaração é praticamente idêntica a de interfaces ethernet, como se pode ver abaixo:

pc1[type]=generic
pc2[type]=generic
sw1[type]=switch
sw2[type]=switch

pc1[eth0]=sw1-port0:ip=192.168.0.1/24
pc2[eth0]=sw2-port0:ip=192.168.0.2/24

sw1[eth0]=sw1-port0
sw2[eth0]=sw2-port0

# Define em cada switch uma interface bond0 que agrega dois enlaces.
# O enlace agregado deve ser composto por uma ou mais interfaces ethernet.
# O nome do enlace agregado é sw1-sw2 no exemplo.

sw1[bond0]=sw1-sw2:interfaces=eth1,eth2:mode=8023ad
sw2[bond0]=sw1-sw2:interfaces=eth1,eth2:mode=8023ad

Nesse exemplo o enlace agregado foi criado entre os switches sw1 e sw2. Como se pode notar, existe uma opção de configuração adicional interfaces, usada para listar as interfaces ethernet a serem agrupadas. Essas interfaces não devem ser declaradas explicitamente. Além disso, não se podem configurar VLANs na interface agregada (bond0 no exemplo). Por fim, mais de um enlace agregado pode ser criado no mesmo switch, bastando identificá-los por interfaces bond diferentes (bond1, bond2, ...).

O exemplo acima cria a seguinte rede:

Bond.png


A definição de interfaces bonding possui os seguintes atributos:

Atributo Possíveis valores Descrição
mode round-robin, backup, xor, 8023ad, tlb, alb o tipo de escalonamento de quadros entre as interfaces físicas (default: round-robin)
interfaces lista de nomes de interfaces ethernet as interfaces físicas agregadas
miimon um número inteiro intervalo de monitoramento (em milissegundos) do estado do enlace de cada interface física (default: 100)
lacp_rate {slow, fast} taxa de envio de quadros LACP (slow: a cada 30s, fast: a cada 1s). Default = slow

Máquinas com suporte a PPPoE

A configuração de uma infraestrutura de acesso baseada em PPPoE implica o ajuste de vários detalhes tanto nos clientes quanto no AC (servidor PPPoE). Muitos desses detalhes podem ser abreviados explorando-se opções existentes no Netkit.

Na configuração do Netkit um AC PPPoE deve ser uma máquina virtual do tipo pppoe, que é uma extensão do tipo gateway. Desta forma, todas as capacidades apresentadas por gateway estão presentes no tipo pppoe. Já as opções necessárias para o funcionamento de um AC devem ser especificadas usando-se o atributo pppoe. O cliente PPPoE, por sua vez, precisa apenas indicar em que interface ethernet será iniciado o enlace PPPoE. O exemplo abaixo mostra uma pequena rede com um AC e dois clientes:

sw1[type]=switch
sw2[type]=switch
ac[type]=pppoe
cliente1[type]=generic
cliente2[type]=generic
servidor[type]=generic

# define as opções do AC PPPoE
ac[pppoe]=nome_ac:interface=eth0:users=aluno1/blabla,aluno2/rruahhh:range=172.18.1.1,172.18.1.10:ip=172.18.1.20

sw1[eth0]=sw1-port0
sw1[eth1]=sw1-port1
sw1[eth2]=sw1-port2

sw2[eth0]=sw2-port0
sw2[eth1]=sw2-port1

ac[eth0]=sw1-port0
ac[eth1]=sw2-port0:ip=192.168.0.1/24

servidor[eth0]=sw2-port1:ip=192.168.0.10/24

# Define que a interface eth0 de cliente1 e cliente2 devem operar em modo PPPoE.
cliente1[eth0]=sw1-port1
cliente1[ppp0]=nome_ac:type=pppoe:user=aluno1:password=blabla:interface=eth0

cliente2[eth0]=sw1-port2
cliente2[ppp0]=nome_ac:type=pppoe:user=aluno2:password=rrruahh:interface=eth0

A configuração acima gera uma rede com dois computadores clientes, um AC PPPoE e um servidor, como mostrado na seguinte figura:

Netkit-pppoe.png


A definição do AC PPPoE precisa de algumas opções específicas do PPPoE. Elas devem ser listadas no atributo pppoe da máquina virtual que representa o AC:

# define as opções do AC PPPoE
ac[pppoe]=nome_ac:interface=eth0:users=aluno1/blabla,aluno2/rruahhh:range=172.18.1.1,172.18.1.10:ip=172.18.1.20

A primeira opção mostrada acima (nome_ac) corresponde ao nome do AC, usado durante a etapa de descoberta PPPoE feita pelos clientes. As demais opções do AC são:

  • interface: a interface ethernet onde o AC vai esperar por pedidos de estabelecimento de enlace PPPoE.
  • range: a faixa de endereços IP a serem concedidos aos clientes.
  • ip:o endereço IP a ser usado pelo AC na sua ponta dos enlaces PPPoE.
  • users: a lista de usuários e respectivas senhas, usados para autenticar os acessos vindos dos clientes.

Um cliente precisa definir uma interface PPP que deve operar em modo PPPoE, informando sobre qual interface ethernet ela deve operar. Além disso, devem ser especificadas as opções PPPoE, como destacado abaixo:

# A interface eth0 deve existir para que possa criar a interface ppp0
cliente1[eth0]=sw1-port1

# Aqui se declara a interface ppp0 em modo PPPoE
cliente1[ppp0]=nome_ac:type=pppoe:user=aluno1:password=blabla:interface=eth0

As opções PPPoE do cliente são:

  • user: o nome de usuário para fins de autenticação PPP.
  • password: a senha do usuário para fins de autenticação PPP.
  • ac: o nome do AC com que se deseja estabelecer o enlace.

Uma vez estabelecido um enlace PPPoE, é criada automaticamente uma rota default no cliente usando o AC como gateway.

Roteadores

Roteadores podem ser criados no Netkit usando máquinas virtuais do tipo router. Um roteador tem sua função de gateway ativada automaticamente, e executa o programa Quagga, que implementa protocolos de roteamento (tais como OSPF, RIP e BGP). O exemplo abaixo mostra a criação de uma pequena rede com dois roteadores interligados por um link PPP.

r1[type]=router
r2[type]=router
pc1[type]=generic
pc2[type]=generic

r1[ppp0]=link0:ip=10.0.0.1/30
r1[eth0]=lan0:ip=192.168.0.254/24
r1[route]=default:dev=ppp0

r2[ppp0]=link0:ip=10.0.0.2/30
r2[eth0]=lan1:ip=192.168.1.254/24
r2[route]=default:dev=ppp0

pc1[eth0]=lan0:ip=192.168.0.1/24
pc1[default_gateway]=192.168.0.254

pc2[eth0]=lan1:ip=192.168.1.2/24
pc2[default_gateway]=192.168.1.254

Exp-routers.png


Ao iniciar, um roteador apresenta um shell parecido com o de um roteador Cisco real, como pode ser visto nas duas telas abaixo.


Netkit-router1.png Netkit-router2.png


Esse shell provê somente os comandos de configuração do Quagga. Para executar programas da máquina virtual Linux deve-se usar o comando start-shell. Isso abre um shell usual (bash), onde se podem executar programas do Linux.

Ativação de protocolos de roteamento

A ativação de protocolos de roteamento pode ser feita automaticamente no arquivo de configuração. As configurações de cada protocolo de roteamento residem em arquivos contidos no subdiretório /etc/quagga, os quais estão inicialmente vazios. Após iniciar a rede virtual pode-se usar o console do roteador para configurá-lo, e então executar o comando write memory para gravar sua configuração. Recomenda-se definir o atributo preserve na máquinas virtuais do tipo roteador, de forma a preservar as configurações desses protocolos (lembre de usar o menu File -> Export APÓS encerrar a execução da rede virtual, como já explicado).

# Ativa os protocolos RIP e OSPF no roteador r1
r1[router]=rip,ospf

# Preserva as configurações do roteador r1
r1[preserve]=/etc/quagga

Os protocolos de roteamento que podem ser ativados são:

Protocolo Parâmetro
RIP rip
OSPF ospf
RIPNG ripng
OSPF6 ospf6
BGP bgp
ISIS bgp

Switches MPLS

MPLS é uma tecnologia para redes WAN que usa o conceito de circuitos virtuais (chamados no MPLS de LSP - Label Switched Path). Existe um projeto no Linux para implementar parte da funcionalidade MPLS, o qual está disponível nas máquinas virtuais do Netkit. Apesar desse projeto estar incompleto, algumas funcionalidades básicas podem ser experimentadas, tais como criação de LSP estáticos e túneis MPLS. No entanto, ainda não é possível criar VPNs MPLS (chamadas de VPLS) ou estabelecer LSP dinâmicos. Assim, no Netkit podem-se criar experimentos explorando essas funções elementares do MPLS.

Um equipamento que comuta rótulos, ou switch MPLS, pode ser criado usando uma máquina virtual do tipo mpls. Em cada switch MPLS devem-se configurar:

  • FEC: classes de equivalência de tráfego, que classificam PDUs não-MPLS que entram na rede MPLS. Essa classificação será usada para definir posteriormente (via NHLFE) que rótulo deve ser adicionado.
  • NHLFE: definem o que deve ser feito com uma PDU (usualmente que rótulo adicionar e por que interface transmiti-la).
  • Labelspace: especificam conjuntos de interfaces por onde se recebem PDUs MPLS.
  • ILM: define que rótulos são aceitos vindos de cada labelspace.

Assim, um switch MPLS precisa usualmente ter configuradas essas quatro informações. A configuração do Netkit mostrada abaixo cria umapequena rede com dois switches MPLS e dois computadores comuns.

sw1[type]=mpls 
sw2[type]=mpls
h1[type]=generic
h2[type]=generic

# FEC: mapeia subrede destino para nhlfe
sw1[fec]=192.168.1.0/24:nhlfe=1
sw2[fec]=192.168.0.0/24:nhlfe=1

# NHLFE: como encaminhar uma PDU MPLS
sw1[nhlfe]=1:interface=eth0:label=100:ip=10.0.0.2
sw2[nhlfe]=1:interface=eth0:label=200:ip=10.0.0.1

# ILM: como identificar PDUs MPLS recebidas
sw1[ilm]=200:labelspace=0
sw2[ilm]=100:labelspace=0

# Labelspace: os mapeamentos de labelspaces a interfaces
sw1[labelspace]=0:interfaces=eth0
sw2[labelspace]=0:interfaces=eth0

sw1[eth1]=lan0:ip=192.168.0.254/24
sw1[eth0]=link1:ip=10.0.0.1/24
sw2[eth0]=link1:ip=10.0.0.2/24
sw2[eth1]=lan1:ip=192.168.1.254/24

h1[eth0]=lan0:ip=192.168.0.1/24
h2[eth0]=lan1:ip=192.168.1.1/24

h1[default_gateway]=192.168.0.254
h2[default_gateway]=192.168.1.254

Mpls1.png

Para configurar cada ítem do switch MPLS devem-se usar alguns atributos:

  • FEC: usa-se o atributo fec
    sw1[fec]=192.168.1.0/24:nhlfe=1
    
    Esse atributo possui apenas duas opções:
    • IP/Máscara: a rede destino (192.168.1.0/24 no exemplo)
    • nhfe=um_número: o número do NHLFE a ser usado (nhlfe=1 no exemplo)
  • NHLFE: usa-se o atributo nhlfe
    sw1[nhlfe]=1:interface=eth0:label=100:ip=10.0.0.2
    
    As seguintes opções existem:
    • um_número: o número do NHLFE. Funciona como um identificador a ser usado no ILM ou FEC.
    • label=um_número: o número de rótulo a ser adicionado.
    • interface=nome_interface: a interface por onde será transmitido o pacote MPLS.
    • ip=um_IP: endereço IP do próximo switch MPLS (o que deve receber as PDUs transmitidas de acordo com esta NHLFE)

      Além dessa opções pode-se especificar um NHLFE de forma a empilhar rótulos (adicionar dois ou mais rótulos a uma mesma PDU), o que é necessário na entrada de túneis MPLS:
      sw1[nhlfe]=1:label=200:nhlfe=2
      
      Nesse caso não se usam as opções ip e interface, porém adiciona-se a seguinte opção:
    • nhlfe=um_número: identificador da NHLFE a ser usada depois da aplicação desta NHLFE.
  • ILM: usa-se o atributo ilm
    sw1[ilm]=1000:labelspace=0:nhlfe=2
    
    As opções que podem ser usadas são:
    • um_número: o número do rótulo que será reconhecido.
    • labelspace=um_número: o número do labelspace de onde se aceitará o rótulo.
    • nhlfe=um_número: o identificador do NHLFE a ser usado para encaminhar essas PDUs MPLS.

      Uma forma alternativa de definir o ilm omite a opção nhlfe. Nesse caso a PDU MPLS será aceita, o rótulo será removido e a PDU será então processada normalmente pela camada de rede IP.
  • Labelspaces: usa-se o atributo labelspace
    sw1[labelspace]=0:interfaces=eth0,eth1
    
    Suas opções são apenas:
    • um_número: o número do labelspace (OBS: na versão do MPLS usada, existe somente labelspace global ... portanto o número do labelspace é ignorado).
    • interfaces=if1,if2,...: a lista de uma ou mais interfaces que pertencem a esse labelspace.

Qualquer um desses atributos pode ser especificado múltiplas vezes, como exemplificado abaixo:

sw1[nhlfe]=1:interface=eth0:label=100:ip=192.168.0.2
sw1[nhlfe]=2:label=1000:nhlfe=1

A configuração acima irá adicionar duas NHLFE em sw1.

Um exemplo de uma rede um pouco maior contém três switches MPLS:

sw1[type]=mpls 
sw2[type]=mpls
sw3[type]=mpls
h1[type]=generic
h2[type]=generic
h3[type]=generic

# FEC: mapeia subrede/mask para nhlfe
sw1[fec]=192.168.1.0/24:nhlfe=1
sw1[fec]=192.168.2.0/24:nhlfe=2
sw2[fec]=192.168.0.0/24:nhlfe=1
sw2[fec]=192.168.2.0/24:nhlfe=2
sw3[fec]=192.168.0.0/24:nhlfe=1
sw3[fec]=192.168.1.0/24:nhlfe=2

# NHLFE: como encaminhar uma PDU MPLS ... (push)
sw1[nhlfe]=1:interface=eth0:label=110:ip=10.0.0.2
sw1[nhlfe]=2:interface=eth0:label=120:ip=10.0.0.2
sw2[nhlfe]=1:interface=eth0:label=210:ip=10.0.0.1
sw2[nhlfe]=2:interface=eth1:label=220:ip=10.0.2.3
sw2[nhlfe]=3:interface=eth1:label=130:ip=10.0.2.3
sw3[nhlfe]=1:interface=eth0:label=310:ip=10.0.1.1
sw3[nhlfe]=2:interface=eth1:label=320:ip=10.0.2.2

# ILM: como identificar PDUs MPLS recebidas (implicitamente faz um pop)
sw1[ilm]=210:labelspace=0
sw1[ilm]=310:labelspace=0
sw2[ilm]=110:labelspace=0
sw2[ilm]=120:labelspace=0:nhlfe=3
sw2[ilm]=320:labelspace=0
sw3[ilm]=130:labelspace=0
sw3[ilm]=220:labelspace=0

# Labelspace: os mapeamentos de labelspaces a interfaces
sw1[labelspace]=0:interfaces=eth0,eth1
sw2[labelspace]=0:interfaces=eth0,eth1
sw3[labelspace]=0:interfaces=eth0,eth1

sw1[eth0]=link1:ip=10.0.0.1/24 
sw1[eth1]=link2:ip=10.0.1.1/24 
sw1[eth2]=lan0:ip=192.168.0.254/24 

sw2[eth0]=link1:ip=10.0.0.2/24 
sw2[eth1]=link3:ip=10.0.2.2/24 
sw2[eth2]=lan1:ip=192.168.1.254/24

sw3[eth0]=link2:ip=10.0.1.3/24 
sw3[eth1]=link3:ip=10.0.2.3/24 
sw3[eth2]=lan2:ip=192.168.2.254/24

h1[eth0]=lan0:ip=192.168.0.1/24
h2[eth0]=lan1:ip=192.168.1.1/24
h3[eth0]=lan2:ip=192.168.2.1/24

h1[default_gateway]=192.168.0.254
h2[default_gateway]=192.168.1.254
h3[default_gateway]=192.168.2.254

Mpls2.png

Opções e configurações avançadas

Preferências

Atributos globais definem parâmetros válidos para o experimento como um todo. Esses atributos devem ser especificados com a sintaxe global[nome_do_atributo]=valor_do_atributo. No momento há apenas o atributo path, que define o diretório onde devem ser criados os arquivos temporários e discos virtuais do experimento. O diretório de trabalho pode ser especificado com um caminho relativo, como exemplificado abaixo:

# o diretório de trabalho do experimento será o subdiretório "tmp" dentro do diretório onde
# está o arquivo de configuração (i.e. diretorio_do_arquivo_de_configuracao/tmp)
global[path]=tmp

... ou um caminho absoluto:

# o diretório de trabalho do experimento será o subdiretório "/home/aluno/tmp".
global[path]=/home/aluno/tmp

Se o atributo global path não for definido, o netkit2 irá criar um subdiretório dentro do diretório onde está o arquivo de configuração, e usá-lo como diretório de trabalho. O nome desse subdiretório será da forma tmp-xxxxx, sendo xxxxx um número aleatório.

Projetos

Modo de instalação de software

Uma biblioteca de exemplos de experimentos

Para facilitar o aprendizado de como usar o Netkit foi criada uma pequena coleção de experimentos.

Experimentos com LANs

  • LAN simples: uma LAN com quatro computadores (pc1, pc2, pc3, pc4). Os computadores virtuais têm IPs 192.168.1.X, sendo X o número computador (ex: pc1 tem IP 192.168.1.1). Use ping para fazer testes de comunicação. Veja o arquivo Lab.conf (configuração da rede) e pc1.startup, pc2.startup, pc3.startup e pc4.startup (scripts que configuram cada máquina virtual após o boot). A rede criada nesse experimento está mostrada abaixo:

Exemplo-Lan1-netkit.png


Ao executar esse experimento quatro terminais surgirão (um para cada máquina virtual). A figura abaixo mostra o experimento em execução, e nele a máquina virtual pc fazendo um ping em broadcast e em pc2 e pc3 sendo executado tcpdump para ver as mensagens ICMP geradas pelo ping:

Ier-lan1-netkit.png


  • Duas LANs interligadas com PPP: uma LAN com quatro computadores (pc1, pc2, pc3, pc4) ligada com PPP a outra LAN (pc5, pc6 e pc7). O link PPP é implantado sobre as portas seriais das máquinas virtuais pc4 e pc5. Ver os arquivos Lab.conf, pc4.startup e pc5.startup. A rede do experimento está mostrada abaixo:

Lan-ppp.png


  • LAN com switch: uma LAN com quatro computadores (pc1, pc2, pc3, pc4) interligados por um switch. O switch é implementado por um computador com Linux com 4 portas ethernet. Ver os arquivos Lab.conf e switch.startup. A rede do experimento está mostrada abaixo:

Exemplo-Bridge-netkit.png


  • LAN com dois switches: uma LAN com 6 computadores (pc1 a pc6) interligados por dois switches (switch1 e switch2). Ambos switches são implementados por computadores com Linux com 4 portas ethernet. Ver os arquivos Lab.conf, switch1.startup e switch2.startup. A rede do experimento está mostrada abaixo:

Exemplo-lan2.png

Experimentos com VLAN

Observar os quadros com tag nas interfaces que operam em modo tagged. Teste também o isolamento entre VLANs.

  • Switch e duas VLANs: duas VLANs com quatro computadores cada. VLAN 5 tem IPs 192.168.1.0/24 e contém pc1, pc2, pc3, pc4; VLAN 10 tem IPs 192.168.2.0/24 e contém pc4, pc5, pc6, pc7. O switch Linux foi configurado para que a interface eth3 esteja nas VLANs 5 e 10 (i.e. em modo tagged), as interfaces eth0, eth1, eth2 estejam na VLAN 5 em modo untagged, e as interfaces eth4, eth5 e eth6 estejam na VLAN 10 em modo untagged. O computador pc4 opera como gateway entre as VLANs, usando duas interfaces virtuais (i.e. a interface eth0 foi posta nas VLANs 5 e 10 em modo tagged). Nesse exemplo se usa VLAN tagging IEEE 802.1q.

Bridge2.png


  • Dois switches e duas VLANs: duas VLANs com quatro computadores cada. VLAN 5 tem IPs 192.168.1.0/24 e contém pc1, pc2, pc3, pc4; VLAN 10 tem IPs 192.168.2.0/24 e contém pc5, pc6, pc7, pc8. O switch Linux foi configurado para que a interface eth3 esteja nas VLANs 5 e 10 (i.e. em modo tagged), as interfaces eth0, eth1, eth2 estejam na VLAN 5 em modo untagged, e as interfaces eth4, eth5 e eth6 estejam na VLAN 10 em modo untagged. O computador pc4 opera como gateway entre as VLANs, usando duas interfaces virtuais (i.e. a interface eth0 foi posta nas VLANs 5 e 10 em modo tagged). Nesse exemplo se usa VLAN tagging IEEE 802.1q. O diagrama abaixo ilustra essa rede:

Bridge3.png

Leia os arquivos de inicialização switch1.startup, switch2.startup e pc4.startup para entender como foram configuradas as VLANs.

API do Netkit

O Netkit possui uma API para iniciar e parar experimentos, entre outras coisas. Ela está implementada no módulo ${NETKIT2_HOME}/bin/netkit.py, mas não deve ser usada diretamente. Para usá-la é recomendável usar NetkitParser, uma classe que interpreta arquivos de configuração e a partir deles cria objetos Network. A classe Network representa uma rede virtual do Netkit, e com ela se pode inciar, parar, ou mudar preferências. O exemplo abaixo mostra como usar a classe NetkitParser e o objeto Network obtido por meio dela:

import nkparser

# Cria o parser, informando o arquivo de configuração a ser interpretado
parser = nkparser.NetkitParser('teste.conf')

# Interpreta o arquivo de configuração
parser.parse()

# Obtém um objeto Network que representa a rede descrita no arquivo de configuração
rede = parser.get_network()

# Executa a rede. Cada VM terá sua console vinculada a um xterm
rede.start()


As classes envolvidas na API do Netkit estão representadas no diagrama de classes abaixo. Existem muitas outras classes no Netkit, mas estas são suficientes para utilizá-lo:


Netkit-class-diagram1.png


Este outro exemplo explora as classes acima apresentadas. Ele inicia uma rede a partir de um arquivo de configuração, porém vincula cada VM a um Terminal (que pode ser um xterm ou alguma outra forma de interagir com a VM). As classes contidas no diagrama acima, e usadas neste programa, estão descritas nas próximas subseções.

# Cria um experimento Netkit
parser = nkparser.NetkitParser('teste.conf')

parser.parse()

rede = parser.get_network()

# Cria um gerador de terminais
pool = TermPool()

# Inicia o experimento usando o gerador de terminais
rede.start(pool)

# Inicia todos os terminais e, consequentemente, todas as VM do experimento
pool.start()

# Obtém o terminal da VM pc1
term = pool.get_term('pc1')

# Através do objeto term se pode conversar com a console da VM pc1 ...
term.write('poweroff\n')

Classe NetkitParser

Definida em nkparser.py


NetkitParser.png


Um objeto da classe NetkitParser implementa um parser (analisador sintático). Com ele se pode interpretar um arquivo de configuração de uma rede, e criar a rede ali descrita. Se houver erros de sintaxe, ou mesmo semânticos, o parser dispara uma exceção avisando sobre o erro e em que parte do arquivo ele foi encontrado. Se o arquivo de configuração não tiver erros, o parser cria um objeto Network para representar a rede. O parser pode também ser usado para analisar um arquivo de configuração, sem criar um objeto Network, desta forma apenas verificando a correção da configuração.


constructor: NetkitParser(conf_path)

Parâmetro Descrição
conf_path caminho para o arquivo de configuração da rede a ser criada


Métodos:

parse(): interpreta o arquivo de configuração. Erros de sintaxe causam exceções do tipo ParseError, e erros semânticos (ex: uso de uma VM não declarada) disparam exceções do tipo SemanticError. Essas exceções informam sobre a localização do erro dentro do arquivo de configuração.

get_network(): obtém um objeto Network que representa a rede descrita no arquivo de configuração. Esse método somente pode ser chamado após o arquivo ter sido interpretado (i.e. após parse()).

update_prefs(prefs): modifica as preferências da rede de forma permanente, acrescentando-as ao arquivo de configuração.

tokenize(): faz a análise léxica do arquivo de configuração, retornando uma lista com todos os tokens encontrados.

Classe ParseError

A classe ParseError especializa a classe Exception para representar erros na análise léxica ou sintática de um arquivo de configuração. Uma exceção ParseError possui os seguintes atributos:

  • n: o número da linha onde foi identificado o erro.
  • column: a coluna onde inicia o texto incorreto.
  • value: a palavra ou token incorreto.
  • line: a linha completa onde se encontra o erro.

Classe SemanticError

A classe SemanticError especializa a classe Exception para representar erros na análise semântica de um arquivo de configuração. Uma exceção SemanticError possui os seguintes atributos:

  • n: o número da linha onde foi identificado o erro.
  • value: a causa do erro.
  • line: a linha completa onde se encontra o erro.

Classe Network

Definida em netkit.py


Network.png


A classe Network representa redes do Netkit. Um objeto dessa classe contém todas as especificações para a criação e configuração de uma rede. Através dele se pode iniciar e para a execução de uma rede. No entanto, objetos da classe Network devem ser criados por meio de um objeto NetkitParser.


A classe Network possui os seguintes métodos:

  • start(pool=None): inicia uma rede usando o pool indicado (ver TermPool). Um pool serve para acoplar terminais às máquinas virtuais da rede. Se o pool não for especificado, é usado um pool padrão, que conecta cada máquina virtual a um xterm.
  • stop(): para a execução de uma rede.
  • get_nodes(): retorna uma lista com os nomes do nodos que fazem parte da rede virtual.
  • get_prefs(): retorna um dicionário com as preferências de execução da rede virtual.
  • update_prefs(prefs): modifica as preferências de execução da rede de acordo com o dicionário prefs.
  • get_pool(): obtém uma referência ao objeto [Netkit2#interface_TermPool|TermPool]] usado pela rede.
  • get_path(): retorna o caminho do diretório (pathname) de trabalho da rede virtual.


As preferências são compostas pelos seguintes atributos:

  • mem (inteiro): quantidade de memória (em MB) a ser alocada a cada máquina virtual.
  • path (string): caminho do diretório de trabalho da rede virtual.
  • rw (booleano): ativa o modo leitura-escrita, se True. Nesse modo as modificações no sistema de arquivos das máquinas virtuais são permanentes. Use com cuidado !
  • compact (booleano): compacta o arquivo de projeto, caso seja utilizado (ver atributo preserve de uma máquina virtual).


Outros atributos podem ser adicionados às preferências, o que pode ser útil para softwares que utilizem esta API. Por exemplo, netkit2 é um aplicativo gráfico para a execução de redes do Netkit que usa o atributo vm para especificar quantas máquinas virtuais podem ser executadas em paralelo, e clean para indicar se o diretório de trabalho da rede deve ser removido após sua execução.

Classe VM

Definida em uml_layer.py


VM.png


A classe VM representa máquinas virtuais UML. Um objeto dessa classe pode iniciar, parar e acessar a console de uma máquina virtual. Objetos dessa classe são criados automaticamente ao se inciar uma rede (i.e. ao se chamar o método start() de um objeto Network). As operações dessa classe são:

  • start(): executa uma máquina virtual UML correspondente a um nodo de uma rede virtual. A máquina virtual é executada em um processo filho, e sua console é conectada ao lado escravo de um pseudo-terminal. O descritor de arquivo do lado mestre é retornado como resultado deste método.
  • startWithin(command): executa uma máquina virtual UML usando o comando indicado. Este método serve para usar aplicativos de terminal (ex: xterm, gnome-terminal) como terminais das máquinas virtuais. A linha de comando que inicia a máquina virtual é simplesmente acrescentada logo após o nome do comando fornecido.
  • stop(): termina a execução de uma máquina virtual.
  • wait(): aguarda uma máquina virtual terminar sua execução.
  • getPty(): obtém o descritor de arquivo (fd) do lado mestre do pseudo-terminal conectado a console da máquina virtual.
  • started(): retorna True se a máquina virtual estiver em execução, e False caso contrário.
  • get_name(): retorna o nome da máquina virtual.

interface TermPool

Definido pelo software que usa a API do Netkit. O TermPool default está em uml_layer.py


TermPool.png


A interface TermPool define um concentrador de terminais para as máquinas virtuais. Sua função é criar um terminal para cada VM a ser executada. Esses terminais devem ser objetos que implementam a interface Terminal, os quais desempenham esse papel para as VM. Quer dizer, cada objeto Terminal deve se associar à console de uma VM e agir como um terminal de fato.

Métodos:

  • addVM(vm_object): adiciona um Terminal e o associa à VM representada porvm_object, que é um objeto da classe VM.
  • start(): inicia todas as VM em seus respectivos terminais.
  • stop(): para todas as VM.
  • get_terms(): retorna um dicionário com todos os terminais indexados pelos nomes de suas VM.
  • get_term(nome): retorna o terminal da VM nome.
  • get_fds(): retorna uma lista com os descritores de arquivos do lado mestre dos pseudo-terminais associados às VM.


OBS: Deve-se implementar uma classe que realize a interface TermPool, a qual é necessária para que se possam executar redes por meio de objetos Network Network.


Exemplo de classe que realiza TermPool:

class TermPool:

  def __init__(self):
    self.terms = {}

  def addVM(self, name, cmd):
    self.terms[name] = NetTerm(name, cmd)

  def start(self):
    for vm in self.terms:
      self.terms[vm].start()

  def stop(self):
    for vm in self.terms:
      self.terms[vm].stop()

  def get_term(self, name):
    return self.terms[name]

  def get_terms(self):
    return self.terms

interface Terminal

OBS: Deve-se implementar uma classe que realize esta interface, a qual é necessária para TermPool.


Terminal.png


A interface Terminal define como devem se apresentar objetos as serem usados como terminais para as VM do Netkit. Um Terminal tem o papel de interfacear o console de uma VM, dependendo da forma com que se deseje acessar a rede em execução. Por exemplo, um Terminal pode simplesmente conectar um xterm ao console da VM, ou fazer algo mais complexo, como vinculá-la a um socket para que possa ser acessada remotamente. Objetos que implementam essa interface não devem ser instanciados diretamente, pois são criados por TermPool.


Construtor: Terminal(vm)

Parâmetro Descrição
vm uma instância da classe VM, a qual representa a VM a ser interfaceada


Métodos:

  • start(): inicia a VM, conectando seu console ao lado escravo de um pseudo-terminal. Esse pseudo-terminal deve ser criado pelo Terminal.
  • stop(): para a VM.
  • read(maxbytes): lê até maxbytes do console da VM , retornando-os como uma string.
  • write(data): escreve os dados contidos na string data no console da VM.
  • getfd(): retorna uma referência ao descritor de arquivo do lado mestre do pseudo-terminal vinculado ao console da VM. Pode ser usado para enviar e receber dados diretamente da VM.


Exemplo de classe que realiza Terminal:

class NetTerm:

  def __init__(self, vm):
    self.name = vm.get_name()
    self.fd = -1

  def start(self):
    pass

  def stop(self):
    pass

API RESTful

A API RESTful foi concebida como uma interface entre clientes remotos e o Netkit. Essa API deve ser implementada por um controlador de instâncias do Netkit, o qual deve ser capaz de traduzir as operações da API para ações sobre redes virtuais do Netkit. Essa interface ainda está em desenvolvimento, e faz parte do TCC de Ricardo Martins (2013-2 a 2014-1).


Esta tabela lista as operações da API RESTful.

  • nas URI que representam os recursos, ID é o nome de uma rede, e NUM é o número de uma instância dessa rede.
  • parâmetros são enviados no corpo da requisição com tipo application/x-www-form-urlencoded. O tipo de cada parâmetro é string, salvo indicado em contrário.
  • resultados, quando houver, são codificados em JSON (tipo application/json), salvo quando indicado outro tipo.


Recurso Método Parâmetros Resultado Descrição da operação
Status
Corpo da resposta
Descrição
/netkit GET 200 {nome_rede: URI_rede} sucesso, e retorna redes existentes no corpo da resposta Obtém a relação de redes existentes no catálogo do controlador
400 erro de execução
/netkit POST {name: nome da rede, config: configuração} 201 sucesso: URI da rede criada no cabeçalho Location Cria uma nova rede identificada por name e com configuração dada por config
409 erro: rede já existe
400 {line: linha, column:coluna, value: token} erro de sintaxe na configuração, e retorna o local do erro no corpo da resposta
/netkit/ID POST 201 {dataport: URI_dataport, nodes: lista de nomes de nodos, active: nome do nodo ativo} sucesso, com URI da instância no cabecalho Location Inicia a execução de uma rede
400 erro genérico
404 rede não existe
/netkit/ID DELETE 200 sucesso Remove uma rede do catálogo
404 rede não existe
423 há instâncias em execução
400 erro genérico
/netkit/ID/config GET 200 configuração da rede (text/plain) sucesso e corpo da mensagem contém a configuração Obtem a configuração de uma rede
404 rede não existe
400 erro genérico
/netkit/ID/config PUT configuração da rede (text/plain) 200 sucesso Modifica a configuração de uma rede
404 rede não existe
400 {line: linha, column:coluna, value: token} erro de sintaxe
406 conteúdo não é text/plain
500 erro genérico
/netkit/ID/preferences GET 200 {mem: memória em MB, rw: modo rw} sucesso Obtém as preferências de execução de uma rede.
404 rede não existe
400 erro genérico
/netkit/ID/preferences PUT {mem: memória em MB, rw: modo rw} 200 sucesso Modifica as preferências de execução de uma rede.
404 rede não existe
400 erro genérico
/netkit/ID/image GET 200 imagem (image/png) sucesso Obtém a imagem de um diagrama da rede.
404 rede não existe
400 erro genérico
/netkit/ID/dot GET 200 conteúdo dot (text/plain) sucesso Obtém a descrição .dot de um diagrama da rede.
404 rede não existe
400 erro genérico
/netkit/ID/NUM GET 200 {dataport: URI_dataport, nodes: lista de nomes de nodos, active: nome do nodo ativo} sucesso Obtém os atributos de uma instância: dataport, lista de nodos, nodo ativo
404 rede ou instância não existe
400 erro genérico
/netkit/ID/NUM PUT {active: nome_do_nodo} 200 {active: nome_do_nodo} sucesso Muda o nodo ativo
404 rede ou instância não existe
400 erro genérico
/netkit/ID/NUM DELETE 200 sucesso Encerra uma instância (termina a execução de uma rede)
404 rede ou instância não existe
400 erro genérico
/netkit/ID/NUM/hostlab GET 200 ['arq', 'arq2', ...] sucesso Obtém uma listagem dos arquivos contidos no diretório hostlab de uma instância
404 rede ou instância não existe
400 erro genérico
/netkit/ID/NUM/hostlab/path GET 200 conteúdo do arquivo (depende do conteúdo) sucesso Obtém o arquivo path, contido no diretório hostlab de uma instância
404 rede ou instância não existe
400 erro genérico
/netkit/ID/NUM/hostlab/path POST conteúdo do arquivo (depende do conteúdo) 200 sucesso Cria o arquivo path dentro do diretório hostlab de uma instância, gravando nele o conteúdo enviado.
404 rede ou instância não existe
400 erro genérico