Таймер повторной передачи TCP в ядре linux
Вы можете настроить два хоста: отправителя и получателя. Настройте соединение между ними и отправьте некоторый трафик, скажем, передав большой файл. Снижение трафика с обеих сторон.
В то время как трафик отправляется, настроенное правило брандмауэра для удаления некоторых пакетов, вот пример случайного падения x%:
# for randomly dropping 10% of incoming packets:
iptables -A INPUT -m statistic --mode random \
--probability 0.1 -j DROP
очистка:
# for the incoming packets:
iptables -D INPUT -m statistic --mode random \
--probability 0.1 -j DROP
Если вы посмотрите на свой захват, вы увидите, что отправитель отправил пакеты несколько раз, чтобы преодолеть те, которые были удалены. Это показывает, что повторная передача работает.
Если вы накачаете падение до 100%, вы увидите повторные передачи только из-за таймаута.
Я решил проблему, и я думаю, я должен поделиться решением. Короче говоря, когда принимается ACK, таймер повторной передачи отключается, вызывая inet_csk_clear_xmit_timer. icsk_pending - это флаг внутри структуры inet_connection_sock. Этот флаг отменяется, когда принимается ACK для получения самых ранних выданных данных и, следовательно, таймер повторной передачи отключен. Из ядра linux 3.7
static inline void inet_csk_clear_xmit_timer(struct sock *sk, const int what)
{
struct inet_connection_sock *icsk = inet_csk(sk);
**if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) {
icsk->icsk_pending = 0;**
#ifdef INET_CSK_CLEAR_TIMERS
sk_stop_timer(sk, &icsk->icsk_retransmit_timer);
#endif
} else if (what == ICSK_TIME_DACK) {
icsk->icsk_ack.blocked = icsk->icsk_ack.pending = 0;
#ifdef INET_CSK_CLEAR_TIMERS
sk_stop_timer(sk, &icsk->icsk_delack_timer);
#endif
}
#ifdef INET_CSK_DEBUG
else {
pr_debug("%s", inet_csk_timer_bug_msg);
}
#endif
}
Он должен работать, иначе это не реализация TCP. См. RFC.
Можно было бы предположить, что к настоящему времени кто-то заметил, что часть системы не работает.
Что касается настройки - см. Параметры конфигурации в разделе /proc/sys/net/ipv4