> 文章列表 > 云内基于 SRv6 的 SFC 方案

云内基于 SRv6 的 SFC 方案

云内基于 SRv6 的 SFC 方案

1. 基于 SRv6 的 SFC 服务链

 

为满足用户的业务数据安全、稳定等需求,提供各种基础保障或增值优化服务,在传统网络中,经常使用业务功能节点(如负载均衡、防火墙等)实现服务供应。但这些业务功能节点往往与网络拓扑和硬件资源耦合紧密,各个业务功能节点均为专用的设备形态且部署繁杂。当开通新业务或业务流程发生变更时,需要更改网络拓扑,甚至改造和升级网络设备,对周边的支撑系统也会有影响。

随着云计算网络的普及、虚拟化技术的成熟和应用,网络功能动态加载,资源按需分配,业务灵活开通等特点明显加强,而服务供应也必不可少。如果还使用传统网络的服务供应部署方式,已无法满足云计算网络灵活多变的组网特点、客户多种多样的业务需求。因此,服务链 SFC 技术被提出,该技术从满足客户业务数据安全、稳定等需求角度出发,更契合新时代网络特点,使业务功能灵活性得到更大的发挥。

SFC ( Service Function Chain 服务链)是由一系列业务节点有序构成,各业务节点可对数据流量进行流量检查、处理等操作。通过将用户数据报文依照业务逻辑以此通过各业务功能节点,就能轻松实现 SFC 服务链功能。随着云服务市场规模的扩大,在云内实现 SFC 也有着庞大的市场需求。

SFC 大部分通过 NSH 标准化服务链技术实现,但这些方案仍存在一定程度的限制:配置时需要根据流量的转发路径,基于每条业务流,依次在各个业务节点上逐跳配置。当 SFC 服务链扩容时,其配置复杂度也随之几何上升。由此可见,现有方案操作复杂,可扩展性差,不利于 SFC 的落地推广。

近年来随着云计算、大数据、物联网、人工智能等信息技术的快速发展和传统产业的数字化转型,数据量呈现几何级增长,同时计算成本快速下降,数字经济正进入算力时代。在算力网络中使用 IPv6 作为新一代 IP 承载协议,由此衍生了许多 IP 新技术。其中, SRv6 ( Segment Routing IPv6 )技术通过 IPv6 扩展头的方式,基于现有 IPV6 转发技术,实现了网络可编程化。

若能利用 SRv6 的路由编排特性实现 SFC ,将大幅简化 SFC 逐跳配置的繁杂度,并且也适应新时代大规模网络的发展。因此本文将探索基于 SRv6 技术支持 SFC 的实现,并尝试在云环境中实现该方案。

2. 城域网 SRv6 SFC 应用场景

基于 SRv6 的 SFC 组网架构

以城域网中 SRv6 使用场景为例,基于 SRv6 的 SFC 方案主要由用于下发服务链路径信息的( SDN 控制器)、业务分类节点( SC )、服务转发节点( SFF )和服务链集群( SFC Domain )组网构成。

如上图,服务供应商可通过 SDN 控制器向 SFC 业务分类节点下发服务链配置信息。服务链配置信息组织了 SFC 服务域中服务器路径次序,如:( VBRAS, FW, CGN, Server ) 、 ( VBRAS,FW ) 、( CGN, Server ) 等。

SC 和 SFF 将以 SRv6 隧道的形式为业务数据提供服务链。其中, SC 负责将业务流量导入 SRv6 隧道中, SFF 负责将业务流量传递到具体的服务供应机器。详细运作过程如下图:

当用户发起访问,业务数据经过 SC 时, SC 将业务数据引入到 SRv6 隧道中进行转发。业务数据随后传递到 SFF , SFF 解读报文中的路径信息,并按信息次序传递数据包到具体的服务链机器( SF )中处理,之后数据包被返还到 SFF , SFF 按路径信息传递到下一个 SFF 或者隧道尾节点。

数据包经过各服务器成功处理后,到达尾节点时,报文中服务链信息部分将被剥去,并按原始业务数据路径被传递。

基于 SRv6 的 SFC 实现原理

SID 标记路径

服务链信息(即服务器地址序列)以 SID 的形式被封装在 IPv6 SRH 扩展头中,作为 SRv6 报文在上文所述的 SRv6 TE Policy 中流转。同时, SC 、 SFF 等地址也可以用 SID 来标记,引导报文路径。因此 SID 相当于网络中的位置标记,其值可使用 IPv6 地址。

