Модуль ядра Linux. Виртуальный сетевой интерфейс.

Вопросы программного кода и архитектуры Linux

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение Olej » 29 янв 2013, 15:32

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

А тема интересная. Есть чего покопать...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение Olej » 29 янв 2013, 19:21

Olej писал(а):А тема интересная. Есть чего покопать...
1. Использую пример с 2-мя новыми обработчиками, показанный выше (download/file.php?id=642).
Вот таким манером:

Код: Выделить всё

int test_pack_rcv_1( struct sk_buff *skb, struct net_device *dev,
                     struct packet_type *pt, struct net_device *odev ) {
   int s = atomic_read( &skb->users );
//   kfree_skb( skb );
   if( debug > 0 ) LOG( "function #1 - %p => users: %d->%d\n", skb, s, atomic_read( &skb->users ) );
   return skb->len;
};

int test_pack_rcv_2( struct sk_buff *skb, struct net_device *dev,
                     struct packet_type *pt, struct net_device *odev ) {
   int s = atomic_read( &skb->users );
//   kfree_skb( skb );
   if( debug > 0 ) LOG( "function #2 - %p => users: %d->%d\n", skb, s, atomic_read( &skb->users ) );
   return skb->len;
};

static struct packet_type
test_proto1 = {
   __constant_htons( ETH_P_IP ),
   NULL,
   test_pack_rcv_1,
   (void*)1,
   NULL
},
test_proto2 = {
   __constant_htons( ETH_P_IP ),
   NULL,
   test_pack_rcv_2,
   (void*)1,
   NULL
};
...
   dev_add_pack( &test_proto1 );
   dev_add_pack( &test_proto2 );
...
2. Если в обработчиках закомментировать kfree_skb( skb ), то при ping на хост получим вот так:

Код: Выделить всё

[olej@fedora netproto]$ dmesg | tail -n7
[11373.754524] ! module net_proto2 loaded for link p7p1
[11398.930057] ! function #2 - ed3dfc00 => users: 2->2
[11398.930061] ! function #1 - ed3dfc00 => users: 3->3
[11399.929838] ! function #2 - ed3dfb40 => users: 2->2
[11399.929843] ! function #1 - ed3dfb40 => users: 3->3
[11400.929522] ! function #2 - ed3df480 => users: 2->2
[11400.929527] ! function #1 - ed3df480 => users: 3->3
Видно, что каждый последующий (по срабатыванию! - обратно регистрации!) обработчик получает skb->users инкрементированным относительно возвращаемого предыдущим обработчиком. Если после последнего обработчика (к дефаултному) skb->users != 1, то буфер сокетный и не будет уничтожен, и утечка памяти будет наблюдаться.

3. А если обработчик протокола завершается kfree_skb( skb ), то этот вызов только декркментирует skb->users, и тогда дефаултный обработчик (?) удалит буфер сокетный после, и не будет никакой утечки памяти. А системный журнал в этом случае покажет:

Код: Выделить всё

[olej@fedora netproto]$ dmesg | tail -n7
[  403.339591] ! module net_proto2 loaded for link p7p1
[  420.305824] ! function #2 - eb6873c0 => users: 2->1
[  420.305829] ! function #1 - eb6873c0 => users: 2->1
[  421.306302] ! function #2 - eb687c00 => users: 2->1
[  421.306308] ! function #1 - eb687c00 => users: 2->1
[  422.306289] ! function #2 - eb687180 => users: 2->1
[  422.306294] ! function #1 - eb687180 => users: 2->1

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение Olej » 29 янв 2013, 19:32

Olej писал(а):и не будет никакой утечки памяти.
В качестве теста передачи очень больших объёмов данных и проверки утечек памяти при этом, предлагаю:

1. делаем и запускаем скрип server на удалённом хосте (или на хосте менеджера VirtualBox):

Код: Выделить всё

dd if=/dev/zero of=z.txt bs=1M count=1

LIMIT=1000000
for ((a=1; a <= LIMIT ; a++))
do
   cat z.txt | nc -l 12345
done
2. делаем скрипт client, и запускаем его на хосте с тестируемым модулем net_proto2.ko :

Код: Выделить всё

LIMIT=1000000
for ((a=1; a <= LIMIT ; a++))
do
   rm -а z.txt
   nc 192.168.56.1 12345 > z.txt
   sleep 1
done
(192.168.56.1 - это IP серверного хоста из п.1, а 12345 - TCP порт, через который nc предписывается гонять данные, с ключом -u можете вместо TCP заказать UDP ... любой каприз! ;-) )

3. после чего отправляемся попить кофейку ;-) ... минут на 15-20 как минимум, после чего на тестируемом хосте имеем:

Код: Выделить всё

