Me estoy metiendo en el trabajo del kernel por un poco de mi investigación de verano. Estamos buscando hacer modificaciones al TCP, en cálculos específicos de RTT. Lo que me gustaría hacer es reemplazar la resolución de una de las funciones en tcp_input.c a una función proporcionada por un módulo kernel cargado dinámicamente. Creo que esto mejoraría el ritmo al que podemos desarrollar y distribuir la modificación.¿Puedo reemplazar una función del kernel de Linux con un módulo?
La función que me interesa se declaró estática, sin embargo, he recompilado el núcleo con la función no estática y exportado por EXPORT_SYMBOL. Esto significa que la función ahora está disponible para otros módulos/partes del kernel. Lo he verificado por "cat/proc/kallsyms".
Ahora me gustaría poder cargar un módulo que pueda reescribir la dirección de símbolo desde la inicial a mi función cargada dinámicamente. De manera similar, cuando el módulo se descargue, restaurará la dirección original. ¿Es este un enfoque factible? ¿Todos tienen sugerencias de cómo se podría implementar mejor?
Gracias!
Igual que Overriding functionality with modules in Linux kernel
Editar:
Esta fue mi enfoque final.
Dada la siguiente función (que quería anular, y no se exporta):
static void internal_function(void)
{
// do something interesting
return;
}
modificar así:
static void internal_function_original(void)
{
// do something interesting
return;
}
static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);
Este redefine el identificador de función esperada en cambio, como un puntero de función (que puede llamarse de manera similar) apuntando a la implementación original. EXPORT_SYMBOL() hace que la dirección sea accesible globalmente, por lo que podemos modificarla desde un módulo (u otra ubicación del kernel).
Ahora usted puede escribir un módulo del kernel con la siguiente forma:
static void (*original_function_reference)(void);
extern void (*internal_function)(void);
static void new_function_implementation(void)
{
// do something new and interesting
// return
}
int init_module(void)
{
original_function_reference = internal_function;
internal_function = &new_function_implementation;
return 0;
}
void cleanup_module(void)
{
internal_function = original_function_reference;
}
Este módulo sustituye a la aplicación original con una versión de carga dinámica. Tras la descarga, se restaura la referencia original (y la implementación). En mi caso específico, proporcioné un nuevo estimador para el RTT en TCP. Al usar un módulo, puedo hacer ajustes pequeños y reiniciar las pruebas, todo sin tener que recompilar y reiniciar el kernel.
Terminé yendo por la ruta que sugirió al agregar un gancho global. Fue fácil de implementar y proporcionó exactamente lo que necesitaba. Gracias por la información con respecto a la resolución del símbolo. No había encontrado una fuente que explicara definitivamente cómo y cuándo se accedió a la tabla de símbolos (en cada llamada a función o solo en el enlace). Este fue un consejo útil. –