不同的 SID 其对应的处理逻辑也不一样。比如 SFF 需要解析并保存 SRv6 报文信息,将数据包分发给不同的 SF ,如果 SF 不支持 SRv6 、 IPv6 等,在分发前 SFF 还需要解封 SRv6 外层报文等等。所以节点在收到 SDN 控制器下发的服务链配置信息后,也会在本地建立相应的 SID 表( Local SID Table ) 。

因此,依据 SID 对应的不同操作,可将其分类如下:

报文转发过程

在 SRv6 TE Policy 中 SC 节点、 SFF 节点、尾节点对 SRv6 报文的转发操作如下:

  1. SC 节点收到用户网络原始报文后,根据服务链信息进行SRv6 报文封装,此时 IPv6 报文的目的地址是 SFF 的 End.AS SID , SRH 头部包括服务链全路径信息( SID List )。
  2. SFF 收到报文以后,通过查找 Local SID 表发现目的地址为本地 End.AS SID ,保存当前 SL ( SID List 指针)值,并执行 End.AS SID 对应指令——解封报文,去除 IPv6 报文头部后将原始报文通过配置的出接口发送到 SF 进行处理。
  3. 当 SF 处理完报文并将报文发回给 SFF , SFF 会根据收报文的入接口查找配置信息,然后依据配置的 SID list 重新封装 SRv6 报文,封装后报文 SRH 中 SID list 与 SC 上 SRv6 TE Policy 路径一致, SRH 中的 SL 值为步骤2中保存的 SL 值减1。此时 SRv6 报文目的地址是本地 End.AS SID 之后的下一个 SID (即 Device C 的 End SID )。SFF 根据报文的目的 IPv6 地址,查找 IPv6 路由表转发报文。
  4. ( 在真实服务链路径中,不一定每个节点都需要把报文传递到 SF 中,有时可能只是路径需要经过了该节点,因此节点只需查找路由并转发报文到下一个节点即可。图中 Device C 就是模拟这样的节点。)当 Device C 接收到报文以后,通过查找 Local SID 表发现目的地址为本地 End SID ,按 Srv6 转发流程处理报文。目的地址替换为 D1 (即尾节点的 End SID ), SL-1 ,查找 IPv6 路由表转发报文。
  5. 尾节点接收到报文以后,通过查找 Local SID 表发现目的地址 D1 为本地 SID ,将目的地址替换为 D2 (即尾节点的 End.DT4 SID ), SL-1 变为0。尾节点执行 End.DT4 SID 对应指令——解封装 SRv6 报文,并将原始报文转发到对应 VPN 。

3. Linux 中的 SRv6 SFC 模型

上文通过城域网中基于 SRv6 的 SFC 应用场景,梳理了 SFC 的实现流程。而在通用服务器中实现服务链功能,则需要系统实现 srv6 技术。目前 linux 系统从 4.10 开始已有支持。

Linux SRv6 协议栈

模型图

在机器中部署 namesapce 模拟 SRv6 网络节点。host 1 请求 host 4 的流量将被引导到 SRv6 封装中,经过 host 2 和 host 3 节点处理后再发送到 host 4。host 4 收到 host1 的请求中不带有 SRv6 报文,对 SRv6 过程不感知。

其中 host1 通过 route 命令对原始报文执行 SRv6 封装操作;host2 作为中间转发节点,通过 route 命令对 SRv6 报文执行转发操作;host3 作为 SRv6 过程的尾节点,通过 route 命令配置剥除 SRv6 报文,并将原始报文发送到目标机器 host4 中。

测试方法

