在调度器的实现技术中 , IP负载均衡技术是效率最高的。在已有的IP负载均衡技术中有通过网络地址转( Network Address Translation )将一组服务器构成一个高性能的、高可用的虚拟服务器 , 我们称之为VS/NAT技术(Virtual Server via Network Address Translation) , 大多数商品化的IP负载均衡调度器产品都是使用此方法 , 如Cisco的LocalDirector、F5的BigIP和Alteon的ACEDirector。在分析VS/NAT的缺点和网络服务的非对称性的基础上 , 我们提出通过IP隧道实现虚拟服务器的方法VS/TUN (Virtual Server via IP Tunneling) ,和通过直接路由实现虚拟服务器的方法VS/DR(Virtual Server via Direct Routing) , 它们可以极大地提高系统的伸缩性。所以,IPVS软件实现了这三种IP负载均衡技术 , 它们的大致原理如下

  1. Virtual Server via Network Address Translation(VS/NAT) 通过网络地址转换 , 调度器重写请求报文的目标地址 , 根据预设的调度算法 , 将请求分派给后端的真实服务器 ; 真实服务器的响应报文通过调度器时 , 报文的源地址被重写 , 再返回给客户 , 完成整个负载调度过程。

  2. Virtual Server via IP Tunneling(VS/TUN) 采用NAT技术时 , 由于请求和响应报文都必须经过调度器地址重写 , 当客户请求越来越多时 , 调度器的处理能力将成为瓶颈。为了解决这个问题 , 调度器把请求报文通过IP隧道转发至真实服务器 , 而真实服务器将响应直接返回给客户 , 所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多 , 采用VS/TUN技术后 , 集群系统的最大吞吐量可以提高10倍。

  3. Virtual Server via Direct Routing(VS/DR) VS/DR通过改写请求报文的MAC地址 , 将请求发送到真实服务器 , 而真实服务器将响应直接返回给客户。同VS/TUN 技术一样 , VS/DR技术可极大地提高集群系统的伸缩性。这种方法没有IP隧道的开销 , 对集群中的真实服务器也没有必须支持IP隧道协议的要求 , 但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。

1. NAT模式(VS/NAT)

由于IPv4中IP地址空间的日益紧张和安全方面的原因 , 很多网络使用保留IP地址( 10.0.0.0/255.0.0.0、 172.16.0.0/255.128.0.0和192.168.0.0/255.255.0.0) 。这些地址不在Internet上使用 , 而是专门为内部网络预留的。当内部网络中的主机要访问Internet或被Internet访问时 , 就需要 采用网络地址转换(Network Address Translation , 以下简称NAT) , 将内部地址转化为Internets上可用的外部地址。NAT的工作原理是报文头( 目标地址、源地址和端口等) 被正确改写后 , 客户相信 它们连接一个IP地址 , 而不同IP地址的服务器组也认为它们是与客户直接相连的。由此 , 可以用NAT方法将不同IP地址的并行网络服务变成在一个IP地址 上的一个虚拟服务。

VS/NAT的体系结构 : 在一组服务器前有一个调度器 , 它们是通过Switch/HUB相连接的。这些服务器提供相同的网络服务、相同的内容 , 即不管请求被发送到哪一台服务器 , 执行结果是一样的。服务的内容可以复制到每台服务器的本地硬盘上 , 可以通过网络文件系统( 如NFS)共享 , 也可以通过一个分布式文件系统来提供。

客户通过Virtual IP Address( 虚拟服务的IP地址) 访问网络服务时 , 请求报文到达调度器 , 调度器根据连接调度算法从一组真实服务器中选出一台服务器 , 将报文的目标地址Virtual IP Address改写成选定服务器的地址 ,报文的目标端口改写成选定服务器的相应端口 , 最后将修改后的报文发送给选出的服务器。同时 , 调度器在连接Hash 表中记录这个连接 , 当这个连接的下一个报文到达时 , 从连接Hash表中可以得到原选定服务器的地址和端口, 进行同样的改写操作 , 并将报文传给原选定的服务器。当来自真实服务器的响应报文经过调度器时 , 调度器将报文的源地址和源端口改为Virtual IP Address和相应的端口 , 再把报文发给用户。我们在连接上引入一个状态机 , 不同的报文会使得连接处于不同的状态 , 不同的状态有不同的超时值。在TCP连接中 , 根据标准的TCP有限状态机进行状态迁移 , 这里我们不一一叙述 , 请参见W. Richard Stevens的《TCP/IP Illustrated Volume I》 ; 在UDP中 , 我们只设置一个UDP状态。不同状态的超时值是可以设置的 , 在缺省情况下 , SYN状态的超时为1分钟, ESTABLISHED状态的超 时为15分钟 , FIN状态的超时为1分钟 ; UDP状态的超时为5分钟。当连接终止或超时 ,调度器将这个连接从连接Hash表中删除。

