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

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

Модератор: Olej

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

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

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

Добрый день!
В настоящий момент я занимаюсь задачей по шифрованию трафика на уровне ядра и мне очень помогли статьи Олега Ивановича Цилюрика по разработке модулей ядра, спасибо! Так же помогли статьи Олега с сайта IBM developerWorks.
Для изучения я использовал исходный код модулей из архива network.tgz, взятого от сюда.

Но у меня все еще остается несколько вопросов.

Для начала более общие:

1) Цель моей задачи - изменить содержимое IP пакета на отправляющей стороне, отправить его в сеть (при этом проследить чтобы исходный пакет не ушел в сеть), а на принимающей стороне получить пакет, произвести над ним обратное преобразование и протолкнуть дальше по стеку TCP/IP. Изучив материал, я нашел решение - использовать системный вызов dev_add_pack(). Павильно ли мое решение? Какие могут возникнуть проблемы? Может есть альтернативные решения? :!:

2) Каким образом пакет проходит по стеку TCP/IP если я регистрирую новый обработчик протокола 3-го уровня вызовом dev_add_pack()? Пакет сначала пройдет через мой обработчик, а затем пойдет в стандартный обработчик ip?

3) Мой обработчик будет вызываться при прохождении пакета по стеку TCP/IP как вверх, так и вниз? Я могу как то различать, пришел ли пакет из сети (входящий) или он создан на локальной машине (исходящий)?

4) Что повлечет за собой изменение длины пакета IP в буфере сокета sk_buff на этом уровне?

А теперь вопросы по конкретному модулю из статьи Разработка модулей ядра Linux: Часть 35. Дополнительные аспекты использования модулей ядра для создания сетевых интерфейсов:

3) Я исследовал упрощенную и полную версию данного виртуального интерфейса и заметил что упрощенный интерфейс(virtl.ko) работает как фильтр, т.е. он не различает какие пакеты для родительского интерфейса являются входящими, а какие исходящими, я правильно понимаю?

4) В полном виртуальном интерфейсе(virt.ko) каким образом пакеты проходят через стек TCP/IP? С помощью данного модуля ядра мы добавляем свои обработчики протоколов 3-го уровня, но после того как мы получили пакет и функция start_xmit() обработала его, куда он дальше попадает?

5) При исследовании данного модуля на принимающей сообщения машине я заметил утечку памяти. Если я отправляю 100мб, то на приемной стороне с запущенным модулем забьется ровно 100мб оперативки. Без этого модуля все нормально. После выгрузки модуля память не освобождается. Такое ощущения что буферы сокетов где то клонируются и не освобождаются. :?:

Буду рад любым советам. Спасибо! :geek:

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

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

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

mcrandy писал(а):Буду рад любым советам. Спасибо! :geek:
Давайте смотреть вместе.
Для начала очень хорошо бы сформулировать простейший тестовый проект (облегчённый от всяких деталей) + создать простейший тестовый проект (.tgz), который прикрепить к теме ... а дальше показывать и обсуждать его результаты.

P.S. Т.е.:
- взять какой-то проект ... можно из тех, что уже рассматривались здесь в темах (а их здесь несколько, 2 как минимум, альтернативно)...
- и показать: какие проблемы?, в каком объёме?, когда наблюдались?, и какие методики наблюдений и измерений?
- и править (доводить) здесь код тестового проекта ... так уже делалось не раз.

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

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

Непрочитанное сообщение mcrandy » 23 янв 2013, 11:14

Olej писал(а): Для начала очень хорошо бы сформулировать простейший тестовый проект (облегчённый от всяких деталей) + создать простейший тестовый проект (.tgz), который прикрепить к теме... а дальше показывать и обсуждать его результаты.
Хорошо, сформировал простейший проект. Прикрепил к сообщению.
Данный модуль выполняет системный вызов

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

dev_add_pack( &test_proto);
и добавляет обработчик 3-го уровня test_proto, который просто пропускает пакет через себя и выводит длину пакета

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

printk( KERN_INFO "packet received with length: %u\n", skb->len );
Проблема: создаю трафик между двумя машинами и как только запускаю этот модуль на принимающей сообщения машине, начинает выделяться в 2 раза больше оперативной памяти под трафик и не освобождается, постепенно пямять забивается и машина зависает. После выгрузки модуля память не освобождается.
Вложения
net_proto.tar
(10 КБ) 549 скачиваний

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

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

Непрочитанное сообщение Olej » 23 янв 2013, 16:34

mcrandy писал(а): Хорошо, сформировал простейший проект. Прикрепил к сообщению.
Данный модуль выполняет системный вызов

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

