• ipvs学习笔记(一)


    十分感谢yfydz老大发布ip_vs实现分析系列文章,这使我能尽快理解ipvs的工作原理与源码组成。

    不过yfydz的文章过于长,不便于后续检索。我计划逐步整理,发到blog上。

    1ipvs分为三种负载均衡模式

    NATtunneldirect routingDR

    NAT:所有交互数据必须通过均衡器

    tunnel:半连接处理方式,进行了IP封装

    DR:修改MAC地址,需要同一网段。

    2ipvs支持的均衡调度算法

    轮叫调度(Round-Robin Scheduling) 

    加权轮叫调度(Weighted Round-Robin Scheduling) 

    最小连接调度(Least-Connection Scheduling) 

    加权最小连接调度(Weighted Least-Connection Scheduling) 

    基于局部性的最少链接(Locality-Based Least Connections Scheduling) 

    带复制的基于局部性最少链接(Locality-Based Least Connections with Replication Scheduling) 

    目标地址散列调度(Destination Hashing Scheduling) 

    源地址散列调度(Source Hashing Scheduling)

    3ipvs代码记录

    内核为 Linux-kernel 3.3.7

     

    3.1、结构体

    ipvs各结构体定义在include\net\ip_vs.hinclude\linux\ip_vs.h头文件中

    struct ip_vs_protocol

    这个结构用来描述ipvs支持的IP协议。ipvs的IP层协议支持TCP, UDP, AH和ESP这4种IP层协议

    struct ip_vs_conn

    这个结构用来描述ipvs的链接

    struct ip_vs_service

    这个结构用来描述ipvs对外的虚拟服务器信息

    struct ip_vs_dest

    这个结构用来描述具体的真实服务器信息

    struct ip_vs_scheduler

    这个结构用来描述ipvs调度算法,目前调度方法包括rr,wrr,lc, wlc, lblc, lblcr, dh, sh等

    struct ip_vs_app

    这个结构用来描述ipvs的应用模块对象

    struct ip_vs_service_user

    这个结构用来描述ipvs用户空间的虚拟服务信息

    struct ip_vs_dest_user

    这个结构用来描述ipvs用户空间的真实服务器信息

    struct ip_vs_stats_user

    这个结构用来描述ipvs用户空间的统计信息

    struct ip_vs_getinfo

    这个结构用来描述ipvs用户空间的获取信息

    struct ip_vs_service_entry

    这个结构用来描述ipvs用户空间的服务规则项信息

    struct ip_vs_dest_entry

    这个结构用来描述ipvs用户空间的真实服务器规则项信息

    struct ip_vs_get_dests

    这个结构用来描述ipvs用户空间的获取真实服务器项信息

    struct ip_vs_get_services

    这个结构用来描述ipvs用户空间的获取虚拟服务项信息

    struct ip_vs_timeout_user

    这个结构用来描述ipvs用户空间的超时信息

    struct ip_vs_daemon_user

    这个结构用来描述ipvs的内核守护进程信息

    3.2、模块初始化

    net\netfilter\ipvs\ip_vs_core.c文件

    static int __init ip_vs_init(void)

    ipvs服务初始化

    net\netfilter\ipvs\ip_vs_ctl.c文件

    int __init ip_vs_control_init(void)

    ioctl初始化

    net\netfilter\ipvs\ip_vs_proto.c文件

    int __init ip_vs_protocol_init(void)

    协议初始化

    net\netfilter\ipvs\ip_vs_conn.c文件

    int __init ip_vs_conn_init(void)

    连接初始化

    net\netfilter\ipvs\ip_vs_core.c文件

    static struct nf_hook_ops ip_vs_ops[]

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

    netfilter挂接点数组,具体的数据包处理见数组中对应.hook的函数

    3.3、调度算法具体实现

    各算法与ip_vs_scheduler结构体对应

    rr算法在net\netfilter\ipvs\ip_vs_rr.c文件中实现,以此类推。

    static struct ip_vs_scheduler ip_vs_rr_scheduler = {

    .name =                        "rr",                        /* name */

    .refcnt =                ATOMIC_INIT(0),

    .module =                THIS_MODULE,

    .n_list =                LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),

    .init_service =                ip_vs_rr_init_svc,

    .update_service =        ip_vs_rr_update_svc,

    .schedule =                ip_vs_rr_schedule,

    };

    init_service

    算法初始化,在虚拟服务ip_vs_service和调度器绑定时调用(ip_vs_bind_scheduler()函数)

    update_service()

    函数在目的服务器变化时调用(如ip_vs_add_dest(), ip_vs_edit_dest()等函数)

    而算法核心函数schedule()则是在ip_vs_schedule()函数中在新建IPVS连接前调用,找到真正的服务器提供服务,建立IPVS连接。

    具体的算法实现看源代码+yfydz老大的ipvs实现分析。

    3.4、连接管理

    net\netfilter\ipvs\ip_vs_conn.c文件

    struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)

    进入方向

    struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)

    发出方向

    struct ip_vs_conn *

    ip_vs_conn_new(const struct ip_vs_conn_param *p,

           const union nf_inet_addr *daddr, __be16 dport, unsigned flags,

           struct ip_vs_dest *dest, __u32 fwmark)

    建立连接

    static inline void

    ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)

    绑定真实服务器

    int ip_vs_bind_app(struct ip_vs_conn *cp, struct ip_vs_protocol *pp)

    绑定应用协议

    static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)

    绑定发送方法

    static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)

    将连接结构添加到连接hash

    static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)

    从连接hash表中断开

    static void ip_vs_conn_expire(unsigned long data)

    连接超时

    static inline void ip_vs_control_del(struct ip_vs_conn *cp)

    从主连接中断开

    void ip_vs_unbind_app(struct ip_vs_conn *cp)

    解除与应用的绑定

    static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)

    接触与真实服务器的绑定

    static void ip_vs_conn_flush(struct net *net)

    释放所有连接

    void ip_vs_random_dropentry(struct net *net)

    定时随即删除连接

    static inline int todrop_entry(struct ip_vs_conn *cp)

    判断是否要删除连接

    3.5、协议管理

    net\netfilter\ipvs\ip_vs_proto.c文件

    static int __used __init register_ip_vs_protocol(struct ip_vs_protocol *pp)

    注册一个ipvs协议

    static int unregister_ip_vs_protocol(struct ip_vs_protocol *pp)

    注销一个ipvs协议

    struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)

    查找服务,返回服务结构指针

    void ip_vs_protocol_timeout_change(struct netns_ipvs *ipvs, int flags)

    修改协议超时标记

    int *ip_vs_create_timeout_table(int *table, int size)

    创建状态超时表

    Int ip_vs_set_state_timeout(int *table, int num, const char *const *names,

    const char *name, int to)

    修改状态超时表

    const char * ip_vs_state_name(__u16 proto, int state)

    返回协议状态名称

    下面以TCP协议的实现来详细说明,相关代码文件为net\netfilter\ipvs\ip_vs_proto_tcp.c

    struct ip_vs_protocol ip_vs_protocol_tcp = {

    .name =                        "TCP",

    .protocol =                IPPROTO_TCP,

    .num_states =                IP_VS_TCP_S_LAST,

    .dont_defrag =                0,

    .init =                        NULL,

    .exit =                        NULL,

    .init_netns =                __ip_vs_tcp_init,

    .exit_netns =                __ip_vs_tcp_exit,

    .register_app =                tcp_register_app,

    .unregister_app =        tcp_unregister_app,

    .conn_schedule =        tcp_conn_schedule,

    .conn_in_get =                ip_vs_conn_in_get_proto,

    .conn_out_get =                ip_vs_conn_out_get_proto,

    .snat_handler =                tcp_snat_handler,

    .dnat_handler =                tcp_dnat_handler,

    .csum_check =                tcp_csum_check,

    .state_name =                tcp_state_name,

    .state_transition =        tcp_state_transition,

    .app_conn_bind =        tcp_app_conn_bind,

    .debug_packet =                ip_vs_tcpudp_debug_packet,

    .timeout_change =        tcp_timeout_change,

    };

    static void __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)

    tcp初始化函数

    static void __ip_vs_tcp_exit(struct net *net, struct ip_vs_proto_data *pd)

    tcp退出函数

    static int tcp_register_app(struct net *net, struct ip_vs_app *inc)

    注册tcp应用协议

    static voidtcp_unregister_app(struct net *net, struct ip_vs_app *inc)

    注销tcp应用协议

    static int

    tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,

      int *verdict, struct ip_vs_conn **cpp)

    tcp连接调度,该函数在ip_vs_in()函数中调用。

    struct ip_vs_conn *

    ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,

    const struct ip_vs_iphdr *iph,

    unsigned int proto_off, int inverse)

    进入方向连接查找

    struct ip_vs_conn *

    ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,

     const struct ip_vs_iphdr *iph,

     unsigned int proto_off, int inverse)

    发出方向连接查找

    static int

    tcp_snat_handler(struct sk_buff *skb,

     struct ip_vs_protocol *pp, struct ip_vs_conn *cp)

    该函数完成对协议部分数据进行源NAT操作,对TCP来说,NAT部分的数据就是源端口

    static inline void

    tcp_fast_csum_update(int af, struct tcphdr *tcph,

         const union nf_inet_addr *oldip,

         const union nf_inet_addr *newip,

         __be16 oldport, __be16 newport)

    TCP校验和快速计算法,因为只修改了端口一个参数,可根据RFC1141方法快速计算

    static int

    tcp_dnat_handler(struct sk_buff *skb,

     struct ip_vs_protocol *pp, struct ip_vs_conn *cp)

    该函数完成对协议部分数据进行目的NAT操作,对TCP来说,NAT部分的数据就是目的端口

    static int

    tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)

    计算IP协议中的校验和,对于TCP,UDP头中都有校验和参数,TCP中的校验和是必须的,而UDP的校验和可以不用计算。

    该函数用的都是linux内核提供标准的校验和计算函数

    static const char * tcp_state_name(int state)

    该函数返回协议状态名称字符串

    static const char *const tcp_state_name_table[IP_VS_TCP_S_LAST+1] = {

    [IP_VS_TCP_S_NONE]                =        "NONE",

    [IP_VS_TCP_S_ESTABLISHED]        =        "ESTABLISHED",

    [IP_VS_TCP_S_SYN_SENT]                =        "SYN_SENT",

    [IP_VS_TCP_S_SYN_RECV]                =        "SYN_RECV",

    [IP_VS_TCP_S_FIN_WAIT]                =        "FIN_WAIT",

    [IP_VS_TCP_S_TIME_WAIT]                =        "TIME_WAIT",

    [IP_VS_TCP_S_CLOSE]                =        "CLOSE",

    [IP_VS_TCP_S_CLOSE_WAIT]        =        "CLOSE_WAIT",

    [IP_VS_TCP_S_LAST_ACK]                =        "LAST_ACK",

    [IP_VS_TCP_S_LISTEN]                =        "LISTEN",

    [IP_VS_TCP_S_SYNACK]                =        "SYNACK",

    [IP_VS_TCP_S_LAST]                =        "BUG!",

    };

    TCP协议状态名称定义

    static void

    tcp_state_transition(struct ip_vs_conn *cp, int direction,

         const struct sk_buff *skb,

         struct ip_vs_proto_data *pd)

    tcp状态转换

    static inline void

    set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,

          int direction, struct tcphdr *th)

    设置tcp连接状态

    static struct tcp_states_t tcp_states []

    tcp状态转换表

    static void tcp_timeout_change(struct ip_vs_proto_data *pd, int flags)

    超时变化

    static int

    tcp_app_conn_bind(struct ip_vs_conn *cp)

    本函数实现将多连接应用协议处理模块和IPVS连接进行绑定

    未完待续

     

  • 相关阅读:
    ec20 queclocator V1. 0 test
    javascript JSON.parse and JSON.stringify
    linux command pushd popd
    learning gcc #pragma once
    learning gcc __BEGIN_DECLS and __END_DECLS
    aarch-linux-gnu-g++ install
    启用”开始“菜单中的“运行”功能
    获取本机安装的软件清单
    固定任务栏
    优化菜单显示速度
  • 原文地址:https://www.cnblogs.com/qq78292959/p/2588443.html
Copyright © 2020-2023  润新知