这样 , 客户所看到的只是在Virtual IP Address上提供的服务 , 而服务器集群的结构对用户是透明的。对改写后的报文 , 应用增量调整Checksum的算法调整TCP Checksum的值 , 避免了扫描整个报文来计算Checksum的开销。

lvs-nat : 本质是多目标IP的DNAT ,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和 PORT实现转发

  1. RIP和DIP应在同一个IP网络 , 且应使用私网地址 ;RS的网关要指向DIP

  2. 请求报文和响应报文都必须经由Director转发 ,Director易于成为系统瓶颈

  3. 支持端口映射 , 可修改请求报文的目标PORT

  4. VS必须是Linux系统 , RS可以是任意OS系统。

lvs-nat-struct-4

NAT实现原理过程

  1. 客户端发出的请求数据包经过网络到达LVS网卡 , 数据包源IP为CIP ,目的IP为VIP。

  2. 然后进入PREROUTING链中 , 根据目的IP查找路由 , 确定是否为本机IP地址 , 随后将数据包转发至INPUT链中 , 源IP和目的IP不变。

  3. 到达LVS后 , 通过目的IP和目的PORT查找是否为IPVS服务 , 如是IPVS服务 , 将会选择一个RS来作为后端服务器 , 数据包的目的IP 地址将会修改为RIP , 这时并以RIP为目的IP去查找路由 , 确定下一跳及PORT信息后 , 数据包将会转发至POSTROUTING链中。

  4. 被修改过的数据包经过POSTROUTING链后 , 到达RS服务器 , 数据包源IP为CIP , 目的IP为RIP。

  5. RS服务器经过处理后 , 将会把数据包发送至用户空间的应用程序 , 待处理完成后 , 发送响应数据包 , RS服务器的默认网关为LVS的 IP , 应用程序将会把数据包转发至下一跳LVS服务器 , 数据包源IP为RIP , 目的IP为CIP。

  6. LVS服务器收到RS服务器响应的数据包后 , 查找路由, 目的IP不是本机IP并且LVS服务器开启了FORWARD模式 , 会将数据包转发给它 , 数据包不变。

  7. LVS服务器收到响应数据包后,根据目的IP和 目的PORT查找相应的服务,这时,源IP为VIP ,通过查找路由 ,确定下一跳信息并将数据包发送至网关 ,最终回应给客户端用户。

NAT模式的优缺点

  • 优点

    • 支持Windows操作系统

    • 支持端口映射,如RS服务器PORT与VPORT不一致的话,LVS会修改目的IP地址和DPORT以支持端口映射;

  • 缺点

    • RS服务器需配置网关;

    • 双向流量对LVS会产生较大的负载压力;

    使用场景 : 对Windows操作系统的用户比较友好, 使用LVS,必须选择NAT模式

2. TUN模式(VS/TUN)

在VS/NAT 的集群系统中 , 请求和响应的数据报文都需要通过负载调度器 , 当真实服务器的数目在10台和20台之间时 , 负载调度器将成为整个集群系统的新瓶颈。大多数Internet服务都有这样的特点 : 请求报文较短而响应报文往往包含大量的数据。如果能将请求和响应分开处理 , 即在负载调度器中只负责调度请求而响应直接返回给客户 ,将极大地提高整个集群系统的吞吐量。

IP隧道(IP tunneling) 是将一个IP报文封装在另一个IP报文的技术 , 这可以使得目标为一个IP地址的数据报文能被封装和转发到另一个IP地址。IP隧道技术亦称为IP封装技术(IP encapsulation) 。IP隧道主要用于移动主机和虚拟私有网络(Virtual Private Network) ,在其中隧道都是静态建立的 , 隧道一端有一个IP地址 , 另一端也有唯一的IP地址。

我们利用IP隧道技术将请求报文封装转发给后端服务器 , 响应报文能从后端服务器直接返回给客户。但在这里 ,后端服务器有一组而非一个, 所以我们不可能静态地建立一一对应的隧道 , 而是动态地选择 一台服务器 , 将请求报文封装和转发给选出的服务器。这样 , 我们可以利用IP隧道的原理将一组服务器上的网络服务组成在一个IP地址上的虚拟网络服务。 VS/TUN的体系结构如下图所示,各个服务器将VIP 地址配置在自己的IP隧道设备上。

转发方式 : 不修改请求报文的IP首部(源IP为CIP , 目标IP为VIP) , 而在原IP报文之外再封装一个IP首部(源IP是DIP , 目标IP是RIP) , 将报文发往挑选出的目标RS ;RS直接响应给客户端(源IP是VIP ,目标IP是CIP)

lvs-tun-struct-1
lvs-tun-struct-3