dev_add_pack( &test_proto);
и добавляет обработчик 3-го уровня test_proto, который просто пропускает пакет через себя и выводит длину пакета

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

printk( KERN_INFO "packet received with length: %u\n", skb->len );
Проблема: создаю трафик между двумя машинами и как только запускаю этот модуль на принимающей сообщения машине, начинает выделяться в 2 раза больше оперативной памяти под трафик и не освобождается, постепенно пямять забивается и машина зависает. После выгрузки модуля память не освобождается.
Взял посмотреть...

1. А почему у вас на файлах флаг x установлен? - вы что-то как-то через Windows копируете?

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

bash-4.2$ ls -l
итого 8
-rwxrwx--- 1 olej olej 609 янв.  18 15:52 Makefile
-rwxrwx--- 1 olej olej 793 янв.  23 10:59 net_proto.c
2. Это вы повторяете (пока) пример из Разработка модулей ядра Linux: Часть 34. Протоколы сетевого и транспортного уровней. Это более сложный (и менее плодотворный) путь. Почему вы (хотя бы для начала) не пользуетесь вариантом с созданием нового интерфейса: Разработка модулей ядра Linux: Часть 33. Виртуальный сетевой интерфейс?

3. Реализация на уровне протоколов будет (заведомо) более громоздкой, см. пример: Разработка модулей ядра Linux: Часть 35. Дополнительные аспекты использования модулей ядра для создания сетевых интерфейсов - я пока фиксирую все URL на которые буду ссылаться (как №33, №34, №35).

4. То что вы делаете "создаю трафик между двумя машинами":
- между реальными хостами LAN?
- в виртуальной машине?
- на локальном хосте?
- и самое главное - показывайте пошагово вывод команд! : при загрузке модуля ... ifconfig при (после) присвоения IP ... какой командой создаётся трафик и т.д. - показывайте протоколы выполнения, а не рассказывайте "на пальцах"!

5.
mcrandy писал(а): как только запускаю этот модуль на принимающей сообщения машине, начинает выделяться в 2 раза больше оперативной памяти под трафик и не освобождается, постепенно пямять забивается и машина зависает. После выгрузки модуля память не освобождается.
- каким образом (подробно!) вы меряете: сколько "начинает выделяться"? как "память забивается"? ... какие команды? какие цифры?
- как всё таки это происходит? "как только запускаю этот модуль" или "создаю трафик между двумя машинами" - это 2 очень разные вещи.

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

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

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

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

Пока это выглядит так:

- проверял в схеме:

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

192.168.1.5 <--LAN--> 192.168.1.9 <--VirtualBox--> 192.168.1.137 (DHCP)
Fedora 17             Fedora 15                    Fedora 17
- собрал в неизменном виде ваш модуль ... только убрал строку (такой "отладкой" при плотном трафике можно любые буфера исчерпать):

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

   printk( KERN_INFO "packet received with length: %u\n", skb->len );
- устанавливаем модуль на виртуальном хосте 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
- цифры распределения памяти меняются, но работоспособность хоста никак не рушится.

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

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

Непрочитанное сообщение mcrandy » 24 янв 2013, 12:18

1. А почему у вас на файлах флаг x установлен? - вы что-то как-то через Windows копируете?
Да, у меня основная система Winows 7, на ней установлено 2 виртуальных машины VirtualBox c Fedora14. Между ними настроено сетевое соединение типа мост.
Таким образом имитирую 2 физических машины и сеть между ними.
2. Это вы повторяете (пока) пример из Разработка модулей ядра Linux: Часть 34. Протоколы сетевого и транспортного уровней. Это более сложный (и менее плодотворный) путь. Почему вы (хотя бы для начала) не пользуетесь вариантом с созданием нового интерфейса: Разработка модулей ядра Linux: Часть 33. Виртуальный сетевой интерфейс?
У меня версия ядра 2.6.35

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

Linux IP239 2.6.35.14-106.fc14.x86_64
и соответственно системного вызова netdev_rx_handler из статьи №33 у меня нету.
Дело в том что очень велика вероятность того что мой модуль будет работать на версии ядра не выше 2.6.35.
3. Реализация на уровне протоколов будет (заведомо) более громоздкой, см. пример: Разработка модулей ядра Linux: Часть 35. Дополнительные аспекты использования модулей ядра для создания сетевых интерфейсов - я пока фиксирую все URL на которые буду ссылаться (как №33, №34, №35).
Согласен, пример из 35 выглядит громоздким и как раз с ним у меня проблемы по утечке памяти, но я не знаю как еще можно решить задачу для ядра 2.6.35.
4. То что вы делаете "создаю трафик между двумя машинами"
У меня есть своя клиент-серверная программка организующая передачу рандомного сообщения заданной длины. В ней используются стандартные функции send() и recv() для передачи/приема соответственно. Используется протокол TCP. Она осложнена только тем что в начало сообщения записывает длину этого сообщения которое собирается передать, чтобы сервер знал сообщение какой длины ему ожидать. Программку прикрепляю к сообщению. Внутри есть небольшой README.
каким образом (подробно!) вы меряете: сколько "начинает выделяться"? как "память забивается"? ... какие команды? какие цифры?
- как всё таки это происходит? "как только запускаю этот модуль" или "создаю трафик между двумя машинами" - это 2 очень разные вещи.
Сейчас попробую описать подробнее.
Наблюдаю за загрузкой системы посредством стандартной для Fedora графической утилиты "Системный монитор".
На VM1(виртуальная машина 1 - будет принимать сообщения):
Запускаю модуль net_proto

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

