Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [kernel] передача сетевому от канального уровня, подготовка буфера сокета 
V
    Опции темы
null56
Дата 28.1.2011, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



Всем привет, не ясен процесс подготовки сокетного буфера (sk_buff), при передаче вышележащим протоколам
Собсвенно шаги:
- регистрирую обработчик кадров канального уровня со своей сигнатурой
Код

void dev_add_pack(struct packet_type *pt);

- получив кадр в колбаке, удаляю из заголовка кадра, все что мне нужно, оставляя лишь стандартные данные структуры 
Код

 118struct ethhdr {
 119        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
 120        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
 121        __be16          h_proto;                /* packet type ID field */
 122} __attribute__((packed));

- отправляю вышележащим протоколам
Код

int netif_rx(struct sk_buff *skb)


Вопрос: я нахожусь на канальном уровне, должен ли я отделять данные канального уровня?
или же я должен передавать вышележащему уровню полный кадр, а он сам отделит сетевой уровенЬ?
Код

static inline void skb_reset_network_header(struct sk_buff *skb)


заранее благодарен за помощь
PM MAIL   Вверх
null56
Дата 28.1.2011, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



другими словами, что нужно сделать перед отправкой
Код

int netif_rx(struct sk_buff *skb)

удалить полностью заголовок кадра ethernet
Код

unsigned char *skb_pull(struct sk_buff *skb, unsigned int len);

и выставить смещение протокола ip
Код

static inline void skb_reset_network_header(struct sk_buff *skb)

или же достаточно только выставить смещение, в этом случае смещения протоколов канального и сетевого у нас будут совпадать

Это сообщение отредактировал(а) null56 - 28.1.2011, 17:57
PM MAIL   Вверх
MAKCim
Дата 29.1.2011, 16:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



есть NAPI и legacy драйвера сетевых устройств
legacy в контексте _аппаратного_ прерывания вызывают netif_rx
затем backlog-устройство для данного cpu добаляется в poll-список, пакет - в входную очередь и генерируется NET_RX_SOFTIRQ
затем в контексте NET_RX_SOFTIRQ обработчик process_backlog берет пакеты и дергает netif_receive_skb
там, ВНИМАНИЕ, вызывается skb_reset_network_header и далее уже вызываются обработчики packet-сокетов
т. е. в netif_rx _уже_ передается пакет с увеличенным data (на 14+ для ethernet  или в зависимости от канального уровня)

в NAPI аналогично
за исключением того, что netif_receive_skb дергается драйвером в process_xxxx

обрати внимание на
это
packet-сокеты обрабатываются _в контексте_ netif_rx (явном или неявном)
поэтому нельзя из них вызывать netif_rx


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
null56
Дата 29.1.2011, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



Цитата(MAKCim @  29.1.2011,  16:13 Найти цитируемый пост)
там, ВНИМАНИЕ, вызывается skb_reset_network_header и далее уже вызываются обработчики packet-сокетов
т. е. в netif_rx _уже_ передается пакет с увеличенным data (на 14+ для ethernet  или в зависимости от канального уровня)

да, спасибо, это уже нашел, смещение хранимое в поле network_header уже соответствует моему канальному уровню (14) + мой апендикс, убирая мой апендикс и перемещая eth_hdr, я работаю с data, поэтому трогать network_header, не нужно.

Цитата(MAKCim @  29.1.2011,  16:13 Найти цитируемый пост)
packet-сокеты обрабатываются _в контексте_ netif_rx (явном или неявном)
поэтому нельзя из них вызывать netif_rx

но вот в это меня смущает, вечерком поищу этот момент, где вызываются packet сокеты. просто как же тогда передать вышележащим протоколам? если знаешь где идет вызов, кинь ссылочку на исходник, я гляну.... буду очень благодарен

Добавлено через 7 минут и 19 секунд
ты это имеешь в виду?
http://lxr.free-electrons.com/source/net/core/dev.c#L1548

Добавлено через 13 минут и 10 секунд
я не вижу больше вызова колбака обработки в dev.c
PM MAIL   Вверх
null56
Дата 29.1.2011, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



