Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
|
|
Мы рассмотрели большинство вопросов, связанных с сетевыми интерфейсами. Но все еще не рассмотрели детально структуру sk_buff. Структура является сердцевиной сетевой подсистемы Linux, мы рассмотрим два главных поля структуры, и функции для работы с ними.
hardorsoft
26.10.10 в 03:13
|
|
Хотя, точное понимание содержимого sk_buff не обязательно, но это может помочь вам при поиске проблем и при оптимизации кода. Например, если вы взгляните на loopback.c, вы увидите оптимизацию, основанную на понимании содержимого sk_buff. Здесь надо предупредить: если вы пишите код использующий содержимое sk_buff, то вы должны быть готовы кое-что переделать, в будущих реализациях ядра. До сих пор, издержки разработки оправдывались уменьшением издержек в эксплуатации.
hardorsoft
26.10.10 в 03:13
|
|
Мы не описываем здесь всю структуру и поля, которые могут быть использованы в драйвере. Если вы хотите узнать больше, ознакомитесь с файлом <linux></linux>skbuff.h>, там определены структуры и объявлены прототипы функций. Дополнительную информацию о том, какие функции и поля могут быть использованы, можно без труда найти в исходных текстах ядра.
hardorsoft
26.10.10 в 03:13
|
|
|
|
|
Перечисленные здесь поля могут быть необходимы драйверу. Они приведены не упорядочено.
hardorsoft
26.10.10 в 03:14
|
|
struct net_device *dev;
hardorsoft
26.10.10 в 03:14
|
|
устройство посылает и принимает этот буфер.
hardorsoft
26.10.10 в 04:11
|
|
union { /* ... */ } h; union { /* ... */ } nh; union { /*... */} mac;
hardorsoft
26.10.10 в 03:14
|
|
Указатели на заголовки различного уровня, содержащиеся в пакете. Каждое поле union – указатель на различные типы структур данных. h – указатели на заголовки транспортного уровня (например, структура tcphdr *th); nh – заголовки сетевого уровня (такие как iphdr *iph); mac - коллекция указателей на заголовки канального уровня (link-layer) (такие как ethdr *ethernet).
hardorsoft
26.10.10 в 04:12
|
|
Если вашему драйверу требуется адрес отправителя и получателя TCP пакета, он может найти его в skb->h.th. Для получения полного набора заголовков типов, к которым можно получить доступ таким образом, смотрите заголовочный файл.
hardorsoft
26.10.10 в 04:12
|
|
Обратите внимание на то, что драйверы сетевых устройств отвечают за установку указателя mac в поступающих пакетах. Эта задача обычно выполняется eth_type_trans, но не Еthernet- драйверы должны сами установить skb->mac.raw, как показано в подразделе "Не Ethernet-заголовки "
hardorsoft
26.10.10 в 04:13
|
|
unsigned char *head; unsigned char *data; unsigned char *tail; unsigned char *end;
hardorsoft
26.10.10 в 03:14
|
|
Указатели используются для адресации данных в пакете. head укатывает на начало выделенного пространства, data – начало доступных октетов (обычно data больше чем head), tail – конец доступных октетов, end – содержит максимальный адрес, который может достичь tail. Иными словами, с skb->end по skb->head находится доступное пространство буфера, в котором используется пространство размером (skb->tail – skb->data).
hardorsoft
26.10.10 в 04:14
|
|
unsigned int len; unsigned int data_len;
hardorsoft
26.10.10 в 03:14
|
|
len – полное количество данных в пакете, data_len – длинна фрагментированной части пакета. data_len содержит «0», если сегментированный ввод-вывод (scatter/gather I/O) не используется.
hardorsoft
26.10.10 в 04:14
|
|
unsigned char ip_summed;
hardorsoft
26.10.10 в 03:14
|
|
Контрольная сумма для этого пакета. Поле устанавливается драйвером при прибытии пакета, как описано в подразделе «Прием пакетов»
hardorsoft
26.10.10 в 04:14
|
|
unsigned char pkt_type;
hardorsoft
26.10.10 в 03:15
|
|
Используется для классификации пакетов. Драйвер устанавливает это поля в PACKET_HOST (этот пакет для меня), PACKET_OTHERHOST (этот пакет для не меня), PACKET_BROADCAST или PACKET_MULTICAST. Ethernet-драйвер не модифицирует это поле явно, т.к. за него это делает eth_type_trans.
hardorsoft
26.10.10 в 04:15
|
|
shinfo(struct sk_buff *skb); unsigned int shinfo(skb)->nr_frags; skb_frag_t shinfo(skb)->frags;
hardorsoft
26.10.10 в 03:15
|
|
Для повышения производительности, некоторая информация skb, храниться в отдельной структуре, которая находится сразу после skb в памяти. Эта «совместно используемая информация» (так названа потому, что может быть совместно использоваться копиями skb в сетевом коде) может быть доступна через макрос shinfo. Большинство полей этой структуры выходит за рамки данной книги. Мы рассмотрим nr_frags и frags в подразделе «Сегментированный ввод-вывод».
hardorsoft
26.10.10 в 04:15
|
|
Оставшиеся поля в структуре не очень интересны. Они используются для хранения списка буферов, учета памяти буферов сокетов, и т.д.
hardorsoft
26.10.10 в 04:15
|
|
17.10.2. Функции работы с буферами сокетов.
hardorsoft
26.10.10 в 04:15
|
|
Сетевые устройства выполняют различные действия над структурой sk_buff, через служебные функции интерфейса. Многие функции работают с буферами сокетов. Вот наиболее интересные:
hardorsoft
26.10.10 в 04:16
|
|
struct sk_buff *alloc_skb(unsigned int len, int priority); struct sk_buff *dev_alloc_skb(unsigned int len);
hardorsoft
26.10.10 в 03:15
|
|
Выделение буфера. Функция alloc_skb выделяет буфер и инициализирует skb->data, и skb->tail к skb->head. Функция dev_alloc_skb является сокращенным вызовом alloc_skb с приоритетом GFP_ATOMIC и резервированием некоторого пространства между skb->head и skb->data. Это пространство используется в оптимизации сетевого уровня, и не затрагивает драйвер.
hardorsoft
26.10.10 в 04:16
|
|
void kfree_skb(struct sk_buff *skb); void dev_kfree_skb(struct sk_buff *skb); void dev_kfree_skb_irq(struct sk_buff *skb); void dev_kfree_skb_any(struct sk_buff *skb);
hardorsoft
26.10.10 в 03:15
|
|
Функции освобождают буфер. Вызов kfree_skb используется ядром. Драйвер использует одну из форм kfree_skb: dev_kfree_skb – вызывается не в контексте прерывания; dev_kfree_skb_irq – вызывается в контексте прерывания; dev_kfree_skb_any – для кода, который может работать в любом контексте.
hardorsoft
26.10.10 в 04:17
|
|
unsigned char *skb_put(struct sk_buff *skb, int len); unsigned char *_ _skb_put(struct sk_buff *skb, int len);
hardorsoft
26.10.10 в 03:15
|
|
Обновляют поля tail и len в структуре sk_buff. Функции используются для добавления данных к концу буфера. Каждая функция возвращает предыдущее значение skb->tail (другими словами указатель на только что созданное пространство). Драйвер может использовать возвращаемое значение для копирования: memcpy(skb_put(...), data, len) или подобным образом. Функции отличаются тем, что skb_put проверяет, помещаются ли данные в буфере, тогда как __skb_put – не проверяет.
hardorsoft
26.10.10 в 04:17
|
|
unsigned char *skb_push(struct sk_buff *skb, int len); unsigned char *_ _skb_push(struct sk_buff *skb, int len);
hardorsoft
26.10.10 в 03:15
|
|
Функция уменьшает skb->data и увеличивает skb->len. Работает аналогично skb_put, но данные добавляются в начало пакета, а не в конец. Возвращается указатель на созданное пространство. Функция используется для добавления аппаратного заголовка перед отправкой пакета. Отличие __skb_push в том, что проверка на наличие свободного пространства не производиться.
hardorsoft
26.10.10 в 04:18
|
|
int skb_tailroom(struct sk_buff *skb);
hardorsoft
26.10.10 в 03:15
|
|
возвращает размер доступного пространства в буфере для приходящих данных. Если драйвер помещает больше данных, чем может вместить буфер, происходит критическая ошибка системы(system panics). Хотя Вы могли бы возразить, что вызова printk будет достаточно, для того чтобы отметить ошибку, но искажение содержимого памяти может быть настолько вредно для системы, что разработчики решили предпринять категоричное действие. Практически, вы не должны проверять доступное пространство, если буфер был распределен правильно. Драйверы обычно получают размер пакета перед выделением буфера, только не корректно реализованные драйвера помещают слишком много данных в буфер, вследствии чего получают критическую ошибку.
hardorsoft
26.10.10 в 04:18
|
|
int skb_headroom(struct sk_buff *skb);
hardorsoft
26.10.10 в 03:16
|
|
Возвращает количество доступного пространства перед началом данных, сообщая, сколько октет можно поместить посредством skb_push в буфер.
hardorsoft
26.10.10 в 04:19
|
|
void skb_reserve(struct sk_buff *skb, int len); Увеличивает data и tail. Функция может быть использована для резервирования пространства перед заполнением буфера. Большинство Ethernet-интерфейсов резервируют 2 байта в начале пакета, после 14-байтного заголовка Ehernet; поэтому ip- заголовок выровнен по 16-байтной границе. snull делает также, хотя эти команды не показаны в подразделе «Прием пакетов», чтобы не вводить дополнительные понятия.
hardorsoft
26.10.10 в 04:19
|
|
unsigned char *skb_pull(struct sk_buff *skb, int len);
hardorsoft
26.10.10 в 03:16
|
|
Удаляет данные из начала пакета. Драйверу нет необходимости использовать эту функцию, но она приведена здесь для полноты описания. Функция уменьшает skb->len и увеличивает skb->data. Эти действия удаляют аппаратный заголовок (Ethernet или подобный) находящийся в начале пришедшего пакета.
hardorsoft
26.10.10 в 04:19
|
|
int skb_is_nonlinear(struct sk_buff *skb);
hardorsoft
26.10.10 в 03:16
|
|
Возвращает true если этот skb разделен на несколько фрагментов для сегментированного ввода-вывода (scatter/gather I/O).
hardorsoft
26.10.10 в 04:19
|
|
int skb_headlen(struct sk_buff *skb);
hardorsoft
26.10.10 в 03:16
|
|
Возвращает длину первого сегмента skb (часть на которую указывает skb->data).
hardorsoft
26.10.10 в 04:22
|
|
void *kmap_skb_frag(skb_frag_t *frag); void kunmap_skb_frag(void *vaddr);
hardorsoft
26.10.10 в 03:16
|
|
Если вам необходим прямой доступ к фрагментам в нелинейном skb из ядра, то вам будут нужны эти функции. kmap используется атомарно, и вы не сможете отобразить более одного фрагмента одновременно.
hardorsoft
26.10.10 в 04:22
|
|
В ядре определены и другие функции, работающие с буферами сокетов, но они предназначены для работы на более высоком уровне сетевого кода, и драйверу они не нужны.
hardorsoft
26.10.10 в 04:22
|
|