Envío de paquetes UDP desde el kernel de Linux

Incluso si ya existe un tema similar, noté que data de hace dos años, así que creo que es más apropiado abrir uno nuevo …

Intento 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 modificado completo aquí ).

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 trato de monitorear los eventos del disco: genera un pánico en el kernel durante el arranque.

En consecuencia, esta es 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)

Alternativamente, he leído sobre la API netpoll, que se supone que maneja este tipo de problemas UDP en el núcleo. Desafortunadamente, 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? Si es así, ¿tiene algún ejemplo?

Cualquier ayuda sería apreciada. Gracias por adelantado.

PD: Es mi primera pregunta aquí, así que no dudes en decirme si estoy haciendo algo mal, lo tendré en cuenta para el futuro 🙂


#include  #include  #include  #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 (errorops->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); 

Resolví 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 usar en unos pocos contextos (interrupciones). Usarlo en el lugar equivocado conduce a un KP.

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

  • Dispositivos Ethernet
  • Red IP
  • UDP solo (sin TCP)
  • Diferentes computadoras para enviar y recibir paquetes (No puede enviarse a usted mismo)

Asegúrese de respetarlos, 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  #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; 

Utilizar

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

Espero que pueda ayudar a alguien.

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 stack puede ayudar a determinar qué sucedió realmente.

En cuanto a su problema, creo que está tratando de hacer algo simple, ¿por qué no seguir con las 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 El uso de trace _printk () en el siguiente artículo debe enseñarle todo lo que necesita saber: http://lwn.net/Articles/365835/