хотя не, ты наверное имел в виду deliver_skb, оттуда вызываются колбаки 
http://lxr.free-electrons.com/source/net/core/dev.c#L2715
но вопрос все равно остается, как же передать вышележащим уровням?
PM MAIL   Вверх
null56
Дата 30.1.2011, 01:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



MAKCim, я запутался....
да, netif_rx дергается из хардваре, да он добавляет в очередь poll и перепланирует NET_RX_SOFT. далее в netif_receive_skb рано или поздно дергается __netif_receive_skb, из него вызываются зарегистрированные колбаки и все? мне более не надо ничего делать, кроме как поправить протокол?
Код

skb->protocol;

вышележащим уровням все будет передаваться в теле __netif_receive_skb? так как у вышележащих протоколов есть свои системные колбаки
http://lxr.free-electrons.com/source/net/core/dev.c#L3001

поправлю вышесказанное мной...
Цитата(MAKCim @  29.1.2011,  16:13 Найти цитируемый пост)
т. е. в netif_rx _уже_ передается пакет с увеличенным data (на 14+ для ethernet  или в зависимости от канального уровня)

так ли это? ведь в __netif_receive_skb происходит
Код

 skb_reset_network_header(skb); //skb->network_header = skb->data - skb->head;
 skb_reset_transport_header(skb); //skb->transport_header = skb->data - skb->head;
 skb->mac_len = skb->network_header - skb->mac_header;

получается, что data не изменяется, она как указывала, так и указывает на начало моего канального кадра? то есть после этих манипуляций я не могу использовать функцию
Код

ip_hdr(skb);

так как
Код

static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
        return skb->head + skb->network_header;
}

мы получим смещение на мак, а там совсем другие данные? другими словами, я не вижу, где data смещается на заголовок сетевого уровня
спасибо



Это сообщение отредактировал(а) null56 - 30.1.2011, 02:01
PM MAIL   Вверх
MAKCim
Дата 30.1.2011, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(null56 @  30.1.2011,  01:07 Найти цитируемый пост)
мне более не надо ничего делать, кроме как поправить протокол?

угу

твой зарегистрированный packet-обработчик вызывается тут
http://lxr.free-electrons.com/source/net/core/dev.c#L2953

а дальше в этой же функции тут
http://lxr.free-electrons.com/source/net/core/dev.c#L3002
обработчики для протокола

в частности для ipv4 тут
http://lxr.free-electrons.com/ident?i=dev_add_pack
идет регистрация обработчика для ipv4


Цитата(null56 @  30.1.2011,  01:07 Найти цитируемый пост)
так ли это? ведь в __netif_receive_skb происходит

так
тут
http://lxr.free-electrons.com/source/inclu.../skbuff.h#L1271
network header вычисляется как data - head
head указывает на начало линейного буфера (=заголовок канального уровня)
значит data при reset'е указывает на network header, смещение которого мы и устанавливаем (т. к. dev-уровень не знает и не должен ничего знать о том, через что пакет физически попал в ядро)


Цитата(null56 @  30.1.2011,  01:07 Найти цитируемый пост)
получается, что data не изменяется, она как указывала, так и указывает на начало моего канального кадра? то есть после этих манипуляций я не могу использовать функцию

вот ip_rcv
http://lxr.free-electrons.com/source/net/i...ip_input.c#L375
обработчик packet-сокета для ipv4
там ip_hdr юзается вполне нормально


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
MAKCim
Дата 30.1.2011, 11:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(null56 @  30.1.2011,  01:07 Найти цитируемый пост)
мы получим смещение на мак, а там совсем другие данные? другими словами, я не вижу, где data смещается на заголовок сетевого уровня

вот драйвер реалтековский
r8169.c
функция rtl8169_rx_interrupt (обработчик прерывания сетевой карты)
http://lxr.free-electrons.com/source/drive...?v=2.6.25#L2831
skb_put(skb, pkt_size) формирует линейный буфер сокета
eth_type_trans тут
http://lxr.free-electrons.com/source/net/ethernet/eth.c#L158
в skb_reset_mac_header мы вычисляем mac header как data - head
(data и head тут одинаковы)
дальше skb_pull_inline на ETH_HLEN
т. е. это и есть увеличение data

