Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Пн Апр 11 2005 15:56 Заголовок сообщения: Перекидывание структур из ядра в пространство пользователя. |
|
|
В Linux.
Пытаюсь написать модуль, который будет выхватывать IP-пакеты, идущие через определенный интерфейс. Соответственно внутри модуля можно работать со структурой sk_buff. Требуется выкинуть ее наружу, чтобы уже другой программой что-то с этим sk_buff'ом делать.
Первая очевидная идея - использовать обычные средства ipc, в частности разделяемую память. Модули не умеют использовать все эти вещи. К сожалению.
Вторая идея - создать устройство, через который выкидывать информацию, а программой соответственно читать. Как выяснилось, символьные устройства для этого непригодны (передать sk_buff как последовательность байтов просто так не получится).
Вопрос: как можно сделать что-то вроде разделяемой памяти, доступной из ядра и из пространства пользователя? Была идея по поводу блочных устройств, но хотелось бы попроще как-нибудь.
Еще один вариант - попробовать превратить sk_buff в последовательный набор байт (то есть по сути обратно в ip-пакет), а потом его разбирать. Насколько реально такое? _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
Ersh
Зарегистрирован: 20.01.2004 Сообщения: 107
|
Добавлено: Пн Апр 11 2005 19:09 Заголовок сообщения: |
|
|
может ты что-то не так делаешь, но модули тоже умеют работать с шаред мемори... _________________ Анархия - мать порядка!!!!!!!!! |
|
Вернуться к началу |
|
|
benoni
Зарегистрирован: 12.04.2005 Сообщения: 1
|
Добавлено: Вт Апр 12 2005 15:59 Заголовок сообщения: |
|
|
Используй ф.с /proc, помоему она для этого и предназначена. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Вт Апр 12 2005 21:05 Заголовок сообщения: |
|
|
Получилось с символьным устройством.
Проблема в том, чтобы в пространстве пользователя работать со структурой типа sk_buff - компилятор ругается, что incomplete type, а если подключить linux\skbuff.h, то вылетает огромное количество ошибок в тех библиотеках, которые skbuff.h за собой тянет.
Пересылать структуру iphdr наружу уже получается. _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
pzz
Зарегистрирован: 13.04.2005 Сообщения: 4
|
Добавлено: Ср Апр 13 2005 16:25 Заголовок сообщения: 2 Aragaer: skb и character devices |
|
|
Нет ничего сложного в том, чтобы использовать skb'шки совместно с character device'ами. Надо только передавать не структуру sk_buff, а ее содержимое.
Буфера, предназначенные для отправки из ядра в user space должны где-то складываться (в ядре, т.е. в драйвере/модуле) в очередь, т.к. появляются они, скорее всего, независимо от желания user space их читать. Чтение должно брать первый буфер из очереди, и копировать его в пользовательский буфер. Если буфер слишком маленький, есть два варианта: либо обрезать данные, либо возвращать ошибку (-EMSGSIZE), чтобы намекнуть user space'у, что неплохо бы предложить буфер побольше. Если чтение произошло без ошибок, буфер удаляется из очереди. Если же при попытке чтения выясняется, что очередь пуста, операция чтения блокируется (т.е., понадобится научиться работать с очередями ожидания, что не сложно).
О чем стоит подумать, это о том, что делать, если SKB'шки для чтения накапливаются, но их никто не читает (например, программа зависла, или ее просто нет). Иначе существует опасность собрать в очереди для чтения всю память ядра, после чего системе, очевидно, придет кирдык
При записи наоборот, SKB'шка аллоцируется, в нее копируются пользовательские данные, и она передается дальше по назначению.
Особой разницы, делать это через /dev или через /proc нету. Это во многом вопрос вкуса. Отмечу одну особенность /dev'а: если devfs не используется, то имя в /dev придется добавить вручную, что не всегда удобно.
Еще одна возможность, раз уж данные внутри ядра представлены SKB'шками, это создать socket, работающий между ядром и userspace. Посмотри в сторону, например, rtnetlink, как это делается. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Ср Апр 13 2005 18:19 Заголовок сообщения: |
|
|
Пришел к выводу, что передавать всю skb'шку мне смысла нет. Даже и весь IP-заголовок не нужен, только saddr. /dev удобнее тем, что в него можно писать, с /proc это (насколько я понял из LKMPG) сложнее.
Но я никак не могу понять, как можно из ядра делать системные вызовы. Те же семафоры мне например понадобились. Понятно, что нужно подключить какую-то библиотеку. Но какую именно? _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
pzz
Зарегистрирован: 13.04.2005 Сообщения: 4
|
Добавлено: Ср Апр 13 2005 22:09 Заголовок сообщения: |
|
|
В ядре свои семафоры:
struct semaphore sem;
init_MUTEX( &sem );
down( &sem );
up( &sem );
Но вообще, надо бы тебе книжку какую-нибудь найти и почитать. |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Ср Апр 13 2005 22:29 Заголовок сообщения: |
|
|
Книжки в гугле искал. Тщательно. Так и не нашел ничего про системные вызовы. То есть нашел про unistd.h, но почему-то не хочет работать.
Еще есть вариант с таблицей системных вызовов. Но в ядре 2.6 это дело спрятано.
Семафорить мне нужно наружу.
То есть снаружи (в пространстве пользователя) некий процесс ожидает смены семафора. Как только это произойдет - читает из нашего символьного устройства.
Хотя, по идее раз мы находимся в режиме ядра, то можно вручную семафоры переключать. В крайнем случае.
А хочется сделать вызов типа sys_semget и не волноваться, что порушу таблицу семафоров. _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
Ersh
Зарегистрирован: 20.01.2004 Сообщения: 107
|
Добавлено: Чт Апр 14 2005 15:29 Заголовок сообщения: |
|
|
Советую замечательную книжу: "Программирование в Unix" Автор Робачевский. _________________ Анархия - мать порядка!!!!!!!!! |
|
Вернуться к началу |
|
|
pzz
Зарегистрирован: 13.04.2005 Сообщения: 4
|
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Пн Апр 18 2005 19:24 Заголовок сообщения: |
|
|
Да-да, уже все написал. Сделал блокируемой операцию чтения и все заработало.
Единственное что, так это странный глюк с ERESTARTSYS. А именно: в драйвере Код: | if (cur == -1) { // Нечего передать наружу
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&read_wq);
return -ERESTARTSYS;
} |
А в "клиенте" Код: | res = read(fh, &saddr, 4)
if(res < 0)
perror("Read error");
|
Проскакивало сообщение "Read error: unknown error 512", то есть тот самый ERESTARTSYS, который вообще-то вне ядра вообще не должен быть виден. _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
pzz
Зарегистрирован: 13.04.2005 Сообщения: 4
|
Добавлено: Вт Апр 19 2005 20:00 Заголовок сообщения: |
|
|
Зачем тебе возвращать ERESTARTSYS? Почему бы тебе не сделать цикл прямо в драйвере? |
|
Вернуться к началу |
|
|
Aragaer
Зарегистрирован: 28.03.2005 Сообщения: 164
|
Добавлено: Ср Апр 20 2005 14:11 Заголовок сообщения: |
|
|
Потому что это более логично.
Дело в том, что в процессе ожидания пользователь может закрыть внешнее приложение. Это тоже прервет ожидание, но это еще не значит, что надо что-то передавать. Такое обрабатывается следующим образом: Код: | interruptible_sleep_on(&read_wq);
if (cur == -1) //Все еще нечего передать - значит мы вышли по прерыванию
return 0; |
Вроде нормально, но только вот cur надо пересчитывать заново (он у меня не хранится в чистом виде), а это опять запирать спинлоками доступ к структуре, содержащей информацию (а вдруг что-то в этот момент прийдет - опять все указатели перемешаются), в итоге получается проще послать ERESTARTSYS.
Можно, конечно, ввести просто еще одну переменную, которая будет превращаться в единицу при каждом приходе пакета и в ноль при каждом чтении. Ее можно будет использовать, чтобы узнать, было прерывание или нет. Но ведь есть же специально предназначенный механизм - перезапустить еще раз системный вызов. _________________ Open your eyes.
And Awaken. |
|
Вернуться к началу |
|
|
|