[olej@fedora netproto]$ ifconfig p7p1
p7p1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.56.3  netmask 255.255.255.255  broadcast 192.168.56.3
        inet6 fe80::a00:27ff:fe08:9abd  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:08:9a:bd  txqueuelen 1000  (Ethernet)
        RX packets 2017560  bytes 3048762624 (2.8 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 398156  bytes 26283474 (25.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[olej@fedora netproto]$ free
             total       used       free     shared    buffers     cached
Mem:        768084     260636     507448          0      23392     129108
-/+ buffers/cache:     108136     659948
Swap:      1540092          0    1540092
P.S. Почему в ifconfig стоит 2.8 GiB, а не ... 28? Для меня при первом взгляде было озадачивающим (у меня тест работал часов 5 ... он ведь мне работать не мешает? ;-) ).
Да потому, что 32-бит ifconfig после 4GiB снова обнулит всё... В показанном примере у меня перегнано було несколько сот гигабайт - никаких утечек!

mcrandy
Активист
Сообщения: 18
Зарегистрирован: 21 янв 2013, 12:51
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение mcrandy » 04 фев 2013, 11:32

Очень жаль, что mcrandy потерял интерес к обсуждаемой теме.
(скорее всего, по принципу: как-то заработало - и ладно, а что там происходит - Бог с ним... )

А тема интересная. Есть чего покопать...
Нет, нет, нет! На прошлой неделе меня не было вблизи интернета... Я уезжал из Москвы и забыл предупредить что не смогу писать сюда какое то время.
Спасибо что продолжали писать в тему!
Сейчас я прочитаю и переварю все что пропустил и продолжу дискуссию)

mcrandy
Активист
Сообщения: 18
Зарегистрирован: 21 янв 2013, 12:51
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение mcrandy » 04 фев 2013, 14:01

Видно, что каждый последующий (по срабатыванию! - обратно регистрации!) обработчик получает skb->users инкрементированным относительно возвращаемого предыдущим обработчиком. Если после последнего обработчика (к дефаултному) skb->users != 1, то буфер сокетный и не будет уничтожен, и утечка памяти будет наблюдаться.
Теперь все понятно! Загадка хранилась в счетчике использований skb->users и в реализации функции kfree_skb()...
Очень понравился пример с добавлением двух обработчиков. Сразу стало понятно каким образом skb проходит через каждый из них. Спасибо! :-)

mcrandy
Активист
Сообщения: 18
Зарегистрирован: 21 янв 2013, 12:51
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение mcrandy » 04 фев 2013, 14:08

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

- устанавливаем модуль на виртуальном хосте 192.168.1.137 и к нему же обращаемся по копированию больших файлов туда-сюда... командами типа:

Код: Выделить всё

bash-4.2$ scp olej@192.168.1.137:/boot/initramfs-3.6.11-5.fc17.i686.img img1
olej@192.168.1.137's password:
initramfs-3.6.11-5.fc17.i686.img                                                                   100%   18MB  17.6MB/s   00:01

Код: Выделить всё

bash-4.2$ scp img1 olej@192.168.1.137:/home/olej/i1
olej@192.168.1.137's password:
img1                                                                                               100%   18MB  17.6MB/s   00:01
- вот сразу после загрузки модуля

Код: Выделить всё

[olej@fedora net_proto]$ lsmod | head -n5
Module                  Size  Used by
net_proto              12448  0
lockd                  77991  0
sunrpc                215746  1 lockd
bnep                   18864  2
[olej@fedora net_proto]$ free
             total       used       free     shared    buffers     cached
Mem:        768084     271044     497040          0      38992     123124
-/+ buffers/cache:     108928     659156
Swap:      1540092          0    1540092
- погонял туда сюда ... сотни мегабайт

Код: Выделить всё

[olej@fedora net_proto]$ free
             total       used       free     shared    buffers     cached