иными словами, задача _каждого_ драйвера - увеличение data на нужный ему известный размер


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
null56
Дата 30.1.2011, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



получается, что после обработчика прерывания сетевой мы уже имеем в обработчике packet_type:
data == network
mac = data - (my_mac_size + ETH_SIZE)
смещаюсь на мой мак, правлю, убирая мой апендикс и изменяю protocol, далее уже будет вызов в обработчике ip уровня

Цитата(MAKCim @  30.1.2011,  11:34 Найти цитируемый пост)
head указывает на начало линейного буфера (=заголовок канального уровня)

не факт, я про заголовок канального уровня...  head указывает на начало зарезервированного headroom участка, который может быть куда больше заголовка канального уровня, на картинке это хорошо заметно, посмотри функцию push
http://www.skbuff.net/skbbasic.html
именно поэтому
http://lxr.free-electrons.com/source/net/core/dev.c#L2936
Код

skb->mac_len = skb->network_header - skb->mac_header;


в общем спасибо, что помог разобраться с последовательностью вызовов и изменением полей sk_buff, остальное увижу в отладчике или отладочной печати
PM MAIL   Вверх
ROKR
Дата 31.1.2011, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 26.9.2009

Репутация: 1
Всего: 1



Если я правильно понимаю, о чем речь, то:

When setting up receive packets that an ethernet device will DMA into, we typically call skb_reserve(skb, NET_IP_ALIGN). By default NET_IP_ALIGN is defined to '2'. This makes it so that, after the ethernet header, the protocol header will be aligned on at least a 4-byte boundary. Nearly all of the IPV4 and IPV6 protocol processing assumes that the headers are properly aligned.  Взято отсюда

Вот пример того, что я делал:

Код

new_skb = dev_alloc_skb(length + NET_IP_ALIGN);

    skb_reserve(new_skb, NET_IP_ALIGN);

    memcpy(skb_put(new_skb, length), data, length);

    new_skb->protocol = eth_type_trans( new_skb, netdev );

#ifdef PRINT_PACKAGE_DATA
    DPRINTK(DEBUG, "Received length: %d, new_skb->len: %d", length, new_skb->len );

    memcpy(&eth, eth_hdr( new_skb ), sizeof( eth ));
    DPRINTK(DEBUG, "mac daddr = %02x.%02x.%02x.%02x.%02x.%02x"
        , eth.h_dest[0], eth.h_dest[1], eth.h_dest[2]
        , eth.h_dest[3], eth.h_dest[4], eth.h_dest[5]);
    DPRINTK(DEBUG, "mac saddr = %02x.%02x.%02x.%02x.%02x.%02x"
        , eth.h_source[0], eth.h_source[1], eth.h_source[2]
        , eth.h_source[3], eth.h_source[4], eth.h_source[5]);
    DPRINTK(DEBUG, "type = %04x", eth.h_proto);
#endif

    err = netif_receive_skb(new_skb);


В data уже лежал целиковый ethernet-пакет. Ну и указывать протокол: new_skb->protocol = eth_type_trans( new_skb, btmbnep_netdev ); тоже обязательно.
PM MAIL   Вверх
null56
Дата 11.2.2011, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



Продолжу тему, ибо столкнулся с проблемой....
1) при отправке пакета, изменяю идентификатор протокола на свой
Код

int boff_xmit(struct sk_buff *skb, struct net_device *dev)
{
    skb_reset_mac_header(skb);
    eth_hdr(skb)->h_proto = htons(0xBBCE);
    dev_queue_xmit(skb);

2) на другой машине ставлю фильтр для этого типа пакетов
Код

    l3proto.type = htons(0xBBCE);
    l3proto.func = func;
    dev_add_pack(&l3proto);

3) пакеты как и полагается попадают в колбак, где я пытаюсь изменить протокол и отправить вышележащим
Код

