Поддержка в сетевом стеке драйверов различных типов
В этой главе:
Сетевой стек поддерживает следующие типы драйверов:
Современные драйвера можно отличить от legacy драйверы по имени:
Драйверы NetBSD менее тесно интегрированы в стек io-pkt-*. Поскольку в операционной системе NetBSD они работают с отключенными прерываниями, в них, как правило, реже возникают неполадки с мьютексами при отправке и приеме пакетов. Если драйвер напрямую портирован из NetBSD, стек по умолчанию работает в однопоточном режиме для предотвращения возможных проблем с синхронизацией передачи и приема в многопоточной среде. Если драйвер тщательно проверен и его методы синхронизации работают корректно, при его присоединении к стеку можно указать флаг, который разрешает выполнение в многопоточном режиме.
![]() | Если один драйвер работает в однопоточном режиме, все остальные драйверы также будут работать в однопоточном режиме. |
Все современные драйверы и портированные из NetBSD подключаются непосредственно к стеку схожим образом. Legacy драйверы взаимодействуют со стеком io-pkt-* с помощью интерфейса-прокладки ( shim), который преобразует двоичный интерфейс устаревшего стека в совместимый интерфейс io-pkt-*. В состав ЗОСРВ «Нейтрино» входит специальный драйвер-прокладка devnp-shim.so, который автоматически загружается при запуске legacy драйвера и обеспечивает двоичную совместимость с существующими legacy драйверами. Таким образом, эти драйверы также не имеют тесного сопряжения со стеком — например, они не могут использовать функции динамической настройки среды передачи и пакеты Jumbo. Поскольку эти драйверы работают в контексте устаревшего стека, их эффективность ниже, чем у современных драйверов. Помимо приема и передачи пакетов, драйверы устройств могут интегрировать функции ускорения аппаратного кодирования непосредственно в стек.
Информацию о конкретных драйверах можно найти в разделах:
Существует тонкая грань между драйверами, которые написаны специально для стека io-pkt-*, и портированными драйверами. Если перенос выполнен тщательно, функциональные возможности конечного и исходного драйверов практически одинаковы, однако имеется ряд нюансов:
По этой причине флаг в конфигурации драйвера по умолчанию указывает, что он не поддерживает многопоточное выполнение. В результате весь стек работает в однопоточном режиме (если один драйвер не поддерживает многопоточное выполнение, все остальные драйверы также работают в однопоточном режиме). Можно изменить этот флаг, если тщательная проверка драйвера показывает, что в нем отсутствуют ошибки синхронизации.
Тем не менее, в ЗОСРВ «Нейтрино» функция delay() принимает время в миллисекундах, что может приводить к очень длительным задержкам при ее использовании в драйверах в существующем виде. Мы определили функцию DELAY(), которая преобразует время задержки из микросекунд в миллисекунды, поэтому во всех драйверах, портированных из NetBSD, необходимо заменять delay() на DELAY().
Между legacy драйверами и другими драйверами существуют следующие различия:
/dev/io-net/enx
в пространстве имен, а современные драйверы — нет. ![]() | По этой причине ожидание появления указанного имени с помощью команды waitfor в файлах сборки и сценариях работает некорректно. Вместо команды waitfor /dev/io-net/en0 следует использовать команду if_up -p en0. |
Драйверы можно загружать в сетевой стек io-pkt-* с помощью командной строки:
io-pkt-v4-hc -di82544
Эту команду можно применять как к современным драйверам, так и к legacy. Стек автоматически определяет тип драйвера и загружает библиотеку devnp-shim.so для legacy драйверов.
![]() | Можно не задавать полное имя устройства в командной строке при условии, что все драйверы находятся в каталогах, указанных в переменной окружения LD_LIBRARY_PATH. |
Также можно монтировать драйвер стандартным способом с помощью утилиты mount:
mount -Tio-pkt /lib/dll/devnp-i82544.so
Для обратной совместимости с существующими сценариями команда mount по-прежнему поддерживает параметр io-net:
mount -Tio-net /lib/dll/devnp-i82544.so
Стандартным способом удаления драйвера из стека является команда ifconfig iface destroy. Пример:
ifconfig wm0 destroy
При возникновении неполадок первым инструментом для отладки любых сетевых драйверов (помимо ifconfig) является утилита nicinfo. Она позволяет определять корректность согласования параметров канального уровня драйвером и наличие/отсутствие приема/передачи пакетов.
Убедитесь, что демон slogger работает, и после возникновения неполадки запустите утилиту sloginfo, чтобы определить наличие диагностической информации от драйвера. Чтобы получать от драйвера более подробную диагностическую информацию, следует передать ему командно-строковый параметр verbose. Многие драйверы поддерживают различные уровни детализации диагностической информации; можно попробовать передать драйверу параметр типа verbose=10.
Если драйвер портирован из стека NetBSD и не поддерживает функции утилиты nicinfo, можно воспользоваться командой netstat -I iface, чтобы получить краткую информацию о приеме и передаче пакетов. Команда ifconfig возвращает краткую информацию об устройстве, а команда ifconfig -v – более подробную информацию.
Совместное использование одного прерывания несколькими устройствами — технически элегантное решение, однако оно полезно лишь при условии, что в системе недостаточно линий прерываний. Более того, оно может вызывать проблемы. Например, если драйвер не работает (не принимает пакеты), следует проверить, использует ли он прерывание совместно с другим устройством, и если да, перенастроить плату таким образом, чтобы отключить этот механизм.
Совместное использование прерываний часто используется без необходимости (т.е. при наличии свободных прерываний) и снижает производительность системы, поскольку при возникновении прерывания all использующие его устройства должны проверять, требуется ли обрабатывать его. Если изучить исходный код драйверов, можно увидеть, что некоторые из них действуют «правильно» — считывают регистры в обработчике прерывания и игнорируют прерывание от другого устройства. Тем не менее, многие драйверы работают иначе: они проверяют устройства с помощью механизма обработки событий на уровне потоков, что является неэффективным и снижает производительность системы.
При использовании шины PCI можно получать информацию о назначенных прерываниях с помощью команды pci -v.
Совместное использование прерываний может значительно увеличивать задержку их обработки в зависимости от алгоритма работы каждого драйвера. После возникновения прерывания ядро не разрешает его до тех пор, пока all обработчики не сообщают ядру о своем завершении. Таким образом, если один драйвер долго обрабатывает маскированное совместно используемое прерывание и в это время другое устройство генерирует такое же прерывание, длительность задержки его обработки неизвестна.
Совместное использование прерываний может вызывать неполадки, ухудшать производительность системы, повышать нагрузку на процессор и значительно увеличивать задержки. Этот механизм следует использовать только по необходимости. Следует убедиться, что при совместном использовании прерываний ваши драйверы действуют «правильно».
Исходный код, скачанный из нашего публичного репозитория https://git.kpda.ru/drivers/network, включает в себя техническую статью с описанием процедуры создания драйвера (см. README.md
).
Чтобы отладить драйвер с помощью инструмента gdb, необходимо сначала проверить, что при компиляции исходного кода была включена отладочная информация. Если код драйвера размещен в подходящем каталоге дерева исходного кода, выполните следующие действия:
make CPULIST=x86 clean make CPULIST=x86 CCOPTS=-O0 DEBUG=-g install
Отладочная версия драйвера создана; теперь можно запустить инструмент gdb и задать точку останова в функции main() бинарного файла io-pkt-*.
![]() | Не забудьте указать драйвер в аргументах и проверьте, что переменные окружения PATH и LD_LIBRARY_PATH заданы корректно. |
После достижения точки останова в функции main(), выполните команду sharedlibrary в отладчике gdb. Вы увидите загруженную библиотеку libc. Задайте точку останова в функции dlsym(). В момент ее достижения драйвер загружен, но стек io-pkt-* еще не выполнил первое обращение к нему. Выполните команду set solib-search-path, добавьте путь к драйверу, а затем еще раз выполните команду sharedlibrary. Отладчик загрузит символы для драйвера, после чего можно задать точку останова в точке начала отладки.
Уровень 802.11 стека может создавать дампы с отладочной информацией. Включение и выключение дампирования осуществляется с помощью настроек sysctl. Если выполнить команду:
sysctl -a | grep 80211
для драйвера Wi-Fi, будут отображены переменные net.link.ieee80211.debug и net.link.ieee80211.vap0.debug. Включите вывод отладочной информации с помощью команд:
sysctl -w net.link.ieee80211.debug = 1 sysctl -w net.link.ieee80211.vap0.debug=0xffffffff
Теперь можно просмотреть журнал отладки утилитой sloginfo.
В отличие от обычных пакетов, Jumbo пакеты включают в себя более 1500 байт данных. У них нет четкого определения, и разработчики используют пакеты разной длины. Для применения Jumbo-фреймов необходимо, чтобы их поддерживали стек протоколов, драйверы и сетевые коммутаторы:
Использование Jumbo-фреймов значительно повышает эффективность передачи данных через стек io-pkt-*, благодаря уменьшению затрат времени на обработку заголовков пакетов.
Пример настройки Jumbo-фреймов в драйвере:
ifconfig wm0 ip4csum tcp4csum udp4csum ifconfig wm0 mtu 8100 ifconfig wm0 10.42.110.237
Для достижения максимальной производительности мы также включили функцию аппаратного вычисления контрольных сумм принимаемых и отправляемых пакетов и выбрали произвольную длину Jumbo пакета — 8100 байт. Следует иметь в виду, что стек io-pkt-* по умолчанию выделяет области размером 2 Кбайт для буферов пакетов. Этот механизм эффективен, если размер пакетов составляет 1500 байт, однако при получении Jumbo-фрейма размером 8 Кбайт выделяются четыре связанных области. Для повышения производительности можно указать стеку io-pkt-*, что мы будем использовать Jumbo пакеты:
io-pkt-v6-hc -d i82544 -p tcpip \ pagesize=8192,mclbytes=8192
С помощью параметров pagesize и mclbytes мы даем стеку команду выделять непрерывные буферы размером 8 Кбайт (которые могут занимать две соседние страницы размером 4 Кбайт, что вполне рационально). Это снижает затраты времени на обработку пакетов, увеличивает пропускную способность и уменьшает нагрузку на процессор.
Если длина пакета Ethernet составляет менее ETHERMIN
байт, для соблюдения минимальной длины можно воспользоваться механизмом заполнения пакета. Во избежание снижения производительности драйвер не заполняет пакеты самостоятельно, а делегирует эту задачу устройству, если оно может выполнить ее. Данные, которыми заполняется пакет, определяются устройством.
Функция Transmit Segmentation Offload (TSO) поддерживается некоторыми современными сетевыми платами (примеры см. в статье http://en.wikipedia.org/wiki/Large_segment_offload). Разбиение крупного IP-пакета на блоки MTU осуществляется не стеком, а драйвером, что значительно снижает нагрузку на процессор при передаче больших объемов данных.
Чтобы определить, поддерживает ли драйвер функцию TSO, можно ввести команду ifconfig и просмотреть раздел функций передачи интерфейса. tso будет указана в списке доступных функций. Для активации функции TSO в драйвере можно ввести следующие команды:
ifconfig wm0 tso4 ifconfig wm0 10.42.110.237
Предыдущий раздел: перейти