LVS中使用toa模块遇到的坑

1140阅读 0评论2022-03-24 frankzfz
分类:云计算

LVS中的fullnat模式中,为了获取clientIP地址,会使用到LVS中的toa模块,该模块的作用就是替代系统中的getname系统调用,在rs端通过getname的系统调用获取到clientIP地址。在toa模块中使用到kallsyms_lookup_name函数,该函数的作用就是获取sock_def_readable函数的地址。但是在一些内核发行版中kallsyms_lookup_name函数并没有被EXPORT出来,所以在编译toa模块时,会出现下面的警告:

WARNING: "kallsyms_lookup_name" [/data/toa_v1/toa.ko] undefined!

使用insmod安装出现下面的提示信息: toa: Unknown symbol kallsyms_lookup_name 安装失败。如果内核版本是直接维护的话,可以重新编译内核模块,EXPORT kallsyms_lookup_name函数,如果不方便更换内核,可以使用下面的两个方法进行规避:
1. kallsyms_lookup_name函数没有被EXPORT情况下的处理方法:

1)可以使用下面的方法获取到sock_def_readable结构体的地址,

 grep sock_def_readable /proc/kallsyms

ffffffff8145a610 t sock_def_readable

grep sock_def_readable /boot/System.map-2.6.32-573.26.1.el6.x86_64

ffffffff8145a610 t sock_def_readable

     获取到具体的地址后,可以在toa的代码中硬编码,

  sk_data_ready_addr = ffffffff8145a610;

2)  kallsyms_lookup_name没有被EXPORT时,可以使用kallsyms_on_each_symbol函数替换,该函数在大部分内核版本上都会被EXPORT

点击(此处)折叠或打开

  1. static int find_fn (void *data, const char *name, struct module *mod, unsigned long addr)
  2. {
  3.   if (name != NULL && strcmp (name, "sock_def_readable") == 0) {
  4.      sk_data_ready_addr = addr;
  5.     return 1;
  6.   }
  7.   return 0;
  8. }

  9. static void get_fn_addr (void)
  10. {
  11.   kallsyms_on_each_symbol (find_fn, 0);
  12. }

static int __init toa_init(void)

{

…..

get_fn_addr();

…….

}

2. centos2.6.32-573.26.1.el6.x86_64内核版本上,还出现了pagefault的情况,

<6>TOA: toa loaded

<1>BUG: unable to handle kernel paging request at ffffffff81677818

<1>IP: [] toa_exit+0x9/0xc9 [toa]

<4>PGD 1a8f067 PUD 1a93063 PMD 80000000016001e1

<4>Oops: 0003 [#1] SMP

<4>last sysfs file: /sys/devices/system/cpu/online

<4>CPU 0

<4>Modules linked in: toa(-)(U) xt_conntrack ipt_MASQUERADE iptable_filter iptable_nat ipt_addrtype ip_tables nf_nat nf_conntrack_ipv4

<4>

<4>Pid: 14149, comm: rmmod Not tainted 2.6.32-573.26.1.el6.x86_64 #1 Red Hat KVM

<4>RIP: 0010:[]  [] toa_exit+0x9/0xc9 [toa]

<4>RSP: 0018:ffff8801389cbed8  EFLAGS: 00010282

该问题出现在hook_toa_functions函数中下面的代码中,

  inet_stream_ops_p = (struct proto_ops *)&inet_stream_ops;

  inet_stream_ops_p->getname = inet_getname_toa; 

   可以通过下面的方法解决:

点击(此处)折叠或打开

  1. void set_addr_rw(unsigned long addr)
  2. {
  3.     unsigned int level;
  4.     pte_t *pte = lookup_address(addr, &level);

  5.     if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
  6. }

  7. void set_addr_ro(unsigned long addr)
  8. {
  9.     unsigned int level;
  10.     pte_t *pte = lookup_address(addr, &level);

  11.     pte->pte = pte->pte &~_PAGE_RW;
  12. }
  13. 在hook_toa_functions函数中
  14. inet_stream_ops_p = (struct proto_ops *)&inet_stream_ops;
  15. set_addr_rw((unsigned long)(&inet_stream_ops.getname));
  16. inet_stream_ops_p->getname = inet_getname_toa;
  17. set_addr_ro((unsigned long)(&inet_stream_ops.getname));
上一篇:execsnoop使用在Linux kernel5.9内核中的遇到问题
下一篇:centos7下编译llvm