6

I am modifying a Linux Kernel to add some functionality to the Linux Virtual Server (LVS).

I developed a module (which I called net/netfilter/ipvs/ip_vs_utils.c) with some functions to be used when load-balancing. All the functions here are exported using EXPORT_SYMBOL().

This module, logically is not loaded all the time. My intention is to allow the user to decide if he want to use this additional functionality or not (loading or unloading the module).

My question is how could I invoke these functions OPTIONALLY (depending if the module is running or not) from a existing (and of course modified) module (net/netfilter/ipvs/ip_vs_core.c). Something like this:

if(ip_vs_utils_IsLoaded)
{
  function1(arg1, arg2, arg3); // being function1 defined on ip_vs_utils.c
}
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
marcocamejo
  • 798
  • 1
  • 7
  • 20
  • 1
    Lai's answer is quite good if your `if(ip_vs_utils)` code is intended to be in the kernel all the time; but if that code is itself located in another loadable module, probably simple module dependency is the better approach. See `depmod(8)` for full details. – sarnold Jul 16 '12 at 22:35

1 Answers1

5

I think you need a trampoline always(or almost always) loaded into kernel.

In trampoline code, you need to such variables.

struct module *ip_vs_utils_mod;
EXPORT_SYMBOL(ip_vs_utils_mod);

/* function pointers */
ret_type (*ip_vs_utils_afunc_ptr)(func_arg_list); /* Add static if you put it in a header file! */
EXPORT_SYMBOL(ip_vs_utils_afunc_ptr); /*  ******EXPORTED***** */

When the ip_vs_utils is loaded, you need to init all the variables, initialization code in ip_vs_utils.c:

ip_vs_utils_mod = THIS_MODULE;

/* init function pointers */

/* ip_vs_utils_afunc_impl is the real implementation
 * of the function, it is *****NOT***** needed to export it
 */
ip_vs_utils_afunc_ptr = ip_vs_utils_afunc_impl;

And add the trampoline functions in trampoline code:

ret_type ip_vs_utils_afunc(func_arg_list)
{
   ret_type ret = DEFAULT_RET;

   if (try_module_get(ip_vs_utils_mod)) {
       ret = (*ip_vs_utils_afunc_ptr)(func_arg_list);
       module_put(ip_vs_utils_mod);
   }
   return ret;
}

try_module_get() is needed to protect the module from being suddenly unloaded while ip_vs_utils_afunc_ptr() is being invoked. You can also use RCU instead to reduce the overhead of try_module_get()/module_put(). (But it is hard)

Or you can used some trampoline-hack like dynamic link in userspace(you may need to change a lot in the linux kernel)

txomon
  • 642
  • 1
  • 6
  • 21
Lai Jiangshan
  • 1,420
  • 1
  • 13
  • 23
  • Thank you very much for your answer, I think this will work for me. Just a question. What happens if my module ip_vs_utils is loaded before the others? Won't the line `ip_vs_utils_afunc_ptr = ip_vs_utils_afunc_impl;` throw an error because ip_vs_utils_afunc_ptr is not in the symbol table yet? – marcocamejo Jul 13 '12 at 13:36
  • 1
    In this case, you may need to fore the trampoline is linked into the kernel(or a module which is always loaded while the system boot). trampoline is typically extremely smaller than the real implementation, it is OK to make it always loaded. – Lai Jiangshan Jul 13 '12 at 15:51