主要参考了http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/ 这个系列讲的非常详细。以及yfydz的博客,很多对代码的注释都是直接转载的他的内容,先说明一下,我自己写的主要是对代码整体脉络和思路的分析。
IPVS这部分的代码看了挺长时间了,对于普通应用的处理,相对简单。
对于FTP这种多连接的处理,IPVS虽然目前只支持FTP,但是用了很多代码来处理这种affinity connection,其中用到了persistent connection和template。其中,persistent connection是指对于多连接的服务,需要把connection都定向到同一个server上面,persistent这个标记是在ipvsadm 添加service时就配置的。template是指对于多连接的服务,创建了一个template connection作为其他连接的template,(这里的其他连接是指从同一个src发出的,被iptables打过mark的连接,iptables可以对相关的连接根据端口号打上mark,方便IPVS的处理。)这样其他连接就根据template中指向的dest,也定向到了dest。也就说相关的连接都发到了同一个dest。
根据LVS官方网站的介绍,LVS支持三种负载均衡模式:NAT,tunnel和direct routing(DR)。
NAT是通用模式,所有交互数据必须通过均衡器;后两种则是一种半连接处理方式,请求数据通过均衡器,而服务器的回应则是直接路由返回的,
而这两种方法的区别是tunnel模式下由于进行了IP封装所以可路由,而DR方式是修改MAC地址来实现,所以必须同一网段.
[主要数据结构]
这个结构用来描述IPVS支持的IP协议。IPVS的IP层协议支持TCP, UDP, AH和ESP这4种IP层协议
struct ip_vs_protocol {
//链表中的下一项
struct ip_vs_protocol *next;
//协议名称, "TCP", "UDP".
char *name;
//协议值
__u16 protocol;
//不进行分片
int dont_defrag;
//协议应用计数器,根据是该协议的中多连接协议的数量
atomic_t appcnt;
//协议各状态的超时数组
int *timeout_table;
void (*init)(struct ip_vs_protocol *pp); //协议初始化
void (*exit)(struct ip_vs_protocol *pp); //协议释放
int (*conn_schedule)(struct sk_buff *skb, struct ip_vs_protocol *pp, int *verdict, struct ip_vs_conn **cpp); //协议调度
//查找in方向的IPVS连接
struct ip_vs_conn * (*conn_in_get)(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse);
//查找out方向的IPVS连接
struct ip_vs_conn * (*conn_out_get)(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse);
//源NAT操作
int (*snat_handler)(struct sk_buff **pskb, struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
//目的NAT操作
int (*dnat_handler)(struct sk_buff **pskb, struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
//协议校验和计算
int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
//当前协议状态名称: 如"LISTEN", "ESTABLISH"
const char *(*state_name)(int state);
//协议状态迁移
int (*state_transition)(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_protocol *pp);
//登记应用
int (*register_app)(struct ip_vs_app *inc);
//去除应用登记
void (*unregister_app)(struct ip_vs_app *inc);
int (*app_conn_bind)(struct ip_vs_conn *cp);
//数据包打印
void (*debug_packet)(struct ip_vs_protocol *pp, const struct sk_buff *skb, int offset, const char *msg);
//调整超时
void (*timeout_change)(struct ip_vs_protocol *pp, int flags);
//设置各种状态下的协议超时
int (*set_state_timeout)(struct ip_vs_protocol *pp, char *sname, int to);
};
这个结构用来描述IPVS的连接。IPVS的连接和netfilter定义的连接类似
struct ip_vs_conn {
struct list_head c_list; //HASH链表
__u32 caddr; //客户机地址
__u32 vaddr; //服务器对外的虚拟地址
__u32 daddr; //服务器实际地址
__u16 cport; //客户端的端口
__u16 vport; //服务器对外虚拟端口
__u16 dport; //服务器实际端口
__u16 protocol; //协议类型
atomic_t refcnt; //连接引用计数
struct timer_list timer; //定时器
volatile unsigned long timeout; //超时时间
spinlock_t lock; //状态转换锁
volatile __u16 flags; /* status flags */
volatile __u16 state; /* state info */
struct ip_vs_conn *control; //主连接, 如FTP
atomic_t n