IPVS负载均衡(六)浅析ip_vs_core.c

来源:互联网 发布:qemu-ga windows 1053 编辑:程序博客网 时间:2024/05/17 06:44

IPVS负载均衡(六)浅析ip_vs_core.c

ip_vs_core.c

先从linux内核module_init和module_exit开始。

module_init

函数:ip_vs_init

函数原型:static int __init ip_vs_init(void)

初始化ip_vs模块所需的各种

/* *  Initialize IP Virtual Server */static int __init ip_vs_init(void){    int ret;    ret = ip_vs_control_init();    if (ret < 0) {        pr_err("can't setup control.\n");        goto exit;    }    ip_vs_protocol_init();    ret = ip_vs_conn_init();    if (ret < 0) {        pr_err("can't setup connection table.\n");        goto cleanup_protocol;    }    ret = register_pernet_subsys(&ipvs_core_ops);   /* Alloc ip_vs struct */    if (ret < 0)        goto cleanup_conn;    ret = register_pernet_device(&ipvs_core_dev_ops);    if (ret < 0)        goto cleanup_sub;    ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));    if (ret < 0) {        pr_err("can't register hooks.\n");        goto cleanup_dev;    }    ret = ip_vs_register_nl_ioctl();    if (ret < 0) {        pr_err("can't register netlink/ioctl.\n");        goto cleanup_hooks;    }    pr_info("ipvs loaded.\n");    return ret;cleanup_hooks:    nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));cleanup_dev:    unregister_pernet_device(&ipvs_core_dev_ops);cleanup_sub:    unregister_pernet_subsys(&ipvs_core_ops);cleanup_conn:    ip_vs_conn_cleanup();cleanup_protocol:    ip_vs_protocol_cleanup();    ip_vs_control_cleanup();exit:    return ret;}

主要调用了:

->ip_vs_control_init->ip_vs_protocol_init,协议所需初始化->ip_vs_conn_init,链接管理初始化->register_pernet_subsys->register_pernet_device->nf_register_hooks,注册netfilter钩子函数,后续代码流程会从这里开始->ip_vs_register_nl_ioctl

其中跟IPVS主要流程最相关的是nf_register_hooks、ip_vs_protocol_init、ip_vs_conn_init,后续会主要从nf_register_hooks这里–在netfilter上注册的钩子函数上梳理主干流程

module_exit

函数:ip_vs_cleanup

函数原型:static void __exit ip_vs_cleanup(void)

卸载ip_vs模块,释放占用的资源等操作

static void __exit ip_vs_cleanup(void){    ip_vs_unregister_nl_ioctl();    nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));    unregister_pernet_device(&ipvs_core_dev_ops);    unregister_pernet_subsys(&ipvs_core_ops);   /* free ip_vs struct */    ip_vs_conn_cleanup();    ip_vs_protocol_cleanup();    ip_vs_control_cleanup();    pr_info("ipvs unloaded.\n");}

主要调用:

->ip_vs_unregister_nl_ioctl->nf_unregister_hooks->unregister_pernet_device->unregister_pernet_subsys->ip_vs_conn_cleanup->ip_vs_protocol_cleanup->ip_vs_control_cleanup

可以注意到,ip_vs_cleanup资源释放顺序,与ip_vs_init申请资源顺序刚好相反;且与ip_vs_init中的出错处理部分顺序基本相同。

看完模块注册去注册流程,那么后面则开始寻找

nf_register_hooks钩子函数

通过nf_register_hooks注册的钩子函数进一步梳理代码流程

ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));

ip_vs_ops的定义

