Linux SRv6实战:VPN、流量工程和服务链(第一篇)

作者简介:李嘉明 思科系统工程师、苏远超 思科首席工程师、钟庆 思科系统工程师

摘要:本文基于Linux SRv6功能,结合Mininet、Quagga、Python等工具,验证SRv6的一系列功能,包括VPN、流量工程、服务链等。

本文所有代码见: https://github.com/ljm625/srv6_Sandbox
本文第二篇详见:Linux SRv6实战:服务链功能详解(第二篇)
本文第三篇详见:Linux SRv6实战:多云环境下Overlay(VPP) 和Underlay整合测试(第三篇)

一、SRv6简介

Segment Routing(以下简称SR)指由思科发明,并主要由IETF SPRING(Source Packet Routing In Networking)工作组进行标准化的新一代网络传送技术。SR基于源路由并且只在网络边缘维持状态,这使得SR非常适合于超大规模SDN部署,在极大简化网络的同时,SR也为网络提供了高度的可编程能力以及端到端的流量工程能力。因此在出现仅短短五年后,SR已经成为业界共识,是新一代网络尤其是5G网络的事实SDN架构标准。

SR数据平面有两种实现方式,一种是SR MPLS,重用了MPLS数据平面;另一种是SRv6,使用IPv6数据平面。SR架构可以运行在这两种数据平面上,这是自SR提出第一天起就确立的原则。

SRv6采用IPv6标准中定义的路由扩展报头(Routing Extension Header)承载新定义的SRH(Segment Routing Header)扩展路由报头,SRH类型号定义为4。在SRH中包含了Segment列表。SRv6 Segment形式上是一个128位的IPv6的地址,但其实此Segment由Locator(定位器)和Function(指令)构成(还可以含有”参数”信息, 本文先略过),Locator用于IPv6路由,Function用于指定节点需要对数据包施加的各种SRv6操作,实现网络的可编程性。

和SR MPLS不一样,在数据包的转发过程中SRv6通常不会弹出Segment,而是通过SRH中的Segment Left(剩余Segment,是个不小于0 的数值)字段作为指针,指向活动Segment,类似于SR MPLS中的顶层标签。每经过一个SRv6端节点,Segment Left减1,更新IPv6报头的目的地址为Segment 列表中当前Segment Left对应的Segment,并遵循常规的IPv6路由把数据包转发出去。

需要强调的是, 如果网络中有节点只支持常规的IPv6而不支持SRv6,当此节点收到SRv6数据包时, 按照IPv6 RFC的规定,由于数据包目的地址不是节点自身网段地址, 此节点不处理扩展报头,而只是单纯地根据数据包目的地址进行IPv6转发。这意味着,SRv6可以与现有的IPv6网络无缝互操作,换句话说,SRv6可以在IPv6网络上实现增量部署,无须替换现网所有设备。

以下是本文用到的SRv6操作简介:

End : 该操作要求Segment Left不为0(不是最后一跳),会将Segment Left减1,并更新IPv6数据包的目的地址为下一个Segment,这是最常见的SRv6操作。相当于SR MPLS中的Prefix-SID。

End.X:该操作和End操作基本一致,区别是可以将处理过的数据包发送到指定的下一跳地址。相当于SR MPLS中的Adj-SID。

End.DX4:该操作要求Segment Left为0且数据包内封装了IPv4数据包,会去掉外层的IPv6报头,并将内部的IPv4数据包转发给指定的下一跳地址。相当于VPNv4 Per-CE标签。

End.DX6:该操作要求Segment Left为0且数据包内封装了IPv6数据包,会去掉外层的IPv6报头,并将内部的IPv6数据包转发给指定的下一跳地址。相当于VPNv6 Per-CE标签。

End.B6:该操作会在已有的SRH的基础上,插入一个新的SRH,并可以定义新的Segment列表,数据包将首先按照插入的新的SRH进行转发。相当于Binding-SID。

End.B6.Encaps:该操作和End.B6基本一致,区别是该操作将在数据包外层新增一个新的IPv6报头和SRH,而不是仅仅添加一个SRH的路由报头。

T.Encaps:该操作在中转节点(即数据包经过的支持SRv6的路由器,但节点本身不在Segment列表中)上执行,会在数据包外层新加一个IPv6报头以及SRH报头,并可以定义新的Segment列表,数据包将首先按照新IPv6报头中的SRH进行转发。

二、Why Linux SRv6?

