OpenVZ Forum


Home » International » Russian » Как сделать ipip tunnel mtu > 1480 ?
Как сделать ipip tunnel mtu > 1480 ? [message #37870] Thu, 29 October 2009 05:06 Go to next message
maxx is currently offline  maxx
Messages: 13
Registered: November 2008
Location: Volgograd, Russia
Junior Member
Использую контейнеры как виртуальные роутеры. Прокидываю в них вланы и туннели с нужных точек и подсетей, а внутри настраиваю все, что нужно клиенту (маршрутизацию, фаервол / nat, шейпинг и так далее). Использую также обычные ipip tunnel. У некоторых клиентов возникает проблема с mtu, так как большие пакеты с пометкой DF (не фрагментировать) через туннель 1480 байт не проходят.

Собственно, проблема. Описана также тут http://forum.nag.ru/forum/index.php?showtopic=52117.

Нужно на 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. Вот, откуда и возник изначальный вопрос. Буду благодарен любому опыту в решении этого вопроса.
Re: Как сделать ipip tunnel mtu > 1480 ? [message #37883 is a reply to message #37870] Thu, 29 October 2009 20:57 Go to previous messageGo to next message
RXL_ is currently offline  RXL_
Messages: 147
Registered: July 2009
Location: Moscow/Russia
Senior Member
Конечно, первое, что вызывает сомнение в правильности принятых решений - VE для маршрутизации. Linux обладает развитыми возможностями и не сложно настроить даже самую заковыристую маршрутизацию без множества VE. См. ip route help и параметр table в частности, а так же ip rule help и маркировку пакетов в iptables. Для каждого клиента можно сделать персональную таблицу маршрутизации.

Но все же по теме...

Вы не пробовали увеличить MTU сперва на физическом интерфейсе, а уже потом на туннеле?

На другом конце туннеля какое оборудование стоит? Может оно само соберет фрагменты, как это делает Linux?


... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Re: Как сделать ipip tunnel mtu > 1480 ? [message #37888 is a reply to message #37883] Fri, 30 October 2009 10:39 Go to previous messageGo to next message
maxx is currently offline  maxx
Messages: 13
Registered: November 2008
Location: Volgograd, Russia
Junior Member
По порядку:

1. "Для каждого клиента можно сделать персональную таблицу маршрутизации." Да, можно, но когда их хотя бы 100, это уже не прикольно. Использование VE просто упрощает настройки и дальнейшую поддержку абонентов. Хотя, конечно, это дело вкуса, использовать один роутер или много виртуальных.

2. Что касается физического интерфейса. Конечно, пробовал. Туннельный интерфейс действительно варьирует свой mtu в пределах до mtu физического, минус 20 байт. Однако, при попытке выставить mtu на физике > 1500 получаю вот такое:
SIOCSIFMTU: Invalid argument
Езернет в ядре линукс зажат на 1500.

Хотя, это, конечно, зависит от ядра, - пробовал на другом - работает, однако с другой стороны физического интерфейса управляемый свитч, на котором не выставить mtu > 1500, так что это не решает проблемы.

3. Про другой конец туннеля - иногда это не наше оборудование. И тут уже не все от нас зависит.

Собственно, мне кажется, что более логично затронуть настройки только туннеля (поднять mtu до 1520) с обоих концов, не трогая ничего другого. А этого как раз не могу сделать.

Уверен, что это можно поправить в ядре (или модуле ipip), но сам я не kernel developer, так что пока так глубоко не лезу...
Re: Как сделать ipip tunnel mtu > 1480 ? [message #37909 is a reply to message #37888] Sat, 31 October 2009 22:08 Go to previous messageGo to next message
RXL_ is currently offline  RXL_
Messages: 147
Registered: July 2009
Location: Moscow/Russia
Senior Member
1. На вкус и цвет, но с VE ресурсов используется больше.

2. Не надо грешить на Linux - это данный драйвер не позволяет. Возможно, что ограничение в драйвере связано с возможностями самой сетевой карты.

Вот примеры с разным железом. ОС одна и та же - CentOS 5.4 i386.

Контроллер Intel 82546EB.
# ip l s dev eth1 mtu 1540
# ip l sh dev eth1
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1540 qdisc pfifo_fast qlen 1000
    link/ether 00:30:48:2b:dd:e3 brd ff:ff:ff:ff:ff:ff
# ip l s dev eth1 mtu 1500
# ip l sh dev eth1
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:30:48:2b:dd:e3 brd ff:ff:ff:ff:ff:ff


Контроллер 3Com 3c940.
# ip l sh dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc prio qlen 1000
    link/ether 00:80:48:5d:cb:65 brd ff:ff:ff:ff:ff:ff
# ip l s dev eth0 mtu 1540
SIOCSIFMTU: Invalid argument


Только надо еще понимать, что весь транспортный путь должен поддерживать увеличенный MTU.

3. Невозможно увеличить MTU туннеля без увеличения MTU физического интерфейса - передача в туннеле пакетная. Вот если использовать прослойку с PPP, то можно MTU как угодно крутить, т.к. HDLC, используемый в PPP, обеспечивает битовый поток, независимый от нижележащего транспорта.


... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.

[Updated on: Sat, 31 October 2009 22:12]

Report message to a moderator

Re: Как сделать ipip tunnel mtu > 1480 ? [message #37931 is a reply to message #37870] Tue, 03 November 2009 13:20 Go to previous messageGo to next message
maxx is currently offline  maxx
Messages: 13
Registered: November 2008
Location: Volgograd, Russia
Junior Member
По пункту (2) полностью согласен. Действительно, с правильными картами mtu выставляется > 1500.

А вот с пунктом (3) не могу согласиться. Передача-то, конечно, пакетная, но ведь ip-фрагментацию никто не отменял.

В BSD все замечательно работает. MTU на езернете 1500 и на туннеле 1500. Если приходит пакет 1500 байт с DF, который надо поместить в туннель, то так как размер туннеля 1500, то он без проблем проходит инкапсуляцию. Итоговый пакет получается 1520 байт, но уже без DF, поэтому он подвергается ip-фрагментации и делится на 2 пакета - 1500 и 40 байт (это вместе с еще одним ip заголовком). В итоге, приложения клиента, использующие DF пакеты 1500 байт, работают без проблем.

Это нормальное поведение любого роутера (не важно, Linux, BSD или Cisco). И все это умеют, в том числе и Linux, конечно.
"Проблема" в том, что Linux не дает увеличить mtu туннеля больше mtu физики - 20. Абсолюно понятно, что это сделано для избежания излишней ip-фрагментации, так как это дополнительно нагружает роутер (фрагментация требует ресурсов роутера: cpu и ОЗУ).

Можно поднять mtu физики 1520, но тогда, как минимум, и на соседней точке нужно это сделать, но тогда ip-фрагментация просто переносится на другой узел сети, - чего хотелось бы избежать.

Собственно, мой вопрос в том, где правильнее отключить ограничение mtu на туннеле в Linux. Сам думаю, что нужно править ядро. Просто сам не имею опыта осмысленного изменения исходников ядра, так что прошу помощи. Может, кто знает, где и как это правильно поправить?

Поиском в инете нарыл, что есть патчи для ядер 2.4.x и 2.6.x, которые позволяют с помощью iptables снимать с пакетов DF. Но это тоже патчи, к тому же не понятно, заработают ли они корректно для OpenVZ.

Если есть решение проще, - буду рад узнать...

[Updated on: Tue, 03 November 2009 13:24]

Report message to a moderator

Re: Как сделать ipip tunnel mtu > 1480 ? [message #37933 is a reply to message #37931] Tue, 03 November 2009 18:40 Go to previous messageGo to next message
RXL_ is currently offline  RXL_
Messages: 147
Registered: July 2009
Location: Moscow/Russia
Senior Member
# ip t a tun1 mode ipip remote 1.2.3.4 dev eth0
# ip l s dev tun1 mtu 1500
# ip l sh dev tun1
6: tun1@eth0: <POINTOPOINT,NOARP> mtu 1500 qdisc noop
    link/ipip 0.0.0.0 peer 1.2.3.4
# ip l sh dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 100
    link/ether 00:17:31:5e:1d:cd brd ff:ff:ff:ff:ff:ff


Проверил с ipip и gre на ядрах 2.4.18 и 2.6.18. Без проблем сменил mtu. Чтобы проверить работоспособность нужно уже собирать модельку.



... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Re: Как сделать ipip tunnel mtu > 1480 ? [message #37936 is a reply to message #37933] Wed, 04 November 2009 13:53 Go to previous message
maxx is currently offline  maxx
Messages: 13
Registered: November 2008
Location: Volgograd, Russia
Junior Member
Да, выставляется - я об этом упоминал в начале задачи. Но, когда у меня большие пакеты через туннель с флагом DF не ходили с такой ошибкой "Frag needed and DF set (mtu = 1480)", то я подумал, что на туннеле не выставляется mtu реально больший, чем mtu физики, через которую уходят пакеты после инкапсуляции, однако был не прав - с туннелями и mtu на них все в порядке. Проблема в другом и теперь, после некоторых опытов, могу ее описать в правильном свете.

То, что я описал в предыдущем своем сообщении про ip-фрагментацию, все верно. Я думал, что проблема в том, что реальный mtu на туннеле в Linux не поднимается более mtu физики - 20, поэтому сделал между HN и VE veth-интерфейс с mtu 1540 (с запасом, на всякий случай). При таком раскладе mtu на туннеле внутри VE должен был бы работать не меньше 1520. Его я и выставил. Тогда на HN с VE должны были приходить бы пакеты большего, чем 1500 размера и фрагментироваться на HN, так как mtu реальных интерфейсов, как и положено - 1500.

Пустил пинг и получил тот же самый ответ:
Frag needed and DF set (mtu = 1480)

И тут меня заинтересовало, кто же мне дает такой ответ, неужели HN, так как это на нем интерфейсы с mtu 1500. И оказалось, что да. С помощью tcpdump внутри VE увидел, что получен ICMP ответ от HN "unreachable - need to frag (mtu 1500)" и проблема на самом деле в том, что когда в контейнере пакет с флагом DF проходит инкапсуляцию, то этот флаг переносится в заголовок IPIP-пакета (капсулы). И уже IPIP пакет с флагом DF и размером большим 1500 благополучно проходит veth от VE до HN, но натыкается на реальный интерфейс с mtu 1500 внутри HN, после чего, как и положено HN отвечает ICMP сообщением в сторону VE "unreachable - need to frag (mtu 1500)".

На всякий случай привожу выкладки эксперимента (VE 102).

На HN:
13: veth102.0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1540 qdisc noqueue
inet 192.168.11.1/30 scope global veth102.0

C HN доступна сеть, куда в том числе будем приземляться туннель (192.168.22.150).

Внутри VE102:
7: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1540 qdisc noqueue
inet 192.168.11.2/30 brd 192.168.11.3 scope global eth0
11: tun0@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1520 qdisc noqueue
link/ipip 192.168.11.2 peer 192.168.22.150
inet 192.168.100.13 peer 192.168.100.14/30 brd 192.168.100.15 scope global tun0

Есть еще 192.168.2.1/30 на eth1 интерфейсе, с которого буду пускать пинг в сеть 192.168.1.0/24, находящуюся на другой стороне туннеля.

[root@vr102 /]# ip ro
192.168.1.0/24 via 192.168.100.14 dev tun0
default via 192.168.11.1 dev eth0

На другом конце настройки аналогичные, ОС только не Linux. Да это и не столь важно...

Теперь сам тест - пускаю пинг с VE на 192.168.1.1.

[root@vr102 /]# ping -s 1452 -M do -I 192.168.2.1 192.168.1.1

Пинги ходят... Смотрю, что происходит...

[root@vr102 /]# tcpdump -nv -i tun0

tcpdump: listening on tun0, link-type RAW (Raw IP), capture size 96 bytes
04:43:08.156747 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1480) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17231, seq 1, length 1460
04:43:08.160526 IP (tos 0x0, ttl 255, id 45198, offset 0, flags [DF], proto: ICMP (1), length: 1480) 192.168.1.1 > 192.168.2.1: ICMP echo reply, id 17231, seq 1, length 1460
...

[root@vr102 /]# tcpdump -nv -i eth0
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
04:43:08.156767 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: IPIP (4), length: 1500) 192.168.11.2 > 192.168.22.150: IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1480) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17231, seq 1, length 1460
04:43:08.160526 IP (tos 0x0, ttl 252, id 45199, offset 0, flags [none], proto: IPIP (4), length: 1500) 192.168.22.150 > 192.168.11.2: IP (tos 0x0, ttl 255, id 45198, offset 0, flags [DF], proto: ICMP (1), length: 1480) 192.168.1.1 > 192.168.2.1: ICMP echo reply, id 17231, seq 1, length 1460
...

Аналогичные пакеты и на HN на интерфейсе veth102.0.
Как видно, флаг DF присутствует не только в IP-заголовке ICMP, но и в IP-заголовке IPIP пакета (капсулы, так сказать).

Увеличил размер пакета на 1:

[root@vr102 /]# ping -s 1453 -M do -I 192.168.2.1 192.168.1.1

[root@vr102 /]# tcpdump -nv -i tun0
04:43:15.777312 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1481) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17487, seq 1, length 1461
04:43:16.777686 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1481) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17487, seq 2, length 1461

(ICMP только в одну сторону, ответа нет)

[root@vr102 /]# tcpdump -nv -i eth0
04:43:15.777321 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: IPIP (4), length: 1501) 192.168.11.2 > 192.168.22.150: IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1481) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17487, seq 1, length 1461
04:43:15.777354 IP (tos 0xc0, ttl 64, id 62606, offset 0, flags [none], proto: ICMP (1), length: 576) 192.168.11.1 > 192.168.11.2: ICMP 192.168.22.150 unreachable - need to frag (mtu 1500), length 556
IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: IPIP (4), length: 1501) 192.168.11.2 > 192.168.22.150: IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto: ICMP (1), length: 1481) 192.168.2.1 > 192.168.1.1: ICMP echo request, id 17487, seq 1, length 1461[|icmp]

