Перейти к содержимому
Калькуляторы

Lunix. Как сделать tun mtu > 1480 ?

Проблема.

Нужно на IPIP туннеле в Linux выставить mtu > 1480. Например, 1520. Команда "ip link set tun0 mtu 1520 up" замечательно работает, не ругается и затем "ip link show" показывает, что mtu стоит 1520, однако реально он равен mtu интерфейса, через который уходят инкапсулированные пакетыв минус 20 байт. Это легко проверить с помощью "ping -s 1500 -M do ...". Если включен PMTU на tunX, то ICMP сообщение четко показывает актуальный mtu на tunX.

 

Предполагаю, что потребуется пересборка ядра. Прежде чем копаться глучже, хотел узнать, может кто решал уже эту проблему. В BSD, кстати, все замечательно работает. Сколько поставишь mtu на туннеле, столько реально и будет (в разумных пределах конечно, на все ведь есть свои ограничения).

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Краткий экскурс в проблему:

 

Собственно, поведение Linux в данной ситуации вполне разумно - понятно, что так делается для избежания излишней фрагментации больших пакетов. Однако, может возникать известная проблема. Несовпадение mtu у клиента (обычно 1500) с mtu на некоторых участках в сети провайдера (например, на туннелях, 1480), как известно, может приводить к нежелательной фильтрации пакетов большого размера с меткой DF (не фрагментировать).

Для решения этой проблемы есть специальный инструмент - PMTU, который подбирает MSS таким, чтобы пакеты этого размера с пометкой DF спокойно проходили от клиента до сервера (обычно, WEB). Механизм прост - если пришел слишком большой пакет с пометкой DF и он, например, не может упаковаться без фрагментации в туннель, то этот пакет отбрасывается, а отправителю посылается ICMP пакет с сообщением, каким должен быть максимальный размер сегмента в сети (MSS). Клиент уменьшает размер пакета и отправляется его снова, запоминая MSS для текущего TCP соединения.

Однако по ряду причин, PMTU может не работать. Самая распространенная из них - это фаервол на стороне клиента (к примеру, фильтруют все ICMP), причем клиент часто может отказываться подстраивать фаервол, а просто требует, чтобы все работало.

 

Что делают в таком случае? Есть разные варианты:

 

1. Принудительно заставлять все TCP соединения, проходящие через туннель, использовать подходящий MSS. Делают это с помощью фаервола. В Linux, например, так:

 

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

 

или так

 

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss <value>

 

2. Принудительно сбрасывать флаг DF с пакетов, проходящих через туннель. Обычно, для этого используют патч для ядра и, опять-таки, с помощью фаервола, проделывают такой трюк.

 

Оба эти метода замечательно работают, но есть одно исключение - большие пакеты UDP с пометкой DF.

 

В итоге, остается вариант, делать на всем пути следования таких пакетов mtu 1500, а на IPIP туннелях, соответственно, 1520. Вот, откуда и возник изначальный вопрос. Буду благодарен любому опыту в решении этого вопроса.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

C ipip не возился. Работал с openvpn - на нем ставится mtu больше чем в несущей сети. Но несчет больше 1500 не пробовал - прокидывал 1500 поверх 1480

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Проблема оказалась не в том, что mtu на туннеле не выставляется, а в том, что DF флаг переносится в заголовок IPIP пакета (капсулы).

Эксперименты описаны здесь http://forum.openvz.org/index.php?t=msg&am...msg_37870.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Жаль, что MaxGear не описал решение проблемы. В файле linux/net/ipv4/ipip.c надо изменить вот что:

--- 0ipip.c	2012-05-03 13:49:32.000000000 +0400
+++ ipip.c	2012-05-03 13:49:32.000000000 +0400
@@ -618,14 +618,14 @@
	iph 			=	ip_hdr(skb);
	iph->version		=	4;
	iph->ihl		=	sizeof(struct iphdr)>>2;
-	iph->frag_off		=	df;
+	iph->frag_off		=	0;
	iph->protocol		=	IPPROTO_IPIP;
	iph->tos		=	INET_ECN_encapsulate(tos, old_iph->tos);
	iph->daddr		=	rt->rt_dst;
	iph->saddr		=	rt->rt_src;

	if ((iph->ttl = tiph->ttl) == 0)
-		iph->ttl	=	old_iph->ttl;
+		iph->ttl	=	30;

	nf_reset(skb);

После изменения нужно пересобрать модуль ipip.

Изменение переменной iph->ttl нужно, только если TTL исходного пакета не хватает для прохождения внутри туннеля с учетом "внешних" хопов. В частности, в multicast-пакетах обычно TTL=1, поэтому они через туннель не пройдут, если "снаружи" больше 1 хопа. Число 30 взято из исходников FreeBSD'шного gif-интерфейса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

итого - прошло почти 3 года )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.