Форум по операционной системе GNU/Linux и свободному программному обеспечению
Текущее время: 24 апр 2019, 07:21

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 43 ]  На страницу Пред.  1, 2, 3, 4, 5  След.
Автор Сообщение
Непрочитанное сообщениеДобавлено: 24 янв 2013, 18:08 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
mcrandy писал(а):
Цитата:
Ох! Боюсь я таких "своих" программ-тестеров!

Открою секрет :) Эта программа основана на функциях _send(), ucnet_send(), _recv(), ucnet_recv(), которые являются базовыми для передачи трафика между машинами в создаваемой системе. Объем трафика там небольшой, не будет таких больших сообщений, которые я пытаюсь передавать.

Цитата:
Потому как по TCP нельзя передавать сообщения, да ещё и "заданной длины"(с) - TCP это stream, поток, "труба", в один конц которой можно "вливать", а из другой - "вытекает"...

Честно говоря я не понимаю... Разве я не так использую TCP?


Да. Вы принципиально используете TCP "не так".
В TCP нет, и вообще быть не может, никаких "сообщений".

А если это "являются базовыми для передачи трафика между машинами в создаваемой системе"(с) - то это значит, что вы закладываете в свою систему то, от чего ей ... прийдёт гоплык :lol:
И проявляться это будет, скорее, именно на коротких передаваемых сообщениях, чем на больших.

Но это предмет отдельного разговора ... для отдельной темы, да и не здесь, а где-то в Сети (там, кстати, есть темы, затрагивающие в примерах эти ваши вопросы).

mcrandy писал(а):
Я должен быть уверен что сообщение доставлено, а UDP не подтверждает доставку...
Программа же не пытается отправить все громоздкое сообщение целиком, а отправляет его по частям.


Смотрите протокол SCTP (вместо TCP и UDP) - я ссылку выше показывал.


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 00:23 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
- Такой пример с установкой фильтра протоколов описывается (именно в таком виде) давно, начиная с ядер 2.4 (а может быть и раньше). Возможно в поздних ядрах (2.6.29 и далее) что-то поменялось? ... Только чтобы никто ничего не заметил и не описал?


Пройдусь поиском что пишут по этому случаю полезного ... те публикации, которые могут даль пищу к размышлению:

