Админские байки: в погоне за фрагментацией туннелей в оверлейной сети

    Лирическое вступление


    Когда администраторы сталкиваются с неожиданной проблемой (раньше работало, и, вдруг, после обновления, перестало), у них существует два возможных алгоритма поведения: fight or flight. То есть либо разбиратся в проблеме до победного конца, либо убежать от проблемы не вникая в её суть. В контексте обновления ПО — откатиться назад.

    Откатиться после неудачного апгрейда — это, можно сказать, печальная best practice. Существуют целые руководства как готовиться к откату, как их проводить, и что делать, если откатиться не удалось. Целая индустрия трусливого поведения.

    Альтернативный путь — разбираться до последнего. Это очень тяжёлый путь, в котором никто не обещает успеха, объём затраченных усилий будет несравним с результатом, а на выходе будет лишь чуть большее понимание произошедшего.

    Завязка драмы


    Облако «Instant Servers» Webzillа. Рутинное обновление хоста nova-compute. Новый live image (у нас используется PXE-загрузка), отработавший шеф. Всё хорошо. Внезапно, жалоба от клиента: «одна из виртуалок странно работает, вроде работает, но как начинается реальная нагрузка, так всё замирает». Инстансы клиента переносим на другую ноду, проблема клиента решена. Начинается наша проблема. Запускаем инстанс на этой ноде. Картинка: логин по ssh на Cirros успешен, на Ubuntu — зависает. ssh -v показывает, что всё останавливается на этапе «debug1: SSH2_MSG_KEXINIT sent».

    Все возможные внешние методы отладки работают — метаданные получаются, DHCP-аренда инстансом обновляется. Возникает подозрение, что инстанс не получает опцию DHCP с MTU. Tcpdump показывает, что опция отправляется, но не известно, принимает ли её инстанс.

    Нам очень хочется попасть на инстанс, но на Cirros, куда мы можем попасть, MTU правильный, а на Ubuntu, в отношении которой есть подозрение о проблеме MTU, мы как раз попасть не можем. Но очень хотим.

    Если это проблема с MTU, то у нас есть внезапный помощник. Это IPv6. При том, что «белые» IPv6 мы не выделяем (извините, оно пока что не production-ready в openstack), link-local IPv6 работают.

    Открываем две консоли. Одна на сетевую ноду. Проникаем в network namespace:

    sudo stdbuf -o0 -e0 ip net exec qrouter-271cf1ec-7f94-4d0a-b4cd-048ab80b53dc /bin/bash
    

    (stdbuf позволяет отключить буфферизацию у ip net, благодаря чему вывод на экран появляется в реальном времени, а не с задержкой, ip net exec выполняет код в заданном network namespace, bash даёт нам шелл).

    На второй консоли открываем compute-node, цепляемся tcpdump к tap'у нашей ubuntu: tcpdump -ni tap87fd85b5-65.

    Изнутри namespace делаем запрос на all-nodes link-local мультикаст (эта статья не про ipv6, но суть происходящего вкратце: каждый узел имеет автоматически сгенерированный ipv6 адрес, начинающийся с FE80::, кроме того, каждый узел слушает на мультикаст-адресах и отвечает на запросы по ним. В зависимости от роли узла список мультикастов разный, но каждый узел, хотя бы, отвечает на all-nodes, то есть на адрес FF02::1). Итак, делаем мультикаст-пинг:

    ping6 -I qr-bda2b276-72 ff02::1
    PING ff02::1(ff02::1) from fe80::f816:3eff:fe0a:c6a8 qr-bda2b276-72: 56 data bytes
    64 bytes from fe80::f816:3eff:fe0a:c6a8: icmp_seq=1 ttl=64 time=0.040 ms
    64 bytes from fe80::f816:3eff:fe10:35e7: icmp_seq=1 ttl=64 time=0.923 ms (DUP!)
    64 bytes from fe80::f816:3eff:fe4a:8bca: icmp_seq=1 ttl=64 time=1.23 ms (DUP!)
    64 bytes from fe80::54e3:5eff:fe87:8637: icmp_seq=1 ttl=64 time=1.29 ms (DUP!)
    64 bytes from fe80::f816:3eff:feec:3eb: icmp_seq=1 ttl=255 time=1.43 ms (DUP!)
    64 bytes from fe80::f816:3eff:fe42:8927: icmp_seq=1 ttl=64 time=1.90 ms (DUP!)
    64 bytes from fe80::f816:3eff:fe62:e6b9: icmp_seq=1 ttl=64 time=2.01 ms (DUP!)
    64 bytes from fe80::f816:3eff:fe4d:53af: icmp_seq=1 ttl=64 time=3.66 ms (DUP!)
    

    Возникает вопрос — кто тут кто? По очереди пробовать зайти неудобно и долго.

    Рядом у нас в соседнем окне tcpdump, слушающий интерфейс интересующего нас инстанса. И мы видим в нём ответ только от одного IP — интересующего нас IP. Это оказывается fe80::f816:3eff:feec:3eb.

    Теперь мы хотим подключиться по ssh к этой ноде. Но любого, попробовавшего команду ssh fe80::f816:3eff:feec:3eb ждёт сюрприз — " Invalid argument".

    Причина в том, что link-local адреса не могут быть использованы «просто так», они имеют смысл только в пределах линка (интерфейса). Но ssh нет опции «использовать такой-то исходящий IP/интерфейс такой-то»! К счастью, есть опция по указанию имени интерфейса в IP-адресе.

    Мы делаем ssh fe80::f816:3eff:feec:3eb% qr-bda2b276-72 — и оказываемся на виртуалке. Да, да, я понимаю ваше возмущение и недоумение (если у вас его нет — вы ненастоящий гик, либо у вас много лет работы с IPv6). «fe80::f816:3eff:feec:3eb% qr-bda2b276-72» — это такой «ИП-адрес». У меня не хватает языка передать степень сарказма в этих кавычках. IP-адрес, с процентами и именем интерфейса. Интересно, что будет, если кто-то загрузит себе аватаркой что-то вроде http://[fe80::f816:3eff:feec:3eb%eth1]/secret.file с сервера в локалке веб-сервера на каком-нибудь сайте…

    … И мы оказываемся на виртуалке. Почему? Потому что IPv6 лучше, чем IPv4 умеет обрабатывать ситуации плохого MTU, благодаря обязательному PMTUD. Итак, мы на виртуалке.

    Я ожидаю увидеть неправильное значение MTU, идти в логи cloud-init'а и разбираться почему так. Но вот сюрприз — MTU правильный. Упс.

    В дебрях отладки


    Внезапно, проблема из локальной и понятной становится совсем не понятной. MTU правильный, а пакеты дропаются.… Если же подумать внимательно, то и с самого начала проблема была не такой уж простой — миграция инстанса не должна была поменять ему MTU.

    Начинается мучительная отладка. Вооружившись tcpdump'ом, ping'ом и двумя инстансами (плюс network namespace на сетевой ноде), разбираемся:

    • Локально два инстанса на одном compute друг друга пингуют с пингом максимального размера.
    • Инстанс с сетевой ноды не не пингуется (здесь и дальше — с пингом максимального размера)
    • Сетевая нода инстансы на других компьютах пингует.
    • Пристальное внимание к tcpdump'у внутри инстанса показывает, что когда сетевая нода пингует инстанс, он пинги видит и отвечает.

    Упс. Большой пакет доходит, но теряется по дороге обратно. Я бы сказал, asymmetric routing, но какой там к чёрту роутинг, когда они в соседних портах коммутатора?

    Пристальное внимание на ответ: ответ виден на инстансе. Ответ виден на tap'е. Но ответ не виден в network namespace. А как у нас обстоят дела с mtu и пакетами между сетевой нодой и компьютом? (внутренне я уже торжествую, мол, нашёл проблему). Рраз — и (большие) пинги ходят.

    Чо? (и длинная недоумевающая пауза).

    Что дальше делать не понятно. Возвращаюсь к оригинальной проблеме. MTU плохой. А какой MTU хороший? Начинаем экспериментировать. Бисекция: минус 14 байт от предыдущего значения. Минус четырнадцать байт. С какой стати? После апгрейда софта? Делаю vimdiff на список пакетов, обнаруживаю приятную перспективу разбираться с примерно 80 обновившимися пакетами, включая ядро, ovs, libc, и ещё кучу либ. Итак, два пути отступления: понизить MTU на 14 байт, либо откатиться назад и дрожать над любым апдейтом.

    Напомню, что о проблеме сообщил клиент, а не мониторинг. Так как MTU — это клиентская настройка, то «непрохождение больших пакетов с флагом DF» — это не совсем проблема инфраструктуры. То есть совсем не проблема инфраструктуры. То есть если оно вызвано не апгрейдом, а предстоящим солнечным затмением и вчерашним дождём, то мы даже не узнаем о возврате проблемы, пока кто-нибудь не пожалуется. Дрожать над апдейтом и опасаться неведомого о чём не узнаешь заранее? Спасибо, перспектива, о которой я мечтал всю свою профессиональную жизнь. А даже если мы понизим MTU, то почему четырнадцать байт? А если завтра станет двадцать? Или нефть подешевеет до 45? Как с этим жить?

    Однако, проверяем. Действительно, MTU чуть ниже в опциях DHCP, и перезагрузившийся инстанс отлично работает. Но это не выход. ПОЧЕМУ?

    Начинаем всё с начала. Возвращаем старый MTU, трейсим пакет tcpdump'ом ещё раз: ответ виден на интерфейсе инстанса, на tap'е… Смотрим tcpdump на сетевом интерфейсе ноды. Куча мелкого раздражающего флуда, но с помощью grep'а мы видим, что запросы приходят (внутри GRE), но ответы не уходят обратно.

    АГА!

    По крайней мере видно, что оно теряется где-то в процессе. Но где? Я решаю сравнить поведение с живой нодой. Но вот беда, на «живой» ноде tcpdump показывает нам пакеты. Тысячи их. В милисекунду. Добро пожаловать в эру tengigabitethernet. Grep позволяет из этого флуда наловить что-то, но вот нормального дампа получить уже не удастся, да и производительность такой конструкции вызывает вопросы.

    Фокусируемся на проблеме: я не знаю, как фильтровать трафик с помощью tcpdump'а. Я знаю, как отфильтровать по source, dest, port, proto и т.д., но как отфильтровать пакет по IP-адресу внутри GRE — я совершенно не знаю. Более того, это довольно плохо знает и гугль.

    До определённого момента я этот вопрос игнорировал, считая, что чинить важнее, но нехватка знания начала очень больно кусать. Коллега (kevit, которого я привлёк к вопросу, занялся им. Прислал ссылку tcpdump -i eth1 'proto gre and ( ip[58:4] = 0x0a050505 or ip[62:4] = 0x0a050505 )'.

    Ух. Хардкорный 0xhex в моих вебдванольных облачных сингулярностях. Ну, что ж. Жить можно.

    К сожалению, правило срабатывало неправильно или не срабатывало вовосе. Ухватив идею, методом brute force я поймал искомые смещения: 54 и 58 для source и dest IP-адресов. Хотя kevit показал откуда он взял смещения — и это выглядело чертовски убедительно. IP-заголовок, GRE, IP-заголовок.

    Важное достижение: у меня появился инструмент для прецизионного разглядывания единичных пакетиков в многогигабитном флуде. Разглядываем пакеты… Всё равно ничего не понятно.

    Tcpdump наш друг, но wireshark удобнее. (Я знаю про tshark, но он тоже неудобный). Делаем дамп пакетов (tcpdump -w dump, теперь мы его можем сделать), утаскиваем к себе на машину и начинаем разбираться. Я решил для себя разобраться с смещениями (из общей въедливости). Открываем в wireshark'е и видим…



    Смотрим на размеры заголовков и убеждаемся, что правильное смещение начала IP-пакета — 42, а не 46. Списав эту ошибку на чью-то невнимательность, я решил продолжить разбираться дальше на следующий день, и пошёл домой.

    Уже где-то совсем рядом с домом меня осенило. Если исходные предположения про структуру заголовков неверны, то это означает, что оверхед от GRE при туннелировании другой.

    Ethernet-заголовок, vlan, IP-заголовок, GRE-заголовок, инкапсулированный IP-пакет…

    Стоп. Но на картинке совсем другой заголовок. GRE в neutron'е инкапуслирует вовсе не IP-пакеты, а ethernet-фреймы. Другими словами, начальные предположения о том, какую часть MTU на себя отъедает GRE неверны. GRE «берёт» на 14 байт больше, чем мы рассчитывали.

    Нейтрон строит overlay network поверх IP с помощью GRE, и это L2 сеть. Разумеется, там должны быть инкапуслированные ethernet-заголовки.

    То есть MTU и должен быть на 14 байт меньше. С самого начала. Когда мы планировали сеть, предположения про cнижение MTU из-за GRE, мы сделали ошибку. Довольно серьёзную, так как это вызывало фрагментацию пакетов.

    Ладно, с ошибкой понятно. Но почему после обновления оно переставало работать? По предыдущим изысканиям стало понятно, что проблема связана с MTU, неверным учётом заголовка GRE и фрагментацией GRE-пакетов. Почему фрагментированные пакеты перестали проходить?

    Внимательный и пристальный tcpdump показал ответ: GRE стал отсылаться с DNF (do not fragment) флагом. Флаг появлялся только на GRE-пакетах, которые инкапсулировали IP-пакеты с DNF флагом внутри, то есть флаг копировался на GRE из его полезной нагрузки.

    Для пущей уверенности я посмотрел на старые ноды — они фрагментировали GRE. Шёл основной пакет, и хвостик с 14 байтами полезной нагрузки. Вот так ляп…

    Осталось выяснить, почему это началось после апгрейда.

    Чтение документации


    Самыми подозрительными на регрессию пакетами были Linux и Openvswitch. Readme/changelog/news не прояснило ничего особенного, а вот инспекция git'а (вот и ответ, зачем нам нужен открытый исходый код — чтобы иметь доступ к Документации) открыла что-то крайне любопытное:

    commit bf82d5560e38403b8b33a1a846b2fbf4ab891af8
    Author: Pravin B Shelar <pshelar@nicira.com>
    Date:   Mon Oct 13 02:02:44 2014 -0700
    
        datapath: compat: Fix compilation 3.11
        
        Kernel 3.11 is only kernel where GRE APIs are available but
        not vxlan. Add check for vxlan xmit to detect this case.
    


    Сам патч ничего интересного из себя не представляет и к сути дела не относится, но зато даёт подсказку: GRE API в ядре. А у нас апгрейд с 3.8 до 3.13 как раз происходил. Гуглим в бинге… Находим патч в openvswitch (datapath module), в ядре: git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=aa310701e787087dbfbccf1409982a96e16c57a6. Другими словами, как только у нас ядро начинает предоставлять сервисы GRE, ядерный модуль openvswitch передаёт обработку gre в модуль ядра ip_gre. Изучаем код ip_gre.c, спасибо за комментарии в нём, да, мы все «любим» циску.

    Вот заветная строчка:

    static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
    {
        struct ip_tunnel *t = netdev_priv(dev);
        struct ip_tunnel_parm *p = &t->parms;
    
        if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
            ....
            nla_put_u8(skb, IFLA_GRE_PMTUDISC,
                   !!(p->iph.frag_off & htons(IP_DF))))
    
    


    Другими словами, ядро копирует IP_DF из заголовка инкапсулируемого пакета.

    (Внезапный интересный оффтопик: Linux копирует из оригинального пакета так же и TTL, то есть GRE-туннель «наследует» TTL у инкапсулируемого пакета)

    Сухая выжимка


    Самолёт упал, потому что по направлению полёта оказалась Земля.

    Во время начальной настройки инсталляции мы выставили MTU для виртуальных машин в рамках ошибочного предположения. Из-за механизма фрагментации мы отделались незначительной деградацией производительности. После апгрейда ядра с 3.8 на 3.13, OVS переключился на ядерный модуль ip_gre.c, который копирует флаг do not fragment из исходного IP-пакета. Большие пакеты, которые не «влазили» в MTU после дописывания к ним заголовка, больше не фрагментировались, а дропались. Из-за того, что дропался GRE, а не вложенный в него пакет, ни одна из сторон TCP-сесии (посылающей пакеты) не получала ICMP-оповещений о «непроходимости», то есть не могла адаптироваться к меньшему MTU. IPv6 в свою же очередь, не рассчитывал на наличие фрагментации (её нет в IPv6) и обрабатывал потерю больших пакетов правильным образом — уменьшая размер пакета.

    Кто виноват и что делать?


    Виноваты мы — ошибочно выставили MTU. Едва заметное поведение в ПО привело к тому, что ошибка начала нарушать работу IPv4.

    Что делать? Мы поправили MTU в настройках dnsmasq-neutron.conf (опция dhcp-option-force=26,), дали клиентам «отстояться» (обновить аренду адреса по DHCP, вместе с опцией), проблема полностью устранена.

    Можно ли такое обнаружить мониторингом упреждающе? Сказать честно, разумных вариантов я не вижу — слишком тонкая и сложная диагностика, требующая крайней кооперации со стороны клиентских инстансов (на это мы полагаться не можем — вдруг, кто-то, по собственным нуждам, пропишет что-нибудь странное с помощью iptables?).

    Лирическое заключение


    Вместо того, чтобы трусливо откатиться на предыдущю версию ПО и занять позицию «работает — не трогай», «я не знаю, что поменяется, если мы обновимся, так что обновляться мы больше никогда не будем», было потрачено примерно 2 человекодня на отладку, но была решена не только локальная (видимая) регрессия, но и найдена и устранена ошибка в существующей конфигурации, повышающая оверхед от работы сети. Помимо устранения проблемы ещё значительно улучшилось понимание используемых технологий, была разработана методика отладки сетевых проблем (фильтрация трафика в tcpdump по полям внутри GRE).

    Комментарии — сила


    Внезапно, в комментариях ildarz подсказал отличную идею, как находить подобное — смотреть статистику IP и реагировать на рост числа фрагментов (/proc/net/snmp, netstat -s). Я ещё не изучил это вопроса, но он выглядит очень перспективно.
    Webzilla
    0,00
    Компания
    Поделиться публикацией

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 35

      +1
      Здорово, что так все получилось. И отдельно круто, что это все уложилось в пару человекодней — например, для тех команд, с которыми я взаимодействую, я бы выставлял первоначальную оценку «на покопаться» без гарантий результата в пару-тройку человеконедель. Тут, конечно, повезло, что в changelog'ах что-то получилось найти, но в целом скорость работы — прокопать такое за пару дней — впечатляющая. И инфраструктура должна быть весьма отточенная для такого.
        +2
        Ну, я изложил сильно прилизанную историю. В процессе там был ещё случайно поставленный в нашем роутере (для тестового тенанта) mtu 1400, который мне изрядно попил крови, ибо я совсем офигевал от цифры 1400 в MTU, некоторое количество глупостей и ложных следов (я в какой-то момент заподозрил, что это KVM tap'ы портит и полез не туда читать).

        Но основное, это, конечно, доступные сырцы. Для проприетарного оно бы так и осталось загадкой.
          0
          Т.е. «два человекодня» — это не оценка «сколько получилось», а «сколько должно было бы получиться, если бы все разбирательство шло сразу по оптимальному маршруту»?

          Для проприетарного — все превращается в пинание мячика с очередными китайцами / индусами / кем-нибудь подобным из IBM / HP / EMC / Dell / Cisco / кем-нибудь таким… Решить можно, но да, обычно на порядок-два дольше и в итоге, как правило, совсем нерентабельно, если только ты не какой-нибудь гугл или фейсбук, чтобы у вендора был стимул довести решение до рабочего состояния, а не пройти очередной раз по маршруту вида «мы с вашей железкой уже полгода копаемся, у нас вон вообще новая вышла — покупайте, что ли, ее, мигрируйте, а там видно будет — и баг этот ваш скорее всего пройдет».
            0
            Я занимался не только этой штукой, реально история заняла по wallclock примерно три дня, первый день я сильно затупил на mtu 4000, поставленным внутри виртуального роутера у нашего тестового тенанта.

            Да, я наблюдал это перепинывание с Juniper'ом, когда их SRX намертво подвисал при маленьком флуде PUP-пакетами на входящих интерфейсах. Индусы честно собрали стенд, воспроизвели проблему. За те пол-года, как я наблюдал за историей, никаких подвижек не было.
              0
              Ну, в итоге-то все как бы грустно и утыкается в то, что, например, насколько я понимаю, внутреннее устройство ядра какого-нибудь IOS'а или хотя бы какого-нибудь MegaRAID — представляют что-нибудь типа десяток человек на этой планете. Эти люди загружены работой на ближайшие лет 10-20, и индусы из внедрения, очевидно, в их число не входят.
                0
                Ну, IOS это фатально, да. А MegaRAID в случае затруднений локализуется (по появляющейся проблеме) и заменяется на HBA.

                Другое дело, что SAS HBA — это тот ещё лес со своим интеллектом и глюками. На удивление, наиболее беспроблемными были обычные интеловские южные мосты с AHCI.
                  0
                  Эх, умели бы еще эти чудесные южные мосты больше 5-6 дисков — цены б им не было.

                  А так — да, у меня на самом деле особенно к производителям storage за последние пару недель какая-то объективная ненависть нарастает. Ну, блин, как можно было до такого ада в индустрии дойти — «ах, у нас есть SMART, но мы вам не скажем, что он показывает, это наша Большая Военная Тайна»…
                    0
                    Есть ещё smartctl -x, там иногда лог ошибок можно почитать. Это в контексте дисков, конечно.
                      0
                      Да я как бы в курсе… На самом деле — сколько смотрю уже из опыта за последние лет 5 — у меня чем дальше, тем больше зреет ненулевое желание отказаться от SMART нафиг.

                      Меня по сути не очень интересует окончательная смерть конкретного диска — ее распознают вполне штатными средствами и диск поменяют. Меня не интересует предварительная сигнализация о скорой смерти диска (по первоначальной задумке полезная для унылых «домашних» пользователей десктопа-с-одним-жестким-диском-без-бэкапов) — мне не нужно в этом случае внезапно начинать рвать волосы и пытаться спасти с диска хоть что-нибудь. Сдохнет — и фиг с ним, на новый данные накатятся из реплики и будет все ок.

                      Гораздо неприятнее когда диск стабильно начинает ощутимо тормозить (в 2-3-5-10-100 раз) или внезапно впадать в ступоры по 3-5 секунд (что внезапно будет означать падение iops до эдак ~0.2..0.3) — при этом в SMART все кристально чисто, якобы формальных поводов для тревоги нет. Разумеется, будучи элементом какого-либо массива или распределенной файловой системы, внезапно, от такого «слабого звена» начинает страдать весь массив или ФС.

                      Универсального рецепта я для себя так пока и не выработал. По идее хорошо бы проводить время от времени эталонные тесты и замеры скоростей всех шпинделей, но для этого надо вводить в систему некие интервалы на обслуживание — скажем, объявлять каждую ночь пятиминутку тестирования, когда приостанавливается вся дисковая активность и мы прогоняем тесты. К сожалению, на практике так делать можно далеко не всегда — для того же вычислительного кластера, скажем, тупо остановка может занимать минут 30-40, а потом еще минут 15 на запуск — терять час времени в сутки печально. Если на диски все время идет некая более-менее равномерная активность — то можно обойтись без тестов и мерять среднее значение этой активности. Но это тоже не универсальный рецепт — далеко не везде есть равномерная активность…
                        0
                        Я про SCT ERC давно уже писал: geektimes.ru/post/92701/
                          0
                          Про ERC я тоже в курсе. До ERC в этих случаях не доходит — здесь нет такого, чтобы запрошенный сектор или чанк читался больше ERC-времени (или соответствующих count'ов в SAS) — конкретный сектор-то прочитается, а вот средняя скорость будет очень печальной (ну или не очень, а просто печальной — внезапные 15-20 МБпс вместо положенных 80-100, скажем — уже печально).

                          Выставлять таймауты ERC в какие-то сильно маленькие значения желания тоже нет — в конце концов, совершенно не хочется иметь перспективу умирающего на пустом месте сервера / деградирующего и всех соответствующих перестроений из-за одной случайной мелочи.

                          В идеале хотелось бы видеть именно то, для чего изначально был придуман SMART — четко видеть остаток ресурса HDD и его деградацию со временем. SMART же в текущем его состоянии годится в лучшем случае различать 3 состояния «вроде бы жив, почти мертв, мертв». Если не повезет — то даже 2 крайних.
        +1
        … копирует флаг do not fragment из исходного IP-пакета. Большие пакеты, которые не «влазили» в MTU после дописывания к ним заголовка, больше не фрагментировались, а дропались.


        Это объясняет, почему перестали проходить пинги с явно выставленным DF, но почему обычный трафик отваливался?

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


        А фрагментацию пакетов мониторить не получится?
          0
          Честно, не разбирался, но, подозреваю, что это связано с реализацией PMTUD в TCP на IPv4, которая ожидает получения ICMP о превышении размера. Оно должно было отработать, если бы пакет не пролезал в роутер, но вместо этого не пролезал в интерфейс уже GRE-пакет. Хост слал ICMP отправителю GRE, а до отправителя TCP оно не доходило, так что TCP тупило до упора. В сравнении с этим TCP IPv6 обрабатывает эту ситуацию не ожидая ICMP.

          Мониторить фрагментацию… Идея интересная, но я метрик пока не видел. Найду, сделаем.
            0
            А фрагментацию пакетов мониторить не получится?

            А она разве сама по себе что-то говорит? Даже если выделить пакеты одного клиента и найти среди них фрагментированные — то надо вводить тучу каких-то неочевидных, вычислительно сложных и, самое главное, сильно зависящих от типового трафика клиента правил типа «два больших пакета = хорошо, а один большой и один обкусок на 12 байт = плохо». Не говоря уже о том, что это все надо делать на потоке из скольких-то там миллионов пакетов в секунду…
              0
              Тут проблема в другом — у нас были фрагменты на контролируемых нами интерфейсов, то есть у нас были кривые MTU.
                0
                А, т.е., грубо говоря, в этом конкретном роутере правильное количество фрагментаций должно быть 0?
                  0
                  Не роутере. Схема openstack'а: инстансы работают на compute, их трафик попадает в overlay network, откуда отсылается на сетевые ноды, откуда уже уходит в интернеты (и обратно аналогично). В этой схеме пользовательский трафик ходит только в туннелях, то есть «голыми» на интерфейсах есть только служебные (контролируемые нами) пакеты. Если с нашей стороны всё настроено правильно, то фрагменты не должны возникать.
              +1
              Внезапно, netstat -s показывает количество фрагментов. С учётом, что у нас интерфейсы на compute контролируются только нами, их быть не должно. Спасибо большое, будем мониторить.
                0
                Ещё можно снимать счётчики с правила iptables, в котором в качестве селектора фигурирует "-f".
                  +1
                  Тогда уж лучше cat /proc/net/snmp | grep '^Ip:'. Формат, правда, у всего этого snmp-подобного, мягко говоря, не очень удобный.
                    0
                    Спасибо, да.
                0
                В tshark (ключик -R) можно пофильтровать все, хоть черта лысого, так же как и в wireshark. очень полезный навык при дебаге всяких сетевых непоняток.
                  0
                  От wireshark'а меня интересуют не фильтры, а «потыкать мышкой по пакету». Для остального tcpdump и pcap-filter справляются.
                    0
                    Сам же в статье написал что не справилось.
                      0
                      Эм… Тут всё сложнее. И wireshark, и tcpdump не фильтруют сами, а используют механизм pcap-filter, который фильтрует пакеты в ядре, и интересные присылает по netsocket'у. То есть если pcap в нормальном режиме не отработает, то он одинаково не отработает у всех. То есть правило для tshark'а будет выглядеть так же, как для wireshark'а — с указанием диапазона байтов и hex-кодов.
                        +1
                        У wireshark/tshark есть еще и свои фильтры. Которые позволяют сделать например так:

                        tgz@dhcp1 ~ % sudo tshark -i eth0 -R «bootp.type == 1»
                        Running as user «root» and group «root». This could be dangerous.
                        Capturing on eth0
                        34.743298 10.11.64.64 -> 172.33.193.81 DHCP 333 DHCP Request — Transaction ID 0x30cd1ee4
                        34.743687 10.11.64.64 -> 172.33.193.81 DHCP 333 DHCP Request — Transaction ID 0x30cd1ee4
                        34.743854 10.11.64.64 -> 172.33.193.81 DHCP 333 DHCP Request — Transaction ID 0x30cd1ee4
                        34.743934 10.11.64.64 -> 172.33.193.81 DHCP 333 DHCP Request — Transaction ID 0x30cd1ee4

                        Как видим, никаких диапазонов и прочей hex'овни. Причем фильтр сработает даже если этот DHCP пакет был внутри GRE, который внутри IP, который внутри PPP, который внутри MPLS и так далее.

                          0
                          О, а вот это уже очень интересно. Я исходил из предположения, что там у всех pcaps без вариантов. Сейчас поиграюсь, спасибо.

                          … wow. Он ловит грешный трафик. Спасибо!
                            +1
                            Там очень серьёзные фильтры.
                            Была задача собирать логи звонков с H.323, проходящего транзитом через микротик.
                            Оказалось, что всё декодирование можно сделать консольным tshark'ом — он легко достаёт всю необходимую информацию из туннеля TZSP (в нём микротик отдаёт зеркалированный трафик), в котором лежат пакеты с Q.931.
                  +2
                  Великолепно. Напомнило старую историю об электронной почте, которая «не ходит дальше 300 миль» =) Тоже регрессия после обновления, ага.
                    0
                    500 же вроде %) Но да, чем-то похоже ;)
                    +1
                    Кажется, что наследование DF протоколом GRE из IP, это баг.
                      0
                      Промахнулся ответом, см. чуть ниже.
                      +1
                      Сложный вопрос. Я нашёл место, где его добавили (почти) текущий код:

                      commit c19e654ddbe3831252f61e76a74d661e1a755530
                      Author: Herbert Xu <herbert@gondor.apana.org.au>
                      Date: Thu Oct 9 11:59:55 2008 -0700

                      gre: Add netlink interface

                      This patch adds a netlink interface that will eventually displace
                      the existing ioctl interface. It utilises the elegant rtnl_link_ops
                      mechanism.

                      This also means that user-space no longer needs to rely on the
                      tunnel interface being of type GRE to identify GRE tunnels. The
                      identification can now occur using rtnl_link_ops.

                      Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
                      Signed-off-by: David S. Miller <davem@davemloft.net>



                      + NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));

                      Но при этом убрали функцию ipgre_tunnel_init, а к ней есть такой потрясающий комментарий в модуле:

                      2. Networking dead loops would not kill routers, but would really
                      kill network. IP hop limit plays role of «t->recursion» in this case,
                      if we copy it from packet being encapsulated to upper header.
                      It is very good solution, but it introduces two problems:

                      — Routing protocols, using packets with ttl=1 (OSPF, RIP2),
                      do not work over tunnels.
                      — traceroute does not work. I planned to relay ICMP from tunnel,
                      so that this problem would be solved and traceroute output
                      would even more informative. This idea appeared to be wrong:
                      only Linux complies to rfc1812 now (yes, guys, Linux is the only
                      true router now :-)), all routers (at least, in neighbourhood of mine)
                      return only 8 bytes of payload. It is the end.

                      Hence, if we want that OSPF worked or traceroute said something reasonable,
                      we should search for another solution.

                      One of them is to parse packet trying to detect inner encapsulation
                      made by our node. It is difficult or even impossible, especially,
                      taking into account fragmentation. TO be short, tt is not solution at all.

                      Current solution: The solution was UNEXPECTEDLY SIMPLE.
                      We force DF flag on tunnels with preconfigured hop limit,
                      that is ALL. :-) Well, it does not remove the problem completely,
                      but exponential growth of network traffic is changed to linear
                      (branches, that exceed pmtu are pruned) and tunnel mtu
                      fastly degrades to value <68, where looping stops.
                      Yes, it is not good if there exists a router in the loop,
                      which does not force DF, even when encapsulating packets have DF set.
                      But it is not our problem! Nobody could accuse us, we made
                      all that we could make. Even if it is your gated who injected
                      fatal route to network, even if it were you who configured
                      fatal static route: you are innocent. :-)


                      То есть раньше GRE всегда шёл с DNF, потом требования смягчили. А у собственной реализации OVS это поведение настраивается опциями, то есть в процессе переключения неявно поменяли дефолты в OVS'е и отключили один из вариантов поведения. Линукс винить нельзя, OVS винить нельзя, нас винить нельзя, никто не виноват, а на выходе оно работает «не так».

                      Потрясающая история даже вне контекста беготни за MTU.
                        +1
                        История несомненно увлекательная! Но у меня возник вопрос про MTU на виртуалках. Зачем там MTU меньше чем 1500?
                        Мне, как конечному пользователю, привычнее видеть MTU = 1500 байт. Опять же чем меньше MTU тем больше overhead стека TCP/IP.
                        Разве не лучше увеличить MTU на сетевом оборудовании датацентра и спрятать туда весь транспортный overhead оверлейных сетей?
                          0
                          Специфичные ограничения оборудования. В общем случае, да, сделать jumbo и поднять MTU на интерфейсах до 1542 будет чуть-чуть эффективнее. На практике, при правильно выставленном MTU, разницы почти никакой (меньше 3%).

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое