ip_vs初识

概述


LVS是章文嵩博士十几年前的开源项目,已经被何如linux kernel 目录十几年了,可以说是国内最成功的kernle 开源项目, 在10多年后的今天,因为互联网的高速发展LVS得到了极大的应用, 是当今国内互联网公司,尤其是大型互联网公司的必备武器之一, 从这一点上来说,LVS名副其实。

搞了这么多年linux 网络开发维护, 由于一直偏通信方向,自己竟然从来没有读过ipvs的代码,不能不说是一个遗憾。这两天花时间研究了一下LVS,阅读LVS的kernel与ipvsadm的代码,终于搞清楚了其工作原理与细节问题,感觉队LVS的认识提高了一个等级,再次感谢章博。

LVS架构以及代码分析

LVS是非常典型的【控制面 + 数据面】的网络体系架构。

控制面


ipvsadm 作为控制面的工具运行在用户空间,其本身是一个非常简单的linux命令。ipvsadm可以使用两种方式和内核进行通信 : netlink 与 raw socket,这两种方式我们在这里不做详细介绍。现在基本上默认都使用netlink的方式,这也是现在绝大多数的用户空间与内核空间通信所选择的方式。ipvsadm的工作原理和代码都非常简单 : 分析命令行,将命令行信息打包进nl_msg,即netlink与内核通信的数据结构,然后发给内核即可。

数据面


LVS的数据面完全在linux kernel中实现, 并且是实现在netfilter的框架中, 对netfilter的介绍并不在本文范围之内。

LVS本身以内核核心模块的方式存在,我们首先来看其初始化函数【static int __init _vs_init(void)】做了些什么 : 

    ---> ip_vs_control_init()    :    初始化virtual server HASH表与virtual server firewall HASH表,注册netdevice 的notification 处理相应事件 ip_vs_dst_notifier
    ---> ip_vs_protocol_init()  :    注册协议处理结构,目前支持tcp,udp,sctp,ah,esp
    ---> ip_vs_conn_init()        :   初始化connection HASH表,默认HASH表头4096个
    ---> register_pernet_subsys()    :   注册namespace子系统
    ---> register_pernet_device()     :   注册namespace device 子系统
    ---> nf_register_hooks()    :    注册LVS处理函数到netfilter框架
    ---> ip_vs_register_nl_ioctl()    :    注册netlink处理函数与set/getsockopt处理函数

核心处理流程在netfilter框架中(我们可以暂时不关注namespace相关的操作)。

以IPV4为例,我们看看LVS都在netfilter框架中做了什么 : 

1829 static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1830         /* After packet filtering, change source only for VS/NAT */
1831         {
1832                 .hook           = ip_vs_reply4,
1833                 .owner          = THIS_MODULE,
1834                 .pf             = NFPROTO_IPV4,
1835                 .hooknum        = NF_INET_LOCAL_IN,
1836                 .priority       = NF_IP_PRI_NAT_SRC - 2,
1837         },
1838         /* After packet filtering, forward packet through VS/DR, VS/TUN,
1839          * or VS/NAT(change destination), so that filtering rules can be
1840          * applied to IPVS. */
1841         {
1842                 .hook           = ip_vs_remote_request4,
1843                 .owner          = THIS_MODULE,
1844                 .pf             = NFPROTO_IPV4,
1845                 .hooknum        = NF_INET_LOCAL_IN,
1846                 .priority       = NF_IP_PRI_NAT_SRC - 1,
1847         },
1848         /* Before ip_vs_in, change source only for VS/NAT */
1849         {
1850                 .hook           = ip_vs_local_reply4,
1851                 .owner          = THIS_MODULE,
1852                 .pf             = NFPROTO_IPV4,
1853                 .hooknum        = NF_INET_LOCAL_OUT,
1854                 .priority       = NF_IP_PRI_NAT_DST + 1,
1855         },
1856         /* After mangle, schedule and forward local requests */
1857         {
1858                 .hook           = ip_vs_local_request4,
1859                 .owner          = THIS_MODULE,
1860                 .pf             = NFPROTO_IPV4,
1861                 .hooknum        = NF_INET_LOCAL_OUT,
1862                 .priority       = NF_IP_PRI_NAT_DST + 2,
1863         },
1864         /* After packet filtering (but before ip_vs_out_icmp), catch icmp
1865          * destined for 0.0.0.0/0, which is for incoming IPVS connections */
1866         {
1867                 .hook           = ip_vs_forward_icmp,
1868                 .owner          = THIS_MODULE,
1869                 .pf             = NFPROTO_IPV4,
1870                 .hooknum        = NF_INET_FORWARD,
1871                 .priority       = 99,
1872         },
1873         /* After packet filtering, change source only for VS/NAT */
1874         {
1875                 .hook           = ip_vs_reply4,
1876                 .owner          = THIS_MODULE,
1877                 .pf             = NFPROTO_IPV4,
1878                 .hooknum        = NF_INET_FORWARD,
1879                 .priority       = 100,
1880         },

我们可以看到,LVS使用了netfilter五个HOOK点中的三个,分别是 : LOCAL_IN,LOCAL_OUT,FORWARD,我们分别介绍 :

LOCAL_IN 节点


LOCAL_IN节点LVS一共注册了两个函数,分别是 ip_vs_reply4 和  ip_vs_remote_request4。

ip_vs_reply4 : 只用于 LVS NAT 模式,并且只能处理TCP,UDP,SCTP


    ---> ip_vs_out()
        ---> ip_vs_fill_iph_skb() : 得到IP头
        ---> 判断是否是ICMP,如果是则调用ip_vs_out_icmp()函数处理
        ---> ip_vs_proto_data_get() : 取四层处理结构
        ---> 检查处理分片
        ---> 调用proto->conn_out_get() 得到当前connection
            ---> 如果得到connection,则调用handle_response()处理response
            ---> handle_response()
                ---> 
        ---> 如果没有connecton,则检测是否有VS和这个包匹配,如果有则再次检测这个包是否是TCP或RST的包,如果不是则发送ICMP目的不可达消息
            
            

ip_vs_remote_request4 : For DRand TUN模式


    ---> ip_vs_in()
        ---> 首先是合法性检测,ignore不合法的包
        ---> ipvs_fill_iph_skb()    :    得到ip头信息
        ---> 过滤掉RAW SOCKET的包
        ---> 处理ICMP包
        ---> ip_vs_proto_data_get() 找到proto结构,这个结构保存在 net->ipvs->proto_data_table[hash] 表中
        ---> 调用proto结构的 conn_in_get() 取的connection, connection保存在全局的表 ip_vs_conn_tab[hash] 中
            ---> 查找失败则调用 proto->conn_schedule() 创建connection
                ---> ip_vs_scheduler() : 找到与此包匹配的调度策略,创建connection
                    ---> sched->schedule() : 调用调度策略函数,按照既定的调度测率找到real server
                    ---> ip_vs_conn_new()  :  创建新的connection
                        ---> kmem_cache_alloc()    :   为connection分配内存
                        ---> 初始化connection
                        ---> ip_vs_bind_xmit()     :   根据LVS类型绑定connection的发送函数
                        ---> 将此connection加入ip_vs_conn_tab[hash] 表
                    ---> ip_vs_conn_stats()    :    更新connection统计信息
            ---> ip_vs_in_stats()    :    更新统计信息
            ---> connection->packet_xmit()    :     发包
            ---> synchronization 工作
    

LOCAL OUT 节点


LOCAL OUT 节点注册了两个函数 : ip_vs_local_reply4 和 ip_vs_local_request4

ip_vs_local_reply4 : 

    ---> ip_vs_out() :同上 ip_vs_reply4()

ip_vs_local_request4 :     


    ---> ip_vs_in()  :  同上  ip_vs_remote_request4()


FORWARD节点


FORWARD节点注册了两个函数 : ip_vs_reply4 和 ip_vs_forward_icmp

ip_vs_reply4 : 


    ---> ip_vs_out()   :  同上

ip_vs_forward_icmp :


    ---> ip_vs_in_icmp()    :    处理 outside to inside 方向的ICMP报文

我们可以看到,其实LVS在内核中核心的函数其实就两个 : ip_vs_in() 与 ip_vs_out()。



数据流过程分析


我们通过一个数据包在LVS架构中的处理流程来分析LVS的工作过程。
假设我们添加了这样的规则 : 

ipvsadm -A -t 192.168.132.254:80 -s rr -p 120

ipvsadm -a -t 192.168.132.254:80 -r 192.168.132.64:80 -g 
ipvsadm -a -t 192.168.132.254:80 -r 192.168.132.68:80 -g

我们可以看到,此规则为一个VS : 192.168.132.254:80, 两个real server 分别是 192.168.132.64:80 与 192.168.132.68:80, LVS模式为DR,调度算法为Round Robin。

配置过程我们ignore掉。

加入一个client要访问此虚拟服务器,那么一个TCP发起包为 : 192.168.132.111:2345 -》 192.168.132.254:80, 我们看看这个包的处理流程。

    ---> LVS 收到这个包, 然后路由发现此包是到本地虚拟server地址的数据包,然后将其上送到LOCAL_IN HOOK 点。
        ---> ip_vs_reply4() 首先被调用,因为其优先级高
            ---> 尝试找到与此包关联的connection,因为是第一个包,所以找不到
            ---> return NF_ACCEPT, 进入下一个HOOK点处理
        ---> ip_vs_remote_request4() 被调用,
            ---> Call ip_vs_in() 函数
                ---> 首先是包的预处理工作,找到IP头,找到protocol处理结构
                ---> 然后尝试按照此包找到一个已经存在的connection,由于是第一个包,所以失败
                ---> 然后调用proto->conn_schedule() 创建一个新的connection
                    ---> TCP : tcp_conn_schedule()
                        ---> 首先取得TCP 头
                        ---> 调用ip_vs_service_find() 找到虚拟服务器的管理结构
                        ---> 调用 ip_vs_schedule() 
                            ---> 找到此VS所使用的调度器的管理结构,执行调度函数,找到目的real server地址
                            ---> 调用 ip_vs_conn_new() 创建新的connection,将次connection加入全局HASH表
                                ---> 调用 ip_vs_bind_xmit() 为此 connection 绑定发送函数
                ---> 然后调用 connection->packet_xmit()发包
                    ---> 对于DR模式来说,发送函数是 ip_vs_dr_xmit()
                        ---> 调用 __ip_vs_get_out_rt() 来确定新的路由并设置到此skb包中关联
                        --->  调用 ip_vs_send_or_cont() 来最终将此包发送到dst指定的real server
                            ---> 重要的是设置skb->ipvs_property = 1 
                                ---> 发送过程中要经过LOCAL_OUT hook 点
                                ---> 调用ip_vs_out() 函数,直接返回 NF_ACCEPT
                                ---> 再调用ip_vs_in() 函数,直接返回NF_ACCEPT
                                ---> dst_output() 最终发包
                --->  最后更新connection状态

我们的例子是DR模式,real server收到包后可以直接向client返回数据,不必经过LVS server。其他的模式NAT, TUNNEL和DR模式大同小异,在生产环境中DR模式用的多一点,毕竟DR模式在性能上还是有优势的。


总结    


LVS是非常好的,基于国内的,linux开源软件,我在上面大致分析了其数据面,即kernel中的数据处理流程,总的来说LVS的设计以及实现非常的简单但是高效,稳定,是一款优秀的linux open src项目。希望我的分析能够为大家起到抛砖引玉的作用 ;)