Собственно, только в этот момент я внимательнее вгляделся в вывод tcpdump и обратил внимание, что флаг DF перетекает из ICMP в заголовок IPIP пакета.

Обратил внимание также и на пакет от 192.168.11.1 (HN).

04:43:15.777354 IP (tos 0xc0, ttl 64, id 62606, offset 0, flags [none], proto: ICMP (1), length: 576) 192.168.11.1 > 192.168.11.2: ICMP 192.168.22.150 unreachable - need to frag (mtu 1500), length 556

Естественно, что он не может отдать пакет без фрагментации через реальный интерфейс. Он отвечает контейнеру "need to frag (mtu 1500)". А команда ping в свою очередь:

From 192.168.2.1 icmp_seq=3 Frag needed and DF set (mtu = 1480)
From 192.168.2.1 icmp_seq=3 Frag needed and DF set (mtu = 1480)
From 192.168.2.1 icmp_seq=3 Frag needed and DF set (mtu = 1480)
...

По этим 1480 байтам из ответа ping я изначально просто сделал неправильное предположение, что mtu туннеля реально не поднялся больше 1480. Ответ-то, якобы, от 192.168.2.1 - то есть от ip на моей стороне.


Так вот, правильные вопросы у меня теперь такие.
1. Как же правильно, переносить этот флаг DF d заголовок IPIP пакета (как в Linux) или не переносить (как в BSD) ?
2. Получается, что в Linux нужно только поправить модуль ipip, а не само ядро. Верно ? И правильно ли будет с этим обратиться к разработчикам OpenVZ ? Может вынести некоторый параметр в sysctl для выбора, как должны пакеты с флагом DF инкапсулироваться ?


P.S. Про использование контейнеров в качестве роутера. Все же есть в этом свои плюсы. Есть и минус - накладные расходы ресурсов. В нашем случае первое сильно перевешивает второе. Так что очень хочется довести проблему до ее решения.

[Updated on: Wed, 04 November 2009 16:02]

Report message to a moderator

Previous Topic: [solved] eth0 много dropped
Next Topic: Ломаются блокировки в samba
Goto Forum:
  


Current Time: Thu Apr 18 14:45:34 GMT 2024

Total time taken to generate the page: 0.01656 seconds