Кодим в ядре Linux`а №6 - написано давно, очень поверхностно ... но может быть;
Следопыты
Экспериментальная реализация стека сетевых протоколов e6 в ядре ОС Linux
Инфицирование на лету - это просто пацанячьий визг ... но можно глянуть ;-)


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 00:29 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
mcrandy писал(а):
Решил помучать google на эту тему и нашел где то в комментарих соображения о том что после использования данного системного вызова следует выполнять kfree_skb(skb);. Решил попробовать:
Код:
int test_pack_rcv( struct sk_buff *skb, struct net_device *dev,
                   struct packet_type *pt, struct net_device *odev ) {
//   printk( KERN_INFO "packet received with length: %u\n", skb->len );
   kfree_skb(skb);
   return skb->len;
};


И, к моему удивлению, утечки памяти прекратились! Работа системы не нарушилась и сообщения приходят и отправляются... Беда в том что теперь я совсем не понимаю как работает системный вызов dev_add_pack()? какой буферный сокет я уничтожил?


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


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 02:07 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
mcrandy писал(а):
И, к моему удивлению, утечки памяти прекратились! Работа системы не нарушилась и сообщения приходят и отправляются... Беда в том что теперь я совсем не понимаю как работает системный вызов dev_add_pack()? какой буферный сокет я уничтожил?


Смотрим код реализации dev_add_pack() - http://lxr.free-electrons.com/source/ne ... dev.c#L410 :
Код:
410 void dev_add_pack(struct packet_type *pt)
411 {
412         struct list_head *head = ptype_head(pt);
413
414         spin_lock(&ptype_lock);
415         list_add_rcu(&pt->list, head);
416         spin_unlock(&ptype_lock);
417 }

Структура struct packet_type добавляется в список обработчиков для данного типа протоколов, добавляется, но не замещает существующий обработчик. Если для сокетных буферов данного протокола существует N установленных обработчиков, то достаточно логично, чтобы для каждого из поступающих struct sk_buff создавалось N клонов структуры, чтобы каждый из N обработчиков мог независимо обработать свой экземпляр struct sk_buff.

Но "логично" не значит "так и есть".
Нужно проверять.
Кроме того, мне непонятна семантика целочисленного значения, возвращаемого обработчиком протокола.


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 02:44 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
mcrandy писал(а):
Цитата:
4. То что вы делаете "создаю трафик между двумя машинами"

У меня есть своя клиент-серверная программка организующая передачу рандомного сообщения заданной длины. В ней используются стандартные функции send() и recv() для передачи/приема соответственно. Используется протокол TCP. Она осложнена только тем что в начало сообщения записывает длину этого сообщения которое собирается передать, чтобы сервер знал сообщение какой длины ему ожидать. Программку прикрепляю к сообщению. Внутри есть небольшой README.


Ох! ;-) Боюсь я таких "своих" программ-тестеров!


В дополнение:
- UNIX - это не Windows, и изживать привычки Windows ой как не просто...
- в UNIX все консольные команды (и API) подчиняются стандартам POSIX, а поэтому первейшее и самое достоверное тестирование любого программного изделия - это тестирование штатными консольными командами...
- если это локальные программы (модули) - то командами: cat, echo, copy, ...
- если это сетевые компоненты, то командами: scp, sftp, nc, ...

В Windows подобное трудно представить (попробуйте командой направить поток в последовательный порт? ;-) ), а здесь это именно так. И только отработав на штатных командах POSIX, имеет смысл переходить на какие-то специально писанные тесты + только в том случае, если штатными тестами что-то проверить невозможно (но чаще такая ситуация - это недостаток изобретательности).


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 17:13 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
mcrandy писал(а):
Беда в том что теперь я совсем не понимаю как работает системный вызов dev_add_pack()?


Никогда не называйте это "системный вызов" - это имя API ядра (или символ ядра ... вызов API ядра, на худой конец).
(дело не в названии, а в том, что за неправильным названием потянется и неправильность в понимании)

mcrandy писал(а):
какой буферный сокет я уничтожил?


А здесь история в том, думаю, что вы неправильно толкуете понятие буфера сокетов struct sk_buff. И в этом причина и того, что в примерах в литературе показывают примеры без kfree_skb( skb ).

Я так понимаю это так:
- в прежних версиях версиях ядра 2.4 (и, похоже, ранних 2.6) struct sk_buff действительно представлял собой "пакет", содержащий все заголовки разных уровней (Ethernet, IP, TCP, ...) + сами данные сетевого пакета
- но сейчас struct sk_buff содержит только служебную информацию + указатели на заголовки разных уровней, расположенные в теле пакета, которое находится совсем отдельно
- см. http://www.ibm.com/developerworks/ru/li ... index.html
Код:
typedef unsigned char *sk_buff_data_t;
struct sk_buff {
   struct sk_buff *next; /* эти два элемента должны быть объявлены первыми. */
   struct sk_buff *prev;
...
   sk_buff_data_t  transport_header; // заголовок TCP
   sk_buff_data_t  network_header;   // заголовок IP
   sk_buff_data_t  mac_header;       // заголовок MAC
...
   sk_buff_data_t  tail;                     
   sk_buff_data_t  end;              // конец области полного пакета
...
   unsigned char *head,              // начало области полного пакета
                 *data;
...
};

- отсюда происходит и неверный смысл отладочного сообщения в примерах:
Код:
  printk( KERN_INFO "packet received with length: %u\n", skb->len );

- это не есть длина пакета!

Если это всё так, то можно производить сколько угодно клонов сокетного буфера и уничтожать их - при этом сами данные пакета не потеряются и не уничтожаются. На это указывает и то, что среди API ядра операция с сокетными буферами, наряду с alloc_skb, skb_copy, ... - есть и skb_clone.


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 18:52 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
Но "логично" не значит "так и есть".
Нужно проверять.
Кроме того, мне непонятна семантика целочисленного значения, возвращаемого обработчиком протокола.


Есть там и ещё один вопрос, принципиально важный:
- если устанавливается несколько функций обработчиков последовательными вызовами dev_add_pack(), то в какой последовательности они будут вызываться при приёме пакета?
- и отсюда очень важное следствие: новый установленный dev_add_pack() обработчик будет вызываться раньше дефаултной обработки (так казалось бы должно быть).

Сделал я дополнительный пример, в котором устанавливаются 2 обработчика с похожими функциями фильтрации:
Код:
int test_pack_rcv_1( struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *pt, struct net_device *odev ) {
   LOG( "filter function #1: %p\n", skb );
   kfree_skb( skb );
   return skb->len;
};


И вот что в результате:
Код:
[olej@fedora netproto]$ sudo insmod net_proto2.ko link=p7p1
[olej@fedora netproto]$ dmesg | tail -n1 | grep !
[ 9097.858345] ! module net_proto2 loaded for link p7p1

Код:
Теперь с другого хоста:
[olej@nvidia ~]$ ping 192.168.56.3
PING 192.168.56.3 (192.168.56.3) 56(84) bytes of data.
64 bytes from 192.168.56.3: icmp_req=1 ttl=64 time=0.508 ms
64 bytes from 192.168.56.3: icmp_req=2 ttl=64 time=0.304 ms
64 bytes from 192.168.56.3: icmp_req=3 ttl=64 time=0.290 ms
^C
--- 192.168.56.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.290/0.367/0.508/0.100 ms

И в итоге:
Код:
[olej@fedora netproto]$ sudo rmmod net_proto2
[olej@fedora netproto]$ dmesg | tail -n8 | grep !
[ 9097.858345] ! module net_proto2 loaded for link p7p1
[ 9142.121590] ! filter function #2: ed9bbcc0
[ 9142.121596] ! filter function #1: ed9bbcc0
[ 9143.121499] ! filter function #2: ed9bbd80
[ 9143.121504] ! filter function #1: ed9bbd80
[ 9144.121650] ! filter function #2: ed9bb0c0
[ 9144.121655] ! filter function #1: ed9bb0c0
[ 9257.459095] ! module net_proto2 unloaded

1. вызываются оба обработчика...
2. вызываются они в порядке обратном установке (позже установленный вызывается первым)...
3. т.е. все они будут вызваны раньше дефаултной обработки
4. но!!! функции обработчики получают одинаковый адрес struct sk_buff, т.е. указатель на одну копию :-o
5. а kfree_skb() выполненная дважды над одной структурой - не приводит к краху системы (как это было бы при kfree())
6. нужно смотреть код в ядре реализации kfree_skb().


Вложения:
netproto.tgz [6.11 КБ]
Скачиваний: 425
Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 19:31 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
6. нужно смотреть код в ядре реализации kfree_skb().

http://lxr.free-electrons.com/source/ne ... uff.c#L624
Код:
610 void __kfree_skb(struct sk_buff *skb)
611 {
612         skb_release_all(skb);
613         kfree_skbmem(skb);
614 }
...
617 /**
618  *      kfree_skb - free an sk_buff
619  *      @skb: buffer to free
620  *
621  *      Drop a reference to the buffer and free it if the usage count has
622  *      hit zero.
623  */
624 void kfree_skb(struct sk_buff *skb)
625 {
626         if (unlikely(!skb))
627                 return;
628         if (likely(atomic_read(&skb->users) == 1))
629                 smp_rmb();
630         else if (likely(!atomic_dec_and_test(&skb->users)))
631                 return;
632         trace_kfree_skb(skb, __builtin_return_address(0));
633         __kfree_skb(skb);
634 }
635 EXPORT_SYMBOL(kfree_skb);

Даже не глядя в код, по комментариям ... - если число использования struct sk_buff становится нулевым, тогда буфер освобождается, а иначе число использования декрементируется (грубо).

Т.е. здесь объяснение необходимости kfree_skb():
- если вы установили новый обработчик, то skb->users увеличивается...
- если обработчик не делает kfree_skb(), то к дефаултному (последнему) обработчику struct sk_buff приходит с user > 1 ...
- а после этого дефаултного обработчика удалять буфер уже некому и уменьшить user уже некому.

P.S. Характерно, что среди API ядра операций с сокетными буферами есть alloc_skb, но нет ничего подобного destroy_skb ... потому, что в самом теле struct sk_buff определяется функция-деструктор:
Код:
...
void (*destructor)( struct sk_buff* );
...


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 25 янв 2013, 20:23 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
И только отработав на штатных командах POSIX, имеет смысл переходить на какие-то специально писанные тесты + только в том случае, если штатными тестами что-то проверить невозможно


Один из лучших естественных тестов для обсуждаемой нами вашей задачи - это утилита nc - сетевой cat.

Вот как это может выглядеть:

- на удалённом хосте (на хостовой машине VM) делаем:
Код:
[olej@nvidia _TMP]$ echo 0123456789 > dg.txt
[olej@nvidia _TMP]$ cat dg.txt | nc -l 12345


- на отрабатываемой (модуль net_proto2.ko) машине (VM):
Код:
[olej@fedora netproto]$ nc 192.168.56.1 12345 > file.txt
[olej@fedora netproto]$ cat file.txt
0123456789


- и сообщения протокольных обработчиков модуля:
Код:
[olej@fedora netproto]$ dmesg | tail -n20
[15252.925763] ! filter function #2: eb50d600
[15252.925764] ! filter function #1: eb50d600
[15346.592897] ! filter function #2: ed4f4000
[15346.592902] ! filter function #1: ed4f4000
[15404.210491] ! filter function #2: ed4f4000
[15404.210495] ! filter function #1: ed4f4000
[15404.210753] ! filter function #2: ed431900
[15404.210756] ! filter function #1: ed431900
[15404.210808] ! filter function #2: ed431f00
[15404.210810] ! filter function #1: ed431f00
[15404.211728] ! filter function #2: ed431f00
[15404.211732] ! filter function #1: ed431f00
[15505.423315] ! filter function #2: eb50d6c0
[15505.423319] ! filter function #1: eb50d6c0
[15505.423492] ! filter function #2: eb50d780
[15505.423493] ! filter function #1: eb50d780
[15505.423528] ! filter function #2: eb50d3c0
[15505.423529] ! filter function #1: eb50d3c0
[15505.423775] ! filter function #2: eb50d6c0
[15505.423777] ! filter function #1: eb50d6c0


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Непрочитанное сообщениеДобавлено: 26 янв 2013, 18:03 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 11699
Откуда: Харьков
Olej писал(а):
Т.е. здесь объяснение необходимости kfree_skb():
- если вы установили новый обработчик, то skb->users увеличивается...
- если обработчик не делает kfree_skb(), то к дефаултному (последнему) обработчику struct sk_buff приходит с user > 1 ...
- а после этого дефаултного обработчика удалять буфер уже некому и уменьшить user уже некому.


В тему - http://www.osp.ru/os/2001/12/180759/:
Цитата:
При более внимательном изучении процедуры net_rx_action можно заметить еще два интересных момента. Один из них заключается в том, что можно зарегистрировать модуль «для всех протоколов» и пользоваться им для анализа всех пакетов. Второй, более тонкий, заключается в том, что пакет не отдается немедленно тому протоколу, тип которого соответствует нужному. Сначала делается попытка найти еще одно соответствие и только потом принимается решение о передаче пакета протокольной процедуре. Зачем? Для того чтобы оптимизировать передачу данных. Если имеется более одной записи для данного пакета (т.е. пакет придется отдать более чем одной процедуре/протоколу), то перед передачей выполняется действие atomic_inc(&skb->users), чтобы установить режим работы copy on write («копирование при записи»). Если одна из процедур решит, что это не ее пакет, то она освободит его, передав в полное распоряжение другой; если же нет, произойдет клонирование пакетов.


Вернуться к началу
 Профиль Отправить личное сообщение Отправить email  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 43 ]  На страницу Пред.  1, 2, 3, 4, 5  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


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

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB
[ Time : 0.370s | 16 Queries | GZIP : On ]