TUN实现原理过程

  1. 客户端发送数据包经过网络后到LVS网卡 , 数据包源IP为CIP , 目的IP为VIP。

  2. 进入PREROUTING链后 , 会根据目的IP去查找路由 , 确定是否为本机IP ,数据包将转发至INPUT链中 , 到LVS , 源IP和目的IP不变。

  3. 到LVS后 , 通过目的IP和目的PORT查找是否为IPVS服务 , 如是 IPVS 服务,将会选择一个RS后端服务器 , 源 IP 为DIP ,目标IP为RIP , 数据包将会转发至 POSTROUTING 链中。数据包根据路由信息到达LVS 网卡 , 发送至路由器网关 ,最终到达后端服务器。

  4. 后端服务器收到数据包后 , 会拆掉最外层的IP地址后 , 会发现还有一层 IP 首部 , 源IP为CIP , 目的 IP 为VIP , TUNL0 上配置 VIP ,查找路由后判断为本机IP 地址 , 将会发给用户空间层的应用程序响应后VIP为源IP , CIP 为目的IP 数据包发送至网卡 , 最终返回至客户端用户。

  • TUN模式特点

    1. DIP、VIP、RIP可以是公网地址

    2. RS的网关一般不能指向DIP

    3. 请求报文要经由Director, 但响应不经由Director

    4. 不支持端口映射

    5. RS的OS须支持隧道功能

  • TUN模式的优缺点

    • 优点 :

      • 单臂模式,LVS负载压力小

      • 数据包修改小,信息完整性高;

      • 可跨机房

    • 缺点

      • 不支持端口映射;

      • 需在RS后端服务器安装模块及配置VIP;

      • 隧道头部IP地址固定, RS后端服务器网卡可能会不均匀;

      • 隧道头部的加入可能会导致分片,最终会影响服务器性能

使用场景 : 如对转发行要求较高且具有跨机房需求,可选择TUN模式。

3. DR模式(VS/DR)

跟VS/TUN方法相同 , VS/DR利用大多数Internet服务的非对称特点, 负载调度器中只负责调度请求 , 而服务器直接将响应返回给客户 ,可以极大地提高整个集群 系统的吞吐量。该方法与IBM的NetDispatcher产品中使用的方法类似(其中服务器上的IP地址配置方法是相似的) , 但IBM的NetDispatcher是非常昂贵的商品化产品 , 我们也不知道它内部所使用的机制 , 其中有些是IBM的专利。

VS/DR的体系结构中 , 调度器和服务器组都必须在物理上有一个网卡通过不分断的局域网相连 , 如通过高速的交换机或者HUB相连。VIP地址为调度器和服务器组共享 , 调度器配置的VIP地址是对外可见的 , 用于接收虚拟服务的请求报文 ; 所有的服务器把VIP地址配置在各自的Non-ARP网络设备上 , 它对外面是不可见的 , 只是用于处理目标地址为VIP的网络请求。

vs-dr.jpg

VS/DR连接调度和管理与VS/NAT和VS/TUN中的一样 ,它的报文转发方法又有不同 , 将报文直接路由给目标服务器。在VS/DR 中 , 调度器根据各个服务器的负载情况 , 动态地选择一台服务器,不修改也不封装IP报文 , 而是将数据帧的MAC地址改为选出服务器的MAC地址 , 再将修改后的数据帧在与服务器组的局域网上发送。因为数据帧的MAC地址是选出的服务器 , 所以服务器肯定可以收到这个数据帧,从中可以获得该IP报文。当服务器发现 报文的目标地址VIP是在本地的网络设备上,服务器处理这个报文,然后根据路由表将响应报文直接返回给客户。

在VS/DR中 , 根据缺省的TCP/IP协议栈处理 , 请求报文的目标地址为VIP , 响应报文的源地址肯定也为VIP , 所以响应报文不需要作任何修改 , 可以直接返回给客户 , 客户认为得到正常的服务 , 而不会知道是哪一台服务器处理的。

VS/DR负载调度器跟VS/TUN一样只处于从客户到服务器的半连接中 , 按照半连接的TCP有限状态机进行状态迁移。

LVS-DR : Direct Routing , 直接路由 , LVS默认模式,应用最广泛,通过为请求报文重新封装一个MAC首部 进行转发 , 源MAC是DIP所在的接口的MAC , 目标MAC是某挑选出的RS的RIP所在接口的MAC地址 ; 源IP/PORT , 以及目标IP/PORT均保持不变

lvs-dr-struct-1