执行如下脚本:

      
#!/bin/bashTMUX=4hs1sw# Kill tmux previous session
tmux kill-session -t $TMUX 2>/dev/null# Clean up the previous network namespaces
for ns in h1 h2 h3 h4 switch; doip netns delete ${ns} 2>/dev/null
doneip netns add h1
ip netns add h2
ip netns add h3
ip netns add h4
ip netns add switchip -netns switch link add veth1 type veth peer name enp0s8 netns h1
ip -netns switch link add veth2 type veth peer name enp0s8 netns h2
ip -netns switch link add veth3 type veth peer name enp0s8 netns h3
ip -netns switch link add veth4 type veth peer name enp0s8 netns h4###################
#### Node: h1 #####
###################
echo -e "\\nNode: h1"
ip netns exec h1 sysctl -w net.ipv6.conf.all.forwarding=1ip -netns h1 link set dev lo upip -netns h1 link set dev enp0s8 address 00:00:00:00:00:01
ip -netns h1 addr add fc00::1/64 dev enp0s8
ip -netns h1 link set dev enp0s8 upip -netns h1 -6 route add fcf0:12::100 via fc00::2# 2 SIDs here!
# - fcf0:12::100 steers the packet to node h2 where the SRv6 End function is
#   applied (SL=1 on ingress -> SL=0 on egress)
# 
# - fcf0::23::6006 steers the packet to node h3 where the decap function is
#   applied (SL=0 on ingress)
ip -netns h1 -6 route add fc00::4 encap seg6 mode encap \\segs fcf0:12::100,fcf0:23::6006 dev enp0s8###################
#### Node: h2 #####
###################
echo -e "\\nNode: h2"
ip netns exec h2 sysctl -w net.ipv6.conf.all.forwarding=1ip -netns h2 link set dev lo upip -netns h2 addr add fc00::2/64 dev enp0s8
ip -netns h2 link set dev enp0s8 address 00:00:00:00:00:02
ip -netns h2 link set dev enp0s8 upip -netns h2 -6 route add fcf0:23::6006 via fc00::3# apply the SRv6 End function for updating the active SID
ip -netns h2 -6 route add fcf0:12::100 encap seg6local action End dev enp0s8###################
#### Node: h3 #####
###################
echo -e "\\nNode: h3"
ip netns exec h3  sysctl -w net.ipv6.conf.all.forwarding=1ip -netns h3 link set dev lo upip -netns h3 addr add fc00::3/64 dev enp0s8
ip -netns h3 link set dev enp0s8 address 00:00:00:00:00:03
ip -netns h3 link set dev enp0s8 up# apply the SRv6 End.DT6 function to decap the packet and to deliver
# the inner packet to host h4.
ip -netns h3 -6 route add fcf0:23::6006 encap seg6local \\action End.DT6 table 254 dev enp0s8# all the hosts are in the same network...
#
#                  +-----+---------------------------------+-----+
#  - decap packet: | ... | IPv6 DA=fc00:1, SA=fc00::4, ... | ... |
#                  +-----+---------------------------------+-----+
# 
# host h3 tries to route the decap packet and it finds out that such
# packet can be sent directly from node h1 to node h4.
# As a result, the node h3 sends an icmpv6 redirect packet to host h1.
# We do not want to send this packet to the host h1, so we filter it.ip netns exec h3 ip6tables -t mangle -A POSTROUTING  \\-p icmpv6 --icmpv6-type redirect -j DROP###################
#### Node: h4 #####
###################
echo -e "\\nNode: h4"
ip netns exec h4  sysctl -w net.ipv6.conf.all.forwarding=1ip -netns h4 link set dev lo upip -netns h4 addr add fc00::4/64 dev enp0s8
ip -netns h4 link set dev enp0s8 address 00:00:00:00:00:04
ip -netns h4 link set dev enp0s8 up#######################
#### Node: switch #####
#######################
echo -e "\\nNode: switch"
ip -netns switch link set dev lo up
ip -netns switch link set dev veth1 up
ip -netns switch link set dev veth2 up
ip -netns switch link set dev veth3 up
ip -netns switch link set dev veth4 upip -netns switch link add sw0 type bridge
ip -netns switch link set dev sw0 upip -netns switch link set dev veth1 master sw0
ip -netns switch link set dev veth2 master sw0
ip -netns switch link set dev veth3 master sw0
ip -netns switch link set dev veth4 master sw0sleep 1## Create a new tmux session
tmux new-session -d -s $TMUX -n h1 ip netns exec h1 bash
tmux new-window -t $TMUX -n h2 ip netns exec h2 bash
tmux new-window -t $TMUX -n h3 ip netns exec h3 bash
tmux new-window -t $TMUX -n h4 ip netns exec h4 bash
tmux new-window -t $TMUX -n switch ip netns exec switch bash
tmux set-option -g mouse on
tmux select-window -t :0
tmux attach -t $TMUX

SREXT 实现 unaware SRv6 SFC 代理

linux 协议栈中已经实现了 srv6 封装、解封、转发的功能。但在目前 SFC 应用场景中, SF 不一定能支持 IPv6 ,需要有 unaware srv6 的代理实现来过渡支持。这方面可通过加载 srext 内核模块来实现。