1.试验环境容易建立
Linux内核从4.10版本(2017年2月)开始就支持SRv6,距今已经有差不多2年的时间,功能已经比较成熟。事实上本文的所有测试,都是在一台主机上借助Mininet完成。
另一方面,虽然思科在业界率先在网络设备上支持了SRv6,但总体而言,目前业界网络设备对SRv6的支持程度还比较有限,特别是对于流量工程和服务链等高级功能的支持,因此当前用网络设备不能完全体现出SRv6“极简+编程”的革命性创新。但我们相信,随着SRv6成为业界共识,网络设备对SRv6的支持也会越来越好。

2.支持丰富的SRv6操作
目前Linux对SRv6的支持情况如下表所示:

表1:Linux支持SRv6情况

可以看到Linux已经支持大部分SRv6功能,但部分功能需要使用srext这个内核扩展模块来实现。本文中我们将只使用Linux内核中原生支持的功能进行验证,srext支持的功能将在下一篇文章中进行讲述。

3.适用于虚拟化/叠加网络环境
在数据中心/云端广泛采用Linux+NFV技术提供防火墙、入侵检测(IDS)、负载均衡等增值网络业务及服务链(Service Chaining)功能,Linux SRv6可以在其中大显身手。

另一方面,不少用户在数据中心/云端采用主机叠加网络(Host Overlay)来为租户服务,但如何在Host Overlay与Underlay间实现无缝耦合、保证SLA一直是个难题。Linux SRv6可以完美整合Overlay和Underlay,因为无论是Overlay还是Underlay,本质上都是对应着不同的SRv6 Segment(操作)而已;如果需要提高Linux SRv6性能,可以优化DPDK或者使用FD.IO(VPP),其中FD.IO已经内置了完善的SRv6支持,在使用上会更为方便。

三、准备工作

验证环境基于Ubuntu以及Mininet,也可以使用Vagrant+Virtualbox实现。

  • Linux,要求内核版本高于 4.15
  • 最新版Mininet
  • Quagga(在Mininet虚拟拓扑下,提供路由器的静态路由/OSPF/BGP等路由协议支持)
  • Python (通过脚本建立测试拓扑及初始配置)

四、安装教程

下面的安装教程基于Ubuntu 18.04 LTS。
1.升级内核到推荐版本(4.15.0-38)

2.重启,检查内容是否安装完成

3.安装Mininet和Quagga

4.安装最新版的iproute2

5.安装Python的依赖包

6.下载实验拓扑的配置文件

五、验证场景

5.1 Linux SRv6实现VPN+流量工程

5.1.1 概述
目的:使2台仅支持IPv4的主机(主机a和主机b),通过SRv6实现VPN互通,并实现流量工程。
拓扑如下图所示:

图1:Linux SRv6实现VPN+流量工程拓扑

图1中路由器R1、R3和R4为支持SRv6的路由器,R2为仅支持IPv6的路由器,通过开源Quagga实现静态路由,路由器与路由器之间仅通过IPv6实现互通。

在这个测试中,我们的目的是让主机a与主机b实现IPv4互通,并让数据包经由R3路由器,从而实现VPN及流量工程。

详细的数据包转发流程及每一跳的报头变化如下图所示,图中报文上的数字表示数据包在网络中的转发顺序。

请注意: 图中的Segment列表是逆序排列的,即排在列表的第一个Segment是路径上的最后一跳,排在列表的最末位Segment是路径的第一跳。

图2:Linux SRv6实现VPN+流量工程-数据包转发流程

从主机a发出的数据包,到达支持SRv6的路由器R1,R1会根据所配置的操作对数据包进行封装,在外层加上IPv6以及SRH的报头,并进行正常的IPv6转发。在仅支持IPv6的路由器R2,R2根据IPv6报头基于目的IPv6地址进行转发。在R3,R3路由器根据Segment执行End操作,将Segment Left减1,并根据Segment列表更新IPv6的目的地址,将数据包转发至下一跳R4。在支持SRv6的路由器R4,R4根据Segment执行End.DX4操作,剥掉外层的IPv6报头,将内含的IPv4数据包发给主机b,完成转发流程。

5.1.2 具体步骤
1.首先启动实验拓扑

2.在R1路由器上配置T.Encaps操作(SRv6流量工程),将去往10.0.2.0/24的数据包,封装入SRv6,并配置SRH包含的Segment列表为(逆序排列)