AlphachnVSIP服务器虚拟化解决方案 VSIP服务器虚拟化解决方案全文共35页,当前为第1页。 内容大纲 VSIP虚拟化系统概述 VSIP虚拟化系统功能 VSIP虚拟化系统性能 VSIP虚拟化系统安全性 VSIP虚拟化系统兼容性 VSIP成功客户应用案例 关于盛思睿 VSIP服务器虚拟化解决方案全文共35页,当前为第2页。 VSIP服务器虚拟化技术    VSIP系统提供基于Linux内核的KVM(Kernel-based Virtual Machine)虚拟机,通过软硬件模拟具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统,把一台X86物理服务器虚拟成若干个独立的虚拟服务器,支持裸金属架构和全虚拟化,兼具良好的虚拟化性能、可靠性、兼容性和安全性。 进程隔离 强制访问控制(MAC) 基于角色的访问控制 裸金属架构 认证 审计跟踪 CC安全评估级 CC安全测试用例集 FIPS 140-2 认证加密 源代码开放 资源控制 磁盘加密 VSIP服务器虚拟化解决方案全文共35页,当前为第3页。 数据中心虚拟化   数据中心基础架构(Data Center Infrastructure)是指支撑各类应用程序相关信息进行集中存储、处理、传输、交换、管理等功能和服务所需的各类服务器、网络、存储设备及其安全可靠运行所需要的环境及物理支持。 VSIP虚拟化 VSIP服务器虚拟化解决方案全文共35页,当前为第4页。 VSIP系统总体架构    VSIP 服务器虚拟化系统采用基于智能代理的分布式系统架构。 … … VSIP主管理服务器   VSIP主管理服务器实现对多个资源池所属的大量资源服务器进行统一虚拟化管理、资源调度和运行监控。 VSIP资源池服务器   资源池服务器(又称为宿主服务器)基于安全高效的Linux KVM虚拟机技术在服务器硬件和操作系统之间引入虚拟化层,将一台物理机从逻辑上划分成多个虚拟机。 多级存储系统   存储用于集中存放虚拟机文件、虚拟机模板、软件镜像、备份等资源池相关数据文件。 VSIP SAG安全访问网关   安全访问网关可以为虚拟机提供统一的远程管理入口,对远程访问虚拟机的帐号行为进行记录和控制。 VSIP服务器虚拟化解决方案全文共35页,当前为第5页。 VSIP系统逻辑架构 虚拟资源层:虚拟计算资源(虚拟机)、虚拟存储资源(虚拟磁盘)和虚拟网络资源(虚拟网卡、虚拟交换机。 资源数据层:资源网格模型与数据、虚拟机模板数据、软件镜像数据、事件和日志数据、物理机和虚拟机历史监控数据。 资源调度控制层:任务及任务策略在线编辑、分布式任务调度、任务调度规则管理、调度任务监控、任务队列监控。 资源管理层:资源池管理、物理机和虚拟机全生命周期管理、虚拟机模板管理、软件镜像管理、存储管理、网络管理、系统管理。 交互接入层:基于Web浏览器的可视化配置管理工具;基于安全访问网关的虚拟机Web远程管理;基于REST的物理机和虚拟机的生命周期管理、虚拟机快照管理、虚拟机迁移管理等API接口。 VSIP服务器虚拟化解决方案全文共35页,当前为第6页。 VSIP系统部署架构 管理 工作站 windows/Linux 应用网 交换机 管理网 交换机 主管理 服务器 存储网 交换机 资源池 服务器 SAN存储 虚拟机及应用对外服务交换网络,1Gb以上网络连接 存储交换网络,虚拟机文件及备份数据交换,至少10Gb以上网络连接 运行虚拟机的宿主服务器,CPU必须支持VT技术,CPU总核心数量至少8核,内存容量大于16GB 运行VSIP管理服务的主控服务器,单台服务器CPU总核心数量至少4核,内存容量大于8GB 主管理服务器监控与远程管理宿主服务器的交换网络,至少千兆网络连接 集中存储虚拟机文件及备份数据,支持FC-SAN或IP-SAN Internet/ Intranet VSIP服务器虚拟化解决方案全文共35页,当前为第7页。 内容大纲 VSIP虚拟化系统概述 VSIP虚拟化系统功能 VSIP虚拟化系统性能 VSIP虚拟化系统安全性 VSIP虚拟化系统兼容性 VSIP成功客户应用案例 关于盛思睿 VSIP服务器虚拟化解决方案全文共35页,当前为第8页。 VSIP系统核心功能视图 能管理多个不同的资源池(不同用途或服务级别); 能支持对资源池资源(CPU、内存、存储、物理主机、虚拟机)整体利用状态进行监视; …… 能提供对虚拟机的查询、启动、停止、暂停/恢复、重启等基本控制操作; 能支持通过系统软件镜像启动创建、虚拟机模板克隆复制等多种方式创建单台或批量虚拟机; 能支持虚拟机的vCPU、内存、磁盘、网卡等资源停机或在线动态追加; 能支持虚拟机的备份和快照管理; 能支持虚拟机在线迁移和跨存储迁移; …… 能提供对物理服务器详细配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值