2012-05-08 27 views
15

Incluso si un tema similar ya existe, he notado que se remonta dos años, por lo que supongo que es más adecuado para abrir uno nuevo ...envío de paquetes UDP desde el núcleo de Linux

Estoy intentando averiguar cómo enviar paquetes UDP desde el Kernel de Linux (3.3.4), para monitorear el comportamiento del generador de números aleatorios (/drivers/char/random.c). Hasta ahora, he logrado controlar algunas cosas debido a las funciones sock_create y sock_sendmsg. Puede encontrar la pieza de código que uso al final de este mensaje. (También es posible que desee descargar el archivo random.c completo modificado here.)

Al insertar este código dentro de las funciones random.c apropiadas, puedo enviar un paquete UDP para cada acceso a/dev/random y/dev/urandom, y cada evento de teclado/mouse utilizado por el generador de números aleatorios para cosechar entropía. Sin embargo, no funciona en absoluto cuando intento monitorear los eventos del disco: genera un pánico en el kernel durante el arranque.

En consecuencia, aquí está mi pregunta principal: ¿Tiene alguna idea de por qué mi código causa tantos problemas cuando se inserta en la función de eventos del disco? (add_disk_randomness)

O bien, he leído sobre netpoll API, que se supone que maneja este tipo de problemas UDP-en-kernel. Lamentablemente, no he encontrado ninguna documentación relevante aparte de una presentación de Red Hat bastante interesante pero obsoleta desde 2005. ¿Crees que debería usar esta API? En caso afirmativo, ¿tiene algún ejemplo?

Cualquier ayuda sería apreciada. Gracias de antemano.

PD: Es mi primera pregunta aquí, así que por favor no dude en decirme si yo estoy haciendo algo mal, lo tendré en cuenta para el futuro :)


#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); 
+4

Generalmente, es preferible que no haga nada en el kernel que podría hacer en el espacio de usuario; probablemente sería mejor exponer la información al espacio de usuario a través de mecanismos de registro o sysfs y luego enviar un daemon al sistema remoto . –

+0

Cuando ya existe un tema similar, vincúlelo. Hizo un trabajo razonable al explicar por qué cree que la pregunta existente no es lo suficientemente buena (es posible que haya dicho algo sobre la versión del núcleo más nueva, etc.). Pero tener la pregunta existente fácilmente disponible hace posible que las respuestas se centren en lo que ha cambiado desde entonces. –

+0

@BenVoigt Thx por su consejo. Aquí está el [tema anterior] (http://stackoverflow.com/questions/1814485/sending-udp-packet-in-linux-kernel). – tvuillemin

Respuesta

13

he resuelto mi problema hace unos meses. Esta es la solución que utilicé.

La API estándar de envío de paquetes (sock_create, connect, ...) no se puede utilizar en unos pocos contextos (interrupciones). Usarlo en el lugar equivocado conduce a un KP.

La API netpoll es más "de bajo nivel" y funciona en todos los contextos. Sin embargo, hay varias condiciones:

  • dispositivos Ethernet
  • red IP
  • única UDP (sin TCP)
  • diferentes ordenadores para enviar y recibir paquetes (No se puede enviar a usted mismo.)

Asegúrese de respetarlas, ya que no recibirá ningún mensaje de error si hay un problema. Simplemente fallará en silencio :) Aquí hay un poco de código.

Declaración

#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; 

inicialización

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; 

Uso

char message[MESSAGE_SIZE]; 
sprintf(message,"%d\n",42); 
int len = strlen(message); 
netpoll_send_udp(np,message,len); 

Esperanza que puede ayudar a alguien.

+0

como planteado [aquí] (http://stackoverflow.com/questions/35880786/why-do-i-get-this-error), kernel versión 3.9 (abril de 2013) realizó un cambio radical en 'linux/netpoll.h 'entonces este código ya no compila –

0

El pánico durante el arranque puede deberse a que intenta utilizar algo que aún no se ha inicializado. Observar el seguimiento de la pila puede ayudar a determinar qué sucedió realmente.

En cuanto a su problema, creo que está tratando de hacer algo simple, ¿por qué no utilizar herramientas simples? ;) printks podría ser una mala idea, pero dale una oportunidad a trace_printk. trace_printk es parte de la infraestructura Ftrace.

Sección Utilización del rastreo _printk() en el siguiente artículo os enseñe todo lo que necesita saber: http://lwn.net/Articles/365835/

Cuestiones relacionadas