Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
|
|
Прием данных из сети сложнее, чем их передача, потому что sk_buff должен создаваться и обрабатываться верхними уровнями атомарно. Существуют 2 режима приема пакетов, которые могут быть реализованы сетевым драйвером: через прерывания и опрос. Большинство драйверов используют прерывания, и этот режим мы рассмотрим в первую очередь. Некоторые драйверы, для широкополосных адаптеров, могут реализовывать режим опроса, мы рассмотрим этот способ в подразделе «Подавление приема прерываний».
hardorsoft
26.10.10 в 02:50
|
|
Реализация snull разделяет аппаратно-зависимые и аппаратно- независимые действия. Поэтому функция snull_rx вызывается из обработчика прерывания snull после приема пакета аппаратурой, и где он передается в память компьютера. snull_rx получает указатель на данные и длину пакета. Это ответственная задача - передать пакет и дополнительные поля на верхние уровни сетевого кода. Этот код не зависит от полученных данных и их длинны.
hardorsoft
26.10.10 в 02:50
|
|
void snull_rx(struct net_device *dev, struct snull_packet *pkt) { struct sk_buff *skb; struct snull_priv *priv = netdev_priv(dev); /* * Пакет принимается из передающей среды. Формируется * skb, чтобы верхние уровни могли обработать его. */ skb = dev_alloc_skb(pkt->datalen + 2); if (!skb) { if (printk_ratelimit( )) printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; goto out; } memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); /* формируем метаданные и приступаем к приему пакета */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; /* контрольная сумма не нужна */ priv->stats.rx_packets++; priv->stats.rx_bytes += pkt->datalen; netif_rx(skb); out: return; }
hardorsoft
26.10.10 в 02:50
|
|
Функция достаточно общая, чтобы послужить шаблоном, но, для того чтобы вы могли уверенно пользоваться этим фрагментом кода, необходимы некоторые пояснения.
hardorsoft
26.10.10 в 02:50
|
|
На первом шаге выделяется буфер под пакет. Обратите внимание, что функции выделения буфера dev_alloc_skb, необходимо передать его длину. dev_alloc_skb вызывает kmalloc атомарно, таким образом, это может быть безопасно использовано в обработчике прерывания. Ядро предлагает другие интерфейсы для выделения буферов сокета, но они не приведены здесь. Буферы сокета детально рассмотрены в подразделе «Буферы сокетов».
hardorsoft
26.10.10 в 02:50
|
|
Значение, возвращаемое dev_alloc_skb, необходимо проверить, и snull делает это. Мы вызывает printk_ratelimit для сообщения об ошибке. Генерация сотен или тысяч сообщений в секунду является хорошим способом затормозить работу системы и скрыть реальный источник проблем. printk_ratelimit помогает предотвратить эту проблему, функция возвращает 0, если на консоль поступает слишком много сообщений.
hardorsoft
26.10.10 в 02:51
|
|
После получения skb, пакет данных копируется в буфер, вызовом memcpy. Функция skb_put, обновляет указатель конца данных в буфере, и возвращает указатель на созданную область памяти.
hardorsoft
26.10.10 в 02:51
|
|
Если пишется высокопроизводительный драйвер для интерфейса, который может управлять передачей данных по шине ввода-вывода (full bus-mastering I/O), то в нем имеется возможность оптимизации. Её мы рассмотрим. Некоторые драйверы выделяют буфер сокета для принятия пакетов заранее, тогда интерфейс размещает данные пакета непосредственно в пространстве буфера сокета. Для этого сетевой уровень выделяет все буферы сокетов в области доступной для ПДП (которая может быть в верхней памяти, если у вашего устройства установлен флаг NETIF_F_HIGHDMA). Данный подход позволяет избежать дополнительной операции копирования в буфер сокета, но требует обратить внимание на выбор размера буфера, поскольку размер принимаемого пакета заранее неизвестен. В этой ситуации оказывается полезным метод change_mtu, поскольку позволяет драйверу реагировать на изменение максимального размера пакета.
hardorsoft
26.10.10 в 02:51
|
|
Прежде чем принять пакет, сетевой уровень должен получить дополнительную информацию. Должны быть сформированы поля dev и protocol. Код поддержки Ethernet экспортирует вспомогательную функцию eth_type_trans, которая находит подходящее значение для поля protocol. Затем мы должны указать, как вычисляется контрольная сумма для пакета, и вычисляется ли вообще (в snull, не нужно вычислять контрольную сумму). Возможные значения:
hardorsoft
26.10.10 в 02:51
|
|
|
|
|
Устройство вычисляет контрольную сумму аппаратно. Пример аппаратного вычисления контрольной суммы – интерфейс SPARC HME.
hardorsoft
26.10.10 в 02:52
|
|
|
|
|
Контрольная сумма не проверяется. Задача должна выполнятся системным программным обеспечением. Это значение используется по умолчанию, для вновь выделенного буфера.
hardorsoft
26.10.10 в 02:52
|
|
|
|
|
Не производится никаких вычислений контрольной суммы. Это значение используется в snull и интерфейсе loopback.
hardorsoft
26.10.10 в 02:52
|
|
Вы можете удивиться, почему статус контрольной суммы задается здесь, если мы уже установили флаг в поле features нашей структуры net_device. Дело в том что этот флаг информирует ядро об отправляемых пакетах. О входных же пакетах информируется отдельно.
hardorsoft
26.10.10 в 02:53
|
|
В конце концов, драйвер обновляет статистический счетчик, регистрируя принятый пакет. Статистическая структура состоит из нескольких полей. Наиболее важные из них: rx_packets, rx_bytes, tx_packets, и tx_bytes. Поля содержат количество принятых и отправленных пакетов и общее количество переданных октетов. Полостью все поля описаны в подразделе «Статистическая информация».
hardorsoft
26.10.10 в 02:53
|
|
На последнем шаге приема пакета выполняется функция netif_rx, которая передает буфер сокета верхним уровням. netif_rx возвращает целое значение, NET_RX_SUCCESS (0) если пакет успешно принят, и другое значение в случае возникновения проблем. Имеются три значения (NET_RX_CN_LOW, NET_RX_CN_MOD и NET_RX_CN_HIGH) которые показывают уровень перегрузки сетевой подсистемы; NET_RX_DROP - количество пакетов было минимальным. Драйвер может использовать эти значения для прекращения подачи пакетов в ядро, когда возникнет перегрузка, но на практике многие драйверы игнорируют значение возвращаемое netif_rx. Если вы пишите драйвер для устройства с высокой пропускной способностью и хотите все сделать хорошо, то, для реагирования на перегрузку, лучше всего реализовать NAPI, который мы рассмотрим после обработчиков прерываний.
hardorsoft
26.10.10 в 02:53
|
|