static struct nf_hook_ops ip_vs_ops[] __read_mostly = {    /* After packet filtering, change source only for VS/NAT */    {        .hook       = ip_vs_reply4,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_LOCAL_IN,        .priority   = NF_IP_PRI_NAT_SRC - 2,    },    /* After packet filtering, forward packet through VS/DR, VS/TUN,     * or VS/NAT(change destination), so that filtering rules can be     * applied to IPVS. */    {        .hook       = ip_vs_remote_request4,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_LOCAL_IN,        .priority   = NF_IP_PRI_NAT_SRC - 1,    },    /* Before ip_vs_in, change source only for VS/NAT */    {        .hook       = ip_vs_local_reply4,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_LOCAL_OUT,        .priority   = NF_IP_PRI_NAT_DST + 1,    },    /* After mangle, schedule and forward local requests */    {        .hook       = ip_vs_local_request4,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_LOCAL_OUT,        .priority   = NF_IP_PRI_NAT_DST + 2,    },    /* After packet filtering (but before ip_vs_out_icmp), catch icmp     * destined for 0.0.0.0/0, which is for incoming IPVS connections */    {        .hook       = ip_vs_forward_icmp,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_FORWARD,        .priority   = 99,    },    /* After packet filtering, change source only for VS/NAT */    {        .hook       = ip_vs_reply4,        .pf     = NFPROTO_IPV4,        .hooknum    = NF_INET_FORWARD,        .priority   = 100,    },#ifdef CONFIG_IP_VS_IPV6    /* After packet filtering, change source only for VS/NAT */    {        .hook       = ip_vs_reply6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_LOCAL_IN,        .priority   = NF_IP6_PRI_NAT_SRC - 2,    },    /* After packet filtering, forward packet through VS/DR, VS/TUN,     * or VS/NAT(change destination), so that filtering rules can be     * applied to IPVS. */    {        .hook       = ip_vs_remote_request6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_LOCAL_IN,        .priority   = NF_IP6_PRI_NAT_SRC - 1,    },    /* Before ip_vs_in, change source only for VS/NAT */    {        .hook       = ip_vs_local_reply6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_LOCAL_OUT,        .priority   = NF_IP6_PRI_NAT_DST + 1,    },    /* After mangle, schedule and forward local requests */    {        .hook       = ip_vs_local_request6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_LOCAL_OUT,        .priority   = NF_IP6_PRI_NAT_DST + 2,    },    /* After packet filtering (but before ip_vs_out_icmp), catch icmp     * destined for 0.0.0.0/0, which is for incoming IPVS connections */    {        .hook       = ip_vs_forward_icmp_v6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_FORWARD,        .priority   = 99,    },    /* After packet filtering, change source only for VS/NAT */    {        .hook       = ip_vs_reply6,        .pf     = NFPROTO_IPV6,        .hooknum    = NF_INET_FORWARD,        .priority   = 100,    },#endif};

由于是浅析,故这里就不会分析IPV6的场景,主要看ipv4的场景。

.hook涉及到的函数有:

  • ip_vs_reply4
  • ip_vs_remote_request4
  • ip_vs_local_reply4
  • ip_vs_local_request4
  • ip_vs_forward_icmp
  • ip_vs_reply4

netfilter钩子函数最后返回值主要有这几种:

名称 含义 NF_DROP 丢弃该数据包 NF_ACCEPT 保留该数据包 NF_STOLEN 忘掉该数据包 NF_QUEUE 将该数据包插入到用户空间 NF_REPEAT 再次调用该hook函数

.pf是IP类型,这里只讨论IPV4的情况

.hooknum则是涉及到netfilter的五处钩子点,简单可以理解为,netfilter在内核协议栈中五处地方有函数指针,如果注册了钩子函数,则会在对应点调用指定的钩子函数,处理报文。netfilter的五处分别为:NF_IP_PRE_ROUTING,在完整性校验之后,选路确定之前;NF_IP_LOCAL_IN,在选路确定之后,且数据包的目的是本地主机;NF_IP_FORWARD,目的地是其它主机地数据包;NF_IP_LOCAL_OUT,来自本机进程的数据包在其离开本地主机的过程中;NF_IP_POST_ROUTING,在数据包离开本地主机“上线”之前。

可以看到在ipvs中,主要用到了NF_IP_LOCAL_IN、NF_IP_LOCAL_OUT、NF_IP_FORWARD。

.priority则是表示优先级,因为可能会挂多个钩子函数,所以设置优先级,会先调用优先级高的,再调用优先级低的进行处理。

下一步

可以看到ip_vs_reply4、ip_vs_local_reply4都是调用了ip_vs_out

ip_vs_remote_request4、ip_vs_local_request4都是调用了ip_vs_in

下面将会简要分析ip_vs_out和ip_vs_in两个函数的处理流程

0 0
原创粉丝点击