UNIVERSIDADE DO VALE DO RIO DOS SINOS – UNISINOS CENTRO DE CIÊNCIAS EXATAS E TECNOLÓGICAS Especialização em Redes de Computadores e Internet TRANSMISSION CONTROL PROTOCOL MARINA SIMON BECKER Orientador: Dr. Marinho Barcellos São Leopoldo, março de 2001. Dedico este trabalho ao meu orientador, pelo incentivo e atenção. SUMÁRIO INDICE DE FIGURAS 5 RESUMO 6 ABSTRACT 7 1 INTRODUÇÃO 8 2 TRANSMISSION CONTROL PROTOCOL 9 2.1 2.2 2.3 FUNCIONAMENTO CONFIABILIDADE CONTROLES 10 12 13 3 CONTROLE DE SESSÃO 15 3.1 3.2 3.3 3.4 15 17 18 18 ESTABELECENDO UMA CONEXÃO MANTENDO UMA CONEXÃO RESETANDO UMA CONEXÃO ENCERRANDO UMA CONEXÃO 4 CONTROLE DE ERRO 21 4.1 4.2 4.3 21 22 23 TIPOS DE ERRO DETECÇÃO DE ERRO RECUPERAÇÃO DE ERRO 5 CONTROLE DE FLUXO 25 5.1 5.2 5.3 5.4 25 26 27 28 JANELA DESLIZANTE SWS - SILLY WINDOW SYNDROME PREVENÇÃO DA SWS NO RECEPTOR PREVENÇÃO DA SWS NO TRANSMISSOR 6 CONTROLE DE CONGESTIONAMENTO 29 6.1 6.2 29 30 SLOW START CONGESTION AVOIDANCE 7 MECANISMOS AVANÇADOS 32 7.1 7.2 7.3 7.4 32 32 33 33 FAST RETRANSMIT FAST RECOVERY SELECTIVE ACKNOWLEDGEMENT FORWARD ACKNOWLEDGEMENT 8 PROBLEMAS COM IMPLEMENTAÇÕES DO TCP 34 8.1 8.2 8.3 8.4 34 35 36 37 CONTROLE DE CONGESTIONAMENTO PERFORMANCE CONFIABILIDADE GERENCIAMENTO DE RECURSOS 9 CONCLUSÃO 39 REFERÊNCIAS 40 4 INDICE DE FIGURAS Figura 2.1: Formato do segmento TCP ________________________________________________________ 10 Figura 2.2: Confirmação positiva ____________________________________________________________ 12 Figura 2.3: Confirmações com o uso da janela deslizante _________________________________________ 13 Figura 3.1: Three Way Handshake ___________________________________________________________ 15 Figura 3.2: Segmento solicitando uma conexão _________________________________________________ 16 Figura 3.3: Segmento aceitando uma conexão __________________________________________________ 16 Figura 3.4: Segmento finalizando o estabelecimento de uma conexão ________________________________ 17 Figura 3.5: Encerramento de uma conexão_____________________________________________________ 18 Figura 3.6: Segmento solicitando encerramento da conexão _______________________________________ 19 Figura 3.7: Segmento de confirmação _________________________________________________________ 19 Figura 3.8: Segmento aceitando o encerramento da conexão_______________________________________ 20 Figura 3.9: Segmento confirmando o encerramento da conexão ____________________________________ 20 Figura 4.1: ACKs duplicados _______________________________________________________________ 23 Figura 5.1: Janela deslizante com nenhum segmento confirmado ___________________________________ 26 Figura 5.2: Janela deslizante com um segmento confirmado _______________________________________ 26 RESUMO Este trabalho tem o objetivo de fazer uma revisão do TCP - Transmission Control Protocol, que é, hoje, um dos protocolos mais importantes e mais utilizados para a transmissão de dados em ambientes de rede heterogêneos como a Internet. A proposta é mostrar o funcionamento do protocolo e os tipos de controle que este possui para garantir a entrega confiável dos dados ao seu destino, assim como problemas encontrados em algumas implementações. Embora este trabalho não apresente propostas para melhorias no TCP, ele resume informações relevantes sobre esse protocolo, fruto de uma revisão bibliográfica profunda e abrangente. Sua contribuição é dissertar sobre o TCP de forma inédita, adotando uma estrutura centrada nos mecanismos de controle do protocolo, e após tratando de problemas verificados em implementações desses mecanismos. ABSTRACT This work revisits TCP - Transmission Control Protocol, the most widely used protocol in the Internet. TCP is used for reliable data transmission, dealing properly with heterogeneous environments. Although this work does not propose improvements to TCP, it shows relevant information about the protocol, with a comprehensive bibliographic review. Its contribution is to discusses TCP in a new way: centering the focus on TCP protocol control mechanisms, and then addressing the problems found on some TCP implementations. 2 TRANSMISSION CONTROL PROTOCOL Na pilha de protocolos TCP/IP existem dois protocolos de transporte, o UDP e o TCP. O TCP é um protocolo de transporte de stream de dados, orientado à conexão, e que fornece a garantia de um serviço de entrega confiável. Faz parte da pilha TCP/IP e, assim como o UDP, é encapsulado dentro do pacote IP. O TCP é um protocolo complexo, pois foi desenvolvido para oferecer confiabilidade trabalhando com diversos ambientes de rede, nas mais diferentes plataformas e com os mais variados aplicativos. Para o TCP, um stream de dados é uma seqüência de bits dividida em octetos (oito bits). A aplicação fornece ao protocolo de transporte os dados em forma de stream, e o protocolo é livre para segmentar o stream da forma que for melhor para a transmissão. Podese dizer então que o TCP transporta segmentos de stream de dados. Os segmentos que o TCP transporta possuem o tamanho variável e o tamanho máximo do segmento é definido no momento em que a conexão é estabelecida. Por ser um protocolo orientado à conexão, antes de iniciar a transferência de dados, ele precisa estabelecer uma conexão com o host destino, para que os dois possam fazer uma série de ajustes, como sincronização, cálculo de tempo, tamanho máximo do segmento, entre outros. Assim como o UDP, o TCP suporta o conceito de portas de comunicação. O TCP identifica cada conexão por end-points. Cada end-point é visto como (host, porta), onde host é o número IP do host de destino e porta é o número da porta TCP deste host ([12]). Cada porta de comunicação corresponde a uma fila de mensagens, a um buffer individual. Isto permite que um host mantenha múltiplas conexões, utilizando uma porta para cada conexão. Existem algumas RFCs que definem portas específicas para serviços conhecidos, como TELNET, FTP, HTTP, POP, SMTP, entre outros. O número da porta TCP normalmente é o mesmo da porta UDP correspondente. As conexões que o TCP estabelece são full duplex, ou seja, a transferência dos dados pode ocorrer em ambos os sentidos, possibilitando que os dois hosts conversem durante a transmissão. Se um dos hosts encerrar a conexão, esta torna-se half duplex, com o fluxo Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol trafegando em apenas um sentido. A vantagem da conexão full duplex em relação a half duplex, é o piggyback, isto é, o protocolo receptor pode retornar informações de controle para o transmissor, reduzindo o tráfego na rede. Para garantir um serviço de entrega confiável, o TCP requer mais CPU e mais largura de banda que outros protocolos de transporte. 2.1 Funcionamento Um segmento TCP é formado por duas partes: a primeira parte é o cabeçalho, onde são enviadas as informações de controle necessárias, e a outra parte é composta dos dados a serem transportados. O cabeçalho do TCP possui um tamanho fixo de 20 bytes e mais um campo opcional de tamanho variável. O tamanho do cabeçalho é medido por múltiplos de 32 bits. O formato do segmento do TCP, que será visto a seguir, é definido na RFC 793 ([1]). A Figura 2.1 mostra o formato do segmento TCP. 32 bits Source Port Destination Port Sequence Number Acknowledgement Number Data Offset U R G Reserved A C K P S H R S T S Y N F I N Checksum Window Urgent Pointer Options Padding Data Figura 2.1: Formato do segmento TCP Source Port (16bits) e Destination Port (16bits): estes campos indicam o número da porta de origem e o número da porta de destino que serão usadas para estabelecerem a conexão. O TCP já tem definido portas padrão para diversos tipos de serviço. Sequence Number (32bits): campo que indica o número de seqüência dos pacotes que permite a remontagem dos dados no destino. O número de seqüência inicial é definido no momento em que a conexão estiver sendo estabelecida. Marina Simon Becker 10 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Acknowledgement Number (32bits): número de reconhecimento, que significa o próximo byte aguardado pelo destino. Informa que até o byte anterior foi tudo recebido corretamente. Data Offset (4bits): chamado também, por alguns autores*, de Header Length (comprimento do cabeçalho). Indica onde os dados iniciam. Contém um número inteiro medido em múltiplos de 32 bits. Devem ser incluídos zeros no final do cabeçalho até que ele se torne um múltiplo de 32 bits. Reserved (6bits): campo reservado para futura utilização. Control Bits (6bits): seis bits de controle, que servem para determinar a finalidade e o conteúdo do segmento. Indicam como interpretar outros campos do cabeçalho. São eles: URG = indica que o campo Urgent Pointer é válido. ACK = indica que o campo Acknowledgement Number é válido. PSH = indica que o receptor deve entregar os dados para a aplicação imediatamente, sem esperar encher o buffer. RST = serve para reiniciar ou rejeitar uma conexão. SYN = utilizado para solicitar uma conexão. FIN = utilizado para encerrar uma conexão. Window (16bits): tamanho da janela oferecido pelo host. Indica quantos bytes podem ser enviados a partir do byte confirmado (Acknowledgement Number). Checksum (16bits): campo que faz a checagem da integridade dos dados e do cabeçalho. A soma de todos os bytes mais o Checksum deve ser igual a zero. Urgent Pointer (16bits): campo que indica a posição no segmento onde os dados urgentes terminam. Options: campo opcional e variável. Uma de suas funções é comunicar o tamanho máximo dos segmentos (MSS, Maximum Segment Size) que pode ser recebido pelo host. A opção MSS contém 16bits. Padding: campo variável, composto de zeros, usado para especificar o final do cabeçalho e o início dos dados. Data: esta é a segunda parte do segmento. Logo após o final do cabeçalho, iniciam os dados que serão transportados. * Em [12], apesar de referenciar a RFC 793, refere-se a este campo como HLEN, que é uma abreviatura de Header Length. Marina Simon Becker 11 Universidade do Vale do Rio dos Sinos – Unisinos 2.2 Transmission Control Protocol Confiabilidade A maioria dos protocolos que oferece serviço confiável de entrega de dados utiliza uma técnica chamada confirmação positiva (positive acknowledgement), ou seja, para cada segmento transmitido o receptor envia um segmento com a flag ACK ativa no campo Control Bits, que significa a confirmação do recebimento do segmento. É através destas confirmações que o TCP consegue fornecer confiabilidade de entrega, pois só assim ele tem como saber se o segmento chegou ao seu destino ou não. Um exemplo do funcionamento de confirmação positiva está ilustrado na Figura 2.2. Envia segmento 1 Recebe segmento 1 Envia o ACK 2 Recebe o ACK 2 Envia segmento 2 Recebe segmento 2 Envia o ACK 3 Recebe o ACK 3 Envia segmento 3 Recebe segmento 3 Envia o ACK 4 Recebe o ACK 4 Envia segmento 4 Recebe segmento 4 Envia o ACK 5 Recebe o ACK 5 Figura 2.2: Confirmação positiva Segundo o exemplo da Figura 2.2, somente após a chegada da confirmação do segmento anterior é que o transmissor pode enviar um novo segmento. Na verdade, este mecanismo gasta uma considerável largura de banda, pois ele espera a chegada da confirmação do segmento anterior para poder transmitir um novo segmento. Isto diminui o throughput na rede, que implica em um mau aproveitamento da banda, pois deixa a rede ociosa enquanto fica à espera da confirmação. Existe um mecanismo que faz com que o processo de recebimento de confirmações seja mais eficaz. Este mecanismo é conhecido como janela deslizante (sliding window), que será abordado no Capítulo 5. A janela deslizante permite que o transmissor envie múltiplos segmentos sem necessitar uma confirmação imediata. Por exemplo, se o tamanho da janela * estiver estipulado para 4 segmentos, o transmissor pode enviar até 4 segmentos e, conforme chegarem as confirmações, novos segmentos poderão ser enviados. Isto aumenta o throughput * O tamanho da janela é estipulado pelo receptor em cada segmento de confirmação. Marina Simon Becker 12 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol na rede fazendo com que a banda seja melhor aproveitada. A Figura 2.3 ilustra as confirmações com o uso da janela deslizante. Envia segmento 1 Envia segmento 2 Envia segmento 3 Envia segmento 4 Recebe o ACK 2 Recebe o ACK 3 Recebe segmento 1 Envia o ACK 2 Recebe segmento 2 Envia o ACK 3 Recebe segmento 3 Envia o ACK 4 Recebe segmento 4 Envia o ACK 5 Recebe o ACK 4 Recebe o ACK 5 Figura 2.3: Confirmações com o uso da janela deslizante 2.3 Controles Como foi visto anteriormente, o TCP garante um serviço de entrega confiável utilizando técnicas de confirmação da chegada dos segmentos ao seu destino. Mas somente isto não é suficiente para que ele possa garantir, além da confiabilidade, um bom funcionamento, uma boa performance e uma boa utilização da rede. Para isto, ele necessita fazer uma série de controles, tais como: controle de erro, controle de fluxo, controle de congestionamento e controle de sessão. O controle de erro faz com que o TCP certifique-se que os dados estão chegando corretamente no destino. Existem vários tipos de erro que podem ocorrer com os segmentos enviados durante uma transmissão, por isto o TCP deve detectar a ocorrência de um erro e tentar recuperar os segmentos que foram vítimas do erro, garantindo assim, a chegada correta dos dados no receptor. O controle de erro será tratado no Capítulo 4. O TCP deve preocupar-se também com o fluxo dos dados durante a transmissão para garantir melhor performance. O fluxo dos dados diz respeito à velocidade e a quantidade de dados que estão sendo enviados. Por exemplo, o transmissor deve saber qual é a capacidade de armazenamento e de processamento do receptor, pois se a capacidade do receptor for muito pequena, ele não dará conta de tratar muitos dados rapidamente, fazendo que o seu buffer se esgote e ocasionando o descarte de segmentos. Sendo assim, o transmissor deve diminuir o Marina Simon Becker 13 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol fluxo de envio para que o receptor possa trata-los de acordo com a sua capacidade. O controle de fluxo será mostrado no Capítulo 5. O outro tipo de controle é o controle de congestionamento, que diz respeito à rede, como o estado dos roteadores que estão ao longo do caminho, entre o transmissor e o receptor. O TCP deve preocupar-se em evitar o congestionamento da rede, pois uma rede congestionada ocasiona não só o atraso, como a perda de pacotes, ou em casos mais extremos é causado o colapso de congestionamento, que pode fazer a rede parar. O controle de congestionamento será discutido no Capítulo 6. O controle de sessão cuida do estado das conexões, controlando desde o estabelecimento até o encerramento de uma conexão. O controle de sessão será abordado no próximo capítulo. Marina Simon Becker 14 3 3.1 CONTROLE DE SESSÃO Estabelecendo uma conexão Para estabelecer uma conexão o TCP utiliza o Three Way Handshake, que significa, literalmente, “um aperto de mão em três vias”, onde são necessários apenas 3 segmentos para que a conexão seja estabelecida. O Three Way Handshake funciona da seguinte maneira: o host que deseja fazer um pedido de conexão envia um segmento com a flag SYN ativa no campo Control Bits. Assim que o outro host recebe o pedido de conexão, ele envia um segmento contendo as flags ACK e SYN ativas, que significa aceitar a conexão. Para finalizar o estabelecimento da conexão, o primeiro host envia um segmento com a flag ACK, indicando ter aceitado a conexão com o host. A partir deste momento a conexão é considerada estabelecida pelo primeiro host. Quando o terceiro segmento é recebido pelo segundo host, este considera a conexão estabelecida. A partir do momento em que um host considera uma conexão estabelecida, ele pode iniciar a transferência de dados. A Figura 3.1 mostra o exemplo de um Three Way Handshake. Envia SYN Recebe SYN Envia ACK, SYN Recebe ACK, SYN Envia ACK Recebe ACK Figura 3.1: Three Way Handshake Para ficar mais claro, o exemplo a seguir mostra cada um dos segmentos ilustrados na Figura 3.1. Estes segmentos foram capturados de uma conexão entre um cliente e um servidor web. A Figura 3.2 apresenta o conteúdo do primeiro segmento. Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Envia SYN Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer Option 1042 80 1084136 0 7 (32-bit word) 0 SYN 8192 0x3047 0x0000 0204021801010402 Figura 3.2: Segmento solicitando uma conexão No primeiro segmento, o TCP do cliente web envia nos campos Source Port e Destination Port o número da porta que ele escolheu para estabelecer a conexão e o número da porta do servidor web que está esperando a conexão. A porta padrão do servidor web é a porta 80. No campo Sequence Number é enviado o número de seqüência inicial, que é um número escolhido aleatoriamente pelo TCP. Por ser o primeiro segmento, o campo Acknowledgement Number é igual a 0, pois ele não sabe ainda o Sequence Number do servidor web. O campo Data Offset é igual a 7, que indica que o tamanho do cabeçalho é 7 vezes 32 bits. O campo Reserved é igual a 0, pois não está sendo usado. No campo Control Bits a flag SYN indica o pedido de conexão. O campo Window indica que o máximo de segmentos que o TCP do servidor web pode enviar corresponde a 8192 octetos, pois este é o tamanho da janela do cliente web. O Checksum é enviado para o TCP do servidor web checar a integridade do segmento. O Urgent Pointer é igual a 0, pois não existem dados urgentes neste segmento. Se existissem dados urgentes neste segmento, a flag URG no campo Control Bits deveria estar setada. E, por último, o campo Options é enviado para comunicar o MSS, ou seja, diz qual é o tamanho máximo de segmento que o TCP do cliente web irá aceitar. Esta opção somente é enviada no segmento de pedido de conexão e se ela não for enviada, o TCP utiliza o valor padrão para o MSS, que é o tamanho total do datagrama IP menos os cabeçalhos IP e TCP. Envia ACK, SYN Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer Option 80 1042 174299038 1084137 6 (32-bit word) 0 ACK, SYN 33232 0x3DCF 0x0000 020405B4 Figura 3.3: Segmento aceitando uma conexão Marina Simon Becker 16 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol A Figura 3.3 apresenta o conteúdo do segundo segmento, que tem no campo Sequence Number o número de seqüência inicial do servidor web. No campo Acknowledgement Number tem o Sequence Number do cliente web mais 1, indicando o próximo segmento que ele espera receber. O campo Control Bits tem as flags ACK e SYN, indicando aceitar a conexão. O campo Window especifica o tamanho da janela do servidor web e o campo Option envia o MSS que será aceito pelo TCP do servidor web. Envia ACK Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer 1042 80 1084137 174299039 6 (32-bit word) 0 ACK 8576 0xB5DC 0x0000 Figura 3.4: Segmento finalizando o estabelecimento de uma conexão A Figura 3.4 ilustra o último segmento do Three Way Handshake. No campo Sequence Number tem o número pedido no Acknowledgement Number do segmento anterior, indicando que este é 6.23988 ca 0 Td(m)Tj0.12.88 0 Td(n)1 0 00 Td(r)Tj0.12 Tc1.2 TwT Marina Simon Becker 17 Universidade do Vale do Rio dos Sinos – Unisinos 3.3 Transmission Control Protocol Resetando uma conexão Existem certas ocasiões que a aplicação não consegue encerrar a conexão da maneira correta. Isto pode acontecer por causa de algum um erro na aplicação, ou simplesmente por ela ter sido abortada. Nestes casos, o TCP deve utilizar o mecanismo de reset para abortar a conexão com a outra ponta. O reset é um segmento com o bit RST ligado no campo Control Bits do cabeçalho TCP. Assim que a outra ponta recebe este segmento, ela deve saber que a conexão foi abortada por algum motivo, e que não deve mais enviar dados. 3.4 Encerrando uma conexão O método utilizado para encerrar uma conexão é como o Three Way Handshake. A diferença é o campo Control Bits. Enquanto que para estabelecer uma conexão utiliza-se a flag SYN, para finalizar a conexão utiliza-se a flag FIN. Outra diferença é que o segundo segmento não inclui o FIN junto com o ACK. Primeiro, vai um segmento com a flag FIN, indicando que um dos hosts não tem mais dados para enviar e quer encerrar a conexão. Em resposta ao pedido de encerramento de conexão, o outro host envia um segmento com a flag ACK, avisando que recebeu o pedido. Este, deve então avisar a aplicação que não existem mais dados para receber e perguntar se pode encerrar a conexão. Caso a aplicação permita o encerramento da conexão, o TCP envia o segmento com a flag FIN para o outro, que por sua vez, envia um ACK finalizando a conexão. A Figura 3.5 apresenta o encerramento de uma conexão. Envia ACK, FIN Recebe ACK, FIN Envia ACK Recebe ACK Envia ACK, FIN Recebe ACK, FIN Envia ACK Recebe ACK Figura 3.5: Encerramento de uma conexão O exemplo a seguir ilustra o encerramento de uma conexão entre um cliente e um servidor web, apresentando o conteúdo de cada segmento visto na Figura 3.5. A Figura 3.6 mostra o conteúdo do primeiro segmento. Marina Simon Becker 18 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Envia ACK, FIN Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer 1109 80 11127669 5238095 5 (32-bit word) 0 ACK, FIN 8044 0xCC48 0x0000 Figura 3.6: Segmento solicitando encerramento da conexão Neste caso, o cliente web já recebeu todos os dados que ele queria e decidiu encerrar a conexão com o servidor web. O TCP envia no campo Control Bits as flags ACK e FIN ligadas, pois o ACK corresponde à confirmação do último segmento recebido do servidor web e o FIN diz que ele quer encerrar a conexão. A Figura 3.7 apresenta o conteúdo do segundo segmento, enviado pelo servidor web. O segmento contém apenas um ACK no campo Control Bits, somente para confirmar que recebeu o último segmento. Envia ACK Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer 80 1109 5238095 11127670 5 (32-bit word) 0 ACK 8241 0xCB83 0x0000 Figura 3.7: Segmento de confirmação A Figura 3.8 apresenta o conteúdo do terceiro segmento, que também é enviado pelo servidor web, pois depois de ter certificado-se com a aplicação que pode encerrar a conexão, ele envia um segmento com as flags ACK e FIN indicando que a conexão pode ser encerrada. Note que o Sequence Number e o Acknowledgement Number são os mesmos do segmento anterior, indicando que este segmento corresponde ao último segmento enviado pelo cliente web. Marina Simon Becker 19 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Envia ACK, FIN Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer 80 1109 5238095 11127670 5 (32-bit word) 0 ACK, FIN 8241 0xCB82 0x0000 Figura 3.8: Segmento aceitando o encerramento da conexão Para finalizar, a Figura 3.9 apresenta o último segmento do encerramento da conexão, que contém um ACK, enviado pelo cliente web, indicando que a conexão foi realmente encerrada. Envia ACK Source Port Destination Port Sequence Number Acknowledgement Number Data Offset (MSB 4 bits) Reserved (LSB 4 bits) Control Bits Window Checksum Urgent Pointer 1109 80 11127670 5238096 5 (32-bit word) 0 ACK 8044 0xCC47 0x0000 Figura 3.9: Segmento confirmando o encerramento da conexão Marina Simon Becker 20 4 4.1 CONTROLE DE ERRO Tipos de Erro Os protocolos de transporte da pilha TCP/IP utilizam os serviços da camada inferior, IP, para a transmissão de datagramas até o host destino. Datagramas IP são encaminhados, hop a hop, de acordo com tabelas de rotea Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol capacidade de processar os dados entre o transmissor e o receptor for muito diferente. O segmento realmente chega ao destino, mas o transmissor não sabe se chegou ou não devido a um atraso no recebimento da confirmação, então ele envia o segmento novamente. Isto faz com que cópias do mesmo segmento cheguem duas ou mais vezes no receptor. O receptor deve descartar as cópias destes segmentos. Pacotes replicados consomem, desnecessariamente, recursos da rede e dos hosts envolvidos. Pacotes corrompidos são pacotes que não chegam completos no receptor, ou pela simples troca de um bit no decorrer do caminho, o cálculo da soma de verificação não confere e o pacote não pode ser reconstruído. Um host ou um roteador descarta o pacote corrompido, fazendo com que o mesmo tenha que ser retransmitido. Já a perda de pacotes pode ser ocasionada pela própria rede. Isto é muito comum quando há um congestionamento e os roteadores necessitem descartar pacotes. Outro motivo que pode ocasionar perdas é o excesso de fluxo que pode estar fazendo com que o receptor esteja recebendo mais pacotes do que consegue dar conta, então o seu buffer de entrada esgota e os pacotes podem ser descartados. O atraso da chegada de segmentos no receptor pode ser causado pelo mesmo motivo da perda, só que não chegam a ser descartados. Uma rede congestionada, ou com o fluxo muito alto, tende a ficar lenta, pois os pacotes ficam no buffer dos roteadores até que eles consigam encaminhá-los devidamente. 4.2 Detecção de Erro Uma das formas de detectar segmentos perdidos é através de um timeout, o RTO (Retransmission Time Out), que é o tempo que o transmissor tem para esperar a chegada de um ACK. Se o RTO expirar antes da chegada do ACK, então o TCP assume que o segmento foi perdido. O RTO é definido através do RTT (Round Trip Time), que significa o tempo entre o envio do segmento e o recebimento do ACK. Estima-se, assim, o tempo entre a ida e a volta de um segmento. A amostra do RTT é feita iniciando um timer para cada segmento enviado. Quando chega a confirmação deste segmento, o timer é cancelado. O valor retirado deste timer é o RTT estimado. O RTO deve ser sempre maior que o RTT, do contrário o timeout poderá expirar antes da confirmação chegar. O valor do RTO é variável, adaptando-se de acordo com o desempenho da conexão. O TCP monitora cada conexão e deduz valores razoáveis para o timeout ([12]). À medida que o desempenho de uma conexão muda, o TCP revisa o seu valor de timeout adaptando-se a mudança. A RFC 1122 ([4]) especifica que, no inicio de uma transmissão, quando ainda não tiver sido calculado o RTT, o RTO deve ser setado para 3 segundos. A RFC 2988 ([21]) sugere que quando o RTO for calculado e o resultado for menor que um segundo, então ele deve ser arredondado para um segundo. E o valor máximo do RTO não deve passar de 60 segundos. Marina Simon Becker 22 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Outra maneira de detectar perdas é através de ACKs duplicados (duplicated ACKs). Suponha que o transmissor envie os segmentos 1, 2, 3 e 4, e o segmento 1 seja perdido. Assim que o segmento 2 chegar, o receptor enviará um ACK com o número de seqüência do segmento 1. Quando receber o segmento 3, ele enviará um ACK com o número de seqüência do segmento 1, e quando o segmento 4 chegar, ele enviará um ACK com o número de seqüência do segmento 1. Enquanto o segmento 1 não chegar, o receptor enviará ACKs com o número de seqüência deste segmento. A Figura 4.1 ilustra este exemplo. Envia segmento 1 Envia segmento 2 Não recebe segmento 1 Envia segmento 3 Recebe segmento 2 Envia o ACK 1 Recebe segmento 3 Envia o ACK 1 Recebe segmento 4 Envia o ACK 1 Envia segmento 4 Recebe o ACK 1 Recebe o ACK 1 Recebe o ACK 1 Figura 4.1: ACKs duplicados Se vários ACKs possuírem o mesmo número de seqüência, eles serão ACKs duplicados. Na verdade, o transmissor não consegue distinguir se o segmento foi perdido ou se simplesmente chegou fora de ordem, então ele assume que mais de 3 ACKs duplicados significam um segmento perdido. A detecção de segmentos que chegam fora de ordem é feita e recuperada no próprio receptor, que os reordena através dos números de seqüência dos segmentos. 4.3 Recuperação de Erro Para que o TCP possa recuperar um segmento perdido ou corrompido, ele utiliza um mecanismo de retransmissão. Assim que o erro é detectado, o TCP providencia a retransmissão do segmento. Com o algoritmo de Karn o TCP não deve utilizar como amostra o RTT de segmentos retransmitidos, ou seja, cada vez que um segmento for retransmitido o TCP não deve ligar o Marina Simon Becker 23 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol timer, ignorando o RTT do segmento retransmitido. Isto pode fazer com que, se o RTT real aumentar, o TCP não poderá perceber e continuará retransmitindo segmentos, pois o seu timeout estará desatualizado. Para que isto não aconteça deve ser utilizado o algoritmo de backoff exponencial descrito a seguir. O algoritmo de backoff exponencial parte do princípio que, se houve uma retransmissão, é por que o timeout expirou. Sendo assim, o backoff aumenta o valor do RTO para que, se houve um aumento do RTT, o timeout não expire novamente para o segmento retransmitido, que provocaria uma nova retransmissão. O cálculo utilizado para aumentar o timeout é: novo_timeout = x * timeout, onde x normalmente é igual a 2. Por exemplo, se o transmissor enviar um segmento e não receber confirmação em 3 segundos, ele faz uma retransmissão aumentando o timeout para 6 segundos. Se a confirmação não chegar, ele dobra o timeout para 12 segundos e assim sucessivamente, até ter sucesso ou encerrar a conexão. Marina Simon Becker 24 5 5.1 CONTROLE DE FLUXO Janela Deslizante O TCP permite que o receptor controle a quantidade de dados que serão enviados pelo transmissor. Isto acontece através do campo Window, que é o tamanho da janela oferecida pelo receptor a cada ACK de confirmação, indicando o quanto de dados ele pode receber. Isto eqüivale ao tamanho do buffer que o receptor possui para armazenar os dados. A janela indica o número máximo de bytes que o transmissor pode enviar. Esta janela é chamada de janela deslizante, pois a cada confirmação que chega ela desliza abrindo espaço para novos segmentos serem enviados. O tamanho da janela deslizante do TCP é variável e o valor dela é medido em quantidade de bytes. O TCP permite que o tamanho da janela varie com o passar do tempo, pois cada ACK que o receptor envia para confirmar um segmento é acompanhado pelo tamanho da janela, então a cada ACK o receptor pode informar um novo tamanho de janela. A cada ACK o receptor envia o valor da janela para o transmissor. Este valor corresponde ao tamanho do buffer disponível no receptor no momento em que o ACK foi enviado. O transmissor utiliza este valor para calcular o tamanho da janela utilizável, que é o tamanho da janela oferecida pelo receptor menos a janela do transmissor, que guarda os segmentos que foram enviados e ainda não foram confirmados. Como resultado deste cálculo, a janela utilizável deve ser sempre igual ou menor que a janela oferecida pelo receptor. Se, por exemplo, o receptor oferecer uma janela de 2000 bytes, e o tamanho máximo de cada segmento esteja estipulado em 500 bytes, o transmissor pode utilizar esta janela para enviar 4 segmentos de 500 bytes cada. Depois que o receptor processar o primeiro segmento, ele tira de seu buffer os 500 bytes que correspondem a este segmento e envia um ACK para o transmissor com o valor do campo Window de 2000 bytes. O transmissor, quando recebe o ACK, faz o cálculo da janela utilizável, que é a janela oferecida de 2000 bytes, menos a quantidade de bytes que estão em trânsito, que são os 3 segmentos de 500 bytes cada, ou seja, Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol 1500 bytes. Isto resulta em uma janela utilizável de 500 bytes, que é o valor máximo que o transmissor pode enviar. A Figuras 5.1 ilustra o exemplo apresentando a janela ofertada de 2000 bytes dividida em 4 segmentos de 500 bytes cada. 1 2 3 4 5 6 7 8 9 10 Figura 5.1: Janela deslizante com nenhum segmento confirmado Já a Figura 5.2 apresenta como a janela desliza após o recebimento do ACK do primeiro segmento de 500 bytes, possibilitando a transmissão de mais um segmento de 500 bytes. 1 2 3 4 5 6 7 8 9 10 Figura 5.2: Janela deslizante com um segmento confirmado Os segmentos que ficam do lado esquerdo da janela são os segmentos que já foram enviados e confirmados. Os segmentos que estão do lado direito da janela são os segmentos que ainda não foram enviados. E os segmentos que estão dentro da janela são os que foram enviados e ainda não foram confirmados ([12]). 5.2 SWS - Silly Window Syndrome A SWS, ou síndrome da janela desnecessária, pode ocorrer quando o transmissor e o receptor possuem velocidades diferentes de transmissão e processamento dos dados. Quando o receptor é muito lento para processar os dados, pode acontecer de ficar sem espaço em buffer até que consiga retirar os dados ali contidos. Sendo assim, ele envia uma confirmação para o transmissor com o tamanho da janela igual a zero. O transmissor começa então a enviar pequenos segmentos para saber se o receptor já pode aceitar mais dados. Se o receptor permanecer com a janela igual a zero por um período muito longo, o transmissor pode achar que o receptor falhou e encerrar a conexão ([2]). Seguindo no exemplo da seção anterior, quando o transmissor recebe a confirmação do primeiro segmento enviado, são liberados 500 bytes na janela. Se o TCP precisar enviar 50 bytes de dados (com a flag PSH ligada no campo Control Bits), o próximo segmento será enviado com os 450 bytes restantes. Quando o segmento de 50 bytes chega no receptor, Marina Simon Becker 26 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol este envia uma confirmação para o transmissor, liberando os 50 bytes na janela para o envio de dados. Assim, o transmissor envia mais um segmento com 50 bytes de dados, mesmo sem ter a necessidade de forçar o envio. Isto também provoca a SWS, pois o transmissor começa a enviar pequenos segmentos, um de cada vez, enquanto que o receptor envia as confirmações dos pequenos segmentos. 5.3 Prevenção da SWS no receptor Existem dois algoritmos para prevenir a SWS, que devem ser implementados no receptor ([2]). O primeiro tem o objetivo de aperfeiçoar o algoritmo da janela deslizante, fazendo com que o receptor ofereça uma janela igual a zero ao invés de oferecer uma janela pequena, até que ele consiga retirar um número suficiente* de bytes de seu buffer. Assim o transmissor verá que não pode enviar mais dados naquele momento, acumulando os dados em seu próprio buffer. Quando o receptor perceber que liberou uma quantidade significativa de espaço no seu buffer, ele volta a oferecer o tamanho da janela anterior. Sendo assim, o transmissor pode enviar segmentos maiores, pois a janela utilizável terá aumentado significativamente. O problema é que, se o receptor enviar uma janela igual a zero, o transmissor começará a enviar pequenos segmentos para saber se o receptor já está aceitando mais dados. O ideal é fazer com que o receptor diminua o tamanho da janela pela metade do seu valor atual, pois quando o transmissor fizer o cálculo da janela utilizável, ela ainda será menor que zero, impedindo que o transmissor envie mais dados. O outro algoritmo é conhecido como “Every-other ACK”, cujo objetivo é aperfeiçoar o algoritmo de geração de ACKs, pois normalmente o TCP receptor envia um ACK para cada segmento recebido, o que é chamado de ACK compulsivo. Existem duas razões para enviar um ACK imediatamente: uma é para evitar retransmissões, e a outra é para permitir que novos segmentos possam ser enviados. Mas se poucos dados forem liberados no receptor, um ACK faria com que o transmissor enviasse um pequeno segmento, e se para cada vez que uma pequena quantidade de dados for liberada no receptor, ele enviar um ACK, então o transmissor irá sempre enviar pequenos segmentos a cada ACK que chegar. O algoritmo sugerido é fazer com que o receptor atrase as confirmações ao transmissor. Desta forma, antes de enviar uma confirmação, ele espera liberar espaço em seu buffer, podendo até, se já tiver processado vários segmentos, enviar uma confirmação única para todos eles. Isto é muito bom, pois economiza banda. O problema desta solução é que o receptor não pode atrasar muito o envio da confirmação, porque o transmissor pode achar que o segmento foi perdido e isto causaria uma retransmissão. Outro problema está no cálculo da estimativa do RTT, pois o retardo nas confirmações pode gerar uma estimativa falsa do RTT, fazendo com que o valor do timeout do transmissor fique muito grande. Por isto, quando este algoritmo for implementado, devem ser levados em conta alguns fatores importantes. Um destes fatores é que o receptor deve saber quanto tempo ele deve esperar acrescentado um timer de espera para enviar a * O que o TCP entende por um número suficiente é o que for maior entre 50 por cento de espaço no buffer do receptor e o valor do tamanho máximo de um segmento. Marina Simon Becker 27 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol confirmação, que não deve passar dos 500 milissegundos*. Quando um segmento de dados chegar, ele inicia o timer e, mesmo que nenhum outro segmento chegue quando o timer expirar, ele deve enviar a confirmação. É sugerido que a espera somente deve acontecer quando o segmento recebido não contiver o bit PSH setado, e quando não houver nenhuma atualização da janela para ser enviada. O receptor deve confirmar pelo menos 1 entre 2 segmentos enviados. 5.4 Prevenção da SWS no transmissor Assim como no receptor, existem 2 algoritmos para a prevenção da SWS no transmissor. Um dos algoritmos foi desenvolvido por Michael Greenwald do MIT. O transmissor utiliza a janela oferecida pelo receptor para calcular a janela utilizável. Então ele compara a janela oferecida com a janela utilizável e, se a proporção entre uma e outra for menor que um certo valor, ele pára de enviar segmentos. Se a janela utilizável for muito menor que a janela oferecida, significa que ainda tem muitos segmentos a serem confirmados, então o TCP transmissor deve esperar até que a janela utilizável chegue a um certo valor para começar a enviar novamente. O valor suficiente para evitar a SWS e alcançar um throughput razoável é de 25% ([2]). O outro é chamado de Algoritmo de Nagle, cujo objetivo é evitar o envio de segmentos pequenos. Ao invés do TCP enviar segmentos a medida em que as confirmações forem chegando, ele deve esperar até que a aplicação forneça dados suficientes para que ele possa preencher um segmento grande. O que ocorre é que o TCP não sabe o quanto de dados a aplicação tem para enviar, portanto não pode ser especificado um tempo fixo de espera. O que o padrão especifica então, é que o TCP utilize um esquema adaptável para retardar a transmissão, armazenando em seu buffer de saída a quantidade suficiente para preencher um segmento com o tamanho máximo. Se uma confirmação chegar antes de ter dados suficientes para preencher um segmento com o tamanho máximo, ele deve enviar todos os dados acumulados no buffer. Esta regra deve ser aplicada mesmo que a aplicação peça para forçar o envio (push). * Existe um algoritmo adaptativo para medir o intervalo do timer ([2]). Marina Simon Becker 28 6 CONTROLE DE CONGESTIONAMENTO Para fazer o controle de congestionamento, o TCP precisa detectar quando há um congestionamento. Os mecanismos utilizados para a detecção de congestionamento são o timeout e os ACKs duplicados, abordados no capítulo anterior, pois o TCP originalmente não conta com notificação explícita de congestionamento (ECN, Explicit Congestion Notification). Quando um erro é detectado, através do timeout, o TCP assume que existe um roteador congestionado e que esta foi a causa da perda. Em outras palavras, a maioria das perdas é causada por congestionamento e não por corrupção. Conforme [3] pacotes corrompidos são responsáveis por apenas 1% das perdas. Para diminuir o risco de colapso na rede, cada fluxo TCP é regido por uma política de controle de congestionamento. Isto assegura que as centenas de fluxos TCP que se cruzam em um roteador qualquer ocupem uma fatia “justa” da banda disponível (fairness). 6.1 Slow Start O Slow Start é um mecanismo de controle de congestionamento utilizado para estabelecer o equilíbrio de uma conexão. O TCP deve iniciar uma transmissão inserindo segmentos na rede de forma gradual, para que ele possa conhecer a capacidade da rede. O equilíbrio da conexão é estabelecido cada vez que o TCP começa a inserir dados na rede, ou seja, a cada início de conexão ou logo após uma perda, fazendo com que a conexão volte ao normal. A quantidade de dados que o TCP começa a transmitir é de acordo com o tamanho da janela do receptor. Quando o receptor oferece uma janela muito grande e a aplicação do transmissor fornece dados suficientes para preencher aquela janela, o TCP transmissor envia muitos segmentos ao mesmo tempo. Isto pode gerar perdas caso algum roteador esteja com muita carga, ocasionando retransmissões. O Slow Start faz com que os segmentos sejam inseridos na rede de uma forma lenta e gradual, melhorando o aproveitamento da banda e evitando o risco de um congestionamento na rede. Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol O Slow Start utiliza a janela de congestionamento (cwnd) que é o limite que o transmissor tem para enviar os dados quando inicia a transmissão ou depois de receber uma confirmação. A janela oferecida pelo receptor (rwnd) é o limite que o receptor tem para receber os dados. O limite que deve ser utilizado para a transmissão é o valor mínimo entre estas duas janelas, ou seja, se a cwnd for menor que a rwnd, então o transmissor deve enviar a quantidade de dados estipulada na cwnd. Outra variável incluída é a Slow Start Threshold (ssthresh), que serve para determinar se o algoritmo do Slow Start será utilizado ou não na transmissão dos dados. A implementação do Slow Start implica nos seguintes passos: deve ser adicionada a cwnd, quando uma transmissão iniciar ou reiniciar após a perda de um segmento. Setar o valor da cwnd para 1 segmento. Para cada ACK que chegar, incrementar a cwnd com 1 segmento e quando o TCP for transmitir, deve transmitir o mínimo entre a cwnd e a rwnd ([3]). Quando a janela de congestionamento é iniciada, ela contém o valor de 1 segmento. O transmissor envia este segmento e espera por sua confirmação. Quando a confirmação chega, aumenta-se a janela de congestionamento em mais 1 segmento, possibilitando a transmissão de 2 segmentos. Quando as 2 confirmações chegarem, aumenta-se mais 2 segmentos na janela, deixando-a com 4 segmentos. Enviando os 4 segmentos, chegarão 4 confirmações, fazendo com que a janela aumente para 8 segmentos e assim sucessivamente, enquanto a janela oferecida pelo receptor permitir. A janela de congestionamento cresce de forma exponencial, o que implica em um crescimento não muito lento. 6.2 Congestion Avoidance Congestion Avoidance é definida em [3] como uma estratégia dividida em duas partes: uma consiste em fazer com que a rede avise aos hosts que poderá ocorrer um congestionamento. Cada roteador que estiver com a sua capacidade em um determinado limite deverá enviar um sinal para os hosts ativando um certo bit no cabeçalho dos pacotes. A outra parte da estratégia é implementada nos end-points, que devem decrementar a utilização quando receberem a notificação e incrementar quando não receberem. O algoritmo definido em [3] utiliza outros dois algoritmos, o Multiplicative Decrease e o Additive Increase, que serão descritos a seguir. Multiplicative Decrease é utilizado após a ocorrência de uma perda. Com a perda de um segmento (quando expira o timer do transmissor) a janela de congestionamento deve ser reduzida pela metade até que ela chegue a um tamanho mínimo de 1 segmento. Para os segmentos que permanecerem na janela permitida, deve ser aplicado o algoritmo de backoff exponencial, descrito no Capítulo 4. Additive Increase funciona como o Slow Start, com a diferença que o incremento da janela de congestionamento é aditivo, em vez de exponencial. Isto faz com que o crescimento da janela fique mais lento. A janela de congestionamento inicia com 1 segmento e aumenta 1 Marina Simon Becker 30 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol segmento dividido pelo tamanho da janela a cada confirmação que chega, ou seja, cwnd = cwnd + 1/cwnd. Por ser aditivo, este algoritmo oferece um crescimento mais suave para a cwnd do que o Slow Start. Os algoritmos Multiplicative Decrease e Additive Increase devem ser utilizados em conjunto, da seguinte maneira: em qualquer timeout, deve ser utilizado o algoritmo Multiplicative Decrease, em qualquer ACK que chegar, deve ser utilizado o algoritmo Additive Increase e quando o TCP for transmitir, deve transmitir o mínimo entre a cwnd e a rwnd ([3]). Marina Simon Becker 31 7 7.1 MECANISMOS AVANÇADOS Fast Retransmit De acordo com a RFC 2001 ([10]) o Fast Retransmit surgiu de algumas modificações no algoritmo Congestion Avoidance de [3]. Inicialmente foi implementado na versão Tahoe (1988), mas é modificado a cada versão do TCP. Conforme descrito no Capítulo 4, quando um segmento chega fora de ordem, o TCP receptor gera um ACK duplicado, para avisar ao transmissor qual o número de seqüência que está sendo esperado. O transmissor, por sua vez, não sabe se o segmento está realmente fora de ordem ou foi perdido. Normalmente, ele aguarda a chegada de outros ACKs duplicados para saber o que fazer, pois se forem segmentos fora de ordem, com 1 ou 2 ACKs duplicados o receptor consegue ordenar, mas se chegarem 3 ou mais ACKs duplicados, então pode ter sido uma perda. Na chegada de 3 ACKs duplicados, o transmissor supõe que um segmento foi perdido, retransmitindo o segmento sem esperar o timer expirar. Após a retransmissão do segmento perdido, o Slow Start é iniciado. 7.2 Fast Recovery O Fast Recovery é uma modificação acrescentada no método Fast Retransmit, implementada na versão Reno (1990), e após, modificada na versão New Reno (1999). De acordo com a RFC 2581 ([15]), o transmissor, depois de receber 3 ACKs duplicados e retransmitir o segmento, não executa o Slow Start. A razão para não executar o Slow Start é que talvez o receptor queira dizer que há mais de um segmento perdido. E o receptor somente pode enviar um ACK duplicado após ter recebido um segmento de dados. Então se, por acaso, não houver segmentos em transito, o transmissor não deve abruptamente parar de enviar segmentos, como é feito no Slow Start. O Fast Recovery implementado na versão Reno faz com que, quando o terceiro ACK duplicado chegue, a janela de congestionamento seja reduzida pela metade do seu valor atual (Multiplicative Decrease), mas ela não deve ficar menor que 2 segmentos. Depois de retransmitir o segmento perdido, a janela de congestionamento deve ser incrementada em 3 vezes o valor de um segmento. Para cada novo Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol ACK duplicado que chegar, incrementa-se a janela de congestionamento com o tamanho do segmento e transmite um novo segmento, se o valor da janela oferecida pelo receptor permitir. Quando chegar o ACK do segmento retransmitido, a janela de congestionamento deve ser incrementada em 3 vezes o valor de um segmento novamente. 7.3 Selective Acknowledgement Conforme [6] o Selective Acknowledgement (SACK) foi implementado na versão SACK (variação da versão Reno). Ele preserva as propriedades das versões Tahoe e Reno, deixando-as mais robustas quanto aos pacotes desordenados e utiliza o RTO como método de recuperação apenas em último caso. De acordo com a RFC 2018 ([9]), com o SACK o receptor pode informar ao transmissor quais foram os segmentos que chegaram corretamente, permitindo então que o transmissor retransmita apenas os segmentos necessários. O SACK utiliza duas opções no cabeçalho do TCP, uma é “SACK-permitted”, que deve ser enviada no segmento SYN, assim que a conexão for estabelecida. A outra é a “SACK”, que pode ser enviada em qualquer conexão que tiver sido iniciada com a opção “SACK-permitted”. A utilização da opção SACK para ACKs duplicados é definida na RFC 2883 ([19]). Durante o Fast Recovery, o SACK mantém uma variável chamada “pipe”, que representa o número estimado de segmentos pendentes ao longo do caminho. Esta variável é incrementada a cada segmento enviado e decrementada a cada confirmação que chega. 7.4 Forward Acknowledgement O Forward Acknowledgement (FACK), foi baseado nos princípios do controle de congestionamento e desenvolvido para ser utilizado em conjunto com a proposta da versão SACK. O FACK faz um controle mais preciso dos dados que são inseridos na rede durante a recuperação de uma perda ([7]). O FACK adiciona mais duas variáveis no TCP transmissor, onde uma é incrementada com a quantidade de dados que foram retransmitidos e decrementada quando a confirmação destes segmentos chegarem. A outra variável guarda o valor da opção SACK do cabeçalho do TCP. O cálculo destas variáveis permite ao TCP uma visão mais precisa do estado da rede durante a conexão. Marina Simon Becker 33 8 PROBLEMAS COM IMPLEMENTAÇÕES DO TCP Foram descobertos vários problemas em algumas implementações do TCP. Estes problemas prejudicam o bom funcionamento do protocolo. Os problemas estão registrados na RFC 2525 ([14]) e serão descritos neste capítulo. Muitas das especificações citadas aqui estão padronizadas na RFC 1122 ([4]). Os problemas estão classificados em categorias como: controle de congestionamento, performance, confiabilidade e gerenciamento de recursos. 8.1 Controle de Congestionamento Slow start ausente. Conforme visto no Capítulo 6, quando o TCP inicia uma transmissão ele deve utilizar o Slow Start para iniciar a cwnd com um segmento e incrementala em um segmento a cada confirmação que chegar. Se o Slow Start falhar no início da conexão, será gerado um fluxo muito intenso, que pode inundar a rede, ocasionando atrasos e perdas de segmentos. As implementações que apresentam este tipo de problema, provavelmente, não estão iniciando a cwnd corretamente. Estas implementações irão sofrer também com o problema de Slow Start ausente após uma retransmissão. Slow start ausente após uma retransmissão. Assim como no início de uma transmissão, o Slow Start deve ser iniciado quando ocorre uma retransmissão, para que o TCP não insira um número muito grande de segmentos, caso haja um congestionamento na rede. Iniciar o Slow Start quando há um congestionamento é fundamental para manter a estabilidade da rede. Se a implementação falhar neste ponto, a rede pode ser inundada de pacotes, gerando um colapso de congestionamento. Janela de congestionamento não inicializada. Foi visto no Capítulo 3 que quando uma conexão é estabelecida, os primeiros segmentos vem com a opção MSS. Quando esta opção não é enviada, é utilizado o valor padrão para o MSS, que é o tamanho de um datagrama IP, menos os cabeçalhos IP e TCP. A falha na implementação está em usar o valor da opção MSS para estipular o tamanho do segmento inicial da janela de congestionamento. Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Se a opção não chegar, os segmentos adicionados na janela de congestionamento poderão conter um tamanho muito grande, inundando a rede e ocasionando a perda de pacotes. Retransmissão com envio de múltiplos segmentos. Em uma retransmissão, o TCP deve enviar apenas um único segmento. O envio de múltiplos segmentos pode ocorrer por causa do campo Options, que aumenta o cabeçalho além dos 20 octetos. Se o TCP não contabilizar o tamanho do campo Options quando for determinar o quanto de dados ele tem que retransmitir, ele enviará dados a mais do que o necessário para preencher um único segmento. Sendo assim, o segmento retransmitido será acompanhado de um pequeno segmento, que contém dados que não precisam ser retransmitidos. Isto acaba injetando mais tráfego na rede desnecessariamente, além do que, esta redundância irá gerar um ACK duplicado do receptor, resultando em mais uma transmissão desnecessária. Falha no backoff após um RTO. Como está descrito no Capítulo 4, sempre que um segmento é retransmitido o valor do timeout é dobrado, de acordo com o algoritmo de backoff. Se isto não ocorrer, o timeout irá expirar antes da chegada do ACK, e se o transmissor não receber um ACK após numerosas tentativas de retransmissão, a conexão é encerrada. A RFC 1122 especifica que é obrigatório o backoff exponencial em um RTO e a finalização da conexão após um período de tempo de, no mínimo, 100 segundos. 8.2 Performance RTO inicial muito curto. Logo que o TCP inicia a transmissão dos dados, ele não possui o valor do RTT necessário para calcular o RTO. A RFC 1122 estabelece que a implementação deve inicializar o RTO com 3 segundos. As conexões que possuem o RTT muito longo* geram a perda de performance do TCP, resultando em retransmissões desnecessárias, pois o RTO irá expirar antes da chegada do ACK. Além disto, quando o RTO for menor que o RTT, o TCP levará um longo tempo para conseguir corrigir o problema, adaptando a estimativa do RTT com o uso do algoritmo de Karn, como foi visto no Capítulo 4. Falha ao enviar um FIN. Quando uma aplicação fecha uma conexão, o TCP deve enviar imediatamente uma notificação FIN. Apesar de não ser estritamente requerido, deve ser incluído no segmento FIN a flag PSH, para assegurar que o segmento será enviado imediatamente. Implementações que não fazem isto podem demorar para enviar o FIN, gerando um grande atraso em conexões com tempo de vida curto. Isto pode diminuir o throughput, pois demora muito para completar o encerramento da conexão. * Deve ser considerado longo qualquer valor de RTT maior que o RTO inicial. Marina Simon Becker 35 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Falha em guardar segmentos que chegam fora de ordem. Quando o TCP recebe um segmento fora de ordem (above-sequence*), ele envia o segmento para um buffer. Quando o sistema necessitar a liberação de memória, é conveniente que o TCP descarte destes segmentos. Se ele fizer isto raramente não é considerado um problema, mas a preocupação é com as implementações que sempre descartam os segmentos que chegam fora de ordem. Adição extra no Congestion Avoidance. A RFC 1122 diz que é obrigatória a implementação do Congestion Avoidance, que utiliza o incremento aditivo na cwnd (Additive Increase). Como foi visto no Capítulo 6, isto incrementa a cwnd em um segmento a cada RTT. Algumas implementações adicionam uma pequena parte de um segmento a este cálculo, fazendo o crescimento da janela ficar mais agressivo. Em ambientes congestionados isto pode prejudicar a performance de outras conexões, acrescentando perdas em todas as conexões que compartilham o mesmo gargalo, prejudicando fairness. Para resolver este problema, é só retirar o excesso do código da implementação. Falha em diminuir a janela após a recuperação de uma perda. Como foi abordado no capítulo anterior, o Fast Recovery permite que o TCP continue enviando novos segmentos durante a recuperação de uma perda. Algumas implementações fazem isto incrementando artificialmente a cwnd em três segmentos para os três primeiros ACKs duplicados que iniciaram o Fast Retransmit, e subseqüentemente um segmento para cada ACK duplicado que chegar. Quando um ACK chegar liberando novos dados, é reduzido o valor que foi artificialmente incrementado na cwnd. A implementação que não reduzir este valor irá enviar muitos segmentos logo após a recuperação da perda, diminuindo a performance e a estabilidade da rede. Este problema pode ser resolvido fazendo com que o protocolo verifique se a cwnd foi artificialmente aumentada, para que ele possa então reduzir o aumento. Intervalo excessivo entre ACKs. Conforme um dos métodos de evitar a SWS descrito no Capítulo 5, um receptor deve gerar um ACK para, pelo menos, cada dois segmentos de dados que ele receber. Se receptor esperar muito para enviar o ACK, fará com que o transmissor gere muito tráfego, diminuindo a performance em ambientes congestionados. A geração de poucos ACKs aumenta o tempo necessário para que o Slow Start possa abrir a cwnd, diminuindo a performance e podendo causar a necessidade de retransmissão. 8.3 Confiabilidade Retransmissão inconsistente. Se, para um determinado número de seqüência, o transmissor retransmitir dados diferentes daqueles que estão sendo esperados para aquele número, o receptor irá reconstruir um stream diferente daquele que está sendo enviado pela aplicação transmissora. Se isto ocorrer, o TCP perde a confiabilidade de entrega. * Segmento com um número de sequência acima do número de sequência esperado e abaixo do número de sequência esperado mais a janela de segmentos recebidos, ou seja: RCV.NXT < SEG.SEQ < RCV.NXT+RCV.WND. Marina Simon Becker 36 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Timeout do keep-alive muito curto. Como foi visto no Capítulo 3, o keep-alive é um mecanismo que serve para checar se uma conexão está ociosa ou se continua ativa. O keepalive possui um timeout de espera para receber a resposta da outra ponta. Se o timeout for muito curto, o keep-alive poderá encerrar conexões que estão funcionando, mas que demoraram para responder devido a alguma falha na rede. O problema pode ser resolvido utilizando um método diferente de timeout para o keep-alive, permitindo um período de tempo maior antes de desistir da conexão. Intervalo insuficiente entre keep-alives. Se um keep-alive for incluído em uma implementação, deve ser configurado o intervalo entre os segmentos do keep-alive, que de acordo com a RFC 1122, não deve ser menor que 2 horas. Se isto não for considerado, poderá ocorrer o encerramento de conexões quando houver um congestionamento. Janela com deadlock. Quando uma aplicação lê somente um byte de uma janela cheia, a janela não deve ser atualizada para evitar a SWS, como pôde ser visto no Capítulo 5. Se o host remoto utilizar apenas um byte para verificar se liberou espaço na janela, este byte pode ser aceito dentro do buffer. Em algumas implementações este é um ponto negativo, pois dados adicionais podem ficar fora da janela e serem descartados, e estes segmentos descartados não serão confirmados. Se a aplicação parar de ler os dados, o buffer nunca irá esvaziar, resultando em um deadlock. Campo Options excluído do cálculo do MSS. Quando o TCP determina a quantidade de dados que irá colocar em um segmento, ele calcula o tamanho do segmento baseado no MTU (Maximum Transfer Unit) da interface de rede, subtraindo o tamanho dos cabeçalhos IP e TCP. Se os campos Options do IP e do TCP não forem contabilizados junto com a subtração, o resultado será um segmento muito grande para a interface de saída, que ainda podem ter o bit DF (don’t fragment) setado no cabeçalho do IP. Com isto a camada do IP não permite que este pacote seja fragmentado ao ser enviado pela interface. Então, ao invés de enviar o segmento, o IP informa ao TCP o tamanho correto do MTU da interface. O TCP calcula novamente o MSS, sem incluir os campos Options dos cabeçalhos IP e TCP, e o problema se repete. Para resolver este problema, a implementação deverá certificar-se que o cálculo do MSS inclua os campos Options do IP e TCP, como está especificado na RFC 1122. 8.4 Gerenciamento de Recursos Falha em enviar um reset após um half duplex close. O TCP deve resetar uma conexão, enviando um segmento RST, se ele continuar recebendo dados após um “half duplex close”. Algumas implementações não enviam o RST quando se encontram nesta situação. Este é um problema sério para TCPs que gerenciam um grande número de conexões, devido a probabilidade de faltar memória ou processos que monitoram o estado das conexões. A falta de um RST pode travar uma conexão permanentemente. Marina Simon Becker 37 Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol Falha em enviar um reset com dados pendentes. Quando uma aplicação fechar uma conexão, ou ficar um longo tempo sem ler nenhum dado recebido, o TCP deve resetar a conexão enviando um RST. Algumas implementações não conseguem resetar a conexão. Assim como no problema anterior, os TCPs que gerenciam um grande número de conexões serão os mais prejudicados. Marina Simon Becker 38 9 CONCLUSÃO Desde o seu surgimento, o TCP teve uma evolução surpreendente, indicando que ele estará sempre sendo desenvolvido, estudado e aprimorado, que o torna um protocolo bastante complexo. Este trabalho teve como objetivo descrever o funcionamento do TCP, assim como mostrar vários mecanismos de controle que foram sendo adicionados ao protocolo com o passar do tempo, para aprimorar o seu funcionamento e a sua performance. Nenhum dos mecanismos citados aqui foi aprofundado, eles foram apenas descritos de forma que o leitor possa ter uma idéia de como o TCP funciona e de onde ele possa buscar a origem destes mecanismos, caso haja interesse. RE F E RÊ NCI AS [1] J. Postel. Transmission Control Protocol. Request for Comments 793, September 1981. [2] D. Clark. Window and Acknowledgement Strategy in TCP. Request for Comments 813, July 1982. [3] V. Jacobson, and M. Karels. Congestion Avoidance and Control. SIGCOMM Symposium on Communications Architectures and Protocols, pages 314--329, 1988. ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z. [4] R. Braden. Requirements for Internet Hosts - Communication Layers. Request for Comments 1122, October 1989. [5] T.J. Socolofsky, and C.J. Kale. TCP/IP Tutorial. Request for Comments 1180, January 1991. [6] K. Fall, and S. Floyd. Simulation-based Comparisons of Tahoe, Reno, and SACK TCP. Computer Communication Review, 26(3), July 1996. [7] M. Mathis, and J. Mahdavi. Forward Acknowledgement: Refining TCP Congestion Control. SIGCOMM’96, August 1996. [8] A. Kumar. Comparative Performance of Versions of TCP in a Local Network with a Lossy Link. WINLAB Technical Report-TR129, Rutgers University, October 1996. [9] M. Mathis, J. Mahdavi, S. Floyd, and A. Romanow. TCP Selective Acknowledgment Options. Request for Comments 2018, October 1996. Universidade do Vale do Rio dos Sinos – Unisinos Transmission Control Protocol [10] W. Stevens. TCP Slow Start, Congestion Avoidance, Fast Retransmit, and Fast Recovery Algorithms. Request for Comments 2001, January 1997. [11] V. Paxson. End-to-end Internet Packet Dynamics. SIGCOMM’97. [12] D. Comer, e D. Stevens. Interligação em Rede com TCP/IP – Volume1: Princípios, Protocolos e Arquitetura. Tradução da terceira edição. Rio de Janeiro: Campus, 1998. [13] D. Comer, e D. Stevens. Interligação em Rede com TCP/IP – Volume2: Projeto, Implementação e Detalhes Internos. Tradução da terceira edição. Rio de Janeiro: Campus, 1999. [14] V. Paxson. Known TCP Implementation Problems. Request for Comments 2525, March 1999. [15] M. Allman, V. Paxson, and W. Stevens. TCP Congestion Control. Request for Comments 2581, April 1999. [16] S. Floyd, and T. Henderson. The NewReno Modification to TCP's Fast Recovery Algorithm. Request for Comments 2582, April 1999. [17] C. Barakat, E. Altman, and W. Dabbous. On TCP Performance in a Heterogeneous Network: a Survey. IEEE Communications Magazine, January 2000. [18] M. Handley, J. Padhye, and S. Floyd. TCP Congestion Window Validation. Request for Comments 2861, June 2000. [19] S. Floyd, J. Mahdavi, M. Mathis, and M. Podolsky. An Extension to the Selective Acknowledgement (SACK) Option for TCP. Request for Comments 2883, July 2000. [20] D. Rubenstein, J. Kurose, and D. Towsley. Detecting Shared Congestion of Flows Via End-to-end Measurement. ACM SIGMETRICS’00. [21] V. Paxson, and M. Allman. Computing TCP's Retransmission Timer. Request for Comments 2988, November 2000. Marina Simon Becker 41