DR实现原理过程

  1. 当客户端用户发送请求时 , 首先首先需要访问客户端网络中的路由器,这时到达 路由器的数据包包括 :源 IP 地址(客户端地址)、目的 IP 地址(LVS对外服务器 IP 地址 , 也就是 VIP)、源 MAC 地址(客户端自带的MAC地址/CIP-MAC)、目标MAC地址(路由器上和客户端同网段的MAC地址, R1-MAC)。

  2. 数据包通过路由器之后, 会直接将数据包发送给LVS的调度服务器上, 这时数据包包括: 源IP地址(客户端地址)、目的IP地址(LVS对外服务器IP地址,也就是VIP)、源MAC地址(路由器和LVS同网段的MAC地址/R2-MAC)、目标MAC地址(LVS调度器上VIP的mac地址/VIP-MAC)。

  3. 数据包到达INPUT链中 , LVS会根据目的IP和Port(端口) , 确认是否为LVS定义的服务 , 如是定义过的VIP服务 , 会根据配置的服务信息 , 从RealServer中选择一个后端服务器RS1 , 然后RS1作为目标出方向的路由 ,确定下一跳信息及数据包通过具体的哪个网卡发出,最好将数据包通过IPVS_HOOK到 POSTROUTING链上。 目的MAC地址将会修改为RealServer服务器MAC地址(RIP-MAC)、源 MAC地址修改为LVS与RS同网段的 IP 地址的MAC地址(DIP-MAC) , 此时数据包将会通过POSTROUTING发送至RealServer 服务器。

  4. 数据包到达RealServer服务器后 , 发现请求报文的目标MAC地址是自己的网卡MAC地址 , 将会接受此报文 , 待处理完成之后 , 将响应报文通过 lo接口传送给eth0网卡然后向外发出。此时的源IP 地址为VIP , 目标IP 为 CIP 。由于vip直接配置在lo环回口上,lo默认没有MAC地址, 因此默认的源MAC地址为eth0口 的mac地址(RIP-MAC)。目的MAC地址为下一跳路由器的MAC地址(R2-CMAC) , 最终数据包通过RS相连的路由器转发给客户端。

DR模式的特点 :

  1. Director和各RS都配置有VIP

  2. 确保前端路由器将目标IP为VIP的请求报文发往Director

    • 在前端网关做静态绑定VIP和Director的MAC地址

    • 在RS上使用arptables工具

      arptables -A IN -d $VIP -j DROP
      arptables -A OUT -s $VIP -j mangle  --mangle-ip-s $RIP
    • 在RS上修改内核参数以限制ARP通告及应答级别

      /proc/sys/net/ipv4/conf/all/arg_ignore
      /proc/sys/net/ipv4/conf/all/arp_announce
  3. RS的RIP可以使用私网地址 , 也可以是公网地址;RIP与DIP在同一IP网络 ; RIP的网关不能指向DIP , 以确保响应报文不会经由Director

  4. RS和Director要在同一个物理网络

  5. 请求报文要经由Director , 但响应报文不经由Director , 而由RS直接发往Client

  6. 不支持端口映射(端口不能修改)

  7. RS可使用大多数OS系统

DS 模式的优缺点:

  • 优点:

    • 响应数据不经过LVS , 性能高 ;

    • 对数据包修改小 , 信息完整性好 ;

  • 缺点:

    • LVS 与RS必须在同一个物理网络;

    • RS上必须配置lo和其他内核参数 ;

    • 不支持端口映射 ;

DS 模式的使用场景: 对性能要求高的 , 可首选DR模式 , 还可透传客户端源IP地址。

NAT 模式:只需一个公网 IP 地址,是最易用的一种负载均衡模式,安全性较好。

TUN 模式 和 DR 模式:负载能力强大、适用范围广、节点安全性较差。

4. FULLNAT模式(VS/FULLNAT)

LVS当前应用主要采用DR和NAT模式, 但这两种模式要求RealServer和LVS在同一个vlan中, 导致部署成本过高; TUNNEL模式虽然可以跨VLAN, 但RealServer上需要部署ipip模块等, 网络拓扑上需要连通外网,较复杂,不易运维。

为了解决上述问题, 我们在LVS上添加了一种新的转发模式:FULLNAT , 该模式和NAT模式的区别是:Packet IN时,除了做DNAT, 还做SNAT(用户IP-->内网IP), 从而实现LVS-RealServer间可以跨vlan通讯, RealServer只需要连接到内网;

在大规模的网络下,如在淘宝的业务中, 官方LVS满足不了需要,原因如下:

  1. 刚才讲的三种转发模式,部署成本较高

  2. 和商用的负载均衡相比,LVS没有DDOS防御攻击功能;

  3. 主备部署模式,性能无法扩展。如某个VIP下的流量特别大怎么办?

第一点, LVS 转发模式的不足, 下面来展开描述一下

DR的不足: 必须要求LVS跟后端所有的REPLY放在同一个VLAN里。当然,有人会提出来分几个区, 每个区布一个LVS ,但一个区VM资源没有了, 就只能用其他区的VM, 而用户需要这些VM挂载同一个VIP下,这是无法实现的。

NAT的不足 : NAT的最主要问题就是配置处理很复杂。阿里原来购买商业设备的时候, 需要在交换机上配策略路由, OUT方向的策略路由, 因为冗余考虑会部署多套负载均衡,走默认路由只能到达一套负载均衡。

