vpp load balance plugin
负载平衡器配置有一组虚拟IP(VIP,可以是前缀),对于每个VIP,配置有一组应用程序服务器地址(ASs)。
有四种方式将流量导向不同的ASs:
1). IPv4+GRE ad IPv6+GRE encap类型:为给定VIP(或VIP前缀)接收的流量通过GRE隧道传输到不同的ASs,以确保给定会话始终通过隧道传输到相同的。
2). IPv4+L3DSR encap类型:L3DSR用于克服直接服务器返回负载平衡的二层限制。它将VIP映射到DSCP位,并重用TOS位将DSCP位传输到服务器,然后服务器将VIP从DSCP映射到VIP。
VIP或ASs都可以是IPv4或IPv6,但对于给定的VIP,所有ASs必须使用相同的encap。类型(即IPv4+GRE或IPv6+GRE或IPv4+L3DSR)。这意味着对于给定的VIP,所有AS地址必须属于同一个家族。
3). IPv4/IPv6+NAT4/NAT6 encap 类型:该类型在用户空间提供 kube-proxy 数据平面,用于替代 linux 内核基于 iptables 的 kube-proxy 代理。
目前,负载平衡器插件支持三种服务类型:a)cluster IP加端口:支持任何协议,包括TCP、UDP。b) NodePort IP加节点端口:当前仅支持UDP。c) 外部负载平衡器。
对于为给定VIP(或VIP前缀)接收的特定会话,第一个数据包根据内部负载平衡算法选择AS,然后执行 DNAT 操作并发送到所选 AS。同时,将创建一个会话条目以存储为所选结果。该会话的以下数据包将首先查找会话表,这将确保给定会话始终路由到与相同的。
对于AS返回的数据包,它将执行SNAT操作并发送出.
当前情况
本文主要介绍 IPv4/IPv6+NAT4/NAT6 类型,和 kube-proxy 数据面功能一样,可以向 kubernetes service 一样使用方法进行使用。
当前社区代码该模块有问题,本人以提 PR 进行解决: https://gerrit.fd.io/r/c/vpp/+/36494
要实现 lb,需要考虑,tcp时,一次业务访问有握手和业务等多个包,此时需要一个后端端点进行处理。需要有链路保持。这一点 vpp 中有实现,有时间再进行分析。
使用
举例,client 端访问 VIP 10.10.2.2/24 Port 8080 到 后端 server (192.168.1.2:80,192.168.1.3:80)。和 kubernetes 的 service 相似。
配置方法
#vpp
lb set interface nat4 in GigabitEthernet0/9/0
lb vip 10.10.2.2/32 protocol tcp port 8080 encap nat4 type clusterip target_port 80
lb as 10.10.2.2/32 protocol tcp port 8080 192.168.1.1 192.168.1.3
客户端 访问 10.10.2.2:8080 会负载到 后端 192.168.1.1:80 和 192.168.1.3:80 服务
分析
配置项1:
lb set interface nat4 in GigabitEthernet0/9/0
功能为设置下行流量入口为 lb nat4,使该接口进入的包进入到 lb-nat4-in2out 节点做 SNAT
配置项2:
lb vip 10.10.2.2/32 protocol tcp port 8080 encap nat4 type clusterip target_port 80
创建一个 vip 10.10.2.2 port 8080 后面 target port 是 80,在 vpp 上的实现
src/plugins/lb/lb.c L1163
//Update flow hash table
lb_vip_update_new_flow_table(vip); // 为 vip 创建合适的 table,当为 vip 加 as 后,会更新该表,该table 设计方案借鉴 meglav 可以看上章。
//Create adjacency to direct traffic
lb_vip_add_adjacency(lbm, vip, &vip_prefix_index); // 将 vip adjacency 加到 ip4 或者 ip6 table。
lb_vip_add_adjacency 将 10.10.2.2/32 加到 ip4 table 中,并 为 ip 设置的 dpo 类型为 nat4_port,和指定的 vip 的 vip_prefix_index
最后将该 vip 存 bihash
key 是 vip_idx protocol port
value 是 vip 索引
配置项3: lb as 10.10.2.2/32 protocol tcp port 8080 192.168.1.1 192.168.1.3
该配置 为 vip 配置 两个后端断点。
创建了 lb as后,为 as 写 fib_table,并设置 dpo
lb.c L681
为下行包写 snat static mapping
L752
lb_vip_update_new_flow_table(vip);
更新 flow table 表
流量
上行流量,当 vpp 收到 目的是 vip + port 的流量时,丢到 lb4-nat4-port 节点处理
处理流程大致如下:
- vip 收到报文,传到dpo 即 vip 的索引, 拿 索引和报文协议号和端口去查 vip
- 从 lb_main 申请 sticky_table hash bucket。
- 计算报文 hash
lb_hash_get (sticky_ht, hash0,
vip_index0, lb_time,
&available_index0, &asindex0);
如果查到已有,返回 asindex0 (as 索引),并在 packet from existing sessions中加 1,即匹配到之前的连接; 如果没有,新建 asindex0,在 first session packet 加1,查处理进程,并更新 hash
4. 如果报文是指定 encap 类型
src/plugins/lb/node.c L489
将报文的目的ip和端口 (vip 的目的和端口)转为后端 as (hash 得到的 asindex0)的ip 和 port; checksum 后发到 lookup 节点处理
-
回包时,先进入 lb-nat4-in2out 节点处理 node.c L778
-
解析报文,查询 nat44_mapping,获取到需要还原成的 ip + port (vip + port),处理,checksum 后发到 LB_NAT4_IN2OUT_NEXT_LOOKUP 进行 lookup 即后续处理。
参考
https://s3-docs.fd.io/vpp/22.06/developer/plugins/lb.html?highlight=load%20balance%20plugin