Готовый перевод Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 17.3. Подробная структура net_device
17.3. Подробная структура net_device
Структура net_device занимает важное место, и заслуживает подробного описания. Здесь описаны все поля. Эта глава кратко
описывает каждое поле, указывая, как оно используется в простом коде.
17.3.1. Основная информация
Первая часть структуры net_device состоит из следующих полей:
char name[IFNAMSIZ];
Имя устройства. Если имя содержит в себе строку %d.
register_netdev, для получения уникального имени, заменяет ее на
число, начиная с номера 0.
unsigned long state;
Состояние устройства. Состоит из нескольких флагов. Драйвер
обычно не работает с флагами напрямую. Для этого
предоставляются функции. Эти функции будут кратко рассмотрены,
при изучении операций драйвера.
struct net_device *next;
Указатель на следующее устройство в глобальном списке. Это поле
не должно затрагиваться драйвером.
int (*init)(struct net_device *dev);
Функция инициализации. Если этот указатель определен, функция
вызывается из register_netdev, для окончательной инициализации
структуры net_device. В настоящее время, драйверу не следует
использовать эту функцию, а выполнять инициализацию до
регистрации интерфейса.
17.3.2. Аппаратная информация
Приведенные здесь поля, содержат низкоуровневую аппаратную
информацию для относительно простых устройств. Это наследие ранних
Linux-сетей. Многие современные драйверы используют их (с возможным
исключением if_port). Приведем список полей:
unsigned long rmem_end;
unsigned long rmem_start;
unsigned long mem_end;
unsigned long mem_start;
Эти поля указывают на начало и конец памяти, используемой
устройством. Если устройство использует различные области
памяти для приема и передачи, то mem- это поля используемые для
передачи, а rmem- для приема. Поля rmem никогда не должно
ссылаться за пределы памяти принадлежащей драйверу. По
соглашению, -end поля указывают на конец, а -start поля – на
начало доступной встроенной памяти.
unsigned long base_addr;
Базовые адреса ввода-вывода сетевого интерфейса. Это поле
подобно предыдущему, но устанавливается драйвером при
тестировании устройства. Команда ifconfig может быть использована для просмотра и изменения текущего значения поля.
base_addr может задаваться из командной строки при загрузке
системы (через netdev = <параметр>), или во время загрузки
модуля. Поля работы с памятью, подобные описанным выше, не
используются ядром.
unsigned char irq;
Назначает номер прерывания. Значение dev->irq выводится
ifconfig, после регистрации интерфейсов. Это значение обычно
устанавливается при загрузке системы или модуля, и
модифицироваться посредством ifconfig.
unsigned char if_port;
Порт используемый в многопортовом устройстве. Например, это
поле используется устройствами поддерживающими два
коннектора ethernet: коаксиальный (IF_PORT_10BASE2) и витую пару
(IF_PORT_100BASET). Поле заполняется типом порта, который
определен в файле <linux></linux>netdevice.h>.
unsigned char dma;
Канал ПДП выделенный устройству. Поле считывается только с
какой-либо периферийной шины, такой как ISA. Не используется за
пределами драйвера устройства, кроме как для информационных
целей (в ifconfig).
17.3.3. Информация интерфейса
Большая часть информации об интерфейсе корректно
устанавливается функцией ether_setup (или другой функцией
подходящей для имеющегося типа аппаратуры). При использовании
Ethernet-карт, можно доверить этим универсальным функциям,
настройку большинства полей. Но поля flags и dev_addr специфичны и
должны определятся при инициализации.
Не Ethernet-интерфейсы могут использовать вспомогательные
функции похожие на ether_setup. Файл <drivers></drivers>net/net_init.c>
экспортирует несколько таких функций, включая следующие:
Не Ethernet-интерфейсы могут использовать вспомогательные
функции похожие на ether_setup. Файл <drivers></drivers>net/net_init.c>
экспортирует несколько таких функций, включая следующие:
Настройка полей для устройств LocalTalk.
void fc_setup(struct net_device *dev);
Инициализация полей для оптоволоконных устройств.
void fddi_setup(struct net_device *dev);
Конфигурирование интерфейса для FDDI (Fiber Distributed Data
Interface - интерфейс для передачи распределённых данных по
волоконно-оптическим каналам) сетей.
void hippi_setup(struct net_device *dev);
Готовит поля для драйвера HIPPI (High-Performance Parallel Interface
- высокоскоростной параллельный интерфейс).
void tr_setup(struct net_device *dev);
Настройка для интерфейса сетевых
доступом (token ring).
Эти классы охватывают большинство устройств. Если у вас есть что-
то еще, радикально новое и отличающееся, то вы должны в ручную
назначить следующие поля:
unsigned short hard_header_len;
Длинна аппаратного заголовка, количество октет в передаваемом
пакете до IP заголовка, или другая информация протокола. Для
Ethernet-интерфейсов hard_header_len = 14 (ETH_HLEN).
unsigned mtu;
Максимальный блок для передачи (MTU - Maximum Transfer Unit).
Это поле используется сетевым уровнем для управления передачей
пакетов. Для Ethernet MTU = 1500 октет (ETH_DATA_LEN). Это
значение может быть изменено с помощью ifconfig.
unsigned long tx_queue_len;
Максимальное количество фреймов, которые могут находиться в
очереди устройства на передачу. ether_setup устанавлиает это
значение равным 1000, но вы можете изменить его. Например, plip
использует 10, чтобы не расходовать системную память (plip имеет
меньшую производительность, чем настоящий интерфейс Ethernet).
unsigned short type;
Тип аппаратного интерфейса. Поле используется ARP для
определения, какое семейство аппаратной адресации
поддерживается интерфейсом. Для интерфейса Ethernet характерно
значение ARPHRD_ETHER, оно устанавливается в ether_setup.
Доступные типы определены в <linux></linux>if_arp.h>.
unsigned char addr_len;
unsigned char broadcast[MAX_ADDR_LEN];
unsigned char dev_addr[MAX_ADDR_LEN];
Длина аппаратного (MAC) адреса и аппаратный адрес устройства.
Длина адреса Ethernet составляет шесть октет (мы имеем ввиду
аппаратный ID интерфейса платы). И широковещательный адрес,
состоящий из шести октет 0xFF. ether_setup корректно определяет
значения этих полей. С другой стороны, MAC адрес должен быть
прочитан из самого устройства, и скопирован драйвером в dev_addr.
Аппаратный адрес используется для генерации корректного
заголовка Ethernet перед отправкой. Устройства snull не
используют физический интерфейс, и поэтому создается свой
аппаратный адрес.
unsigned short flags;
int features;
Флаги интерфейса (описаны ниже).
Поле флагов является битовой маской, ниже перечислены возможные значения. Префикс IFF_ используется для «флагов
интерфейса». Некоторые флаги устанавливаются ядром, а некоторые –
интерфейсом, во время инициализации, задавая различные свойства
интерфейса. Допустимые флаги определены в linux/if.h>:
IFF_UP
Драйвер может только читать этот флаг. Ядро устанавливает его
когда интерфейс активен, и готов передавать пакеты.
IFF_BROADCAST
Флаг управляется сетевым кодом. Состояние флага указывает,
поддерживает ли интерфейс широковещание. Карты Ethernet –
поддерживают.
IFF_DEBUG
Флаг указывает на режим отладки. Может использоваться для
формирования аргументов функций printk и других отладочных
действий. Несмотря на то, что этот флаг используется драйверами,
он может быть изменен пользовательской программой через вызов
ioctl, и это можно использовать в драйвере. Для установки и
снятия этого флага, может быть использована программа
misc-progs/netifdebug.
IFF_LOOPBACK
Этот флаг установлен только для интерфейса loopback. Ядро
проверяет значение этого флага, вместо жесткого задания имени
интерфейса.
IFF_POINTOPOINT
Этот флаг показывает, что интерфейс представляет соединение
точка-точка. Флаг устанавливается драйвером, и иногда ifconfig.
Например, этот флаг установлен у драйвера plip и PPP.
IFF_NOARP
Флаг информирует о том, что интерфейс не поддерживает ARP.
Например, интерфейсу точка-точка не нужна работа ARP, ARP будет
только расходовать трафик, не неся полезной информации. snull
также работает без ARP.
IFF_PROMISC
Этот флаг устанавливается сетевым кодом, для активизации
различных операций. По умолчанию интерфейс Ethernet использует
аппаратный фильтр для обеспечения приема широковещательных
пакетов и обычных пакетов. Программа наблюдения (sniffer) такая
как tcpdump, устанавливает неразборчивый (promiscuous) режим
интерфейса, чтобы принимались все пакеты.
IFF_MULTICAST
Этот флаг устанавливается драйвером. Означает, что интерфейс
может передавать групповые (multicast) сообщения. По умолчанию,
ether_setup устанавливает этот флаг. Если ваш драйвер не
поддерживает этой возможности, вам необходимо очистить этот флаг при инициализации.
IFF_ALLMULTI
Установленный флаг информирует о приеме всех групповых
(multicast) пакетов. Ядро устанавливает флаг если хост производит
multicast-маршрутизацию, при условии что IFF_MULTICAST –
установлен. Флаг не доступен драйверу для записи. Флаги групповой
передачи описываются в подразделе «Групповая адресация».
IFF_MASTER
IFF_SLAVE
Флаги используются для загрузки корректирующего (equalization)
кода. В интерфейсе драйвера эти флаги не используются.
IFF_PORTSEL
IFF_AUTOMEDIA
Эти флаги показывают, что устройство может переключаться между
различными типами передающей среды. Например, не
экранированная витая пара и коаксиальный Ethernet-кабель. Если
флаг IFF_AUTOMEDIA - установлен, то устройство выбирает среду
автоматически. На парактике, ядро может использовать любой
флаг.
IFF_DYNAMIC
Этот флаг устанавливается драйвером. Показывает, что адрес
интерфейса может меняться. В настоящее время, не используется
ядром.
IFF_RUNNING
Флаг показывает, что интерфейс загружен и работает. Используется
для совместимости с BSD. Большинство драйверов могут не
заботиться об этом флаге.
IFF_NOTRAILERS
Не используется в Linux. Нужен для совместимости с BSD.
Когда программа меняет флаг IFF_UP, вызываются методы
устройства open или stop. Кроме того, когда флаг IFF_UP, или любой
другой – модифицируется, вызывается метод set_multicast_list. Если
драйвер выполняет какие-то действия в ответ на модификацию флагов,
они должны производится в set_multicast_list. Например, когда
IFF_PROMISC устанавливается или сбрасывается, set_multicast_list
должен настраивать аппаратный фильтр. Этот метод описан в подразделе
«Групповая адресация».
Поля структуры net_device настраиваются драйвером, для того
чтобы сообщить ядру о характеристиках аппаратного обеспечения.
Некоторые из них, мы обсудили, другие - остались за пределами этой
книги. Вот полный список:
NETIF_F_SG
NETIF_F_FRAGLIST
Оба флага контролируют использование сегментированного ввода-вывода (scatter/gather I/O). Если ваш интерфейс может передавать
пакеты, состоящие из нескольких сегментов памяти, установите
NETIF_F_SG. Конечно, у вас имеется реализация сегментированного
ввода-вывода (мы описываем его в подразделе «сегментированный
ввод-вывод»). NETIF_F_FRAGLIST устанавливается если ваш
интерфейс может работать с фрагментированными пакетами. Это
делает только loopback драйвер в версии ядра 2.6.
Обратите внимание, ядро не будет производить сегментированный
ввод-вывод для вашего устройства, если оно не предоставляет
вычисление контрольной суммы. Причина этого в том, что если ядро
делает проход по фрагментированному (не линейному) пакету, для
вычисления контрольной суммы, то эта операция будет равносильна
копированию, поэтому ядро объединяет фрагменты.
NETIF_F_IP_CSUM
NETIF_F_NO_CSUM
NETIF_F_HW_CSUM
Эти флаги информируют ядро о том, что не нужно вычислять
контрольную сумму для некоторых или всех пакетов проходящих
через этот интерфейс. Установите NETIF_F_IP_CSUM, если ваш
интерфейс вычисляет контрольную сумму только для IP-пакетов.
Если контрольная сумма вообще не вычисляется, то установите
NETIF_F_NO_CSUM. loopback драйвер и snull устанавливают этот
флаг; Пакеты только передаются через системную память, и там с
ними ничего не случиться, и нет необходимости проверять их. Если
ваша аппаратура вычисляет контрольную сумму – установите
NETIF_F_HW_CSUM.
NETIF_F_HIGHDMA
Установите этот флаг если ваше устройство может выполнять ПДП в
верхней памяти (high memory). При отсутствии этот флага буферы
всех пакетов выделяются вашим драйвером в нижней(low) памяти.
NETIF_F_HW_VLAN_TX
NETIF_F_HW_VLAN_RX
NETIF_F_HW_VLAN_FILTER
NETIF_F_VLAN_CHALLENGED
Эти опции описывают поддержку вашей аппаратурой 802.1q VLAN
пакетов. Поддержка VLAN выходит за рамки этой главы. Если ваше
устройство не может работать с VLAN пакетами (чего реально не
будет) установите флаг NETIF_F_VLAN_CHALLENGED.
NETIF_F_TSO
Установите этот флаг, если ваше устройство может убрать
сегментацию TCP. TSO – передовое свойство, которое мы не сможем
рассмотреть здесь.
17.3.4. Методы устройства
Как символьные и блочные устройства, сетевые устройства декларируют функции, необходимые для своей работы. В этом подразделе
перечислены операции, которые могут выполняться сетевым
интерфейсом. Некоторым операциям можно присвоить NULL, другие
можно не задавать, потому что подходящий метод для них установит
ether_setup.
Методы можно разделить на две группы: фундаментальные и
опциональные. Фундаментальные методы - те, которые обязательно
используются интерфейсом. Опциональные методы реализуют
дополнительную, но не обязательную функциональность.
int (*open)(struct net_device *dev);
Открытие интерфейса. Интерфейс открывается, когда ifconfig
активирует его. Метод производит регистрацию используемых
системных ресурсов (портов ввода-вывода, прерываний, ПДП и т.д.)
выполняет включение и настройку вашего устройства.
int (*stop)(struct net_device *dev);
Останавливает работу интерфейса.
операции противоположные open.
int (*hard_start_xmit) (struct sk_buff *skb, struct net_device
*dev);
Метод инициализирует передачу пакета. Полный пакет (с
заголовками протоколов) содержит в себе буферы сокета (структуру
sk_buff). Буфер сокета мы рассмотрим в этой главе позже.
int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned
short type, void *daddr, void *saddr, unsigned len);
Функция (вызывается перед hard_start_xmit) формирует
аппаратный заголовок, содержащий аппаратный адрес назначения и
отправителя, которые были получены заблаговременно. По
умолчанию для Ethernet-интерфейсов, ether_setup заносит в это
поле функцию eth_header.
int (*rebuild_header)(struct sk_buff *skb);
Функция используется для переформирования аппаратного
заголовка, после завершения ARP запроса, но до передачи пакета.
По умолчанию, функция используется Ethernet-устройствами,
поддерживающими ARP, для заполнения пакетов с поврежденной
информацией.
void (*tx_timeout)(struct net_device *dev);
Метод вызывается сетевым кодом, когда пакета не передан за
допустимое время, предполагается, что это произошло из-за потери
прерывания или блокирования интерфейса. Приводит к обработке
ошибки и повторной передачи пакета.
struct net_device_stats *(*get_stats)(struct net_device *dev);
Всякий раз, когда приложению требуется получить статистику по
интерфейсу, вызывается этот метод. Например, это происходит при выполнении команды ifconfig или netstat -i. Простая реализация
метода для snull приведена в подразделе «Статистическая
информация».
int (*set_config)(struct net_device *dev, struct ifmap *map);
Изменяет конфигурацию интерфейса. Этот метод является точкой
входа для конфигурирования драйвера. При использовании
set_config, могут быть изменены адреса ввода/вывода устройства и
номера прерываний. Эта возможность может быть использована
системным администратором, если интерфейс не имеет другой
возможности. Драйверам современных устройств не нужно
реализовывать этот метод.
Опциональные методы:
int weight;
int (*poll)(struct net_device *dev; int *quota);
Метод предоставляется NAPI-совместимыми драйверами, для
работы в режиме опроса, при запрещенных прерываниях. NAPI (и
поле weight) рассмотрены в подразделе «Подавление приема
прерываний»
void (*poll_controller)(struct net_device *dev);
В этой функции драйвер проверяет наличие событий, когда
прерывания запрещены. Используется в специфичных задачах ядра,
таких как удаленная консоль или отладка ядра по сети.
int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
Выполнение специфичных команд интерфейса. Реализация этих
команд описывается в подразделе «Пользовательские команды
ioctrl». Если интерфейс не использует специфичные команды, поле
может быть равно NULL.
void (*set_multicast_list)(struct net_device *dev);
Метод вызывается, когда меняется список групповых адресов и при
изменении флагов. В подразделе «Групповая адресация» метод
рассмотрен подробнее, и приведена простая реализация.
int (*set_mac_address)(struct net_device *dev, void *addr);
Функция реализуется, если интерфейс поддерживает изменение
аппаратного адреса. Многие интерфейсы не поддерживают эту
возможность. Некоторые используют реализацию по умолчанию
eth_mac_addr (из drivers/net/net_init.c). eth_mac_addr только
лишь копирует новый адрес в dev->dev_addr, и это происходит
только если интерфейс не запущен. Драйвер, использующий
eth_mac_addr, должен установить аппаратный MAC адрес из
dev->dev_addr в методе open.
int (*change_mtu)(struct net_device *dev, int new_mtu);
Функция вызывается при изменении MTU (maximum transfer unit –
Максимальный размер передаваемого блока). Если драйверу
необходимы в какие-либо действия, при изменении MTU
пользователем, он должен реализовывать эту функцию. В противном Функция вызывается при изменении MTU (maximum transfer unit –
Максимальный размер передаваемого блока). Если драйверу
необходимы в какие-либо действия, при изменении MTU
пользователем, он должен реализовывать эту функцию. В противном
int (*header_cache) (struct neighbour *neigh, struct hh_cache *hh);
Функция вызывается для заполнения структуры hh_cache c выдачей
запроса ARP. Почти все драйверы Ethernet могут использовать
реализацию по умолчанию – eth_header_cache.
int (*header_cache_update) (struct hh_cache *hh, struct net_device *dev,
unsigned char *haddr);
Метод обновляет адрес назначения в структуре hh_cache. Ethernet-
устройства используют метод eth_header_cache_update.
int (*hard_header_parse) (struct sk_buff *skb, unsigned char *haddr);
Метод извлекает адрес отправителя из пакета, содержащегося в
skb, копирует его в буфер haddr. Функция возвращает длину адреса.
Устройства Ethernet используют метод eth_header_parse.
17.3.5. Полезные поля
Оставшиеся поля структуры net_device используются для хранения
полезной информации. Некоторые поля используются ifconfig и netstat
для предоставления пользователю информации о текущей конфигурации.
Поэтому интерфейс устанавливает значения для этих полей.
unsigned long trans_start;
unsigned long last_rx;
Поля содержат мгновенные значения. Драйвер должен обновлять
эти значения, когда начинается передача, и после приема пакета.
Значение trans_start используется сетевой подсистемой для
детектирования блокировок передатчика. Поле last_rx в настоящее
время не используется, но драйвер должен формировать это поле
для использования в будущем.
int watchdog_timeo;
Минимальное время (в jiffies1) таймаута передачи. При таймауте
вызывается функция драйвера tx_timeout.
void *priv;
Эквивалент filp->private_data. В современных драйверах это поле
формируется alloc_netdev. Прямое обращение к этому полу не
используется, вместо этого применяется netdev_priv.
struct dev_mc_list *mc_list;
int mc_count;
Эти поля используются при групповой(multicast) передачи. mc_count – содержит количество элементов в mc_list. Смотрите подраздел
«Групповая адресация» для получения более полной информации.
spinlock_t xmit_lock;
int xmit_lock_owner;
xmit_lock используется для синхронизации вызовов функции
hard_start_xmit. xmit_lock_owner – номер процессора захватившего
xmit_lock. Драйвер не должен менять значения этих полей.
Остальные поля в структуре net_device не используются сетевым
драйвером.
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется
Переведено на Нотабеноиде
http://notabenoid.org/book/11832/38383
Переводчики: hardorsoft
Настройки
Готово:
