Wysyłanie pakietów UDP z jądra Linuksa

Nawet jeśli podobny temat już istnieje, zauważyłem, że pochodzi z dwóch lat, więc myślę, że lepiej jest otworzyć nowy...

Próbuję dowiedzieć się, jak wysyłać pakiety UDP z jądra Linuksa (3.3.4), aby monitorować zachowanie generatora liczb losowych (/drivers/char/random.c). Do tej pory udało mi się monitorować kilka rzeczy dzięki funkcjom sock_create i sock_sendmsg. Możesz znaleźć typowy fragment kodu, którego używam na końcu tej wiadomości. (Możesz również pobrać kompletny zmodyfikowany losowy.plik c tutaj .)

Poprzez wstawienie tego kodu wewnątrz odpowiedniego losowego.funkcje c, jestem w stanie wysłać pakiet UDP dla każdego dostępu do /dev/random i /dev/urandom oraz dla każdego zdarzenia klawiatury/myszy używanego przez generator liczb losowych do zbioru entropii. Jednak to nie działa w ogóle, gdy próbuję monitorować zdarzenia na dysku: generuje panikę jądra podczas rozruchu.

W związku z tym, oto moje główne pytanie: masz jakiś pomysł, dlaczego mój kod powoduje tyle problemów po włożeniu do funkcji zdarzeń dysku? (add_disk_randomness)

Alternatywnie, czytałem o API netpoll, które ma obsługiwać tego rodzaju problemy UDP-in-kernel. Niestety nie znalazłem żadnej odpowiedniej dokumentacji poza dość ciekawą, ale przestarzałą prezentacją Red Hata z 2005 roku. Czy uważasz, że powinienem raczej używać tego API? Jeśli tak, masz jakiś przykład?

Każda pomoc byłabym wdzięczna. Z góry dzięki.

PS: To moje pierwsze pytanie tutaj, więc proszę nie wahaj się powiedzieć mi, jeśli robię coś źle, będę o tym pamiętać na przyszłość:)


#include <linux/net.h>
#include <linux/in.h>
#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_SEND ((unsigned long int)0x0a00020f) //10.0.2.15
static bool sock_init;
static struct socket *sock;
static struct sockaddr_in sin;
static struct msghdr msg;
static struct iovec iov;

[...]

int error, len;
mm_segment_t old_fs;
char message[MESSAGE_SIZE];

if (sock_init == false)
{
  /* Creating socket */
  error = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
  if (error<0)
    printk(KERN_DEBUG "Can't create socket. Error %d\n",error);

  /* Connecting the socket */
  sin.sin_family = AF_INET;
  sin.sin_port = htons(1764);
  sin.sin_addr.s_addr = htonl(INADDR_SEND);
  error = sock->ops->connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr), 0);
  if (error<0)
    printk(KERN_DEBUG "Can't connect socket. Error %d\n",error);

  /* Preparing message header */
  msg.msg_flags = 0;
  msg.msg_name = &sin;
  msg.msg_namelen  = sizeof(struct sockaddr_in);
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_iov = &iov;
  msg.msg_control = NULL;
  sock_init = true;
}

/* Sending a message */
sprintf(message,"EXTRACT / Time: %llu / InputPool: %4d / BlockingPool: %4d / NonblockingPool: %4d / Request: %4d\n",
  get_cycles(),
  input_pool.entropy_count,
  blocking_pool.entropy_count,
  nonblocking_pool.entropy_count,
  nbytes*8);
iov.iov_base = message;
len = strlen(message);
iov.iov_len = len;
msg.msg_iovlen = len;
old_fs = get_fs();
set_fs(KERNEL_DS);
error = sock_sendmsg(sock,&msg,len);
set_fs(old_fs);
Author: Eugene, 2012-05-08

2 answers

Rozwiązałem swój problem kilka miesięcy temu. Oto rozwiązanie, którego użyłem.

Standardowe API wysyłania pakietów (sock_create, connect, ...) nie może być używany w kilku kontekstach (przerwaniach). Użycie go w złym miejscu prowadzi do KP.

API netpoll jest bardziej "niskopoziomowe" i działa w każdym kontekście. Istnieje jednak kilka warunków:

  • urządzenia Ethernet
  • sieć IP
  • tylko UDP (bez TCP)
  • różne komputery do wysyłania i odbierania pakiety (nie można wysyłać do siebie.)

Upewnij się, że je szanujesz, ponieważ nie otrzymasz żadnego komunikatu o błędzie, jeśli wystąpi problem. Po prostu po cichu zawiedzie :) tu jest trochę kodu.

Deklaracja

#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_LOCAL ((unsigned long int)0xc0a80a54) //192.168.10.84
#define INADDR_SEND ((unsigned long int)0xc0a80a55) //192.168.10.85
static struct netpoll* np = NULL;
static struct netpoll np_t;

Inicjalizacja

np_t.name = "LRNG";
strlcpy(np_t.dev_name, "eth0", IFNAMSIZ);
np_t.local_ip = htonl(INADDR_LOCAL);
np_t.remote_ip = htonl(INADDR_SEND);
np_t.local_port = 6665;
np_t.remote_port = 6666;
memset(np_t.remote_mac, 0xff, ETH_ALEN);
netpoll_print_options(&np_t);
netpoll_setup(&np_t);
np = &np_t;

Użyj

char message[MESSAGE_SIZE];
sprintf(message,"%d\n",42);
int len = strlen(message);
netpoll_send_udp(np,message,len);
Mam nadzieję, że może komuś pomóc.
 13
Author: tvuillemin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-31 22:03:09

Panika podczas rozruchu może być spowodowana próbą użycia czegoś, co nie zostało jeszcze zainicjowane. Patrząc na stack trace może pomóc dowiedzieć się, co naprawdę się stało.

Jeśli chodzi o twój problem, myślę, że próbujesz zrobić prostą rzecz, więc dlaczego nie trzymać się prostych narzędzi? ;) printks może to rzeczywiście zły pomysł, ale daj trace_printk. trace_printk jest częścią infrastruktury Ftrace.

Sekcja używanie trace _printk () w poniższym artykule powinno nauczyć cię wszystkiego musisz wiedzieć: http://lwn.net/Articles/365835/

 0
Author: moorray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-14 20:23:39