TUNNEL的不足 : 隧道的问题也是配置过于复杂,RealServer需要加载一个IPIP模块, 同时做一些配置。

针对上述问题 , 也有相对应的解决方案。

  1. LVS 的3种转发模式 , 部署成本比较高 使用新转发模式FULLNAT , FULLNAT 实现了LVS-RealServer间跨 vlan 通讯 , 并且in/out流都经过LVS。FULLNAT转发数据包是类似NAT模式 , IN和OUT数据包都是经过LVS , 唯一的区别后端RealServer或者交换机不需要做任何配置。FULLNAT 的主要原理是引入local address(内网ip地址) , cip-vip 转换为lip->rip , 而lip和rip均为IDC内网IP , 可以跨vlan通讯 ;

  2. 和商用的负载均衡比 , LVS没有DDOS防御攻击功能 ; 使用SYNPROXY(synflood 攻击防御模块) ,Synproxy实现的主要原理是参照Linux TCP 协议栈中 syncookies 的思想 , LVS构造特殊seq的synack包 , 验证ack包中ack_seq是否合法实现了TCP三次握手代理。

  3. 主备部署模式,性能无法扩展 ; Cluster部署模式。基于FullNAT模式做横向扩展。

FULLNAT实现原理 : FULLNAT是近几年才出现的 , 客户端请求VIP(Director) , Director修改请求报文的源地址(DIP)和目标地址(RIP) 并转发给RS , FULLNAT模型一般是Director和RS处在复杂的内网环境中的实现。

  • fullnat模式特点 :

    1. VIP是公网地址 , RIP和DIP是私网地址 , 且通常不在同一IP网络 ; 因此 , RIP的网关一般不会指向DIP

    2. RS收到的请求报文源地址是DIP , 因此 , 只需响应给DIP ; 但Director还要将其发往Client

    3. 请求和响应报文都经由Director

    4. 相对NAT 模式 , 可以更好的实现LVS-RealServer间跨VLAN通讯

    5. 支持端口映射

    6. RS可以是任意的操作系统

5. 负载均衡技术区别

  1. 是否需要lvs vip跟realserver在同一个网段 :

    DR模式因为只修改package的MAC地址通过ARP广播的形式找到rs , 所以要求LVS的VIP和rs的IP必须在同一个网段内。其余模式可以允许vip和rs不在同一个网段。

  2. 是否需要在rs绑定LVS vip的IP地址 :

    rs收到package后会判断dst ip是否是自己的ip , 如果不是就直接丢掉包 ; 因为DR模式dst没有修改还是LVS的VIP ; 所以需要在rs上面绑定vip ; IP TUNNEL模式只是对package重新包装一层 , rs解析后的IP包的DST仍然是LVS的vip ; 也需要在rs上面绑定vip ; 其他的都不需要。

  3. 四种模式的性能比较 :

    因为DR模式 , IP TUNELL模式都是在package in时经过LVS ; 在package out是直接返回给client ; 所以二者的性能比NAT模式高 ; 但IP TUNNEL因为是TUNNEL模式比较复杂 , 其性能不如DR模式 ; FULL NAT模式因为不仅要更换DST IP还更换SOURCE IP所以性能比NAT下降10%。 所以 , 4中模式的性能如下 : DR –> IP TUNNEL —>NAT —–>FULL NAT

NAT

TUN

DR

Server

any

Tunneling

Non-arp device

Server network

private

LAN/WAN

LAN

Server number

low(10-20)

High(100)

High(100)

Server gateway

load balancer

own router

Own router

  • lvs-nat与lvs-fullnat :

    • 请求和响应报文都经由Director

    • lvs-nat :RIP的网关要指向DIP

    • lvs-fullnat :RIP和DIP未必在同一IP网络 , 但要能通信

  • lvs-dr与lvs-tun

    • 请求报文要经由Director , 但响应报文由RS直接发往Client

    • lvs-dr : 通过封装新的MAC首部实现 , 通过MAC网络转发

    • lvs-tun : 通过在原IP报文外封装新IP头实现转发 , 支持远距离通信

6. VS/TUN和VS/DR模式中的ARP问题

当一个目标IP地址为VIP的数据包进入Director前端的路由器时 , 路由器会向局域网内发送ARP广播 , 以找出VIP地址的MAC地址在哪台主机上。

Director和各RS都配置了VIP。当路由器发送ARP广播后 , Director和RS都会收到这个广播包 , 且都认为这个广播包找的就是自己 , 于是都回应给路由器 , 这样路由器上的ARP缓存表中的条目VIP<-->vip_MAC就不断被覆盖直到最后一个回应。这样一来 , 路由器将把客户端的数据包发送给最后一个回应的主机 , 这台主机的VIP可能是Director上的 , 也可能是某个RS上的。在一定时间内 , 路由器收到目标IP为VIP的数据包都会发送给该主机。但路由器会定时发送ARP广播包 , 这样一来ARP缓存表中的VIP对应的MAC地址可能会换成另一台主机。

