Tutorial SDN + Openflow
Tutorial SDN + Openflow
Tutorial I: http://www.teleco.com.br/tutoriais/tutorialsw1/pagina_1.asp
Tutorial II: http://www.teleco.com.br/tutoriais/tutorialsw2/pagina_1.asp
Sumário
2
Redes Definidas por SW I: Introdução
As redes de computadores nos permitem fazer coisas inimagináveis há poucas décadas.
Seu embrião teve início no final da década de 1960 com a então denominada ARPANET (Advanced
Research Projects Agency Network), que buscava interligar as bases militares e os departamentos de
pesquisa norte-americanos.
Muito evolui desde então. Modelos para protocolos de comunicação foram criados e muitos
protocolos foram desenvolvidos, sejam para suprir a demanda de aplicações, sejam para calcular os
caminhos que os pacotes devem percorrer ao longo da rede.
Devido à essa evolução de ideias, desde o início das pesquisas sobre comutação de pacotes e da
ARPANET, juntamente com a evolução do hardware utilizado, hoje temos inúmeras possibilidades
na rede. Anexar enormes quantidades de arquivos em nossos e-mails, jogar jogos com pessoas do
mundo inteiro em tempo real, ou até mesmo realizar ligações telefônicas através da Internet.
Entretanto, talvez hoje as redes estejam na iminência de uma mudança de paradigma, mudança essa
que possibilitará o desenvolvimento de aplicações cuja implementação com a tecnologia atual seria
impossível. Com a utilização de redes definidas por software (SDN - Software-Defined Networking),
será possível um total controle da rede. Não haverá mais a necessidade de hardwares especializados,
mas sim, poderá se utilizar hardwares genéricos programáveis. Novos protocolos poderão ser
testados e implementados com uma rapidez nunca antes vista e aplicações que hoje são impensáveis
se tornarão absolutamente viáveis através da implementação dessa tecnologia.
Motivação e Objetivos
O conceito de redes programáveis não é novo. Como exemplo, tem-se o conceito de redes ativas na
década de 1990 (Feamster et al., 2014). Entretanto, pela primeira vez, o conceito é amplamente
difundido e aceito. As redes definidas por software vêm apresentando grande aceitação por parte
da comunidade acadêmica e pelos principais fabricantes de equipamentos, que já começaram a
desenvolver soluções voltadas para esse modelo.
Diante o exposto, como objetivo geral, essa monografia pretende apresentar ao leitor esse novo
paradigma em redes de computadores, mostrando o quão importante o mesmo será para
pesquisadores que necessitam testar novos protocolos assim como para gestores que precisam
gerenciar redes de computadores todos os dias.
3
Apresentar conceitos do OpenFlow, implementação mais difundida das redes definidas por
software;
Apresentação de uma aplicação programada em Python, para redes definidas por software.
Essa aplicação altera o caminho de um fluxo pré-estabelecido, mediante a uma alta
utilização da largura de banda do caminho principal;
Tutoriais
Este tutorial parte I apresenta inicialmente os conceitos básicos de redes de computadores para que
seja possível o entendimento posterior das redes definidas por software. A seguir trata dos conceitos
básicos sobre planos de controle e de dados e em seguida da definição de redes definidas por
software. Finaliza apresentando o padrão/protocolo OpenFlow, os switches OpenFlow, e os
principais controladores disponíveis, dando enfoque ao POX, controlador utilizado neste estudo.
Nesta seção serão abordados conceitos como modelo de camadas TCP/IP, endereçamento,
encaminhamento e classificação de pacotes. Conceitos esses fundamentais para o pleno
entendimento das vantagens e desvantagens das redes definidas por software.
Modelo em Camadas
4
Na camada de aplicação, o nível mais alto do modelo, usuários utilizam programas que acessam
serviços disponíveis através da rede TCP/IP. A aplicação irá interagir com protocolos da camada de
transporte para enviar e receber dados. Como será visto adiante, o modelo foi concebido para que
todas as outras camadas sejam transparentes para o usuário final, ou seja, o mesmo não precisa ter
conhecimento sobre a implementação das camadas subjacentes.
A camada de transporte pode também regular o fluxo de informações, podendo inclusive oferecer
um transporte confiável, como por exemplo, verificando periodicamente a conexão estabelecida e
assegurando que os dados estão sendo enviados e recebidos corretamente, chegando sem erros.
São exemplos de protocolos dessa camada, o UDP (Datagram Protocol) e o TCP.
A camada de internet lida com a comunicação de um dispositivo a outro, aceitando pedidos de envio
de pacotes da camada de transporte. A mesma irá encapsular os dados da camada de transporte em
um pacote IP, preenchendo o cabeçalho com diversas informações, inclusive com o endereço lógico
de origem (IP de origem) e o endereço lógico de destino (IP de destino).
A camada de internet também é responsável por encaminhar esses pacotes para a camada de acesso
à rede, onde os mesmos serão encaminhados diretamente para o destino (podendo vir a passar por
dispositivos como switches e hubs), se os hosts estiverem na mesma rede. Caso não estejam, como
duas redes diferentes não se “enxergam” os pacotes devem ser enviados para equipamentos que
fazem a interligação entre redes, denominados roteadores. Através dos roteadores os pacotes
podem ser encaminhados por redes intermediárias, até chegarem ao destino final. A camada de
internet também é responsável por lidar com os pacotes IP's recebidos, checando sua validade e
verificando se os mesmos são destinados para um host na rede local ou se devem ser encaminhados
para outras redes. Maiores detalhes sobre a camada de rede serão vistos na seção sobre
encaminhamento.
A camada de acesso à rede define as regras de acesso ao meio físico definindo o endereçamento
físico e os protocolos necessários para essa transmissão. Além disso, converte os dados vindos da
camada superior (internet) em sinais elétricos/ópticos, tornando possível a transmissão em cabos e
fibras ópticas.
É importante entender que para a camada de internet não importa a localização física das máquinas,
mas a localização lógica das redes. A camada de acesso à rede, é responsável pela identificação de
cada máquina (endereçamento físico) em uma rede local. O ARP (Address Resolution Protocol),
protocolo da camada de rede, fará a tradução do endereço lógico para o endereço físico, quando o
pacote de dados já estiver na rede de destino.
Para finalizar, as redes em camadas são projetadas de modo que uma determinada camada no
destino receba exatamente os mesmos objetos enviados pela mesma camada correspondente na
origem, ou seja, os mesmos dados enviados pela camada de aplicação na origem, devem ser os
mesmos dados recebidos pela camada de aplicação no destino.
As redes de computadores em geral, sobretudo a Internet, foram projetadas para prover uma
interconexão universal entre computadores independentemente das particularidades da rede aos
quais estejam conectados, tornando-se transparente para o usuário, que a vê como uma única rede
5
virtual (como pode ser visto na figura 2, a qual todas as máquinas estão conectadas. Essa
virtualização será importante para o entendimento das redes definidas por software.
Figura 2: Visão do usuário da rede (a) e Estrutura física com enlaces e roteadores (b)
Fonte: Comer, 2013
Endereçamento
Sendo a camada de internet uma das mais importantes do modelo TCP/IP, torna-se interessante o
entendimento da divisão e endereçamento lógicos dos dispositivos, assim como também é
interessante entender como ocorre o roteamento e encaminhamento dos pacotes.
Em uma rede TCP/IP, cada adaptador de rede existente em um dispositivo é identificado por um
número chamado endereço IP. Tomando-se como base o IP versão 4, esse endereço IP consiste em
quatro conjuntos de 8 bits.
Esses octetos, quando representados, são separados por pontos. Um exemplo de endereço IP segue
abaixo:
00001010.00000000.00000000.00000001
Dessa forma, todos os 32 bits são representados. Entretanto, a forma mais usual de representação
do endereço IP, é a decimal. O mesmo endereço IP representado acima, pode ser escrito como:
10.0.0.1
Dito isso, pode-se concluir que o menor octeto possível é o 00000000 (0 em decimal) e o maior octeto
possível é o 11111111 (255 em decimal), ou seja, cada octeto pode variar de 0 a 255.
Parte do endereço IP será utilizada para representar a rede a qual o dispositivo está conectado e a
outra parte será utilizada para representar o dispositivo em si.
Máscara de rede
A máscara de rede é um recurso utilizado para segmentar redes logicamente. Com esse recurso,
pode-se ter várias redes lógicas diferentes disponíveis no mesmo espaço físico, ou ainda, pode-se ter
uma única rede lógica em mais de uma localidade física.
6
Essa rede lógica pode ser entendida como conjuntos independentes de dispositivos (computadores,
impressoras, switches) conectados à rede em um determinado espaço físico. As divisões em redes
lógicas diferentes são feitas justamente com base no endereço IP e na máscara de rede.
A máscara de rede é definida como um conjunto de 32 bits divididos em quatro octetos, assim como
o endereço IP. Entretanto, algumas regras são levadas em consideração na criação da máscara de
rede (Filho, 2013):
Não pode haver a mistura de algarismos 0 e 1;
Não pode haver algarismo 0 antes de algarismo 1;
Segue abaixo um exemplo de máscara de rede, com os bits representados e também na forma
decimal:
11111111.00000000.00000000.00000000
255.0.0.0
Essa máscara de rede será comparada com o endereço IP. Os bits que forem 1 na máscara de rede
representam a porção da rede no endereço IP e os bits que forem 0 representam o dispositivo.
A notação usual, a notação CIDR (Classless Inter-Domain Routing), é a representação do endereço IP,
seguido de uma barra (/) e da quantidade de bits que são correspondentes à porção de rede.
Logo, como foram utilizados oito bits para a máscara de rede acima, temos a seguinte notação:
10.0.0.1/8
10.0.0.0/8
192.168.0.0/24
Os conceitos de máscaras de rede e de endereço de rede são importantes, pois os mesmos serão
utilizados nos roteadores para a realização do encaminhamento que será abordado a seguir.
7
Encaminhamento
Para que o conceito de encaminhamento de pacotes em redes de computadores atuais possa ser
compreendido, é importante diferenciar-se os tipos de serviços que a camada de internet pode
oferecer.
A camada de internet oferece dois tipos distintos de serviços. O serviço orientado a conexão e o
serviço não orientado a conexão. As redes orientadas a conexões são denominadas redes de circuitos
virtuais. Como exemplos, têm-se as redes ATM (Asynchronous Transfer Mode) e Frame Relay. Já a
Internet é uma rede de datagramas, ou seja, uma rede não orientada a conexões. Nesse trabalho,
quando não especificado o contrário, o texto estará tratando das redes não orientadas a conexões.
O serviço de entregas oferecido pela camada de rede em uma rede de datagramas, como a Internet,
pode ser definido como incerto, de melhor esforço (best-effort) e com entrega de pacotes sem
conexão.
O serviço é incerto, pois a entrega de pacotes não é garantida. Os pacotes podem ser perdidos,
duplicados, podem chegar atrasados ou até mesmo fora de ordem. O serviço é dito de melhor
esforço, porque os pacotes tentarão ser entregues, entretanto não há garantias. Não há garantia de
largura de banda e nem mesmo indicações de congestionamento.
Finalmente o serviço também é definido como sem conexão, pois cada pacote é tratado
independentemente. Uma sequência de pacotes enviados de um dispositivo a outro, podem trafegar
por diferentes caminhos. Não existe um circuito pré-definido como existe, por exemplo, nas redes
de circuitos virtuais. Uma exceção seria a tecnologia MPLS (Multiprotocol Label Switching) que será
abordada posteriormente.
O protocolo IP, um dos mais importantes do modelo TCP/IP, apresenta todas as características
supracitadas e ainda:
Define a unidade básica de dados que será transmitida através da rede TCP/IP, especificando
o formato dos pacotes utilizados por todos os dados.
O IP define uma série de regras, como por exemplo, como dispositivos e roteadores devem
processar os pacotes e as condições sob as quais os pacotes podem ser descartados (Comer,
2013)
Conforme dito anteriormente, a transmissão de datagramas IP entre dois dispositivos em uma única
rede física, não envolverá o uso de roteadores. O dispositivo que está enviando os dados encapsulará
8
o datagrama em um quadro, vinculará o endereço do próximo salto ao endereço físico do dispositivo
de destino e enviará o quadro resultante para o dispositivo de próximo salto.
Caso o dispositivo não esteja na mesma rede, o protocolo selecionará o próximo roteador para onde
o pacote deve ser enviado. Esse processo se repete até que o pacote chegue a um roteador que
possa entregar o pacote diretamente para o dispositivo de destino.
O encaminhamento dos pacotes é do tipo próximo salto, ou seja, o roteador que acabou de receber
o pacote, não precisa saber quais são todos os saltos intermediários que o pacote deverá percorrer
até chegar ao destino. Precisa saber apenas qual é o próximo salto, e para isso, o mesmo irá verificar
sua tabela de encaminhamento (FIB - Forwarding information base).
Então, uma tabela de encaminhamento terá, conceitualmente, um conjunto de pares (P,R) onde “P”
é o prefixo da rede e “R”, é o endereço IP do próximo roteador para onde os dados devem ser
enviados com o objetivo de chegarem a rede “P”.
Pode-se pensar que o protocolo de roteamento, software que preencherá as informações na FIB,
escolherá as melhores rotas de acordo com a utilização corrente do link, pelo tamanho do
datagrama, tipo de dados que estão sendo transportados ou ainda de acordo com o custo dos links.
Entretanto, será visto que a maioria dos protocolos de roteamento são bem menos sofisticados,
selecionando rotas baseadas em dados fixos sobre menores caminhos. Fato que é interessante
ressaltar, já que nas redes definidas por software, novos protocolos de roteamento com as mais
diversas métricas poderão ser implementados facilmente, tornando o encaminhamento mais
inteligente e robusto.
9
Figura 4: Algoritmo executado pelo roteador ao receber um pacote
Fonte: Algoritmo baseado em Comer, 2013
Entretanto, para o algoritmo acima funcionar corretamente, algumas condições precisam ser pré-
definidas.
O encaminhamento, como foi visto, é uma das principais funções do protocolo IP e dos roteadores.
O mesmo não poderia atualmente ser executado corretamente, se não existissem os protocolos de
roteamento. Como será visto a seguir, as entradas na tabela de encaminhamento poderiam até ser
configuradas manualmente, mas essa ação com as redes de computadores atuais, principalmente a
Internet, se tornaria impraticável.
Roteamento
Na seção anterior, foi visto o encaminhamento desempenhado pelo IP, onde dado um determinado
pacote IP, é feita a verificação do próximo salto na tabela de encaminhamento e o direcionamento
desse pacote para o mesmo.
As rotas da tabela de encaminhamento podem ser originadas basicamente de três formas. A primeira
são as rotas diretas. São as redes as quais o roteador se conecta diretamente. A segunda é a forma
estática, onde o gestor da rede precisa configurar cada rota manualmente. Pode ser utilizada em
pequenas redes domésticas, entretanto em redes mais complexas, onde existirão diversos
roteadores organizados em uma malha, existindo diversos enlaces entre eles, essa configuração
manual torna-se muito onerosa. A configuração das rotas manualmente também se torna um
problema devido à necessidade de reagir dinamicamente às mudanças da rede, como por exemplo
devido a falhas de um enlace ou ainda quando novos roteadores são acrescentados.
10
Já na terceira forma, chamada de roteamento dinâmico, as rotas serão configuradas
automaticamente, de acordo com os protocolos de roteamento e como será visto, existem
basicamente dois tipos predominantes, os protocolos do tipo vetor distância e do tipo estado de
enlace.
As rotas provenientes a partir dos protocolos de roteamento são combinadas com as rotas estáticas
configuradas e com as rotas diretas descobertas, dando origem a RIB (Routing Information Base).
A RIB apresenta diversas informações sobre as rotas disponíveis na rede. Parte dessa informação
pode sugerir várias rotas para um único destino, e um mecanismo de decisão de roteamento aplica
políticas de roteamento para determinar as melhores rotas. A RIB dará origem a FIB. A FIB oferece
informações não ambíguas ao componente do roteador que encaminha os pacotes de dados.
11
Protocolos do tipo Vetor Distância
A ideia dos protocolos dessa modalidade é bastante simples. Cada roteador mantém uma lista de
todos os destinos alcançáveis da rede e distribui essa lista de tempos em tempos para seus vizinhos.
Cada entrada na tabela de roteamento identificará a rede de destino, o roteador usado para o
próximo salto e a ``distância'' até a rede de destino. Essa distância geralmente será a quantidade de
saltos (hops) até o destino. Por exemplo, uma rede diretamente conectada estará a zero saltos de
distância. Se um datagrama precisa passar por “N” roteadores para chegar ao destino, o destino está
a “N” saltos de distância.
Quando um roteador novo “X” é inserido, primeiramente ele irá se anunciar aos vizinhos. Os vizinhos
propagarão a informação dizendo que podem chegar até “X” com um salto de distância e assim
sucessivamente.
Quando uma mensagem, por exemplo, proveniente de “X”, chega em “Y”, “Y” tomará as seguintes
ações:
Se “X” conhece um destino que “Y” não, “Y” irá adicionar esse destino a sua tabela de
roteamento, configurando como próximo salto “X” e somando 1 ao custo para se chegar a
determinado destino;
Se “X” conhece um caminho mais curto para o destino, “Y” substitui a entrada em sua tabela
de roteamento, configurando o próximo salto para “X” e corrigindo o custo;
Se a entrada para um determinado destino já existe em “Y”, sendo o próximo salto para a
mesma, “X” e “X” anuncia um valor de custo diferente ao anterior, “Y” irá atualizar sua
tabela, corrigindo o custo;
Figura 6: Tabela de encaminhamento de “Y” (a), Mensagem de “X” e mudanças em “Y” (b)
Fonte: Figura baseada em Comer, 2013
Essa modalidade de protocolos, torna-se ideal para redes pequenas a médias, uma vez que a
transmissão de toda a tabela de roteamento para cada vizinho é lenta e a ocorrência de perdas pode
causar loops, demandando um longo tempo para a convergência das informações. Como vantagens,
têm-se a baixa complexidade de implementação e os baixos requisitos de processamento e memória.
Como exemplos de protocolos do tipo vetor distância, têm-se os protocolos RIP (Routing Information
Protocol) e EIGRP (Enhanced Interior Gateway Routing Protocol).
Diferentemente dos protocolos do tipo vetor distância, os protocolos do tipo estado de enlace não
irão distribuir uma lista de rotas, informando os custos e os destinos que o mesmo pode atingir.
12
Os roteadores ficarão, periodicamente, testando os status das conexões com seus vizinhos,
realizando a troca de pequenas mensagens para constatar se o vizinho está ativo e é atingível. Caso
o vizinho responda a mensagem, o link estará up, caso negativo, o mesmo será considerado down.
Após a descoberta dos vizinhos, o roteador envia periodicamente mensagens para informar aos
outros roteadores da rede sobre os status de cada um de seus links (mensagens LSP - Link State
Packet - ou LSA - Link State Advertisement - de acordo com o protocolo). É importante enfatizar que
essas mensagens de status não especificam rotas, informam apenas se a comunicação é possível
entre o par de roteadores referidos na mensagem.
Esse processo de inundação das mensagens é simples. O roteador recebe um LSP e verifica em seu
banco de dados de estado de enlace se já conhece o enlace referido na mensagem. Se conhecer, ele
descartará o LSP, mas caso não conheça, ele acrescentará o enlace ao seu banco de dados e enviará
o novo LSP em cada uma de suas interfaces, exceto a interface em que a mensagem foi recebida
originalmente.
Logo, após a rede convergir, cada roteador possuirá um mapa completo e idêntico da rede.
Para calcular as rotas entre os enlaces disponíveis na rede, os roteadores executam o algoritmo de
Dijkstra, algoritmo esse que irá calcular o melhor caminho entre o roteador local e todos os outros
destinos.
Um dos protocolos de estado de enlace mais conhecidos, o OSPF (Open Shortest Path First), têm
métrica padrão proporcional à largura de banda dos enlaces. Com isso, o melhor caminho sempre
será o mais rápido, ao contrário do vetor distância, que usa o caminho com menor número de saltos.
Outra vantagem dos protocolos de estado de enlace é que cada roteador realiza os cálculos das rotas
independentemente, usando os mesmos dados de status originais, não dependendo de roteadores
intermediários como o vetor distância. Esse tipo de protocolo é ideal para redes grandes, pois sua
percepção de problemas ou de novos roteadores e a consequente propagação dessas informações
são rápidas. Mas, como desvantagem, o cálculo das alterações nas tabelas de roteamento exige
bastante processamento.
Nessa seção, termina-se uma breve introdução ao funcionamento das redes de computadores atuais.
A próxima seção, tem como objetivo apresentar a comutação baseada em rótulos, que será a base
da tecnologia MPLS. Devido à flexibilidade de roteamento existente em tal tecnologia, torna-se
interessante a citação da mesma, para posterior compreensão das redes definidas por software.
A tecnologia nos comutadores explora o indexamento para atingir velocidades extremamente altas
no encaminhamento de dados. Para isso, cada pacote carrega um número inteiro conhecido como
rótulo. Quando um pacote chega no comutador, o comutador extrai o rótulo e usa o valor como
índice na tabela que irá especificar a ação apropriada. Cada comutador pode ter uma série de
interfaces de saída e a ação geralmente consiste em enviar o pacote por uma dessas interfaces.
13
caminho. Pode ser desejado que um tráfego de maior prioridade percorra um caminho mais curto,
enquanto que os tráfegos de menor prioridade, podem ser enviados por caminhos mais longos. A
maioria das técnicas de roteamento como foi visto, costuma enviar o tráfego para o caminho mais
curto.
Como citado, comutação de rótulos consiste em associar um rótulo pequeno e de formato fixo em
cada pacote de dados de modo que ele possa ser encaminhado na rede. Isso significa que cada
pacote, precisa transportar um identificador que irá dizer aos nós da rede como encaminhá-lo. Em
cada salto por meio da rede, o pacote é encaminhado com base no valor do rótulo que chega e é
encaminhado com um novo valor de rótulo. A figura 7 ilustra essa troca de rótulos e o
encaminhamento dos pacotes.
Até o momento, a comutação baseada em rótulos foi descrita como uma tecnologia de rede
orientada para conexões de propósito geral. Será apresentado agora, como a comutação baseada
em rótulos pode ser combinada com a Internet. Em 1991, a IETF (Internet Engineering Task Force)
padronizou através da RFC 3031 o MPLS.
Geralmente o MPLS é utilizado no núcleo de grandes ISP's (Internet Service Providers). Roteadores
na borda da rede do ISP irão examinar cada datagrama e decidir se utilizará algum caminho da rede
MPLS para encaminhar os dados ou se lidará com o datagrama com o encaminhamento
convencional.
O MPLS permite ao ISP oferecer serviços especiais para clientes individuais. Por exemplo, considere
uma grande empresa com escritórios no Rio de Janeiro e em Porto Alegre. Supondo que a empresa
deseje uma conexão segura entre essas duas localidades com performances garantidas, o ISP pode
estabelecer um caminho na rede MPLS entre esses dois escritórios e pode configurar os roteadores
ao longo do caminho para garantir o desempenho contratado.
Classificação de Pacotes
Como citado anteriormente, o MPLS por utilizar comutação por rótulos, permite uma maior
flexibilidade no roteamento. Isso quer dizer que, em muitos casos, gerentes de redes usam
protocolos da camada de transporte para escolherem quais caminhos determinados fluxos de dados
devem seguir dentro da rede MPLS. Por exemplo, pode existir uma regra que especifique que todo
tráfego web percorra um determinado caminho diferente dos outros tráfegos.
14
Com isso, o modelo de camadas tradicional apresentado na seção “Modelo em camadas” é
insuficiente para a tarefa de seleção de caminhos na rede MPLS, já que no modelo tradicional os
datagramas em trânsito não são desencapsulados até a camada de transporte.
Para entender a classificação de tráfego, imagine um pacote que foi recebido no roteador e colocado
na memória. Pensando no pacote como um array de bytes, para saber se um determinado pacote
corresponde a um tráfego web, basta verificar alguns bytes. Como por exemplo, verificar os bytes
correspondentes ao Ethernet type, para saber se é um pacote IP, verificar os bytes correspondentes
ao campo protocolo, no pacote IP, para saber se o protocolo utilizado é o TCP e verificar os bytes
correspondentes a porta de destino, para verificar se os mesmos correspondem à porta 80 (Comer,
2013).
Observe que todas as ações representam pesquisas no array de bytes. O sistema de classificação não
precisa entender nenhum dos cabeçalhos dos protocolos ou o significado dos bytes.
Com esse cenário em mente, a ideia de redes programáveis foi proposta com o objetivo de facilitar
futuras evoluções nas redes de computadores. Nesta seção serão apresentados os conceitos
fundamentais das redes definidas por software, uma forma de programar a rede que vem se
destacando consideravelmente nos últimos anos.
É um novo paradigma que tem como objetivo facilitar substancialmente a gerência de redes e
permitir inovações e evoluções que o nosso modelo ``ossificado'' atual não permite (Nunes et al.,
2014).
Engenharia de Tráfego
Isso exposto, surge a necessidade de realizar uma engenharia de tráfego, ou seja, realizar uma maior
distinção entre os diferentes pacotes e, consequentemente, priorizar alguns em detrimento de
outros, com o objetivo de otimizar o desempenho da rede. Hoje, existem tecnologias que realizam
uma distinção e oferecem ao usuário final garantias de qualidade de serviço, como por exemplo, as
15
já citadas redes MPLS. Nas mesmas, através da criação de circuitos virtuais e da comutação baseada
em rótulos, pacotes com o mesmo endereço IP de destino podem percorrer caminhos diferentes
dentro de uma mesma rede.
Como será visto, implementando o paradigma de redes definidas por software, haverá um salto na
engenharia de tráfego, já que cada fluxo, ou seja, conjunto de pacotes de dados com algumas
características em comum, poderá ser tratado individualmente e novos softwares e formas de
encaminhar esses fluxos poderão ser desenvolvidos e implementados de acordo com as
necessidades do gestor da rede.
O plano de controle é a parte responsável pela “inteligência” do dispositivo. Por exemplo, é o plano
de controle que executa os códigos dos protocolos de roteamento, responsável pela realização do
cálculo das rotas em roteadores. Já o plano de dados é responsável por lidar com os pacotes
entrantes no dispositivo, verificando na tabela de encaminhamento por qual interface o mesmo
deverá ser encaminhado.
Atualmente, os dispositivos convencionais apresentam uma estreita ligação entre esses planos. Essa
interligação torna árdua a depuração de configurações e o controle do comportamento de
roteadores e switches (Feamster et al., 2014).
O conceito base das redes definidas por software consiste em separar o plano de controle do plano
de dados e retirá-lo dos dispositivos. Com isso, a rede será formada por dispositivos “burros”
encaminhadores de pacotes e por uma camada de software programável onde haverá um
controlador de rede que coordenará todas as ações dos dispositivos. Esses dispositivos
encaminhadores de pacotes serão programados através de uma interface aberta, como, por
exemplo, a interface definida pelo OpenFlow, que será visto na próxima seção.
16
A figura 9 ilustra a comunicação do controlador externo com o dispositivo de rede.
Vale salientar que as redes definidas por software suportam tanto controladores externos
totalmente centralizados, ou seja, apenas um controlador com visão total da rede, quanto
distribuídos, onde há alguns controladores controlando a rede (mesmo que de forma lógica
aparentem ser apenas um).
Na figura 10, segue uma representação de dispositivos de redes genéricos, com um sistema
operacional externo conhecedor de toda a topologia rodando no controlador e programas de
controle diversos, sejam novos ou já em uso, como por exemplo, protocolos de roteamento como
OSPF e RIP.
Por ser um novo modelo, existem benefícios e desafios/desvantagens com a sua implementação.
Seguem abaixo alguns benefícios:
Visualização unificada da rede - Com as redes definidas por software, passa-se a ter uma
visão global de toda a rede através do controlador, simplificando configurações e gerência
dos dispositivos.
17
Recuperação mais rápida das falhas - Devido ao controle global, seja a falha em um link ou
em um nó da rede, a rede se reorganizará e convergirá mais rapidamente para uma nova
ótima configuração, devido a utilização de algoritmos centralizados ao invés de algoritmos
distribuídos.
Upgrade e implementação de novas aplicações - Uma das maiores vantagens desse novo
paradigma é a implementação de novas aplicações para a rede. Novos protocolos e novas
formas de encaminhar os dados poderão ser testadas e implementadas rapidamente, pois
não dependem mais de modificações no firmware do switch ou do roteador. Além disso, o
controlador pode ter seu software atualizado e alterado sem haver perda de pacotes em
uma rede em produção.
Com a retirada do plano de controle dos dispositivos, pode-se modelar e moldar dinamicamente a
rede, de acordo com a necessidade do gestor, permitindo que a gerência da rede seja feita de forma
muito mais fácil e eficiente.
Atualmente, as limitações de largura de banda para cada tipo de serviço são uma realidade, nos
permitindo priorizar tráfego VoIP por exemplo, sobre outras aplicações. Entretanto, ao longo do dia,
as necessidades dos usuários da rede podem ser alteradas e possivelmente uma determinada
aplicação pode vir a ter uma prioridade maior que um tráfego VoIP.
Com redes definidas por software, em tempo real, pode-se haver essa troca de prioridades e a
determinada aplicação prioritária passa rapidamente a trafegar com alta prioridade.
Todo esse modelamento do tráfego poderá ser feito através de um console de gerência, e em
instantes, os dispositivos da rede seriam configurados, não havendo mais a necessidade de conectar-
se a cada dispositivo.
Um exemplo similar pode ser visto no webinar da Cisco (Yamamoto e Schara, 2014), onde, num
primeiro momento, um streaming de vídeo não era executado corretamente devido a baixa
prioridade e saturação do link principal. Após rápidos ajustes no controlador, o link secundário
(redundância) que antes estava ocioso, passou a ser utilizado e o streaming foi feito corretamente.
Outro exemplo de implementação foi apresentado pelo Google em 2012 na Open Network
Summit(conferência destinada a discussões sobre SDN), onde o mesmo implementou uma solução
OpenFlow/SDN no backbone que trafega os dados entre seus datacenters (Goole, 2012).
18
Como visto, as redes definidas por software já são uma realidade, mesmo que ainda de forma tímida.
Muito precisa ser evoluído e amadurecido. Questões relativas à segurança precisam ser devidamente
estudadas e analisadas. Mas a liberdade proporcionada por esse modelo não deixa dúvidas de que
num futuro próximo as redes serão muito mais dinâmicas e programáveis que as atuais, seja
utilizando o paradigma SDN ou algum outro que venha a ser derivado do mesmo.
Após a definição do conceito das redes definidas por software, vista na seção anterior, algumas
dúvidas podem vir a surgir como:
Como se dará a comunicação entre o controlador e os dispositivos de rede genéricos?
Quais configurações e controle um determinado dispositivo deve oferecer?
Qual deve ser o formato das mensagens enviadas pelo controlador?
As respostas para tais perguntas podem ser encontradas na implementação mais difundida das redes
definidas por software, o padrão OpenFlow.
É uma tecnologia proposta para padronizar a forma como o controlador se comunica com os
dispositivos de rede em uma arquitetura SDN, definindo também um protocolo para essa
comunicação. Dessa forma, o OpenFlow provê meios de controlar os dispositivos de rede (switches
OpenFlow) sem a necessidade dos fabricantes exporem o código de seus produtos (Lara et al., 2014).
Assim, através do protocolo OpenFlow, os controladores podem programar as tabelas de fluxo dos
switches. Como será visto abaixo, a tabela de fluxos é parte essencial dos switches OpenFlow.
Diferentes versões do protocolo OpenFlow estão disponíveis. A primeira versão foi a 0.2.0 lançada
em Maio de 2008 e atualmente está obsoleta. A versão 1.0.0 lançada em Dezembro de 2009 foi a
mais amplamente divulgada e implementada, com isso a mesma terá um foco maior nesse trabalho.
Após a versão 1.0.0, foram lançadas as versões 1.1, 1.2, e 1.3 e 1.4 (Lara et al., 2014).
O OpenFlow encontra-se em constante evolução e o mesmo é mantido pela ONF (Open Network
Foundation).
Baseando-se na versão 1.0.0, a versão mais difundida do OpenFlow, os switches OpenFlow devem
possuir/suportar as seguintes características (McKeown et al., 2008):
Tabela de Fluxos;
Canal Seguro;
Protocolo OpenFlow.
A tabela de fluxos contém 12 campos que serão utilizados para a classificação de um fluxo, uma ação
para cada fluxo e contadores.
O canal seguro irá conectar o switch OpenFlow ao controlador e permitirá que os comandos passem
por ele.
19
A figura 11 ilustra as características citadas acima.
O switch OpenFlow deve ser capaz de realizar três simples ações com os fluxos entrantes:
Encaminhar o fluxo entrante para uma determinada interface de saída, caso haja uma
entrada equivalente para o fluxo em questão em sua tabela de fluxos;
Caso não haja entrada equivalente na tabela de fluxos, o switch deve ser capaz de encapsular
o primeiro pacote (ou todos, de acordo com a necessidade) e encaminhá-lo para o
controlador através do canal seguro. O controlador que irá decidir o que fazer com esse
pacote. Inclusive, decidirá se uma entrada na tabela de fluxos do switch será adicionada ou
não;
Por último, o switch OpenFlow também deve ser capaz de descartar pacotes;
Tabela de Fluxos
Pode ser observado na figura 12 que uma entrada na tabela de fluxos é composta por:
Os campos de cabeçalho são os campos que serão comparados com o fluxo entrante no switch
OpenFlow.
20
Cada campo do cabeçalho pode ser ou não definido. Por exemplo, para o switch OpenFlow funcionar
como um roteador, basta especificar o campo IP de destino.
Quanto aos contadores existem quatro tipos diferentes: Os contadores por tabela, por fluxo, por
porta e por fila. Os mesmos serão incrementados sempre que fluxos correspondentes às entradas
na tabela entrem no switch e serão utilizados em mensagens de estatísticas, também definidas pelo
OpenFlow.
Quanto às ações que deverão ser tomadas com os pacotes, existem ações obrigatórias que todos os
switches OpenFlow devem implementar e outras opcionais. Ao se conectar ao controlador, o switch
deve informar quais ações opcionais o mesmo implementa.
Cada entrada na tabela de fluxos é associada a uma ou mais ações. Se para uma determinada entrada
na tabela não houver uma ação especificada, os pacotes desse fluxo serão descartados.
21
FLOOD - Inunda o pacote, sem incluir a interface de entrada, levando em
consideração o Spanning Tree.
Enfileirar (opcional) - Encaminha o pacote através de uma fila relacionada a uma porta;
Descartar (obrigatória);
Modificar campo (opcional):
o Setar Vlan ID
o Setar Vlan Priority
o Separar o cabeçalho da Vlan
o Modificar endereço MAC (\textit{Media Access Control}) de origem
o Modificar endereço MAC de destino
o Modificar endereço IP de origem
o Modificar endereço IP de destino
o Modificar ToS
o Modificar a porta de transporte de origem
o Modificar a porta de transporte de destino
Vale salientar que, assim como nos roteadores rotas para sub-redes mais específicas têm prioridade,
entradas na tabela de fluxos que especifiquem exatamente o fluxo entrante, ou seja, entradas na
tabela que não apresentem campos coringa, terão sempre a mais alta prioridade.
O canal Seguro
De acordo com “Comer, 2013”, embora uma conexão TCP seja permitida entre o switch e o
controlador, o uso de SSL/TLS é recomendado com o objetivo de garantir confidencialidade em toda
comunicação. É importante lembrar que o OpenFlow não requer uma conexão física direta entre o
switch e o controlador, podendo utilizar redes já em produção para efetuar a comunicação. Por isso,
a importância de um canal seguro.
22
Abaixo, os sub-tipos de cada uma:
Controlador-Switch
o Características (Features) - O controlador requisita as características do switch. O
switch deve responder com as características suportadas;
o Configuração (Configuration) - Usado para configurar ou solicitar configurações do
switch;
o Modificação de estado (Modify-State) - Usado para adicionar, deletar e modificar a
tabela de fluxos e para setar propriedades nas portas do switch;
o Leitura de estado (Read-State) - Coleta estatísticas;
o Envio de pacote (Send-Packet) - Utilizado para enviar pacotes por uma determinada
porta do switch;
o Barreira (Barrier) - Usado para garantir que as dependências foram atendidas ou
para receber notificações de operações finalizadas;
Assíncrona
o Entrada de pacotes (Packet-In) - Utilizado quando fluxos não classificados entram
no switch.
o Remoção de fluxo (Flow-Removed) - Mensagem enviada para o controlador,
quando um fluxo é removido da tabela. Seja por Idle Timeout, Hard Timeout ou por
uma mensagem de modificação da tabela de fluxos que delete a entrada em
questão;
o Estado da porta (Port-Status) - Mensagem enviada para o controlador sempre que
há mudanças nas configurações das portas;
o Erro (Error) - Notificações de erros;
Simétrica
o Hello - Mensagens trocadas entre o controlador e o switch quando uma conexão é
estabelecida;
o Echo - Mensagens usadas para identificação de latência, largura de banda e
existência de conectividade;
o Vendor - Provêem uma forma padrão para os switches OpenFlow oferecerem
funcionalidades adicionais;
Se as versões forem compatíveis, a comunicação tem continuidade. Caso não sejam, uma mensagem
de erro é gerada (OFPT_ERROR) e a conexão é encerrada.
É interessante informar também que, caso haja alguma perda de conexão entre o switch e o
controlador, o switch tentará se conectar ao controlador back-up, caso exista. Caso essa conexão
também falhe, o switch entrará em modo de emergência, modo esse que utilizará apenas as entradas
na tabela de fluxos marcadas com um bit de emergência e todas as outras entradas serão deletadas.
Para modificar as tabelas de fluxos dos switches, o controlador poderá gerar cinco tipos de
mensagens diferentes. A figura 16 ilustra esses tipos:
23
Fonte: Foundation, 2009
Como pode ser observado, as mensagens ADD adicionarão entradas na tabela de fluxos, as
mensagens do tipo MODIFY modificarão entradas já existentes e as mensagens do
tipo DELETE apagarão entradas na tabela de fluxo. As mensagens *_STRICT (OFPFC_MODIFY_STRICT
e OFPFC_DELETE_STRICT) buscarão entradas na tabela de fluxos idênticas às especificadas.
Outras Versões
Nas seções acima, o OpenFlow 1.0.0 foi apresentado em maiores detalhes, considerando que o
mesmo é a versão mais utilizada e difundida. Entretanto, muitas mudanças foram realizadas desde
o lançamento da versão 1.0.0 até a versão mais atual, a 1.4. Abaixo, seguem algumas características
das versões subsequentes:
OpenFlow 1.1
Na especificação do OpenFlow 1.1, os switches OpenFlow contêm diversas tabelas de fluxos e uma
tabela de grupo, ao invés de uma única tabela de fluxos como na versão 1.0.0.
A figura 17 ilustra os componentes do switch OpenFlow 1.1. Nela podem ser vistas as diversas tabelas
de fluxos, assim como, a tabela de grupo.
24
Figura 18: Fluxograma detalhando o fluxo de pacotes através do switch OpenFlow 1.1
Fonte: Foundation, 2011a
Logo, um fluxo de pacotes ao entrar no switch OpenFlow, poderá passar por várias tabelas de fluxos,
para que diversas ações diferentes sejam realizadas.
A tabela de grupo é um tipo especial de tabela projetada para executar ações que sejam comuns
para diversos fluxos.
Além disso, na versão 1.1.0, três novos campos de cabeçalho foram incluídos: Metadata (pode ser
usada para passar informações entre as tabelas no switch), MPLS label e MPLS traffic class.
Maiores detalhes podem ser encontrados na especificação OpenFlow 1.1.0 em (Foundation, 2011a).
OpenFlow 1.2
O OpenFlow 1.2 foi lançado em dezembro de 2011 e uma das principais implementações foi o
suporte ao protocolo IPv6, incluindo novos campos de cabeçalho nas tabelas de fluxos.
Além disso, o mesmo passou a suportar a possibilidade dos switches se conectarem a mais de um
controlador ao mesmo tempo. Ao se conectar a vários controladores, aumenta-se a segurança já que
o switch pode continuar a operar normalmente mesmo se um controlador ou a conexão ficar
indisponível (Lara et al., 2014).
OpenFlow 1.3
Sendo lançada em Junho de 2012, a versão 1.3.0 do OpenFlow passou a suportar o controle das taxas
de pacotes através de medidores de fluxos, introduzindo a tabela de medições Meter Table.
A tabela de medições por fluxo permite ao OpenFlow implementar simples operações de QoS, como
limitação de taxas de transmissão e pode ser combinada com as filas por porta para criar políticas de
QoS mais complexas.
25
Além disso, a versão 1.3 permite ao switch criar conexões auxiliares para o controlador, ajudando a
melhorar o desempenho de processamento do switch, explorando o paralelismo presente na maioria
dos switches (Foundation, 2012a).
OpenFlow 1.4
Na versão 1.4 do OpenFlow portas ópticas passaram a ser suportadas. Além disso, os conceitos
deEviction e Vacancy events foram introduzidos para evitar que as tabelas de fluxos fiquem cheias,
já que as mesmas tem capacidades finitas. Nas especificações anteriores quando uma tabela de
fluxos enchia, novos fluxos não eram inseridos nas tabelas e uma mensagem de erro era enviada
para o controlador. Entretanto, atingir tal situação era problemático e poderia causar interrupções
no serviço. O Evictionadiciona um mecanismo que permite ao switch apagar automaticamente as
entradas nas tabelas de fluxos que tenham menor importância. Já o Vacancy events permite ao
controlador configurar um limiar, que ao ser atingido, faz o switch enviar mensagens de alerta para
o controlador. Isso permite que o controlador possa reagir com antecedência, evitando que as
tabelas de fluxos fiquem cheias (Foundation, 2012b).
As subseções acima deram apenas uma visão global sobre as características das versões do OpenFlow
posteriores à 1.0.0. Maiores detalhes e outras características podem ser encontradas nas
especificações técnicas, citadas na bibliografia.
POX
Como visto anteriormente, o controlador é parte fundamental nas redes definidas por software, já
que serão os mesmos que irão definir a lógica de encaminhamento através das regras que irão
configurar nos switches OpenFlow. Atualmente, existem alguns disponíveis para o uso, como o NOX
(Gude et al., 2008), POX (http://www.noxrepo.org./pox/about-pox/), Maestro (Cai et al., 2010),
Trema (http://trema.gitub.io/trema/), Beacon (Erickson, 2013), entre outros como pode ser visto na
figura 19.
O controlador utilizado nesse trabalho foi o POX. O mesmo é derivado do NOX clássico, um dos
primeiros controladores OpenFlow. O POX apresenta como vantagens o fato de ser implementado
em Python, sendo ideal para o ambiente acadêmico. Além disso, o mesmo apresenta diversos
componentes reusáveis e bibliotecas interessantes como as seguintes:
openflow.discovery: Utiliza mensagens LLDP (Link Layer Discovery Protocol) para descobrir
a conectividade entre os switches com o objetivo de mapear a topologia da rede. O mesmo
26
cria eventos (os quais podem ser “escutados”) quando um link fica up ou down. Esse
componente foi essencial para a aplicação desenvolvida;
openflow.spanning_tree: Esse componente utiliza o discovery para contruir uma visão da
topologia da rede e constrói uma spanning tree para desabilitar a inundação (flooding) nas
portas dos switches que não estão na árvore;
pox.lib.revent: Biblioteca do POX que implementa eventos. Todos eventos do POX são
instâncias de sub-classes da classe Event;
pox.lib.recoco: Biblioteca do POX que implementa threads e timers;
pox.lib.addresses: Biblioteca utilizada para lidar com endereços IP e Ethernet (MAC);
27
Redes Definidas por SW II: Introdução
Seu embrião teve início no final da década de 1960 com a então denominada ARPANET (Advanced
Research Projects Agency Network), que buscava interligar as bases militares e os departamentos de
pesquisa norte-americanos.
Muito evolui desde então. Modelos para protocolos de comunicação foram criados e muitos
protocolos foram desenvolvidos, sejam para suprir a demanda de aplicações, sejam para calcular os
caminhos que os pacotes devem percorrer ao longo da rede.
Devido à essa evolução de ideias, desde o início das pesquisas sobre comutação de pacotes e da
ARPANET, juntamente com a evolução do hardware utilizado, hoje temos inúmeras possibilidades
na rede. Anexar enormes quantidades de arquivos em nossos e-mails, jogar jogos com pessoas do
mundo inteiro em tempo real, ou até mesmo realizar ligações telefônicas através da Internet.
Entretanto, talvez hoje as redes estejam na iminência de uma mudança de paradigma, mudança essa
que possibilitará o desenvolvimento de aplicações cuja implementação com a tecnologia atual seria
impossível. Com a utilização de redes definidas por software (SDN - Software-Defined Networking),
será possível um total controle da rede. Não haverá mais a necessidade de hardwares especializados,
mas sim, poderá se utilizar hardwares genéricos programáveis. Novos protocolos poderão ser
testados e implementados com uma rapidez nunca antes vista e aplicações que hoje são impensáveis
se tornarão absolutamente viáveis através da implementação dessa tecnologia.
Motivação e Objetivos
O conceito de redes programáveis não é novo. Como exemplo, tem-se o conceito de redes ativas na
década de 1990 (Feamster et al., 2014). Entretanto, pela primeira vez, o conceito é amplamente
difundido e aceito. As redes definidas por software vêm apresentando grande aceitação por parte
da comunidade acadêmica e pelos principais fabricantes de equipamentos, que já começaram a
desenvolver soluções voltadas para esse modelo.
Diante o exposto, como objetivo geral, essa monografia pretende apresentar ao leitor esse novo
paradigma em redes de computadores, mostrando o quão importante o mesmo será para
pesquisadores que necessitam testar novos protocolos assim como para gestores que precisam
gerenciar redes de computadores todos os dias.
28
Apresentar conceitos do OpenFlow, implementação mais difundida das redes definidas por
software;
Apresentação de uma aplicação programada em Python, para redes definidas por software.
Essa aplicação altera o caminho de um fluxo pré-estabelecido, mediante a uma alta
utilização da largura de banda do caminho principal;
Tutoriais
O tutorial parte I apresentou inicialmente os conceitos básicos de redes de computadores para que
seja possível o entendimento posterior das redes definidas por software. A seguir tratou dos
conceitos básicos sobre planos de controle e de dados e em seguida da definição de redes definidas
por software. Finalizou apresentando o padrão/protocolo OpenFlow, os switches OpenFlow, e os
principais controladores disponíveis, dando enfoque ao POX, controlador utilizado neste estudo.
O ambiente utilizado para o desenvolvimento da aplicação e realização dos testes foi o Mininet. Este
se trata de um emulador de redes, desenvolvido por pesquisadores da Universidade de Stanford nos
Estados Unidos, com o objetivo de apoiar pesquisas colaborativas permitindo protótipos autônomos
de redes definidas por software, para que qualquer pessoa possa fazer o download, executar, avaliar,
explorar e ajustar (Lantz et al., 2010).
Na figura 1 é apresentada uma topologia simples que servirá de base para as figuras 2 e 3. Nessas
duas últimas as diferenças citadas acima, entre CBE e a virtualização completa, podem ser
visualizadas.
29
Figura 2: Virtualização completa dos dispositivos
Fonte: Lantz e O’Connor
O Mininet é capaz de emular links, hosts, switches e controladores, utilizando processos que rodem
em espaços de nomes da rede (network namespaces) e pares Ethernet virtuais.
Links: Um par Ethernet virtual atua como um cabo conectando duas interfaces virtuais.
Pacotes enviados através de uma interface são entregues na outra e cada interface se
comporta como uma interface Ethernet completa e funcional para todo o sistema e
aplicação.
Host: É simplesmente um processo do shell movido para o seu próprio espaço de nome da
rede, ou seja, cada host apresenta uma instância da interface de rede independente. Cada
dispositivo apresenta uma ou mais interfaces virtuais e um pipe para um processo pai do
Mininet (mn), que envia comandos e monitora a saída.
Switches: Switches OpenFlow são remotamente configurados e gerenciados pelo
controlador, podendo ser configurados para agirem como switches convencionais.
Controladores: Controladores OpenFlow podem estar em qualquer lugar da rede, ou seja,
tanto na rede física quanto na virtual (Lantz et al., 2010).
Para controlar e gerenciar todos os dispositivos emulados, o Mininet fornece uma CLI (Command
Line Interface) conhecedora de toda a rede, ou seja, através de um único console, pode-se controlar
todos os dispositivos emulados. Outra grande vantagem desse emulador é a facilidade de criação de
topologias customizadas através de uma API (Application Programming Interface) para programação
em Python.
30
O projeto Mininet nasceu com o objetivo de facilitar os experimentos no campo de redes de
computadores, principalmente para auxiliar nas pesquisas das redes definidas por software e do
OpenFlow.
Pode ser verificado em “Heller, 2013” uma análise completa do Mininet, incluindo uma comparação
entre os tipos de plataformas para pesquisas em redes de computadores mais comuns, os
simuladores, testbeds e emuladores.
Em “Handigol et al., 2012”, pode ser verificada a robustez do Mininet ao reproduzir diversos
experimentos de redes de computadores escolhidos por estudantes.
O emulador Mininet encontra-se em constante evolução, sendo mantido por uma ativa comunidade
online. O mesmo encontra-se na versão 2.1.0 lançada em Setembro de 2013.
Com a tecnologia de redes de computadores atual, torna-se inviável o teste de novos protocolos em
redes que estejam em produção, já que as mesmas foram implementadas com hardwares
específicos, que não permitem uma reprogramação.
Conforme visto nas seções anteriores, com as redes definidas por software, essa limitação já não
mais existirá. Equipamentos específicos se tornam genéricos e a figura do controlador aparece para
que possa existir uma rede programável e para que mudanças na forma de encaminhar os pacotes
possam ser realizadas rapidamente.
A aplicação desenvolvida busca mostrar essa facilidade presente nas redes definidas por software.
A mesma foi desenvolvida para alterar o roteamento de um fluxo pré-determinado, quando o uso
da largura de banda do caminho inicial estiver alto. Para tal, foram utilizados conceitos do algoritmo
de Dijkstra para o cálculo dos caminhos e módulos presentes no POX, como será visto adiante.
Executando a Aplicação
Conforme a descoberta vai sendo feita, um peso é atribuído aos enlaces. Esse peso pode ser
interpretado como o delay do link por exemplo ou qualquer outro parâmetro que signifique que
quanto maior o valor, pior é o enlace. Para a emulação realizada, se utilizou um gerador de números
aleatórios para a definição dos pesos de cada enlace.
31
Após a topologia ser salva, com a descoberta de todos os switches e a atribuição dos pesos, o
algoritmo de Dijkstra é, então, executado em um código complementar.
Esse código complementar, apresentado na seção Códigos Implementados deste tutorial parte II,
utiliza conceitos do algoritmo de Dijkstra para realizar o cálculo da melhor e da segunda melhor rotas
entre os switches OpenFlow. O código recebe como parâmetros o nó origem e a topologia e retorna
duas listas, uma contendo o menor custo e a outra contendo o segundo menor custo para se chegar
aos outros nós.
Como pode ser visto no fluxograma acima, toda vez que ocorrer um evento de link, ou seja, quando
um link for descoberto ou quando um link ficar down, a topologia será alterada e o código do
algoritmo de Dijkstra será executado.
Ao receber um pacote, o switch enviará uma mensagem de Packet-In para o controlador, se o switch
não possuir entradas em sua tabela de fluxos. A aplicação no controlador tratará de maneiras
diferentes pacotes ARP (Address Resolution Protocol) e os demais.
Se o pacote for um ARP (seja Request ou Reply) o controlador irá gerar um pacote de Packet-Out, ou
seja, o controlador informa ao switch apenas qual deve ser a ação a ser tomada para um pacote, não
havendo modificação da tabela de fluxos do switch. A figura 6 mostra os Packet-In gerados pelos
switches, com a resposta Packet-Out do controlador:
Caso o pacote não seja ARP, o controlador gera uma mensagem de Flow-Mod que irá inserir uma
entrada na tabela de fluxos do switch, como pode ser visto na figura 7.
32
Figura 8: Fluxograma representando o evento de Packet-In
Para cada par de switches origem e destino, a aplicação monitora a taxa de transmissão, fazendo
requisições periódicas de estatísticas do uso da interface. A quantidade de bytes transmitidos pela
porta conectada ao próximo switch (próximo switch de acordo com o melhor caminho calculado) é
salva em uma variável e será comparada com a quantidade da coleta anterior.
Como na topologia definida para o teste (Código para a Criação da Topologia apresentado na
seção Códigos Implementados deste tutorial parte II) os links foram definidos com uma largura de
banda de 100 Mbps, é feito um cálculo com a diferença de bytes transmitidos em duas coletas e
verifica-se se a quantidade de bits transmitidos por segundo é menor que um determinado limiar.
Esse limiar foi determinado nos testes como 70 Mbps. Caso seja, todos os fluxos destinados ao
mesmo IP de destino passam pelo melhor caminho. Caso a quantidade de bits por segundo seja
maior que 70 Mpbs, os fluxos que apresentem porta UDP igual a 2000 são chaveados para a segunda
melhor rota.
Como pode ser visto no fluxograma da figura 9 com o objetivo de evitar que fiquem ocorrendo
mudanças de rotas a todo momento, foi implementada uma histerese. Assim, existe um contador
que salva o número de ocorrências do evento. Para mudar para o segundo caminho, o mesmo deve
33
ser maior ou igual a 2 (10 segundos). Para que o fluxo volte para o melhor caminho, o uso da banda
do melhor caminho deve ficar abaixo de 70Mbps por no mínimo o tempo que ficou acima desse
limiar. Vale ressaltar que o valor máximo desse contador é 5 (25 segundos).
O incremento desse contador, assim como outros detalhes menores, não foi indicado no fluxograma.
Em um primeiro momento, optou-se pela captura da quantidade de pacotes descartados pela
interface. Quando o mesmo chegasse a um limiar estabelecido, ocorreria o chaveamento do fluxo
para o segundo melhor caminho. Entretanto mesmo após estressar o link, o contador dos pacotes
descartados não foi incrementado. Acreditando ser uma limitação do Mininet, optou-se então pela
análise da utilização da largura de banda.
A aplicação mostra como o controlador pode agir proativamente com o objetivo de evitar sobrecarga
do link e descartes ou até mesmo para a implementação de políticas de QoS de forma facilitada. Vale
ressaltar, que a escolha da porta UDP 2000 foi feita de forma aleatória e, com facilidade, o código
pode ser generalizado para quaisquer portas ou até mesmo para que altere a rota levando em
consideração quaisquer outros campos de cabeçalho definidos na seção Tabela de Fluxos do tutorial
parte I.
O código completo desenvolvido pode ser analisado na seção Códigos Implementados deste tutorial
parte II.
Para a realização dos testes, foi utilizada uma topologia redundante, conforme define o Código para
a Criação da Topologia apresentado na seção Códigos Implementados deste tutorial parte II.
Como a proposta dessa monografia é apresentar as redes definidas por software, mostrando a
facilidade com que aplicações podem ser desenvolvidas, uma topologia simples foi escolhida para a
realização dos testes.
Nela, foram configurados três hosts e cinco switches. Todos os enlaces foram definidos com as
mesmas características, com o objetivo de facilitar os testes e a análise dos resultados.
34
Figura 10: Topologia utilizada nos testes
Como pode ser visto na figura 12 a aplicação é iniciada com os módulos já citados do POX, discovery
e spanning_tree (seção POX do tutorial parte I), já que por padrão o spanning_tree não é ativado.
Com o Iperf, é possível configurar um host para atuar como servidor, “escutando” em uma
determinada porta e hosts como clientes, que irão enviar tráfegos para o servidor.
Metodologia
Na topologia configurada, o host 3 foi definido como o servidor, e os hosts 1 e 2 como clientes.
Logo, os hosts 1 e 2 gerarão tráfegos para o host 3. Definiu-se que os pacotes enviados pelo host 1
seriam pacotes UDP com a porta de destino 1000. Já o host 2 envia pacotes UDP, usando como porta
de destino a 2000. Além disso, ambas comunicações tentarão utilizar 100% da largura de banda e
ambos os fluxos são gerados por 180 segundos, ao mesmo tempo, como pode ser visto nas figuras
13 e 14.
35
Figura 13: Comandos do Iperf nos clientes
Primeiramente, foram realizados os testes com os dois hosts clientes enviando fluxos por caminhos
diferentes, ou seja, o primeiro host enviando pelo melhor caminho e o segundo host enviando pelo
segundo melhor caminho. O objetivo desse procedimento é conhecer os erros intrínsecos de cada
caminho, para que se tenha uma base de comparação para os próximos procedimentos.
Cada um dos procedimentos foi repetido seis vezes, sendo cada um deles executados após a
inicialização do Mininet e do controlador.
Figura 15: Perda de pacotes com fluxos enviados sempre por caminhos diferentes
36
O fluxo 1, é o fluxo enviado pelo host 1 e o fluxo 2, é o enviado pelo host 2.
Figura 16: Teste com dois hosts enviando por caminhos diferentes
Em seguida, foram realizados os testes com ambos os fluxos sendo enviados pelo melhor caminho.
O objetivo é verificar qual é a porcentagem dos pacotes perdidos, sem utilizar o chaveamento para
o segundo melhor caminho.
O gráfico com o percentual de perda dos pacotes, nos seis testes realizados, é apresentado na figura
17.
Figura 17: Perda de pacotes com ambos os fluxos enviados sempre pelo melhor caminho
Figura 18: Teste com dois hosts enviando pelo mesmo caminho
Por fim, realiza-se o teste com o chaveamento dinâmico ativado. A configuração do caminho
alternativo é efetuada caso a utilização da largura de banda fique acima de 70Mbps. O resultado
pode ser visto na figura 19.
37
Figura 19: Perda dos pacotes realizando a mudança de rota dinamicamente
Os gráficos dos percentuais médios de cada procedimento são apresentados na figura 22.
38
Figura 22: Percentual médio dos erros
Já o gráfico com as taxas médias de transmissão dos fluxos é apresentado na figura 23.
Como pode ser verificado, o uso da aplicação reduziu consideravelmente as perdas de pacotes de
todos os fluxos, chegando a valores próximos ao experimento dos fluxos sempre por caminhos
diferentes. Para os testes em questão, que foram realizados por um período de 180 segundos, a
redução de 1% na perda dos pacotes, equivale a um ganho na recepção de aproximadamente 8000
pacotes!
Considerando que a redução da perda foi de aproximadamente 5%, fica bastante clara a melhoria na
entrega dos pacotes.
39
Redes Definidas por SW II: Códigos Implementados
Topo.__init__( self )
h1 = self.addHost( 'h1' )
h2 = self.addHost( 'h2' )
h3 = self.addHost( 'h3' )
s1 = self.addSwitch( 's1' )
s2 = self.addSwitch( 's2' )
s3 = self.addSwitch( 's3' )
s4 = self.addSwitch( 's4' )
s5 = self.addSwitch( 's5' )
#Adicionando links
40
nos_segundo = nos[:]
for no in nos:
vizinhos[no] = []
for i in topologia:
if (no == i[0]):
vizinhos[no].append([i[2], i[1]])
if (no == i[2]):
vizinhos[no].append([i[0], i[1]])
if (no != no_origem ):
distancias[no] =[-1,-1, 0]
for j in vizinhos[no_origem]:
distancias[j[0]] = j
distancias[j[0]].append(0)
for l in vizinhos_segundo[no_origem]:
distancias_segundo[l[0]] = l
distancias_segundo[l[0]].append(0)
visitado = 0
while visitado == 0:
peso_minimo = -1
no_custo_minimo = None
visitado = 1
for j in distancias:
if (distancias[j][2] == 0):
if (distancias[j][1] != -1):
if ((peso_minimo == -1) or (peso_minimo > distancias[j][1])):
peso_minimo = distancias[j][1]
no_custo_minimo = j
visitado = 0
if visitado == 0:
for vizinho in vizinhos[no_custo_minimo]:
if vizinho[0] != no_origem:
if (distancias[no_custo_minimo][1] + vizinho[1] <= distancias[vizinho[0]][1]) or
(distancias[vizinho[0]][1] == -1):
distancias[vizinho[0]][0] = distancias[no_custo_minimo][0]
distancias[vizinho[0]][1] = distancias[no_custo_minimo][1] + vizinho[1]
distancias[no_custo_minimo][2] = 1
visitado_segundo = 0
41
while visitado_segundo == 0:
peso_minimo_segundo = -1
no_custo_minimo_segundo = None
visitado_segundo = 1
for j in distancias_segundo:
if (distancias_segundo[j][2] == 0):
if (distancias_segundo[j][1] != -1):
if ((peso_minimo_segundo == -1) or (peso_minimo_segundo >
distancias_segundo[j][1])):
peso_minimo_segundo = distancias_segundo[j][1]
no_custo_minimo_segundo = j
visitado_segundo = 0
if visitado_segundo == 0:
for vizinho in vizinhos_segundo[no_custo_minimo_segundo]:
if vizinho[0] != no_origem:
soma_distancias = distancias_segundo[no_custo_minimo_segundo][1] + vizinho[1]
if ((soma_distancias < distancias_segundo[vizinho[0]][1]) or
(distancias_segundo[vizinho[0]][1] == -1)):
if ((soma_distancias > distancias[vizinho[0]][1] or
distancias_segundo[no_custo_minimo_segundo][0] !=
distancias[no_custo_minimo_segundo][0])):
distancias_segundo[vizinho[0]][0] =
distancias_segundo[no_custo_minimo_segundo][0]
distancias_segundo[vizinho[0]][1] = soma_distancias
else:
distancias_segundo[vizinho[0]][0] = no_custo_minimo_segundo
distancias_segundo[vizinho[0]][1] =
distancias_segundo[no_custo_minimo_segundo][1] + vizinho[1]
distancias_segundo[no_custo_minimo_segundo][2] = 1
#For necessario devido ao problema quando um no so tinha um unico vizinho e nao era visitado
para calcular o segundo melhor caminhos.
#Try necessario pois como o Djakstra e chamado antes de toda a topologia estar criada, ele dava
exception. Caso o codigo seja chamado apenas apos a criacao de toda a topologia, a excecao nao
aparecera mais.
try:
for chaves in vizinhos_segundo.keys():
if vizinhos_segundo[chaves][0] != no_origem:
if len(vizinhos_segundo[chaves]) == 1 and distancias_segundo[chaves][0] == -1:
42
distancias_segundo[chaves][1] =
distancias_segundo[vizinhos_segundo[chaves][0][0]][1] +
vizinhos_segundo[chaves][0][1]
distancias_segundo[chaves][0] =
distancias_segundo[vizinhos_segundo[chaves][0][0]][0]
distancias_segundo[chaves][2] = 1
except Exception:
pass
return distancias, distancias_segundo
Lista_nos = list(Conj_nos)
Num_nos = len (Lista_nos)
return Num_nos, Lista_nos
Código da Aplicação
log=core.getLogger()
class switch_multi(object):
mac_map={}
delay_links={}
def __init__(self):
def startup():
core.openflow.addListeners(self, priority=0)
core.openflow_discovery.addListeners(self)
self.connections = set()
core.call_when_ready(startup,('openflow','openflow_discovery'))
43
#Dicionario chave - IP; valores - MAC origem e porta do switch
self.mac_map = {}
self.topologia = []
self.delay_links = {}
self.portas = {}
self.dij_1_melhor = []
self.dij_2_melhor = []
self.dij_1_segundo = []
self.dij_2_segundo = []
#Contador que sera utilizado para executar o Djakstra. Sem o mesmo, o algoritmo de Djakstra
e executado, sem os links terem sido descobertos.
self.count = 0
self.link_count = 0
self.tx_1 = 0
self.tx_2 = 0
self.diferenca = 0
self.LINK_OK = True
self.JA_ENTROU = False
def _handle_LinkEvent(self,event):
chave_1 = str(event.link.dpid1)+str(event.link.dpid2)
chave_2 = str(event.link.dpid2)+str(event.link.dpid1)
delay_1 = self.delay_links.get(chave_1)
delay_2 = self.delay_links.get(chave_2)
if (delay_1 == None and delay_2 == None):
delay = None
chave = chave_1
elif delay_1 != None:
delay = delay_1
chave = chave_1
else:
delay = delay_2
chave = chave_2
if event.added == True:
#Dicionario das conexoes. Retorna o numero da porta de cada conexao
if not chave_1 in self.portas.keys():
self.portas.update({chave_1:event.link.port1})
self.portas.update({chave_2:event.link.port2})
if not (([event.link.dpid1,delay,event.link.dpid2] in self.topologia) or
([event.link.dpid2,delay,event.link.dpid1] in self.topologia)):
if delay == None:
self.delay_links.update({chave:randrange(5,80,5)})
self.topologia.append([event.link.dpid1,self.delay_links.get(chave),event.link.dpid2])
if event.removed == True:
if chave_1 in self.portas.keys():
self.portas.remove({chave_1:event.link.port1})
self.portas.remove({chave_2:event.link.port2})
if ([event.link.dpid1,delay,event.link.dpid2] in self.topologia):
self.topologia.remove([event.link.dpid1,delay,event.link.dpid2])
44
if ([event.link.dpid2,delay,event.link.dpid1] in self.topologia):
self.topologia.remove([event.link.dpid2,delay,event.link.dpid1])
self.count = self.count + 1
for i in event.stats:
print "CHAVE -------", chave
if i.port_no == self.portas.get(chave):
self.tx_1 = i.tx_bytes
if (self.tx_2 != 0):
self.diferenca = ((self.tx_1 - self.tx_2)*8)/5
self.tx_2 = i.tx_bytes
stats = flow_stats_to_list(event.stats)
def _timer_func(self):
print "-------- Entrou timer_func -------- "
core.openflow.getConnection(1).send(of.ofp_stats_request(body=of.ofp_flow_stats_reques
t()))
core.openflow.getConnection(1).send(of.ofp_stats_request(body=of.ofp_port_stats_request
()))
def link_test(self):
#A cada 5 segundos havera verificacao do link. O self.LINK_OK comeca como True. Se a
diferenca apos 10 segundos ficar acima de 70000000
if (self.diferenca > 0 and self.diferenca < 70000000):
if self.link_count > 0:
self.link_count = self.link_count -1
else:
self.LINK_OK = True
45
else:
if self.link_count < 5:
self.link_count = self.link_count + 1
if self.link_count >= 2:
self.LINK_OK = False
if self.JA_ENTROU == False:
msg = of.ofp_flow_mod()
msg.match.dl_type = 0x800
msg.match.nw_proto = 17
msg.match.nw_dst = IPAddr("10.0.0.3")
msg.match.tp_dst = 2000
msg.idle_timeout = 10
msg.hard_timeout = 60
prox_salto2 = self.dij_1_segundo[5][0]
chave2 = str(1)+str(prox_salto2)
porta_saida2 = self.portas.get(chave2)
msg.actions.append(of.ofp_action_output(port = porta_saida2))
core.openflow.getConnection(1).send(msg)
def _handle_PacketIn(self,event):
packet = event.parsed
if packet.type == packet.ARP_TYPE:
IP_ORIGEM = str(packet.payload.protosrc)
IP_DESTINO = str(packet.payload.protodst)
else:
IP_ORIGEM = str(packet.payload.srcip)
IP_DESTINO = str(packet.payload.dstip)
PORTA_ORIGEM = None
PORTA_DESTINO = None
if IP_DESTINO == "10.0.0.3":
#COMO EM PYTHON NAO EXISTE SWITCH CASE:
if event.dpid == 1:
prox_salto = self.dij_1_melhor[5][0]
chave = str(1)+str(prox_salto)
porta_saida = self.portas.get(chave)
elif event.dpid == 2:
prox_salto = self.dij_2_melhor[5][0]
chave = str(2)+str(prox_salto)
porta_saida = self.portas.get(chave)
elif event.dpid == 3:
prox_salto = self.dij_3_melhor[5][0]
chave = str(3)+str(prox_salto)
46
porta_saida = self.portas.get(chave)
elif event.dpid == 4:
prox_salto = self.dij_4_melhor[5][0]
chave = str(4)+str(prox_salto)
porta_saida = self.portas.get(chave)
#ARP
if packet.type == packet.ARP_TYPE:
msg = of.ofp_packet_out()
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 5:
msg.actions.append(of.ofp_action_output(port = 1))
else:
msg.actions.append(of.ofp_action_output(port = porta_saida))
event.connection.send(msg)
else:
if self.LINK_OK:
msg = of.ofp_flow_mod()
msg.match.dl_type = 0x800
msg.match.nw_proto = 17
msg.match.nw_dst = IPAddr("10.0.0.3")
msg.match.tp_dst = PORTA_DESTINO
msg.idle_timeout = 10
msg.hard_timeout = 60
msg.data = event.ofp
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 5:
msg.actions.append(of.ofp_action_output(port = 1))
else:
msg.actions.append(of.ofp_action_output(port = porta_saida))
event.connection.send(msg)
else:
msg = of.ofp_flow_mod()
msg.match.dl_type = 0x800
msg.match.nw_proto = 17
msg.match.nw_dst = IPAddr("10.0.0.3")
msg.match.tp_dst = PORTA_DESTINO
msg.idle_timeout = 10
msg.hard_timeout = 60
msg.data = event.ofp
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 5:
msg.actions.append(of.ofp_action_output(port = 1))
else:
if PORTA_DESTINO != 2000:
msg.actions.append(of.ofp_action_output(port = porta_saida))
else:
if event.dpid == 1:
prox_salto2 = self.dij_1_segundo[5][0]
chave2 = str(1)+str(prox_salto2)
porta_saida2 = self.portas.get(chave2)
47
elif event.dpid == 2:
chave2 = str(2)+str(5)
porta_saida2 = self.portas.get(chave2)
elif event.dpid == 3:
chave2 = str(3)+str(5)
porta_saida2 = self.portas.get(chave2)
elif event.dpid == 4:
chave2 = str(4)+str(5)
porta_saida2 = self.portas.get(chave2)
msg.actions.append(of.ofp_action_output(port = porta_saida2))
event.connection.send(msg)
#ARP
if packet.type == packet.ARP_TYPE:
msg = of.ofp_packet_out()
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 1:
msg.actions.append(of.ofp_action_output(port = porta))
else:
msg.actions.append(of.ofp_action_output(port = porta_saida))
event.connection.send(msg)
else:
if self.LINK_OK:
msg = of.ofp_flow_mod()
msg.match.dl_type = 0x800
msg.match.nw_dst = IPAddr(IP_DESTINO)
msg.idle_timeout = 10
msg.hard_timeout = 30
48
msg.data = event.ofp
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 1:
msg.actions.append(of.ofp_action_output(port = porta))
else:
msg.actions.append(of.ofp_action_output(port = porta_saida))
event.connection.send(msg)
else:
msg = of.ofp_flow_mod()
msg.match.dl_type = 0x800
msg.match.nw_dst = IPAddr(IP_DESTINO)
msg.match.nw_proto = 17
msg.match.tp_src = PORTA_ORIGEM
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.data = event.ofp
msg.buffer_id = event.ofp.buffer_id
if event.dpid == 1:
msg.actions.append(of.ofp_action_output(port = porta))
else:
if (PORTA_ORIGEM != 2000):
msg.actions.append(of.ofp_action_output(port = porta_saida))
else:
if event.dpid == 2:
chave2 = str(2)+str(1)
porta_saida2 = self.portas.get(chave2)
elif event.dpid == 3:
chave2 = str(3)+str(1)
porta_saida2 = self.portas.get(chave2)
elif event.dpid == 4:
chave2 = str(4)+str(1)
porta_saida2 = self.portas.get(chave2)
elif event.dpid == 5:
prox_salto2 = self.dij_5_segundo[1][0]
chave2 = str(5)+str(prox_salto2)
porta_saida2 = self.portas.get(chave2)
msg.actions.append(of.ofp_action_output(port = porta_saida2))
event.connection.send(msg)
def launch():
core.registerNew(switch_multi)
49
Redes Definidas por SW II: Considerações finais
Esse trabalho teve como objetivo introduzir um paradigma diferente da atual implementação de
redes de computadores, modelo esse que pode vir a ser o predominante em poucos anos.
Buscando ajudar na compreensão das redes definidas por software, na seção Conceitos de Redes de
Computadores os conceitos básicos dessas redes de computadores foram explanados. Conceitos
como modelo em camadas, encaminhamento, roteamento e classificação de pacotes, serviram como
uma base para os conceitos seguintes.
A seção Conceitos Fundamentais de SDN apresentou as redes definidas por software, modelo que
propõe a separação dos planos de controle e dados, planos esses encontrados nos dispositivos de
redes como switches e roteadores. Com sua separação, é possível ter um controle total da rede. Já
não são mais necessários hardwares específicos, mas hardwares genéricos podem ser utilizados e,
através do controlador, podem ser programados.
A seção OpenFlow apresentou a implementação mais difundida das redes definidas por software.
Um enfoque maior é dado a versão 1.0.0, a versão mais utilizada do OpenFlow. Entretanto, as
diferenças entre as versões mais novas como as versões 1.1, 1.2, 1.3 e 1.4 são citadas. Nesta seção é
apresentado também o POX, controlador implementado em Python e que foi utilizado nesse
trabalho.
A seção Mininet apresenta esse emulador de redes desenvolvido na universidade de Stanford, cuja
principal vantagem é o fato de empregar uma forma mais leve de virtualização, onde muitos recursos
do sistema são compartilhados.
Nas seções seguintes, a aplicação foi finalmente descrita e seus resultados mostrados.
Como foi visto, uma topologia simples com cinco switches e três hosts foi utilizada. Fluxos são
gerados por dois hosts clientes para o servidor e de acordo com a utilização da largura de banda, o
caminho de um desses fluxos pode ser alterado.
Como visto, foram realizados três procedimentos. No primeiro, foram realizadas uma série de testes
com o objetivo de descobrir a perda intrínseca dos caminhos. Ao fazer isso, encontra-se uma base,
com a qual poderão ser comparados os resultados dos próximos procedimentos.
No segundo procedimento, testes são realizados com os dois fluxos sendo enviados pelo mesmo
caminho. O objetivo é verificar a quantidade de pacotes que estão sendo perdidos devido à utilização
do mesmo link.
No final da seção, um gráfico comparativo dos três procedimentos é apresentado. Nele, percebe-se
que a utilização do algoritmo que realiza a troca de rotas dinamicamente reduziu em torne de 5% a
perda de pacotes.
Logo, a prova de conceito foi realizada com sucesso. Os resultados ficaram dentro do esperado e da
proposta inicial. Ainda, o código da aplicação futuramente pode ser modificado, buscando deixá-lo
mais genérico ou adequando-o a outra situação específica.
50