Обсудив символьные и блочные драйверы, мы
теперь готовы перейти в мир сетей. Сетевые интерфейсы представляют собой
третий стандартный класс устройств Linux и в этой главе описывается,
каким образом они взаимодействуют с остальной частью ядра.
Роль сетевого интерфейса в системе
аналогична таковой для смонтированного блочного устройства. Блочное
устройство регистрирует в ядре свои диски и методы и затем "передаёт" и
"получает" блоки по запросу, означающему вызов его функции request.
Аналогичным образом сетевой интерфейс должен зарегистрировать себя в
определённых структурах данных ядра, чтобы быть вызванным, когда
происходит обмен пакетами с внешним миром.
Есть несколько важных различий между
смонтированными дисками и интерфейсами доставки пакеты. Начнём с того,
что диск существует в виде специального файла в каталоге /dev,
в то время как сетевой интерфейс не имеет такой точки входа. Нормальные
операции с файлами (чтение, запись и так далее) не имеют смысла
применительно к сетевым интерфейсам, так что невозможно применять к ним
подход Unix "всё есть файл". Таким образом, сетевые интерфейсы
существуют в их собственном пространстве имён и экспортируют другой
набор операций.
Хотя вы можете возразить,что при использовании сокетов приложения используют системные вызовы read и write,
эти вызовы на программное обеспечение объекта, который отличается от
интерфейса. На одном физическом интерфейсе может быть мультиплексировано
несколько сотен сокетов.
Но самое важное различие между ними в том,
что блочные драйверы работают только отвечая на запросы из ядра, тогда
как сетевые драйверы получают пакеты асинхронно извне. Таким образом,
если блочный драйвер запрашивается, чтобы послать буфер в ядро, сетевое устройство просит поместить входящие пакеты в ядро. Интерфейс ядра для сетевых драйверов разработан для этого другого режима управления.
Сетевые драйверы также должны быть готовы
поддержать ряд административных задач, таких как настройка адресов,
изменение параметров передачи и поддержание статистики трафика и ошибок.
API для сетевых драйверов отражает эту необходимость и, таким образом,
выглядит несколько отличающимся от интерфейсов, которые мы видели до сих
пор.
Сетевая подсистема ядра Linux разработана
так, чтобы быть полностью независимой от протокола. Это относится как к
сетевым протоколам (Интернет-протокол [IP] по сравнению с IPX и другими
протоколами) и аппаратным протоколам (Ethernet по сравнению с Token Ring
и другими). Взаимодействие между сетевым драйвером и ядром имеет дело
должным образом с одним сетевым пакетом за раз; это позволяет проблемам
протокола быть аккуратно скрытыми от драйвера и физической передаче быть
скрытой от протокола.
В этой главе описывается, каким образом
сетевые интерфейсы вписываются в остальное ядро Linux и предоставляет
примеры в виде базирующегося на памяти модульного сетевого интерфейса,
который называется (как вы догадались) snull.
Для упрощения обсуждения интерфейс использует аппаратный протокол
Ethernet и передаёт IP пакеты. Знания, которые вы приобретаете,
рассматривая snull, могут без
труда применяться к протоколам, отличным от IP, и написание не-Ethernet
драйвера отличается только в мелких деталях, относящихся с необходимому
сетевому протоколу.
Эта глава не говорит о схемах нумерации
IP, сетевых протоколах или других общих концепциях сетей. Такие темы
(как правило) не представляют интерес для автора драйвера и невозможно
предложить удовлетворительный обзор сетевой технологии менее чем в
несколько сот страниц. Заинтересованному читателю настоятельно
рекомендуется обратиться к другим книгам, описывающим сетевые проблемы.
Прежде, чем перейти к сетевым устройствам, сделаем одно замечание по терминологии. Сетевой мир использует термин октет,
чтобы сослаться на группу из восьми битов, которая, как правило,
наименьшая единица, понимаемая сетевыми устройствами и протоколами.
Термин байт почти никогда не встречается в этом контексте. В
соответствии со стандартным использованием, мы будем использовать октет,
когда речь идёт о сетевых устройствах.
Термин "заголовок" также заслуживает
быстрого упоминания. Заголовок представляет собой набор байтов (ошибка,
октетов) предшествующих пакету, так как он передаётся через различные
уровни сетевой подсистемы. Когда приложение отправляет блок данных через
TCP сокет, сетевая подсистема разбивает данные на пакеты и помещает TCP
заголовок, описывающий, где каждый пакет находится в потоке, в начало.
Нижние уровни затем размещают IP заголовок, используемый для
маршрутизации пакетов по назначению, перед TCP заголовком. Если пакет
движется по среде, подобной Ethernet, заголовок Ethernet,
интерпретируемый оборудованием, идёт впереди остального. Сетевым
драйверам не требуется самим заботится о высокоуровневых заголовках (как
правило), но зачастую они должны быть вовлечены в создание заголовка на
аппаратном уровне.