因此 , 必须要保证路由器只保存Director上VIP对应的MAC地址 , 即只允许Director才对路由器的ARP广播进行回应。也就是说 , 所有RS上的VIP必须隐藏起来。

一般通过将Real Server上的VIP设置在lo接口的别名接口上(如lo:0) , 并设置arp_ignore=1和arp_announce=2的方式来隐藏RS上的VIP。

echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce

或

sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.all.arp_announce=2

6.1 arp_ignore和arp_announce说明

arp_ignore设置的是收到请求包后 , 在应答包中将本机的哪个IP地址和MAC地址回应给请求者以供缓存 ; arp_announce设置的是发出请求包时 , 选择哪个IP和MAC地址供响应者缓存 , 这也符合announce的字面意思:向外通告本机的哪个IP地址和MAC地址供其他主机缓存。

6.1.1 arp_ignore

  • 0 : (default) 将本机所有非lo接口的IP地址都回应出去。

  • 1 : 只有当ARP请求中的目标IP地址配置在流入接口上时才响应。

  • 2 : 只有当ARP请求中的目标IP地址配置在流入接口上时 , 且该IP地址(即发送者源地址)是接口地址上的子网地址时才响应(例如192.168.100.10/24和192.168.100.10/16的关系)。

  • 3 : do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied。

  • 4-7 : 保留

  • 8 : 不回应任意地址。

当某接口接收到ARP请求时 , 将取conf/{all,interface}/arp_ignore中值最大的生效。

注意 : 这里的是否响应 , 指的不是是否构建响应 , 而是路由决策后是否让构建好的响应包出去。换句话说 , arp响应包是一定会构建的 , 但是构建好的响应包根据arp_ignore设置的值不同 ,不一定能出的去。

arp_ignore=0, 当主机收到arp请求时,会将本机任意可能的IP地址都应答给arp请求者。

例如 , 主机A有3个网卡 , eth0(192.168.100.17/24) , eth1(192.168.100.36/24)和eth2(172.16.10.10/16) , 主机B有网卡eth0(192.168.100.39)。当主机B发起对192.168.100.36或17的ping时 , 由于主机A回应icmp响应给主机B时 , 默认情况下有以下路由 :