Mem:        768084     726160      41924          0        884      15952
-/+ buffers/cache:     709324      58760
Swap:      1540092      70904    1469188
[olej@fedora net_proto]$ ifconfig p2p1
p2p1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.137  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::a00:27ff:fe87:ea29  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:87:ea:29  txqueuelen 1000  (Ethernet)
        RX packets 253116  bytes 349694488 (333.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 130629  bytes 201012758 (191.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
- цифры распределения памяти меняются, но работоспособность хоста никак не рушится.

Странно что у вас в этот момент не наблюдалась утечка памяти. Ведь функции kfree_skb() еще не вызывалась в этом модуле.
Почему утечка не наблюдалась?

mcrandy
Активист
Сообщения: 18
Зарегистрирован: 21 янв 2013, 12:51
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение mcrandy » 04 фев 2013, 14:21

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

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

Но это предмет отдельного разговора ... для отдельной темы, да и не здесь, а где-то в Сети (там, кстати, есть темы, затрагивающие в примерах эти ваши вопросы).
Либо я что то не понимаю и действительно использую TCP не правильно, либо вы не поняли как устроена тестовая программка. В этом мне хочется разобраться не меньше чем в модуле ядра...
Сейчас полистал темы в разделе "Сети", но ничего на эту тему не нашел. Буду рад, если ткнете пальцем в конкретное место :-)
Или мне следует создать новую тему в том разделе с соответствующими вопросами?

mcrandy
Активист
Сообщения: 18
Зарегистрирован: 21 янв 2013, 12:51
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение mcrandy » 04 фев 2013, 15:20

Раз у меня появился хоть и сырой, но более менее работающий виртуальный сетевой интерфейс, я продолжил реализовывать поставленную задачу.
Я начал передавать небольшие блоки данных и пытаться выводить их и при отправке и при приеме и в userspace и в kernelspace.
Для начала я определил что сам пакет лежит в skb по указателю skb->data, а не где то там в отдельной структуре skb_shared_info.
Потом мне удалось получить длину пакета и всех заголовков, получить указатели на IP и TCP заголовки и в итоге вывести данные из пакета в чистом виде.

Ради эксперимента попробовал переворачивать данные внутри каждого пакета, проходящего через мой обработчик.
При этом установил условие, чтобы работать только с пакетами, содержащими TCP:

Код: Выделить всё

if(iph->protocol != IPPROTO_TCP)
		return 0;
Запустил тест и заметил следующее поведение протокола TCP:
1. Отправляю текст длиной 1024 байт.
2. В модуле ядра на отправляющем хосте из skb печатается этот текст, затем происходит перестановка всех элементов с помощью такого действия:

Код: Выделить всё

unsigned char __user * buffer = kmalloc(data_len,1); //Выделение памяти под перевернутый пакет
	//Изменение данных(переворот):
				int k,m;
				for (k = 0, m = (data_len) - 1; k < (data_len) && m >= 0; k++, m--) 
                                {
				     buffer[k] = *(data_len+ m); //В этом цикле данные поэлементно копируются во временный буфер в обратном порядке
                                }
				memcpy(data_pkt, buffer, data_len); //Возвращаю данные в перевернутом виде на то место, где они лежат в skb
				kfree(buffer);
3. На принимающем хосте с помощью того же модуля ядра вывожу данные из получаемого пакета. Выводится перевернутый набор элементов.
4. И так как контрольная сумма полученного пакета не совпадает с той которая записана в заголовке TCP, то возвращается соответствующее оповещение.
5. Отправляющий хост начинает повторную пересылку и внимание! в мой обработчик попадает пакет с перевернутыми ранее данными, переворачивается снова и отправляется.
6. На принимающем хосте в обработчик попадает пакет с нормальным текстом и в этот раз пакет принимается и в userspace появляется исходный текст.

Все сработало как надо!
Добавляю цикл с переворотом в модуль ядра на принимающей стороне и запускаю тест заново.
Результат ожидаемый:
1. Данные из пакета переворачиваются и пакет уходит к адресату
2. Хост получает пакет, переворачивает данные снова и текст появляется в userspace в неизменном виде!

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

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение Olej » 04 фев 2013, 15:26

mcrandy писал(а): Странно что у вас в этот момент не наблюдалась утечка памяти. Ведь функции kfree_skb() еще не вызывалась в этом модуле.
Почему утечка не наблюдалась?
Нет, без kfree_skb() утечка памяти имеет место - медленно, но уверенно.
С kfree_skb() её нет. Проверено на прогоне через сетевой интерфейс десятков гигабайт.
Этот вопрос понятен, проехали... :lol:

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.

Непрочитанное сообщение Olej » 04 фев 2013, 15:50

mcrandy писал(а):
Olej писал(а): Да. Вы принципиально используете TCP "не так".
В TCP нет, и вообще быть не может, никаких "сообщений".
Либо я что то не понимаю и действительно использую TCP не правильно, либо вы не поняли как устроена тестовая программка. В этом мне хочется разобраться не меньше чем в модуле ядра...
Сейчас полистал темы в разделе "Сети", но ничего на эту тему не нашел. Буду рад, если ткнете пальцем в конкретное место :-)
Или мне следует создать новую тему в том разделе с соответствующими вопросами?
Да, к тестовой программе есть серьёзные вопросы.
Но это определённо нужно обсуждать не здесь, а где-то в новой теме в "Сети" ... в какой-то теме типа: "Передача сообщений TCP/IP".

P.S. Я создал для вас такую тему: Передача сообщений TCP/IP.

Ответить

Вернуться в «Linux изнутри»

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

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