Эта программа обрабатывает пакеты с сетевого интерфейса, собирает статистику (количество полученных пакетов, количество полученных байт, распределение количества пакетов по их размерам) о трафике установленного вида и отправляет броадкастом полученную статистику по ubus.
- актуальное ядро Linux с поддержкой eBPF и XDP (проверено на 4.18);
- ubox и ubus с поддержкой Lua;
- luajit;
- libbcc.
-
Завести автоматические тесты с запуском
tcpreplay
, созданием виртуального сетевого интерфейса и валидацией полученной статистики; -
Провести ручное нагрузочное тестирование на реальном железе с Debian и посмотреть на производительность;
-
Перейти с lua-based конфига на что-то, что можно адекватно валидировать (ini/yaml/toml).
Целевая система: Debian 9 (stretch), amd64
Команды установки и запуска проверены вручную через Vagrant (образ
debian/stretch64
)
echo "deb http://deb.debian.org/debian stretch-backports main contrib non-free" | sudo tee /etc/apt/sources.list.d/backports.list && \
sudo apt-get update && \
sudo apt-get install -y linux-image-4.18.0-0.bpo.1-amd64 \
linux-headers-4.18.0-0.bpo.1-amd64 \
linux-compiler-gcc-6-x86=4.18.6-1~bpo9+1 \
luajit libjson-c3 git && \
wget http://tmp.nazaryev.ru/ifstat/{libbcc_0.7.0-1_all.deb,ubox-0.1.1-Linux.deb,ubus-0.1.1-Linux.deb} && \
sudo dpkg -i libbcc_0.7.0-1_all.deb ubox-0.1.1-Linux.deb ubus-0.1.1-Linux.deb && \
rm -f libbcc_0.7.0-1_all.deb ubox-0.1.1-Linux.deb ubus-0.1.1-Linux.deb && \
git clone https://github.com/3ap/ifstat && cd ifstat && \
git submodule init && \
git submodule update
sudo reboot # для перехода на новую версию ядра
cd ifstat
vi config.lua # настройка фильтров (формат см. ниже)
sudo /usr/sbin/ubusd &
sudo ./ifstatd.lua # запуск сервера (компиляция, инъекция eBPF, отправка)
sudo ./ifstat.lua # запуск клиента (отображение статистики от сервера)
В качестве конфига используется находящийся рядом с ifstatd.lua
файл config.lua
:
local _config = {
delay_ms = 500,
iface = "enp0s8",
filters = {
{
filter_num = 0, -- номер фильтра (от 0 до 4 включительно)
enabled = 1, -- включен (1) / выключен (0)
ipproto = IPPROTO_TCP, -- IPPROTO_TCP, IPPROTO_UDP или ANY
src_ip = "140.82.33.182", -- строка с IPv4 или ANY
dst_ip = ANY, -- аналогично src_ip
src_port = 22, -- номер UDP/TCP-порта или ANY
dst_port = ANY -- аналогично src_port
},
{
filter_num = 1,
enabled = 0,
},
...
}
Для того, чтобы собирать статистику максимально эффективно, используется интерфейс ядра eBPF. Этот интерфейс даёт возможность встроить код прямо в ядро, который будет подсчитывать необходимую статистику. Кроме того, для наибольшей производительности eBPF вешается на XDP-хук (eXpress Data Path), что позволяет получить доступ до пакета даже раньше, чем он будет обработан сетевым стеком ядра.
Основной код, задействованный в фильтрации и подсчёте статистики,
написан на Си (ifstat_kern.c
). Процессом компиляции и инъекцией
этого кода в ядро занимается lua-скрипт, основанный на официальных
байндингах проекта bcc (это фреймворк упрощает процесс
создания утилит, использующих eBPF).
-
Весь критичный к производительности код запускается в ядре и написан на Си, всё остальное (парсинг конфигов и командной строки, инъекция eBPF, вычитка готовых данных, отправка данных по ubus) можно написать на любом подходящем для этих задач языке;
-
Проект
bcc
официально поддерживает нативный интерфейс (библиотеку libbcc) для инъекции eBPF в ядро и байндинги к нему поддерживаются непосредственно разработчиком только для Lua и Python -- выбор сильно сужается; -
Проект
ubus
предоставляет только нативный интерфейс и Lua-байндинги; -
Идея написать с нуля и поддерживать байндинги для
bcc
илиubus
для других языков откидывается сразу.
Таким образом на выбор остаются только Си и Lua. Писать на Lua обработку конфигов и сериализацию/десериализацию данных значительно проще и приятнее, чем на Си, поэтому Lua и был выбран.