[root@Centos ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.100.2 0.0.0.0 UG 100 0 0 eth0
0.0.0.0 192.168.100.2 0.0.0.0 UG 101 0 0 eth1
0.0.0.0 192.168.100.2 0.0.0.0 UG 102 0 0 eth2
172.16.0.0 0.0.0.0 255.255.0.0 U 100 0 0 eth2
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.100.0 0.0.0.0 255.255.255.0 U 101 0 0 eth1
192.168.100.2 0.0.0.0 255.255.255.255 UH 100 0 0 eth2

这时主机A会将eth0和eth1上的IP地址都应答给主机B , 且这两个IP地址对应的MAC地址都是eth0(因为该接口是该网段的第一条路由出口)的MAC地址,因为无论请求的是哪个目标IP ,构建的arp响应都能从eth0出去 , 而eth0的arp_ignore=0 , 允许任意目标的响应包出去。以下是主机B上ping 192.168.100.36后的arp缓存表 , 如果结果不同 , 请ip neigh flush all清空缓存表或者多等待一段时间再测试。

[root@CentOS ~]# ip n s 
192.168.100.36 dev eth0 lladdr 00:0c:29:fb:dd:04 REACHABLE
192.168.100.1 dev eth0 lladdr 00:50:56:c0:00:08 REACHABLE
192.168.100.17 dev eth0 lladdr 00:0c:29:fb:dd:04 STALE

如果将主机A上192.168.100.0 eth0的路由条目删除 , 则主机B ping 192.168.100.36时 , 主机A将不再把eth0 (192.168.100.17)响应给主机B 。 尽管它可以使用eth1对应的路由出去。但如果主机B ping 192.168.100.17 , 那么也会将该地址响应出去 , 使用的源MAC地址也是eth1 (因为路由出口为eth1)。因此 , 主机B只会缓存主机A的192.168.100.36 eth1_MAC 。

由此可知 , 所谓响应任意可能的IP地址并不是响应所有地址 , lo接口、非同一网段地址以及无第一路由的接口地址就不会主动响应出去。同样 , 那些定义在接口上的别名地址也默认不会响应出去, 因为它们的数据的流入流出都是通过它所依附的接口。

arp_ignore=1时 , 当主机收到arp请求时 , 只有arp请求包中目标IP和流入接口上的IP相同时 , 才会响应该IP以及该接口的MAC。

例如 , 设置eth0网卡的该变量值为1。不过 , 为了完善测试 , 先将上面示例中删除的路由条目添加回来。

route add -net 192.168.100.0/24 dev eth0
echo 1 >/proc/sys/net/ipv4/conf/eth0/arp_ignore

这时主机B上ping 192.168.100.17时 , 主机A将只会响应eth0_MAC给主机B ,且ping 192.168.100.36时将ping不通(这一点需要注意 , 在后面配置LVS的arp参数时 , 外界主机往往只能ping通同网段的其中一个地址)。以下是在主机B上ping 192.168.100.36时 在主机A上抓取的数据包。

[root@xuexi ~]# tcpdump -nn host 192.168.100.39
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
12:21:51.739967 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:52.739741 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:53.739868 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:55.742680 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:56.743560 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:57.743086 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

从结果中可以看出 , 主机A收到目标IP为192.168.100.36的ARP请求后 , 并没有响应给主机B。因为主机B发出的ARP请求包到达主机A时的流入接口为eth1 , 构建arp响应包后 , 经过路由决策从eth0出去 , 而eth0上的arp_ignore=1 , 这个arp响应包将响应出不去,主机B也就不知道192.168.100.36的MAC地址 , 从而无法与A主机通信。

这里的关键流入接口是eth1 , 但arp响应包的流出接口是eth0 , eth0的arp_ignore=1意味着只有从eth0流入的arp请求 ,构建的arp 响应包才允许出去。尽管ping的目标是eth0同网段的eth1:192.168.100.36。也就是说 , 只要eth0的arp_ignore=1 那么该主机上该网段的所有地址(除了配置在eth0上的IP)都无法与外界通信。

此时,如果将eth0的路由条目删除 , 或者将eth0的路由优先级设置的比eth1的路由优先级更低(例如将eth0路由的metric的值设置的比eth1的metric更大) , 那么arp响应包的流出接口将是eth1 , 这时主机B ping主机A的eth0_IP或eth1_IP都能通 , 且arp缓存表中 , 这两个地址对应的MAC地址都是eth1_MAC。

再继续,如果没有eth0的路由 , 或者eth0的路由优先级比eth1低 ,且还设置了eth1的arp_ignore=1 , 此时主机B将只能ping通eth1_IP , 因为ping eth0_IP的arp请求从eth0而不是eth1流入 , 但它的响应包经过路由决策后却要从eth1出去 , eth1的 arp_ignore=1不会允许这样的arp响应包出去。

因此在arp请求过程中 , 目标主机路由表中路由的先后顺序非常重要 , 它不仅决定了数据从哪流出 ,更深层面上还决定了流出时使用哪个MAC地址 , 而这直接决定是否能成功ARP请求、ARP响应以及arp缓存的IP<-->MAC映射结果。如果你在学习arp_ignore和arp_announce 时做了很多测试 , 必然能体会到这一点。

6.1.2 arp_announce

arp_announce翻译如下

  • 0 : (default)可以使用本机上任意接口的任意地址。

  • 1 : 尽量不使用不在目标IP所在子网的地址。当目标主机可以通过该接口达到 , 但要求ARP数据包中的源IP地址是逻辑网络接口网段中的地址时 ,设置为该级别很有用。当生成ARP请求数据包时 , 将检测所有包含目标IP的子网(自身网段或子网都可以) , 如果源IP地址处于该子网内 , 则使用该地址。如果没有包含该源IP地址的子网 , 则使用级别2(arp_announce=2)来处理。

  • 2 : 总是为目标地址寻找最佳本地地址作为ARP请求的源IP地址。这种模式下 , 将忽略源IP地址 , 而是尝试选择出能和目标IP最佳通信质量的IP地址。这个IP是通过寻找各流出接口上的主IP地址(primary IP , 不能是secondary IP)得到的 , 它需要和目标IP地址在同网段或属于其子网内。如果没有选出合适的地址 , 将选择第一个流出接口上的IP地址 , 这样不仅可以接收到应答包,还能无视已经手动通告的源地址。

大致意思:

  • arp_announce=0时 , 向外发送ARP请求时 , 很可能会使用流出接口的IP地址和MAC地址 ,这没有硬性限制。但是Linux中ARP的源IP与源MAC与即将要发送的数据包的源IP与源MAC保持一致

  • arp_announce=1时,尽量使用与目标IP地址在同一子网的地址,例如目标IP地址为192.168.100.40/16 , 而本机有IP地址192.168.100.22/24 , 这个IP地址是目标IP地址子网内的一个地址 , 因此会尽量使用该地址作为ARP请求中的源IP地址 , 但是源MAC地址还是数据流出接口上的MAC。

  • arp_announce=2时 , 不管ARP请求包中指定的源IP地址是什么(因为ARP请求包中的源IP和源MAC可以手动指定) , 总会在本地搜索出和目标IP最匹配的IP地址来作为源地址。它会优先选和目标IP同子网的本地IP(primary IP) , 如果没有则选路由表中的第一个流出接口上的IP。

例如 , 如果Linux主机有3个网卡: eth0(IP0)、eth1(IP1)和eth2(IP2)。如果想通过eth2接口流出源地址为IP0的ARP请求广播包 ,默认情况下是行不通的。因为默认情况下 , 使用eth2流出ARP请求的源IP地址必须使用IP2。因此必须设置arp_announce=1或2 , 其实设置为1时也只是有机会流出 , 因为它要判断IP0和目标IP地址是否存在子网所属关系。只有设置arp_announce=2才必然能流出 ,但这时该Linux主机向外通告的IP地址将不是IP0 , 而是IP2。

6.2 arp设置

Linux内核2.0.xx版本中 , 回环接口、回环别名接口(如lo:0 , lo:1)以及回环隧道接口都不会做arp回应 , 对于LVS集群来说 , 这很方便。但从Linux 2.2.xx开始 , 除了回环地址(127.0.0.0/8)和广播地址外 , 其他所有地址(包括回环接口上的别名接口)都会做arp回应。因此 , 在这样的内核版本下配置LVS可能会出现一些问题。从Linux 内核2.2.14开始 , 提供了一个接口标记"hidden"用于从ARP广播中隐藏指定接口。

这意味着对于现在的CentOS6、CentOS7来说 , 虽然每个接口(包括lo接口)都可以设置这两个变量 , 但这两个变量只对能arp回应的接口才生效(如eth0,eth1等对外通信的普通接口)。也就是说 , 在lo接口上设置arp_ignore 、arp_announce等arp参数是没有意义的。

尽管对lo接口设置arp参数没有意义 , 但为了保证lo和普通网卡、隧道设置方法的统一性 , 以及未来的内核可能对此做出改变 , 本文以及网上的文章还是对它进行了同样的设置。

例如 , 设置lo接口的arp_ignore=1、arp_announce=2。

echo 1 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/lo/arp_announce

如果在接口上设置了别名IP , 例如eth0:0 , 由于它们仍然使用所依附的接口流入流出数据 , 因此在接口上设置arp_ignore 和arp_announce对别名IP同样生效。

其实 , 在/proc/sys/net/ipv4/conf下 , 除了各网卡接口的配置目录 , 还有default和all两个目录 , 这两个目录内关于arp参数的值只影响普通网卡 , 不影响lo接口 , 也没有意义去影响lo接口。

[root@CentOS ~]# ls -l /proc/sys/net/ipv4/conf/
total 0
dr-xr-xr-x 1 root root 0 Feb 15  2018 all
dr-xr-xr-x 1 root root 0 Feb 15  2018 default
dr-xr-xr-x 1 root root 0 Feb 14 22:56 eth0
dr-xr-xr-x 1 root root 0 Feb 14 22:56 eth1
dr-xr-xr-x 1 root root 0 Feb 14 22:56 lo

其中:

  • default目录中的变量值为普通网络接口提供初始化值(不影响lo接口)。这个目录其实没什么用 , 因为每次重启操作系统 , /proc/sys下的设置都会失效 , 而直接设置该目录下的值又起不到提供初始化值的作用。之所以放在conf目录内是为了提示我们可以设置default属性的值。例如 , 向sysctl.conf中追加永久设置net.ipv4.conf.default.arp_ignore=1 , 这样每次重启系统后各网卡接口的arp_ignore级别都是1(注意 : 普通网卡才生效 , lo接口不受影响)。

  • all目录中的变量作用范围是所有网卡(不包括lo接口)。

对于每个网卡来说 , 将比较all目录中的变量值和网卡自身的变量值 , 取较大值。例如:

conf/eth0/arp_ignore值为1 , conf/all/arp_ignore值为0 , 则对于eth0接口来说 , arp_ignore=1。

conf/lo/arp_announce值为0 , conf/all/arp_announce值为2 , 则对于lo接口来说 , arp_announce=0 , 因为all目录不影响lo接口。但最终 , lo接口上设置的arp参数值是没有意义的。

通常 , VS/TUN和VS/DR模式下 , Real Server上的VIP设置在lo的别名接口上(如lo:0上) , 因此应该如下设置:

echo 1 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce

其中生效的为第二条和第四条规则 , 第一条和第三条对lo接口的设置语句可有可无。

将conf/all/arp_ignore设置为1 , 可以保证无论哪个对外通信的网卡接口都只会向外响应自己接口上的IP地址(甚至可能有些同网段的接口因为路由顺序排在后面而响应不出去) , 这样就隐藏了设置在lo别名接口上的VIP地址。

将conf/all/arp_announce设置为2 , 可以保证本机只向外通告普通网卡上的IP地址 , lo别名接口上的VIP不可能被通告出去。


熊熊