[Groshev@IP239 net_proto]$ sudo insmod ./net_proto.ko 
[Groshev@IP239 net_proto]$ dmesg | tail -n4
[ 7534.947213] ! virt0: device closed
[ 7534.972086] ! module cryptip unloaded
[ 7534.972088] ! =============================================
[ 7679.842367] module loaded
С системой все в порядке:
Изображение
Запускаю программу для приема сообщений:

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

[Groshev@IP239 test_tcp]$ ./server 
На VM2(виртуальная машина 2 - будет отправлять сообщения):
Запускаю клиентскую часть программы для отправки сообщений 3 раза с интервалом в 15-20 секунд(длина сообщения = 100Мб).

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

[Groshev@IP239 test_tcp]$ ./client 
socket complete.
connect complete.
SEND OK
send_bytes = 104857600
[Groshev@IP239 test_tcp]$ ./client 
socket complete.
connect complete.
SEND OK
send_bytes = 104857600
[Groshev@IP239 test_tcp]$ ./client 
socket complete.
connect complete.
SEND OK
send_bytes = 104857600
[Groshev@IP239 test_tcp]$
Наблюдаю за приемом сообщения на VM1:

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

[Groshev@IP239 test_tcp]$ ./server 
connect accept.
RECIEVE OK
bytes_read = 104857600

connect accept.
RECIEVE OK
bytes_read = 104857600

connect accept.
RECIEVE OK
bytes_read = 104857600
Сразу чувствуется загрузка, VM1 начинает подтормаживать. А на графике выделения память в системном мониторе видно как память выделилась 3 раза и не освободилась.
Изображение

P.S.:Тестировал программу, создающую трафик, без участия модуля ядра - все нормально, память не забивается.
P.P.S.: В модуле net_proto.c конечно же закоментировал строку с выводом printk.
Вложения
test_tcp.tar
(20 КБ) 664 скачивания

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

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

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

mcrandy писал(а):
1. А почему у вас на файлах флаг x установлен? - вы что-то как-то через Windows копируете?
Да, у меня основная система Winows 7, на ней установлено 2 виртуальных машины VirtualBox c Fedora14. Между ними настроено сетевое соединение типа мост.
Таким образом имитирую 2 физических машины и сеть между ними.
1. Но сохранять файлы/архивы вы же можете в файловой системе Fedora + из Fedora выходить в Интернет, чтобы писать сюда в форум и прикреплять файлы... Вот так (хоть это и не Fedora, но разницы нет):
Изображение
Гонять файлы Linux через Windows FS - это плохая практика!

2. Переставьте Fedora 14! В Fedora 14 ядро 2.6.36 (или около того) - оно устаревшее именно в части API сети.
Поставьте RFRemix 17.1, например здесь: http://spreader.yandex.net/fedora/russi ... /i386/iso/ , или где-то рядом.
Тем более, что в VirtualBox это дело достаточно быстрое, а 2-ю и далее ;-) копии - делаем просто копированием созданной VM.

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

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

Непрочитанное сообщение Olej » 24 янв 2013, 16:04

mcrandy писал(а):
4. То что вы делаете "создаю трафик между двумя машинами"
У меня есть своя клиент-серверная программка организующая передачу рандомного сообщения заданной длины. В ней используются стандартные функции send() и recv() для передачи/приема соответственно. Используется протокол TCP. Она осложнена только тем что в начало сообщения записывает длину этого сообщения которое собирается передать, чтобы сервер знал сообщение какой длины ему ожидать. Программку прикрепляю к сообщению. Внутри есть небольшой README.
Ох! ;-) Боюсь я таких "своих" программ-тестеров!
Потому как по TCP нельзя передавать сообщения, да ещё и "заданной длины"(с) ;-) - TCP это stream, поток, "труба", в один конц которой можно "вливать", а из другой - "вытекает"...
Об этом много-много пишут и Стивенс и др., но ... Этот номер проходит "до поры до времени", пока не сработают более сложные механизмы TCP, такие как: отсроченные подтверждения, алгоритм Найгла (объединение "пакетов"), адаптивное изменение окна передачи и приёма и т.д.
Нельзя это делать!