static int l2rx(
        struct sk_buff *skb,
        struct net_device * macdev,
        struct packet_type * pt,
        struct net_device * orig_dev)
{
   eth_hdr(skb)->h_proto  = htons(ETH_P_IP);
   skb_push(skb, ETH_HLEN); // ETH_HLEN == 14
   skb->protocol = eth_type_trans(skb, skb->dev);

и пакет уходит в неизвестном направлении
для примера я использую устройства броадкасты. если посылать пакеты не изменяя h_proto в кадре ethernet и ставя фильтр соответственно на ETH_P_IP, то пакеты также попадают в мой колбак и достигают цели

что не так? почему не достаточно просто поправить протокол? что еще нужно сделать?

буду благодарен за помощь
PM MAIL   Вверх
null56
Дата 11.2.2011, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



смотрю примеры и замечаю, что после определения протокола вызывают netif_rx
http://www.google.com/codesearch/p?hl=ru#M...cd=16&ct=rc

поэтому вопрос пока не решен
PM MAIL   Вверх
null56
Дата 13.2.2011, 04:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



пока не ясно, что еще нужно сделать с skb, чтобы сетевая подсистема отправила сама этот буфер вверх по протоколам... но можно попробовать это
Код

/*
 *      Main IP Receive routine.
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)


но по идее не нужны такие костыли, ведь абсолютно идентичные пакеты, но с обычной ip сигнатурой отправляются, а мои нет... буду мучить, результаты экспериментов не ранее понедельника  smile 
PM MAIL   Вверх
null56
Дата 17.2.2011, 00:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 4
Всего: 12



Цитата(ROKR @  31.1.2011,  14:40 Найти цитируемый пост)
netif_receive_skb(new_skb);

это правильный ответ...  а теперь подробнее
начать наверное лучше всего с регистрации своего обработчика, фукнция dev_add_pack, посмотрим ее исходный код
Код

 398void dev_add_pack(struct packet_type *pt)
 399{
 400        struct list_head *head = ptype_head(pt);
 401
 402        spin_lock(&ptype_lock);
 403        list_add_rcu(&pt->list, head);
 404        spin_unlock(&ptype_lock);
 405}

ключевой является функция ptype_head в строчке номер 400, вот она ниже
Код

 377static inline struct list_head *ptype_head(const struct packet_type *pt)
 378{
 379        if (pt->type == htons(ETH_P_ALL))
 380                return &ptype_all;
 381        else
 382                return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
 383}

и так мы видим, что если мы регистрируем обработчик для любых езернет кадров (например мы делаем снифер) ETH_P_ALL, то получаем список ptype_all, иначе, как в моем случае, мы получаем список ptype_base. это ключевой момент, теперь можно вернуться к функции __netif_receive_skb
первый раз идет вызов обработчиков для ETH_P_ALL
http://lxr.free-electrons.com/source/net/core/dev.c#L2949
Код

2949         list_for_each_entry_rcu(ptype, &ptype_all, list) {
2950                 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
2951                     ptype->dev == orig_dev) {
2952                         if (pt_prev)
2953                                 ret = deliver_skb(skb, pt_prev, orig_dev);
2954                         pt_prev = ptype;
2955                 }
2956         }

обращаем внимание, что используется список ptype_all, а второй раз мы как раз идем по списку с нашим обработчиком ptype_base
http://lxr.free-electrons.com/source/net/core/dev.c#L3001
Код

3001         type = skb->protocol;
3002         list_for_each_entry_rcu(ptype,
3003                         &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
3004                 if (ptype->type == type && (ptype->dev == null_or_orig ||
3005                      ptype->dev == skb->dev || ptype->dev == orig_dev ||
3006                      ptype->dev == orig_or_bond)) {
3007                         if (pt_prev)
3008                                 ret = deliver_skb(skb, pt_prev, orig_dev);
3009                         pt_prev = ptype;
3010                 }
3011         }

тут как раз идем по ptype_base И БОЛЬШЕ НИКТО НИЧЕГО В ЭТОЙ ФУНКЦИИ ВЫЗЫВАТЬ НЕ БУДЕТ. В итоге, как я понял, в нашем обработчике мы должны изменить протокол и вызвать netif_receive_skb, чтобы у меня вызвался обработчик ip кадров и пакет передался выше по стеку протоколов....
так что так

Это сообщение отредактировал(а) null56 - 17.2.2011, 00:29
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0944 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.