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连接进行绑定

未完待续

 

原文地址:https://www.cnblogs.com/qq78292959/p/2588443.html