模型图

部署三个虚机,分别模拟入口节点(ingress),出口节点(egress)和 unaware srv6 服务端代理节点(nfv)。

其中 nfv 节点上有三个 namespace ,模拟 unaware srv6 服务端。

当数据进入 nfv 节点中, srext 将剥除 srv6 部分报文并发送到 vnf namespace 中,待 vnf namespace 处理完后,又将 srv6 部分重新封装到报文中,继续向下一个 srv6 节点发送。

以 client ping server 的请求过程为例,报文处理过程如下图所示:

测试方法

https://netgroup.github.io/SRv6-net-prog/testbed-basic.html

4. 云内基于 SRv6 的 SFC 方案

在云环境中实现基于 SRv6 的 SFC 方案,需要在 OVS 中实现 SRv6 的操作,控制面可通过 SDN Controller 把 SFC 的编排路径下发到 OVS 流表中, OVS 依据流表配置,将业务链信息压入 SRv6 报文中并转发,由此实现 SFC 业务操作。

OVS 中实现 SRv6 转发

模型图

在云环境中, SFC 的部署可能与客户机器在同一个或者不同节点上,两者对 SRv6 数据包的操作大致一样。用户对 OVS 将流量引至 SFC 的过程无感知。

当用户和 SFC 在不同节点上时, OVS 对业务流量操作如下:

  1. 控制面可通过 SDN 控制器、 OVS 命令行等向 OVS 下发服务链信息配置流表,包括目标报文标记( eg. 五元组)和服务链信息( SID 列表),服务链信息流表在 OVS 中将转化为端口对数据包的具体操作(封装、解封、转发)。
  2. OVS 对接用户的端口(port 1)收到业务流量后,查找流表,如果命中了服务链信息配置流,则封装 SRv6 报文,将服务链路径信息依次全部压入 SRH 中 SID List 字段,初始化 SID List 指针,将 IPv6 目的地址指向 SID List 首节点。将报文转发到下一个处理端口(port 2)。
  3. 当中间端口(port 2、port 3)收到 SRv6 报文后,依据控制面的配置,这些端口将执行转发动作:将 SID List 指针值减一,替换 IPv6 目的地址,转发到下一个节点。
  4. 当对接 SF 的端口(port 4、port 5)收到 SRv6 报文后,依据控制面的配置,这些端口将先执行解包动作,保存报文中的 SID 指针等信息,然后发送原始业务报文给对应的 SF ;当 SF 返回原始业务报文后, OVS 再读取保存的信息执行封包动作,然后转发到下一个节点(port 6)。
  5. 当目标客户机所在端口(port 6)收到 SRv6 报文后,依据控制面的配置,这些端口将执行解包动作,删除包含服务链信息的 SRv6 部分,将原始业务报文转发给目标机器。至此完成基于 SRv6 的 SFC 流程,其过程用户无感知。

测试方法

为验证 OVS 对 SFC 业务的 SRv6 过程,在此简化模型如下:

在该模型中验证 OVS 对 SRv6 的封装、转发和解封。其中 namespace1 和 namespace4 模拟业务通信的客户机, namespace2 和 namespace3 模拟 SF ,但这里使用的 namespace 并不具备真正的 SF 功能,因此并未对数据包进行任何操作,只是转发给 OVS ,以此验证 OVS 功能。

https://pan.baidu.com/s/1u2cMprwoTE4-MePA9kEnBg?pwd=u67f

  1. 控制面下发 SFC 配置流表到 OVS , 指定从 port 2 接收到的报文需要依据 SID List 执行 SRv6 的封装;从 port 4 收到的报文执行 SRv6 转发动作;从 port 6 收到的报文执行解封操作。
  2. 当 port 2 收到报文时,检查是否命中 SFC 流表,如果命中则封装 SRv6 报文,并按照流表规则转发到 port3 。其中封装操作将服务链信息全部压入 SRH 中,由于 OVS port2 作为 SID List 的起点,所以初始化指针值为第二个 SID 即下一跳 SID ,并加上 IPv6 报文,且目的地址为下一跳 SID 。
  3. Namesapce 2 将 port3 发来的报文转发给 port 4 。OVS port 4 接收到报文后,如果命中 SFC 流表,则执行 SRv6 转发动作:SID List 指针值减一,更新 IPv6 目的地址。修改完 SRV6 报文后, OVS 按照流表规则转发到 port 5。
  4. Namespace 3 将 port5 发来的报文转发给 port 6。OVS port 6 接收到报文后,如果命中 SFC 流表,则执行 SRv6 解封动作:剥除 IPv6 和 SRH 部分报文,将原始报文发送到 port 7给目标机器。