Пересылать "сообщения заданной длины" можно только UDP ... или SCTP (что ещё лучше).

Но программу теста я гляну.

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

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

Непрочитанное сообщение Olej » 24 янв 2013, 16:22

mcrandy писал(а): Сразу чувствуется загрузка, VM1 начинает подтормаживать. А на графике выделения память в системном мониторе видно как память выделилась 3 раза и не освободилась.
Такой индикатор памяти как GUI "системный монитор" не годится для таких наблюдений (это только индикативный показатель ... чего? - но как индикативный он, наверное, годится на начальном этапе).
В таком качестве уже лучше команды free, top ... но и это ещё не то.

Управление памятью в Linux достаточно сложное. Проделайте в своей пользовательской программе несколько больших malloc() с последующим их free()... Вы, возможно, ожидаете, что свободная память отобразится в индикаторах системы? Это совершенно не так! В сложном управлением памятью - залог эффективности такого управления.

Нужен доверительный механизм наблюдения за тем, что происходит с памятью...
Нужно над этим подумать.

На заметку некоторые соображения, над которыми нужно подумать:

- Такой пример с установкой фильтра протоколов описывается (именно в таком виде) давно, начиная с ядер 2.4 (а может быть и раньше). Возможно в поздних ядрах (2.6.29 и далее) что-то поменялось? ... Только чтобы никто ничего не заметил и не описал?

- В примере перехватываются все типы сетевых протоколов (ETH_P_ALL). Это не есть очень хорошо, т.к. туда попадают пакеты ARP и, что ещё хуже, всякие разные широковещательные пакеты NETBEUI от Windows, которые гуляют в великом множестве. Нужно бы глянуть при установке фильтра только на пакеты протокола TCP/IP (ETH_P_IP) будут ли наблюдаться какие-то артефакты?

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

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

Непрочитанное сообщение mcrandy » 24 янв 2013, 17:43

1. Но сохранять файлы/архивы вы же можете в файловой системе Fedora + из Fedora выходить в Интернет, чтобы писать сюда в форум и прикреплять файлы... Вот так (хоть это и не Fedora, но разницы нет):
Буду придерживаться такой практики :)
2. Переставьте Fedora 14! В Fedora 14 ядро 2.6.36 (или около того) - оно устаревшее именно в части API сети.
Поставьте RFRemix 17.1, например здесь: http://spreader.yandex.net/fedora/russi ... /i386/iso/ , или где-то рядом.
Тем более, что в VirtualBox это дело достаточно быстрое, а 2-ю и далее копии - делаем просто копированием созданной VM.
Дело в том что мне нужно работать именно с этой версией ядра. В конечной системе, в которой будет использоваться шифрование трафика версия ядра будет не выше.
Ох! Боюсь я таких "своих" программ-тестеров!
Открою секрет :) Эта программа основана на функциях _send(), ucnet_send(), _recv(), ucnet_recv(), которые являются базовыми для передачи трафика между машинами в создаваемой системе. Объем трафика там небольшой, не будет таких больших сообщений, которые я пытаюсь передавать.
Потому как по TCP нельзя передавать сообщения, да ещё и "заданной длины"(с) - TCP это stream, поток, "труба", в один конц которой можно "вливать", а из другой - "вытекает"...
Честно говоря я не понимаю... Разве я не так использую TCP? Я должен быть уверен что сообщение доставлено, а UDP не подтверждает доставку...
Программа же не пытается отправить все громоздкое сообщение целиком, а отправляет его по частям.
Такой индикатор памяти как GUI "системный монитор" не годится для таких наблюдений
Согласен, но ведь он показывает общую информацию и видно что память загружается, хоть и не понятно чем именно
Нужен доверительный механизм наблюдения за тем, что происходит с памятью...
Нужно над этим подумать.
Пробовал использовать такие средства анализа памяти как Valgrind и KEDR. С помощью Valgrind я искал утечки в программе test_tcp, а с помощью KEDR в модуле ядра. Но результатов не было, оба средства не находили никаких утечек.
Такой пример с установкой фильтра протоколов описывается (именно в таком виде) давно, начиная с ядер 2.4 (а может быть и раньше). Возможно в поздних ядрах (2.6.29 и далее) что-то поменялось? ... Только чтобы никто ничего не заметил и не описал?
Решил помучать 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()? какой буферный сокет я уничтожил?

Ответить

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

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

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