Перевод сделан автором сайта goxpert.ru
Краткое содежание перевода
- Сети могут вызывать проблемы, и устранение неполадок требует использования инструментов, таких как сетевые пространства имен, виртуальные машины, tc и netfilter.
- eBPF - это новая технология, которая добавляет улучшения в BPF и позволяет записывать данные в память и редактировать пакеты.
- eBPF используется для устранения сложных сетевых неполадок и может быть подключена через XDP или tc.
- Пример использования eBPF включает изменение флагов TCP и обработку пакетов, покидающих виртуальную машину.
- eBPF становится все более популярным и внедряется непосредственно в сетевые адаптеры оборудования.
- Хотя eBPF не является панацеей, она является мощным инструментом для сетевой отладки и заслуживает внимания.
Введение (Introduction)
Работать с сетями интересно, но часто они также являются источником проблем. Устранение неполадок в сети может быть сложным, а воспроизведение плохого поведения, происходящего в полевых условиях, также может быть болезненным.
К счастью, есть несколько инструментов, которые приходят на помощь: сетевые пространства имен( network namespaces ), виртуальные машины, tcи netfilter. Простые сетевые настройки могут быть воспроизведены с помощью сетевых пространств имен и veth устройств, в то время как более сложные настройки требуют подключения виртуальных машин к программному мосту и использования стандартных сетевых инструментов, таких как iptables или tc, для имитации некорректного поведения. Если у вас возникла проблема с ответами ICMP, генерируемыми из-за сбоя SSH-сервера, iptables -A INPUT -p tcp –dport 22 -j REJECT –reject-with icmp-host-unreachable использование правильного пространства имен или виртуальной машины может помочь.
В этой статье описывается использование eBPF ( extended BPF ), расширенной версии Berkeley Packet Filter, для устранения сложных сетевых неполадок. eBPF - довольно новая технология, и проект все еще находится на ранней стадии, документация и SDK еще не готовы. Но это должно улучшиться, особенно с учетом того, что XDP (экспресс-путь передачи данных - eXpress Data Path) поставляется в Red Hat Enterprise Linux 8, который вы можете загрузить и запустить прямо сейчас.
Хотя eBPF и не является серебряной пулей, я думаю, что это очень мощный инструмент для сетевой отладки, и он заслуживает внимания. Я уверен, что он сыграет действительно важную роль в будущем сетей.
Проблема (The problem)
Я отлаживал проблему с сетью Open vSwitch (OVS), повлиявшую на очень сложную установку: некоторые TCP-пакеты были скремблированы(разрознены) и доставлялись не по порядку, а пропускная способность между виртуальными машинами падала с устойчивых 6 Гбит / с до колеблющихся 2-4 Гбит / с. После некоторого анализа выяснилось, что первый TCP-пакет каждого соединения с установленным флагом PSH отправлялся не по порядку: только первый и только по одному на каждое соединение.
Я попытался повторить настройку с двумя виртуальными машинами, и после множества справочных страниц и поисков в Интернете я обнаружил, что оба iptables и nftables не могут изменять флаги TCP, хотя tc могли, но это может только перезаписать флаги, нарушая новые подключения и TCP в целом.
Вероятно, я мог бы справиться с этим, используя комбинацию iptables mark, conntrack и tc, но потом я подумал: это могло бы быть работой для eBPF.
Что такое eBPF? (What is eBPF?)
eBPF - это расширенная версия фильтра пакетов Berkeley. Он добавляет множество улучшений в BPF; в первую очередь, он позволяет записывать данные в память, а не просто считывать их, поэтому он также может редактировать пакеты в дополнение к их фильтрации.
eBPF часто называют BPF, в то время как BPF называется cBPF (классический BPF), поэтому слово BPF может использоваться для обозначения обоих, в зависимости от контекста: здесь я всегда имею в виду расширенную версию.
Изначально eBPF использует очень простую виртуальную машину с байт-кодом, которая может выполнять небольшие фрагменты байт-кода и редактировать некоторые буферы в памяти. eBPF поставляется с некоторыми ограничениями, предотвращающими его злонамеренное использование:
- Циклы запрещены, поэтому программа завершит работу через определенное время.
- Он не может получить доступ к памяти, кроме стека и резервного буфера.
- Могут вызываться только функции ядра из белого списка.
Загруженная программа может быть загружена в ядро многими способами, выполняя множество операций отладки и трассировки. В данном случае нас интересует, как eBPF работает с сетевой подсистемой. Есть два способа использования программы eBPF:
- Подключается через XDP к самому раннему пути RX физической или виртуальной сетевой карты
- Подключается через tc к qdisc точно так же, как обычное действие, при входе или выходе
Чтобы создать программу eBPF для подключения, достаточно написать некоторый код на C и преобразовать его в байт-код. Ниже простой пример использования XDP:
1 | SEC("prog") |
Приведенный выше фрагмент, лишенный include инструкций, помощников и всего ненужного кода, представляет собой программу XDP, которая изменяет TTL полученных эхо-ответов ICMP, а именно pongs, на случайное число. Основная функция получает struct xdp_md, который содержит два указателя на начало и конец пакета.
Чтобы скомпилировать наш код в байт-код eBPF, необходим компилятор с его поддержкой. Clang поддерживает его и создает байт-код eBPF, указывая bpf в качестве целевого во время компиляции:
1 | $ clang -O2 -target bpf -c xdp_manglepong.c -o xdp_manglepong.o |
Приведенная выше команда создает файл, который выглядит как обычный объектный файл, но при проверке вы увидите, что указанный тип компьютера будет Linux eBPF, а не собственный тип операционной системы:
1 | $ readelf -h xdp_manglepong.o |
После упаковки в обычный объектный файл, eBPF программа готова к загрузке и подключению к устройству через XDP. Это можно сделать с помощью ip из iproute2 пакета, используя следующий синтаксис:
1 | # ip -force link set dev wlan0 xdp object xdp_manglepong.o verbose |
Эта команда определяет целевой интерфейс wlan0, и с помощью -force опции она перезапишет любой существующий, уже загруженный код eBPF. После загрузки байт-кода eBPF система ведет себя следующим образом:
1 | $ ping -c10 192.168.85.1 |
Каждый полученный пакет проходит через eBPF, который в конечном итоге выполняет некоторое преобразование и решает отбросить или пропустить пакет.
Как eBPF может помочь (How eBPF can help)
Возвращаясь к исходной сетевой проблеме, мне нужно было изменить некоторые флаги TCP, только по одному на соединение, и ни iptables ни tc не разрешать это делать. Написать код на C для этого сценария было бы очень просто: настройте две виртуальные машины, соединенные мостом OVS, и просто подключите eBPF к одному из двух виртуальных устройств виртуальной машины.
Это выглядит как хорошее решение, но вы должны учитывать, что XDP поддерживает только обработку принятых пакетов, и подключение eBPF по rx пути принимающей виртуальной машины никак не повлияет на коммутатор.
Чтобы должным образом решить эту проблему, eBPF должен быть загружен с помощью tc и подключен по выходному пути внутри виртуальной машины, поскольку tc программы eBPF могут загружаться и подключаться к qdisc точно так же, как любое другое действие. Для обработки пакетов, покидающих хост, необходим выходной qdisc, к которому нужно подключить eBPF.
При загрузке программы eBPF между XDP и tc API есть небольшие различия: имя раздела по умолчанию отличается, аргумент функции main имеет другой структурный тип, и возвращаемые значения отличаются, но это не является большой проблемой. Ниже приведен фрагмент программы, которая выполняет искажение TCP при подключении к tc действию:
1 | #define RATIO 10 |
Компиляция в байт-код выполняется, как в предыдущем примере XDP, следующим образом:
1 | clang -O2 -целевой bpf -c tcp_psh.c -o tcp_psh.o |
Но загрузка отличается:
1 | # tc qdisc add dev eth0 clsact |
На этом этапе eBPF загружен в нужное место, а пакеты, покидающие виртуальную машину, искажены. Проверив полученные пакеты от второй виртуальной машины, вы можете увидеть следующее:
1 | # tcpdump -tnni eth0 -Q in |
tcpdump подтверждает, что новый код eBPF работает, и примерно в 1 из каждых 10 TCP-пакетов установлен флаг PSH. Используя всего 20 строк кода на C, мы выборочно искажали TCP-пакеты, покидающие виртуальную машину, воспроизводя ошибку, возникшую в полевых условиях, и все это без перекомпиляции какого-либо драйвера и даже без перезагрузки! Это значительно упростило проверку исправления Open vSwitch способом, который невозможно было выполнить с помощью других инструментов.
Заключение
eBPF - довольно новая технология, и сообщество придерживается твердого мнения по поводу ее внедрения. Также стоит отметить, что проекты на основе eBPF, такие как bpfilter, становятся все более популярными, и, как следствие, различные поставщики оборудования начинают внедрять поддержку eBPF непосредственно в свои сетевые карты(NIC).
Хотя eBPF не является серебряной пулей, и им не следует злоупотреблять, я думаю, что это очень мощный инструмент для сетевой отладки, и он заслуживает внимания. Я уверен, что он сыграет действительно важную роль в будущем сетей.
Дополнительные ресурсы
Статьи об Open vSwitch
Статьи об открытой виртуальной сети
Представляем stapbpf - новый серверный модуль BPF от SystemTap
Последнее обновление: 14 января 2022 г.