Модуль ядра Linux. Виртуальный сетевой интерфейс.
Модератор: Olej
Модуль ядра Linux. Виртуальный сетевой интерфейс.
Добрый день!
В настоящий момент я занимаюсь задачей по шифрованию трафика на уровне ядра и мне очень помогли статьи Олега Ивановича Цилюрика по разработке модулей ядра, спасибо! Так же помогли статьи Олега с сайта 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мб оперативки. Без этого модуля все нормально. После выгрузки модуля память не освобождается. Такое ощущения что буферы сокетов где то клонируются и не освобождаются.
Буду рад любым советам. Спасибо!
В настоящий момент я занимаюсь задачей по шифрованию трафика на уровне ядра и мне очень помогли статьи Олега Ивановича Цилюрика по разработке модулей ядра, спасибо! Так же помогли статьи Олега с сайта 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мб оперативки. Без этого модуля все нормально. После выгрузки модуля память не освобождается. Такое ощущения что буферы сокетов где то клонируются и не освобождаются.
Буду рад любым советам. Спасибо!
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Давайте смотреть вместе.mcrandy писал(а):Буду рад любым советам. Спасибо!
Для начала очень хорошо бы сформулировать простейший тестовый проект (облегчённый от всяких деталей) + создать простейший тестовый проект (.tgz), который прикрепить к теме ... а дальше показывать и обсуждать его результаты.
P.S. Т.е.:
- взять какой-то проект ... можно из тех, что уже рассматривались здесь в темах (а их здесь несколько, 2 как минимум, альтернативно)...
- и показать: какие проблемы?, в каком объёме?, когда наблюдались?, и какие методики наблюдений и измерений?
- и править (доводить) здесь код тестового проекта ... так уже делалось не раз.
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Хорошо, сформировал простейший проект. Прикрепил к сообщению.Olej писал(а): Для начала очень хорошо бы сформулировать простейший тестовый проект (облегчённый от всяких деталей) + создать простейший тестовый проект (.tgz), который прикрепить к теме... а дальше показывать и обсуждать его результаты.
Данный модуль выполняет системный вызов
Код: Выделить всё
dev_add_pack( &test_proto);
Код: Выделить всё
printk( KERN_INFO "packet received with length: %u\n", skb->len );
- Вложения
-
- net_proto.tar
- (10 КБ) 562 скачивания
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Взял посмотреть...mcrandy писал(а): Хорошо, сформировал простейший проект. Прикрепил к сообщению.
Данный модуль выполняет системный вызови добавляет обработчик 3-го уровня test_proto, который просто пропускает пакет через себя и выводит длину пакетаКод: Выделить всё
dev_add_pack( &test_proto);
Проблема: создаю трафик между двумя машинами и как только запускаю этот модуль на принимающей сообщения машине, начинает выделяться в 2 раза больше оперативной памяти под трафик и не освобождается, постепенно пямять забивается и машина зависает. После выгрузки модуля память не освобождается.Код: Выделить всё
printk( KERN_INFO "packet received with length: %u\n", skb->len );
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
3. Реализация на уровне протоколов будет (заведомо) более громоздкой, см. пример: Разработка модулей ядра Linux: Часть 35. Дополнительные аспекты использования модулей ядра для создания сетевых интерфейсов - я пока фиксирую все URL на которые буду ссылаться (как №33, №34, №35).
4. То что вы делаете "создаю трафик между двумя машинами":
- между реальными хостами LAN?
- в виртуальной машине?
- на локальном хосте?
- и самое главное - показывайте пошагово вывод команд! : при загрузке модуля ... ifconfig при (после) присвоения IP ... какой командой создаётся трафик и т.д. - показывайте протоколы выполнения, а не рассказывайте "на пальцах"!
5.
- каким образом (подробно!) вы меряете: сколько "начинает выделяться"? как "память забивается"? ... какие команды? какие цифры?mcrandy писал(а): как только запускаю этот модуль на принимающей сообщения машине, начинает выделяться в 2 раза больше оперативной памяти под трафик и не освобождается, постепенно пямять забивается и машина зависает. После выгрузки модуля память не освобождается.
- как всё таки это происходит? "как только запускаю этот модуль" или "создаю трафик между двумя машинами" - это 2 очень разные вещи.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Пришлось изрядно повозиться (чтоб повторить ваш эксперимент быстро, да ещё и на сильно обновлённом дистрибутиве).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 );
Код: Выделить всё
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
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Да, у меня основная система Winows 7, на ней установлено 2 виртуальных машины VirtualBox c Fedora14. Между ними настроено сетевое соединение типа мост.1. А почему у вас на файлах флаг x установлен? - вы что-то как-то через Windows копируете?
Таким образом имитирую 2 физических машины и сеть между ними.
У меня версия ядра 2.6.352. Это вы повторяете (пока) пример из Разработка модулей ядра Linux: Часть 34. Протоколы сетевого и транспортного уровней. Это более сложный (и менее плодотворный) путь. Почему вы (хотя бы для начала) не пользуетесь вариантом с созданием нового интерфейса: Разработка модулей ядра Linux: Часть 33. Виртуальный сетевой интерфейс?
Код: Выделить всё
Linux IP239 2.6.35.14-106.fc14.x86_64
Дело в том что очень велика вероятность того что мой модуль будет работать на версии ядра не выше 2.6.35.
Согласен, пример из 35 выглядит громоздким и как раз с ним у меня проблемы по утечке памяти, но я не знаю как еще можно решить задачу для ядра 2.6.35.3. Реализация на уровне протоколов будет (заведомо) более громоздкой, см. пример: Разработка модулей ядра Linux: Часть 35. Дополнительные аспекты использования модулей ядра для создания сетевых интерфейсов - я пока фиксирую все URL на которые буду ссылаться (как №33, №34, №35).
У меня есть своя клиент-серверная программка организующая передачу рандомного сообщения заданной длины. В ней используются стандартные функции send() и recv() для передачи/приема соответственно. Используется протокол TCP. Она осложнена только тем что в начало сообщения записывает длину этого сообщения которое собирается передать, чтобы сервер знал сообщение какой длины ему ожидать. Программку прикрепляю к сообщению. Внутри есть небольшой README.4. То что вы делаете "создаю трафик между двумя машинами"
Сейчас попробую описать подробнее.каким образом (подробно!) вы меряете: сколько "начинает выделяться"? как "память забивается"? ... какие команды? какие цифры?
- как всё таки это происходит? "как только запускаю этот модуль" или "создаю трафик между двумя машинами" - это 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
Запускаю клиентскую часть программы для отправки сообщений 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]$
Код: Выделить всё
[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
P.S.:Тестировал программу, создающую трафик, без участия модуля ядра - все нормально, память не забивается.
P.P.S.: В модуле net_proto.c конечно же закоментировал строку с выводом printk.
- Вложения
-
- test_tcp.tar
- (20 КБ) 676 скачиваний
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
1. Но сохранять файлы/архивы вы же можете в файловой системе Fedora + из Fedora выходить в Интернет, чтобы писать сюда в форум и прикреплять файлы... Вот так (хоть это и не Fedora, но разницы нет):mcrandy писал(а):Да, у меня основная система Winows 7, на ней установлено 2 виртуальных машины VirtualBox c Fedora14. Между ними настроено сетевое соединение типа мост.1. А почему у вас на файлах флаг x установлен? - вы что-то как-то через Windows копируете?
Таким образом имитирую 2 физических машины и сеть между ними.
Гонять файлы 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. Виртуальный сетевой интерфейс.
Ох! Боюсь я таких "своих" программ-тестеров!mcrandy писал(а):У меня есть своя клиент-серверная программка организующая передачу рандомного сообщения заданной длины. В ней используются стандартные функции send() и recv() для передачи/приема соответственно. Используется протокол TCP. Она осложнена только тем что в начало сообщения записывает длину этого сообщения которое собирается передать, чтобы сервер знал сообщение какой длины ему ожидать. Программку прикрепляю к сообщению. Внутри есть небольшой README.4. То что вы делаете "создаю трафик между двумя машинами"
Потому как по TCP нельзя передавать сообщения, да ещё и "заданной длины"(с) - TCP это stream, поток, "труба", в один конц которой можно "вливать", а из другой - "вытекает"...
Об этом много-много пишут и Стивенс и др., но ... Этот номер проходит "до поры до времени", пока не сработают более сложные механизмы TCP, такие как: отсроченные подтверждения, алгоритм Найгла (объединение "пакетов"), адаптивное изменение окна передачи и приёма и т.д.
Нельзя это делать!
Пересылать "сообщения заданной длины" можно только UDP ... или SCTP (что ещё лучше).
Но программу теста я гляну.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Такой индикатор памяти как GUI "системный монитор" не годится для таких наблюдений (это только индикативный показатель ... чего? - но как индикативный он, наверное, годится на начальном этапе).mcrandy писал(а): Сразу чувствуется загрузка, VM1 начинает подтормаживать. А на графике выделения память в системном мониторе видно как память выделилась 3 раза и не освободилась.
В таком качестве уже лучше команды free, top ... но и это ещё не то.
Управление памятью в Linux достаточно сложное. Проделайте в своей пользовательской программе несколько больших malloc() с последующим их free()... Вы, возможно, ожидаете, что свободная память отобразится в индикаторах системы? Это совершенно не так! В сложном управлением памятью - залог эффективности такого управления.
Нужен доверительный механизм наблюдения за тем, что происходит с памятью...
Нужно над этим подумать.
На заметку некоторые соображения, над которыми нужно подумать:
- Такой пример с установкой фильтра протоколов описывается (именно в таком виде) давно, начиная с ядер 2.4 (а может быть и раньше). Возможно в поздних ядрах (2.6.29 и далее) что-то поменялось? ... Только чтобы никто ничего не заметил и не описал?
- В примере перехватываются все типы сетевых протоколов (ETH_P_ALL). Это не есть очень хорошо, т.к. туда попадают пакеты ARP и, что ещё хуже, всякие разные широковещательные пакеты NETBEUI от Windows, которые гуляют в великом множестве. Нужно бы глянуть при установке фильтра только на пакеты протокола TCP/IP (ETH_P_IP) будут ли наблюдаться какие-то артефакты?
Re: Модуль ядра Linux. Виртуальный сетевой интерфейс.
Буду придерживаться такой практики :)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? Я должен быть уверен что сообщение доставлено, а UDP не подтверждает доставку...Потому как по TCP нельзя передавать сообщения, да ещё и "заданной длины"(с) - TCP это stream, поток, "труба", в один конц которой можно "вливать", а из другой - "вытекает"...
Программа же не пытается отправить все громоздкое сообщение целиком, а отправляет его по частям.
Согласен, но ведь он показывает общую информацию и видно что память загружается, хоть и не понятно чем именноТакой индикатор памяти как GUI "системный монитор" не годится для таких наблюдений
Пробовал использовать такие средства анализа памяти как Valgrind и KEDR. С помощью Valgrind я искал утечки в программе test_tcp, а с помощью KEDR в модуле ядра. Но результатов не было, оба средства не находили никаких утечек.Нужен доверительный механизм наблюдения за тем, что происходит с памятью...
Нужно над этим подумать.
Решил помучать google на эту тему и нашел где то в комментарих соображения о том что после использования данного системного вызова следует выполнять kfree_skb(skb);. Решил попробовать:Такой пример с установкой фильтра протоколов описывается (именно в таком виде) давно, начиная с ядер 2.4 (а может быть и раньше). Возможно в поздних ядрах (2.6.29 и далее) что-то поменялось? ... Только чтобы никто ничего не заметил и не описал?
Код: Выделить всё
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;
};
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 17 гостей