Universidade Federal do Rio de Janeiro Bacharelado em Ciência da Computação Teleprocessamento e Redes Prof.: Silvana Implementação das funções da camada de enlace __________________________________________________________________________ Grupo: Diego Felix DRE: 104019581 Marco Reina DRE: 105091358 Pedro Henrique DRE: 105035988 1. Introdução Este trabalho consiste em implementar as funções da camada de enlace da arquitetura de rede utilizando a API de sockets. Essas funções serão utilizadas pela camada de rede para receber e enviar quadros de dados. Este simulador não vai implementar as funcionalidades de entrega confiável e controle de fluxo da camada de enlace. 2. Visão geral da camada de enlace A camada de enlace possui as seguintes características: • Trata o envio, seja por canal broadcast ou por canal ponto-a-ponto, de pacotes(chamados quadros) entre enlaces individuais. • • Define as ações tomadas pelos terminais ao enviar ou receber quadros. Controla o acesso ao meio, especificando regras para transmissão de quadros em enlaces broadcast. • • • Provê empacotamento do datagrama de rede antes da transmissão. Detecção de erros. Transmissão full-duplex. 3. Projeto da camada de enlace • Descrição das estruturas de dados: ◦ T_D_QUADRO: Tamanho do espaço reservado para os dados em um quadro; ◦ T_H_QUADRO: Tamanho do espaço reservado para o cabeçalho de um quadro; ◦ MAX_HOSTS: Número máximo de hosts que podem ser plugados no comutador; ◦ ◦ unsigned char macLocal: Endereço MAC da máquina local. Enlace en: Estrutura de dados da camada de enlace, possui os buffers de envio e recebimento do comutador de enlace, flags para determinar quadros prontos para envio e recebimento, e a Tabela do comutador; ▪ TabelaComutador tc[MAX_HOSTS]: Tabela do comutador de enlace, em cada linha possui o mac do host, seu endereco para conexao e um flag de preenchimento. Se o flag estiver com 0, o host se "plugou" ao comutador, mas ele ainda não possui entrada em sua tabela de controle, se estiver com 1, a tabela do comutador possui uma entrada com o MAC desse host. ◦ int portaComutador: Porta utilizada para a comunicação com o comutador; ◦ struct sockaddr_in addrComut: Estrutura para conexão com o comutador; ◦ • double taxaPerda: Taxa de perda de quadros; Descrição das funções oferecidas: ◦ int L_Activate_Request(unsigned char, int, char *, int): Efetua as inicializações do nível de enlace, recebe como parâmetros o MAC local, porta do comutador e ip do comutador. O último parâmetro indica se é a inicialização de um host ou de um comutador; ◦ void L_Data_Request(unsigned char, char, int): solicita a transmissão de um quadro, recebe como parâmetro o MAC de destino e os dados que vao ser enviados. ◦ int L_Data_Indication(): Testa se há um quadro recebido no nível de enlace; ◦ int L_Data_Receive(unsigned char, char, int): Busca no nível de enlace os dados do último quadro recebido, recebe o MAC do host que enviou o quadro e os seus dados; ◦ void L_MainLoop(): Executa um ciclo básico de execução da camada de enlace, para tratar envio e recebimento de bytes e a manipulação da tabela do comutador; ◦ void L_Set_Loss_Probability(double): Configura a taxa de perda de quadros da camada de enlace, recebe a probabilidade da perda de um quadro; ◦ void L_Deactivate_Request(): Finaliza o funcionamento dos níveis de enlace e físico, no caso do host, ele envia um sinal ao comutador para se "desplugar" dele. No caso do comutador, ele envia um sinal para todos os hosts serem desligados dele; ◦ void l_Recebe_Byte(): Recebe um byte e armazena no buffer da camada de enlace, quando o último byte de um quadro é recebido ele é validado. ◦ void l_Valida_Quadro(): Valida o quadro recebido, verificando se ele foi destinado ao seu MAC ou broadcast, e faz a checagem de erro do quadro; ◦ void l_Transmite_Byte(): Transmite um byte do quadro e checa se terminou a transmissão do quadro.; 4. Implementaçao (emulação) da camada de enlace • Estratégias de implementação adotadas: ◦ Criar um estrutura com todos os dados do comutador da camada de enlace (buffers, flags, tabela, etc.). ◦ Criar apenas uma Tabela para o comutador, onde um flag sinaliza se o MAC do host esta na tabela logica ou nao. ◦ Utilizar a estrutura sockaddr_in para fazer a comunicação com os hosts, estrutura esta que é retornada pela função rcvfrom, e é inserida na tabela do comutador, para este fazer a comunicação com seus hosts. ◦ Reservar endereços MAC especiais para fazer envios de quadro de controle (MAC 1 simboliza o comutador, 2 pedido de conexão, 3 pedido de desconexão/desligamento, etc). ◦ Utilizar um array de tamanho fixo de unsigned chars para representar um quadro, onde os caracteres representados por 0 simbolizam inicio e fim de um quadro. ◦ Utilização dos controles da biblioteca <termios.h> para poder realizar a leitura de dados do teclado de forma não-bloqueante. • Estrutura do programa de teste e resultados obtidos: ◦ O programa de teste pode ser inicializado tanto como um host a se conectar ou um comutador, o primeiro passo do programa é perguntar se vai ser inicializado um host ou um comutador. ◦ Se o programa for um comutador, ele pergunta qual porta será utilizada para a comunicação, inicializa o nivel de enlace e executa o loop de execução do comutador (transmissão de quadros e manipulação da tabela). ◦ Se o programa for um host, ele pergunta o ip do comutador q ele quer se comunicar, porta para comunicação e o MAC do host. Então ele vai poder enviar e receber quadros para hosts conectados a este comutador. ◦ Para cada mudança na tabela do comutador, ele imprime na saída a sua situação atual. ◦ O comutador ou o host imprimem na tela uma mensagem de erro quando a validação do quadro recebido falhar. ◦ O host ao receber um quadro efetivamente, imprime o MAC que enviou o quadro e o seu conteúdo. 5. Dificuldades encontradas O nosso grupo teve muitas dificuldades, muito mais do que tivemos na implementação da camada física. Isso porque além das dificuldades que seriam inerentes à camada de enlace, tivemos que fazer ajustes na camada física ou até mesmo implementar funcionalidades que deixaram a desejar na 1ª etapa do trabalho, desta forma tendo que voltar e repensar um pouco do código que teoricamente não deveria ter sido tocado. Tivemos como primeira dificuldade, já citada acima, o fato de ter que modificar a camada física para atender as necessidades da camada de enlace. Na época que a implementamos ainda não tínhamos noção suficiente de como a camada de enlace funcionava e portanto, de que serviços ela necessitaria. Uma outra dificuldade que herdamos da primeira etapa foi como fazer a leitura do teclado de forma não bloqueante. Na implementação do teste da camada física acabamos por não encontrar uma solução e optamos por testar um host sendo servidor e o outro sendo cliente, já que o teste envolvia apenas duas máquinas. Só para recordar, o problema é que com a função select conseguíamos resolver o problema do rcvfrom(), mas na hora de obter do terminal os bytes a serem enviados, com a função scanf(), por exemplo, acabava sendo bloqueante pois não saia da leitura enquanto não fosse pressionado o ENTER. Porém na camada de enlace, por ter que simular transmissão full-duplex não caberia uma implementação clitente- servidor. Então de certa forma tivemos que retirar a "sujeira debaixo do tapete" e limpar de vez. A solução encontrada foi chamar a biblioteca <termios.h> que permite mudar a forma como se ler do terminal, passando a detectar cada caracter teclado, ao invés de apenas a string após o ENTER. Assim, pudemos usar o select para monitorar o teclado. A implementação da lógica da tabela que o comutador mantém também foi uma dificuldade. Afinal afim de simulá-la, na verdade precisamos manter duas tabelas de forma que as informações de ambas fossem consistentes entre si. Ao se desconectar, por exemplo, a informação do host deve ser retirada e tem que haver toda uma reordenação da tabela. E uma das principais dificuldades foi como testar o que estavamos codificando. Afinal o produto final teria que rodar em três máquinas distintas, no mínimo. Na maior parte do tempo, por falta de disponibilidade de tempo não pudemos testar juntos, os três integrantes do grupo, o que nos levou a modificar um pouco o programa para que simulasse diversos hosts numa só maquina, o que torna as coisas um pouco mais confusa na nossa opinião. 6. Conclusões Achamos essa simulação mais interessante do que a da camada física por já ter mais lógica envolvida nessa camada. Mais uma vez percebemos como a divisão da arquitetura de rede em camadas e suas abstrações facilitam a vida de todos. Apesar de termos tido um pouco de dificuldade em fazer algumas modificações na camada física, ficou óbvio que deu muito menos trabalho do que se tivéssemos que fazer tudo do zero, num bloco só. Até mesmo a divisão da lógica do programa fica bem mais clara, quando se tem a divisão em camadas. E pudemos notar agora de fato, uma camada provendo serviços à outra. 7. Referências bibliográficas • • • • Slides do curso. http://beej.us/guide/bgnet/output/html/multipage/advanced.html http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input Redes de computadores, Andrew S. Tanembaum.