云内基于 SRv6 的 SFC 方案

云环境中基于 OVS 实现 SFC 方案通过在 OVS 中配置服务链信息流表规则,简化逐跳策略路由配置的繁杂步骤,实现服务链业务的快速部署。该方案支持 IPv4/IPv6 双栈的业务流量,在 SFC 中通过使用 SREXT 支持 unaware SRv6 的 SF 接入,即也支持 IPv4/IPv6 双栈 SF 。

模型图

云环境中基于 OVS 实现 SFC 方案最小部署方案如下:

user-domain 和 server-domain 上可部署业务访问源和目标,分别接入 OVS 中两个不同的 port ;sfc-domain 作为服务链域机器,其上可部署具体的服务链应用,在此模型中使用三个不同的 vnf 模拟应用容器。考虑到目前许多环境未支持 SRv6 ,此处用 IPv4 来模拟, SF 中的应用都使用 IPv4 中即可。

OVS 中 user1-port 和 user2-port 作为 SFC SRv6 过程的起止端点,绑定了两个 SID (1:2::1, 2:3::2)作为服务链( SID List )中的起止 SID 。

在部署 sfc-domain 时,将具体的 SF 及其 ipv4 地址写入 Local SID Table 中,并使用两个接口(sfc-domain:ens3, sfc-domain:ens10)分别作为 SFC 域的出入接口对接 OVS 的 port (proxy0-port, proxy1-port)。这两个接口(ens3:[1:2::2], ens10:[2:3::1])分别与 OVS 起止 SID 在同一网段。

上图是以 tcp 消息请求过程为例的流量模型。其主要过程如下:

  1. 控制面配置服务链信息流表到 OVS 中,其中对接业务源的 user1-port 负责将业务报文封装到 SFC 的 SRv6 中,对接目标源的 user2-port 负责将 SFC 的 SRv6 剥除。
  2. 当业务源中客户端发起访问, OVS 中 user1-port 收到数据包后,查询流表内容,发现数据包命中 SFC 规则,于是将规则中的全量 SID (服务链[2::ad:f1,2::ad:f2,2::ad:f3]和 OVS 中起止 SID [1:2::1, 2:3::2] )依次压入 SRH 栈中,初始化 SID List 指针,封装 IPv6 报文,并将目的地址设置为下一跳 SID 即第一个 SF 地址( 2::ad:f1 )。
  3. 当 sfc-domain 接收到报文后,程序查找目的 IPv6 ,发现命中 LOCAL SID Table ,于是保存指针,剥除 SRv6 ,发送原始报文到 vnf1 中。当 vnf1 返还原始报文后, sfc-domain 将读取保存的指针信息,重新封装 SRv6 报文,递减指针值,更新下一跳 SID 到目的 IPv6 地址,查找 LOCAL SID Table 和路由表,如果命中就转发到下一跳 SID 所在接口。
  4. 当 sfc-domain 将报文转发到最后一个 SID (2:3::2)时,将报文通过 proxy1-port 发送到 OVS 中, OVS 查找流表,发现命中 SFC 解包规则,于是剥除 SRv6 部分,将原始报文从 user2-port 发送出去。至此, tcp 请求过程中的 SFC 处理完毕,业务目标收到报文仍是原始报文,对 SFC 处理无感知。

测试方法

  1. 配置好 ovs 端口: https://pan.baidu.com/s/1uxIANuLHiJuJtdM37yEFZQ?pwd=k7xc 
  2. 配置 vm ,并测试: https://pan.baidu.com/s/1hQRDrpd-HrrFVuGWk9mYeQ?pwd=q5yn

综上,本文讨论了 SFC 服务链应用,及其在 linux 中的实现方案,以及在云环境中基于 SRv6 的实现方案,以探索算力网络时代下 SFC 在云环境中的快速部署。模型较为简单,开发仍在不断完善中。

Reference

  1. 《 SRv6 SFC 技术白皮书》
  2. https://github.com/netgroup/p4-srv6-usid/issues/4
  3. Ip route encap introduction https://www.man7.org/linux/man-pages/man8/ip-route.8.html