Alterando o valor do TCP RTO no Linux

12

Desejo alterar o valor do TCP RTO (tempo limite da retransmissão) para uma conexão, e algumas leituras feitas sugerem que eu poderia fazer isso, mas não revela onde e como alterá-lo.

Eu olhei para as /proc/sys/net/ipv4variáveis, mas nenhuma delas está relacionada ao RTO. Eu apreciaria se alguém pudesse me dizer como alterar esse valor.

obiigbe91
fonte
Isso não funciona para mim. No mínimo, incluindo 'ms' com o tempo rto, gera um erro! Eu consegui que o comando funcionasse, mas ss -i diz o contrário. Além disso, os 2 sysctl vars não existem. Estou executando em um kernel 4.4 #
Mark Seger
Eu tentei uma distro mais recente e tive sucesso fazendo ip route replace- parece que a ip routesintaxe mudou um pouco. Eu fui capaz de fazer a modificação com sucesso. Só para nota, você deve comentar sobre a resposta, não a pergunta se você quer me PING - Basicamente, eu vi isso por acidente, pura sorte que era recente :)
Adam C

Respostas:

30

A razão pela qual você não pode alterar o RTO especificamente é porque não é um valor estático. Em vez disso (exceto o SYN inicial, naturalmente), ele é baseado no RTT (Round Trip Time) para cada conexão. Na verdade, é baseado em uma versão suavizada do RTT e na variação do RTT com algumas constantes lançadas na mistura. Portanto, é um valor dinâmico calculado para cada conexão TCP, e eu recomendo este artigo que entra em mais detalhes sobre o cálculo e o RTO em geral.

Também relevante é a RFC 6298, que afirma (entre muitas outras coisas):

Sempre que o RTO é calculado, se for inferior a 1 segundo, o RTO DEVE ser arredondado para 1 segundo.

O kernel sempre define o RTO para 1 segundo? Bem, com o Linux, você pode mostrar os valores atuais de RTO para suas conexões abertas executando o ss -icomando:

State       Recv-Q Send-Q                                                  Local Address:Port     Peer Address:Port
ESTAB       0      0                                                           10.0.2.15:52861   216.58.219.46:http
     cubic rto:204 rtt:4/2 cwnd:10 send 29.2Mbps rcv_space:14600
ESTAB       0      0                                                           10.0.2.15:ssh          10.0.2.2:52586
     cubic rto:201 rtt:1.5/0.75 ato:40 cwnd:10 send 77.9Mbps rcv_space:14600
ESTAB       0      0                                                           10.0.2.15:52864   216.58.219.46:http
     cubic rto:204 rtt:4.5/4.5 cwnd:10 send 26.0Mbps rcv_space:14600

A descrição acima é a saída de uma VM na qual estou conectado com o SSH e tem algumas conexões abertas no google.com. Como você pode ver, o RTO é de fato definido como 200-ish (milissegundos). Você notará que não é arredondado para o valor de 1 segundo da RFC e também pode achar que é um pouco alto. Isso ocorre porque há limites mínimos (200 milissegundos) e máximos (120 segundos) em jogo quando se trata do RTO para Linux (há uma grande explicação sobre isso no artigo que eu linkei acima).

Portanto, você não pode alterar diretamente o valor do RTO, mas para redes com perdas (como a sem fio), você pode tentar ajustar o F-RTO (isso já pode estar ativado, dependendo da sua distribuição). Na verdade, existem duas opções relacionadas ao F-RTO que você pode ajustar (bom resumo aqui ):

net.ipv4.tcp_frto
net.ipv4.tcp_frto_response

Dependendo do que você está tentando otimizar, elas podem ou não ser úteis.

EDIT: acompanhamento da capacidade de ajustar os valores rto_min / max para TCP dos comentários.

Você não pode alterar o RTO mínimo global para TCP (aparte, você pode fazê-lo para SCTP - eles são expostos no sysctl), mas a boa notícia é que você pode ajustar o valor mínimo do RTO em uma rota por rota base. Aqui está minha tabela de roteamento na minha VM CentOS:

ip route
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15 
169.254.0.0/16 dev eth0  scope link  metric 1002 
default via 10.0.2.2 dev eth0

Eu posso alterar o valor rto_min na rota padrão da seguinte maneira:

ip route change default via 10.0.2.2 dev eth0 rto_min 5ms

E agora, minha tabela de roteamento fica assim:

ip route
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15 
169.254.0.0/16 dev eth0  scope link  metric 1002 
default via 10.0.2.2 dev eth0  rto_min lock 5ms

Por fim, vamos iniciar uma conexão e verificar ss -ise isso foi respeitado:

ss -i
State       Recv-Q Send-Q                                               Local Address:Port                                                   Peer Address:Port   
ESTAB       0      0                                                        10.0.2.15:ssh                                                        10.0.2.2:50714   
     cubic rto:201 rtt:1.5/0.75 ato:40 cwnd:10 send 77.9Mbps rcv_space:14600
ESTAB       0      0                                                        10.0.2.15:39042                                                 216.58.216.14:http    
     cubic rto:15 rtt:5/2.5 cwnd:10 send 23.4Mbps rcv_space:14600

Sucesso! O rto na conexão HTTP (após a alteração) é de 15 ms, enquanto a conexão SSH (antes da alteração) é de mais de 200 como antes.

Eu realmente gosto dessa abordagem - ela permite que você defina o valor mais baixo nas rotas apropriadas, em vez de globalmente, onde isso pode atrapalhar outro tráfego. Da mesma forma (consulte a página de manual do ip ), você pode ajustar a estimativa inicial do rtt e o rttvar inicial da rota (usada ao calcular o RTO dinâmico). Embora não seja uma solução completa em termos de ajustes, acho que a maioria das peças importantes está lá. Você não pode ajustar a configuração máxima, mas acho que em geral não será tão útil.

Adam C
fonte
Obrigado @ Adam C pelo esclarecimento, mas você mencionou o mínimo (200 mili) e o máximo (120s), posso alterar algum deles (mínimo ou máximo)? se sim, como ...?
obiigbe91
Acredito que sejam constantes no código, e não conheço uma maneira de defini-las dinamicamente, mas vou cavar um pouco e ver, pois presumo que alterar o código e compilar seu próprio kernel é um pouco demais :)
Adam C
Descobriu como ajustar rto_min e acrescentou que e um par de outras coisas relacionadas na resposta :)
Adam C
Por que não há nada parecido rto_max? Como definimos um tempo limite máximo global?
est
Se você definir o mínimo (ou aceitar o padrão) e, em seguida, alterar o número de tentativas ( net.ipv4.tcp_retries1e net.ipv4.tcp_retries2ou IIRC semelhante) permitido, acho que você pode obter um equivalente a um máximo de RTO.
Adam C