后面的步骤会给出Segment fc00:3::bb,fc00:4::bb fc00:4:bb的定义。
3.同时在R1上配置针对回程数据包的End.DX4操作,让去往主机a的数据包在R1做IPv6的解封装,解出IPv4数据包后发送给主机a

4.在R3路由器上配置End操作,以让R3在收到R1发来的数据包时,Segment Left减1,并更新IPv6 目的地址为当前Segment Left指定的Segment。

5.最后在R4路由器上配置End.DX4操作,以让R4收到数据包之后能够做IPv6解封装,并转发给指定地址。

6.相应地在R4上配置T.Encaps操作,对Ping回程IPv4数据包进行封装。

配置完成后,可以从主机a(10.0.0.1) Ping通主机b(10.0.2.1)。

5.1.3 脚本执行及抓包验证
为了方便,我们将相关的配置都通过Python脚本实现了自动化。代码见https://github.com/ljm625/srv6_Sandbox
1.R1
在R1上配置SRv6。

图3:R1配置脚本

我们从主机a(10.0.0.1) Ping 主机b(10.0.2.1)进行测试。
然后抓包检查,可以看到从主机a发来的IPv4原始数据包。

图4:R1上抓包-主机a发出的IPv4数据包

经过R1路由器后,可以看到数据包外层加了IPv6的报头,路由头类型(Routing Header Type)是4(Segment Routing),里面有2个Segment< fc00:4::bb ,fc00:3::bb>,Segment Left=1,所以IPv6目的地址设置为列表位置为1的地址,即fc00:3::bb。

图5:R1上抓包-R1生成带有2个Segment的SRv6数据包

2.R3
在R3上配置SRv6。

图6:R3配置脚本

R3从不支持SRv6的路由器R2处收到了R1发来的数据包,根据定义的策略会执行End操作,即Segment Left减1,并更新 IPv6目的地址。

图7:R3上抓包-END操作

3.R4
在R4上配置SRv6。

图8:R4配置脚本

R4上收到R3发来的数据包,由于Segment Left已经被R3 更新为0,R4会根据策略执行End.DX4操作,去掉IPv6外层报头,转发到指定的10.0.2.1主机,从而完成了VPNv4以及流量工程。

图9:R4上抓包-END.DX4操作

下图是执行过End.DX4操作后的数据包抓包情况,可见已经还原为原始的IPv4数据包。

图10:R4上抓包-END.DX4操作后的数据包

下图是Ping回程数据包抓包情况,可见加了IPv6报头,目的地址是fc00:1:bb,但SRH中没有Segment,这是因为Segment Left=0(此时其实不需要SRH,具体见参考文献2)。

图11:R4上抓包-Ping回程数据包

互通验证结果:

图12:主机a Ping主机b结果

5.2 Linux SRv6实现服务链+流量工程

5.2.1 概述
目的:使2台仅支持IPv4的主机(主机a和主机b),通过SRv6实现互通,并实现服务链+流量工程。本文中我们首先验证支持SRv6的服务(SR-aware),不支持SRv6的服务(Non SR-aware)将在第二篇中介绍。

图13:Linux SRv6实现服务链+流量工程拓扑

拓扑和第一个场景类似,路由器R1、R3和R4为支持SRv6的路由器,R2为仅支持IPv6的路由器,通过开源Quagga实现静态路由,路由器与路由器之间仅通过IPv6互通。R3路由器上面加入了一台支持SRv6的IDS设备(Snort)。

路由器的Loopback地址间通过IPv6路由可达。

主机a到主机b的流量,在R1上新增的SRH要求经由R3进行转发,因此原流量路径如图蓝色路径所示。
在R3路由器上,修改End操作为End.B6.Encaps操作,将流量先引导到IDS进行处理,再回到R3进行正常转发流程。对应的新的流量路径如图红色路径所示。

End.B6.Encaps的功能我们之前已经简单的进行了介绍,该操作在现有IPv6数据包上封装一个新的IPv6的报头,并添加新的SRH报头;而End.B6操作则不会添加新的IPv6报头,而是直接插入新的SRH报头到现有的IPv6报头当中。这两种操作本质上都相当于是Binding-SID。

具体数据包转发流程中报头的变化可参见图14和图15,图中报文上的数字表示数据包在网络中的转发顺序。

图14:Linux SRv6实现服务链+流量工程-数据包转发流量(Part1)

