Сетевой адаптер давно перестал быть простым преобразователем пакета в сигнал на проводе. Внутри него есть блоки, которые берут на себя часть работы сетевого стека: считают контрольные суммы, режут крупные буферы на кадры, раскладывают входящий трафик по очередям и решают, когда дёрнуть процессор прерыванием. Смысл этих механизмов один — уменьшить количество тактов процессора, потраченных на каждый переданный байт. На скоростях в десятки гигабит без разгрузки одно ядро физически не успевает обработать поток пакетов.
Что именно разгружается
Первый и самый старый механизм — подсчёт контрольных сумм. Стек отдаёт адаптеру пакет с незаполненным полем суммы, карта считает её на лету при отправке и проверяет при приёме. Экономия небольшая на пакет, но она умножается на их количество.
Второй механизм важнее — сегментация. Вместо того чтобы нарезать данные на кадры размером с MTU и прогонять каждый через весь стек, операционная система передаёт адаптеру один крупный буфер и шаблон заголовка, а карта сама формирует нужное число кадров. На приёме работает обратное: подряд идущие сегменты одного соединения склеиваются в один большой буфер и поднимаются наверх один раз. Расход процессора на байт падает в разы, потому что фиксированные затраты на проход по стеку размазываются на больший объём.
Дальше идут более узкие вещи: снятие и установка меток VLAN, обработка заголовков туннелей, чтобы инкапсуляция не отключала остальные механизмы разгрузки, а в специализированных сценариях — прямой доступ к памяти удалённого узла и раздача виртуальных функций адаптера гостевым машинам в обход гипервизора.
Очереди, прерывания и распределение по ядрам
Одна очередь означает одно ядро и один поток обработки. Поэтому современные адаптеры держат много очередей приёма и передачи и распределяют пакеты между ними по хэшу от адресов и портов. Все пакеты одного соединения попадают в одну очередь — это гарантирует сохранение порядка и попадание в один и тот же кэш.
Из этого следует важное ограничение: одно тяжёлое соединение обрабатывается одним ядром, сколько бы очередей ни было. Если тест гоняет единственный поток и упирается в потолок, причина часто не в проводе, а в загруженном под сотню процентов ядре, обслуживающем эту очередь.
Отдельная настройка — модерация прерываний. Адаптер может сообщать о каждом пакете сразу либо копить события и будить процессор пачками. Первое даёт минимальную задержку и максимальный расход процессора, второе — обратное. Выбор зависит от задачи: для торговых и телефонных нагрузок важнее задержка, для передачи больших объёмов — экономия тактов.
Когда разгрузка мешает
Механизмы разгрузки меняют то, что видит стек, и в некоторых ролях это вредно. Склейка входящих сегментов ломает пересылку трафика: машина, работающая мостом или маршрутизатором, получает буфер, который уже нельзя честно отправить дальше кадрами исходного размера. По той же причине в дампе трафика контрольные суммы исходящих пакетов выглядят неверными — их ещё не посчитала карта, и это нормальное поведение, а не признак поломки.
Поэтому при разборе странных потерь или повреждений поочерёдное отключение механизмов разгрузки — стандартный диагностический шаг. Если проблема исчезает, дело в прошивке или драйвере адаптера, а не в сети. Подробности по типам карт и их возможностям собраны в разделе про сетевые адаптеры.
Агрегация каналов и её пределы
Объединение нескольких физических портов в один логический решает две задачи: отказоустойчивость и суммарную полосу. Согласование обычно выполняет протокол управления агрегацией, который проверяет, что оба конца видят друг друга и собрали одну и ту же группу портов. Статический вариант без протокола работает, но не замечает ситуации, когда линк формально поднят, а трафик не проходит.
Ключевой момент — способ выбора порта. Кадр не режется между линками, а целиком отправляется по одному из них, выбранному хэшем от адресов канального уровня, адресов сети или пары портов транспортного уровня. Отсюда правило, которое регулярно удивляет при первых замерах: четыре объединённых порта не дают одному соединению четырёхкратной скорости. Одно соединение всегда идёт по одному линку и ограничено его скоростью. Полоса складывается только на множестве соединений, и то при условии, что хэш раскладывает их равномерно — при десятке крупных потоков перекос вполне вероятен.
Отказоустойчивость требует ещё и правильной топологии: чтобы пережить выход коммутатора, порты должны идти в два разных устройства, объединённых в общую логическую пару. Без этого агрегация защищает только от обрыва провода и отказа порта.
Что проверить перед замерами
Совпадает ли размер кадра по всему пути, включая коммутаторы, — увеличенный кадр даёт заметную экономию тактов, но только если его понимают все узлы. Хватает ли адаптеру линий PCIe: быстрая карта в коротком слоте упрётся в шину раньше, чем в сеть. И к какому сокету подключён слот, если машина многопроцессорная. Порядок такой проверки при подборе узлов описан в разделе про сборку.