图14为数据包的前半部分转发流程,主机a发出IPv4数据包,R1对IPv4数据包进行封装,加入SRv6报头,其中包含2个Segment。数据包首先转发到R3,执行R3::a对应的操作。我们在R3定义R3::a操作为End.B6.Encaps,变化如图右下角,首先Segment Left减1,更新IPv6目的地址,然后在数据包外层增加新的IPv6报头,SRH中添加2个Segment,首先转发到IDS,然后返回R3。

当数据包到达IDS之后,由于IDS支持SRv6,会执行End操作,并检查/过滤数据包内容,当检查完成后进行正常转发,End操作更新最外层IPv6报头,Segment Left减1,目的地址修改为R3::b。

图15:Linux SRv6实现服务链+流量工程-数据包转发流量(Part2)

图15表示接下来的转发流程。当数据包第二次返回R3时,由于Segment为R3::b,R3将执行不同的操作,在这个场景中为End.DX6。End.DX6操作会将外层的IPv6报头去掉,然后正常转发,变化如图中所示。

R4收到数据包之后,会根据Segment执行End.DX4操作,去掉IPv6报头,将IPv4数据包转发给主机b,完成整个转发流程。

从上述过程可以看出,SR实现服务链本质上是基于自身的流量工程能力,事实上服务节点(或服务代理)本质上只是Segment列表中的一个Segment,这不单适用于本例中支持SR的服务,也适用于不支持SR的服务。

5.2.2 具体步骤
1.下面我们启动拓扑

Python脚本会自动配置好设备初始配置以及地址。
2.配置R1
配置T.Encaps操作,为IPv4数据包添加IPv6报头和Segment

为回程数据包执行End.DX4操作,发给主机a

3.配置R3
执行End.B6.Encaps操作,添加新的SRH去往IDS实现服务链

对执行完服务链操作的数据包,去掉外层IPv6报头,进行常规的IPv6转发

4.配置IDS
执行End操作,IDS的内部应用对数据包进行检测

5.最后配置R4
对收到的数据包执行End.DX4操作,去掉IPv6报头,正常转发给主机b

回程路由直接去往R1

配置完成后,从主机a可以Ping通主机b,并且在IDS处可以监测到主机a发往主机b的数据包。

5.2.3 脚本执行及抓包验证
为了方便,我们将相关的配置都通过Python脚本实现了自动化。代码见https://github.com/ljm625/srv6_Sandbox
1.R1
在R1上配置SRv6。

图16:R1配置脚本

2.R3
在R3上配置SRv6。

图17:R3配置脚本

3.IDS
在IDS上配置SRv6。

图18:IDS配置脚本

4.R4
在R4上配置SRv6。

图19:R4配置脚本

我们从主机a(10.0.0.1) Ping 主机b(10.0.2.1)进行测试。
在主机a上Ping主机b的情况:

图20:主机a可以ping通主机b

在R3上的抓包情况:

图21:R3上抓包-执行完End.B6操作之后的数据包

在IDS上的抓包情况:

图22:IDS上抓包-IDS应用执行完操作,准备发给R3的数据包

我们通过在IDS上的Snort进行监测:

图23:Snort监测结果

Snort规则配置为对从10.0.0.1去往10.0.2.1的ICMP包进行告警,可以看到Snort可以正确检测到从10.0.0.1去往10.0.2.1的ICMP包。

六、总结与展望

本文基于两个常见的应用场景(VPN+流量工程,服务链+流量工程)测试了Linux 内核对SRv6的支持情况,测试了常用的End操作,包括End、End.DX4、End.B6.Encaps和T.Encaps。

从测试结果来看,Linux内核已经能很好地支持SRv6常用操作,测试结果令人满意。由于条件所限,本文并未进行性能测试。

在下一篇文章中,我们将测试SRv6 End.AD等操作-即使服务不支持SRv6,仍然可以通过End.AD操作实现服务链。

为了提高性能,业界越来越多使用FD.IO,因此后续文章中我们也会介绍采用FD.IO来实现SRv6,并与网络设备结合,构建高性能的虚拟/物理一体、Overlay/Underlay融合的高性能SRv6网络。

【参考文献】
1. SRH draft: https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-15
2. SRv6 draft:https://tools.ietf.org/html/draft-filsfils-spring-srv6-network-programming-06
3. Segment Routing的相关资料:https://segment-routing.net
4. SRv6 Linux的相关资料/教程:https://segment-routing.org
5. SRv6 VPP的实现和教程:https://wiki.fd.io/view/VPP/Segment_Routing_for_IPv6


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/22842.html
分享到:
相关文章
条评论

登录后才可以评论

SDNLAB君 发表于19-03-01
5