31

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

 5 years ago
source link: https://www.sdnlab.com/22842.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

本文所有代码见: https://github.com/ljm625/srv6_Sandbox

一、SRv6简介

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

Cisco-linux-668x400.jpg

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的支持情况如下表所示:

Cisco-linux-1.png

表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)

Java
apt-get update apt-get install linux-headers-4.15.0-38 linux-headers-4.15.0-38-generic linux-image-4.15.0-38-generic linux-modules-4.15.0-38-generic linux-modules-extra-4.15.0-38-generic
1
2
apt-get update
apt-get install linux-headers-4.15.0-38linux-headers-4.15.0-38-generic linux-image-4.15.0-38-generic linux-modules-4.15.0-38-generic linux-modules-extra-4.15.0-38-generic

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

Java
uname -a Linux ubuntu 4.15.0-38-generic #41-Ubuntu SMP Wed Oct 10 10:59:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
1
2
uname-a
Linux ubuntu4.15.0-38-generic#41-Ubuntu SMP Wed Oct1010:59:38UTC2018x86_64 x86_64 x86_64 GNU/Linux

3.安装Mininet和Quagga

Java
apt-get install mininet gawk libreadline-dev libc-ares-dev wget http://download.savannah.gnu.org/releases/quagga/quagga-1.2.4.tar.gz tar -xzvf ./quagga-1.2.4.tar.gz cd ./quagga-1.2.4 ./configure --enable-vtysh --enable-user=root --enable-group=root --enable-vty-group=root make install
1
2
3
4
5
6
apt-get install mininet gawk libreadline-dev libc-ares-dev
wget http://download.savannah.gnu.org/releases/quagga/quagga-1.2.4.tar.gz
tar-xzvf./quagga-1.2.4.tar.gz
cd./quagga-1.2.4
./configure--enable-vtysh--enable-user=root--enable-group=root--enable-vty-group=root
make install

4.安装最新版的iproute2

Java
wget https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/iproute2-4.9.0.tar.gz tar -xzvf ./iproute2-4.9.0.tar.gz cd ./iproute2-4.9.0 apt-get install bison flex make make install
1
2
3
4
5
6
wget https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/iproute2-4.9.0.tar.gz
tar-xzvf./iproute2-4.9.0.tar.gz
cd./iproute2-4.9.0
apt-get install bison flex
make
make install

5.安装Python的依赖包

Java
pip install mako ipaddress ipmininet --no-deps
1
pip install mako ipaddress ipmininet--no-deps

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

Java
git clone https://github.com/ljm625/SRv6_Sandbox
1
git clonehttps://github.com/ljm625/SRv6_Sandbox

五、验证场景

5.1 Linux SRv6实现VPN+流量工程

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

Cisco-linux-2.png

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

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

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

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

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

Cisco-linux-3.png

图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.首先启动实验拓扑

Java
sudo python topo.py
1
sudo python topo.py

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

Java
ip route add 10.0.2.0/24 encap seg6 mode encap segs fc00:3::bb,fc00:4::bb dev r1-eth1
1
ip route add10.0.2.0/24encap seg6 mode encap  segs fc00:3::bb,fc00:4::bb dev r1-eth1

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

Java
ip -6 route add fc00:1::bb/128 encap seg6local action End.DX4 nh4 10.0.0.1 dev r1-eth1
1
ip-6route add fc00:1::bb/128encap seg6local action End.DX4 nh410.0.0.1dev r1-eth1

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

Java
ip -6 route add fc00:3::bb/128 encap seg6local action End dev r3-eth2
1
ip-6route add fc00:3::bb/128encap seg6local action Enddev r3-eth2

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

Java
ip -6 route add fc00:4::bb/128 encap seg6local action End.DX4 nh4 10.0.2.1 dev r4-eth1
1
ip-6route add fc00:4::bb/128encap seg6local action End.DX4 nh410.0.2.1dev r4-eth1

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

Java
ip route add 10.0.0.0/24 encap seg6 mode encap segs fc00:1::bb dev r4-eth1
1
ip route add10.0.0.0/24encap seg6 mode encap  segs fc00:1::bb dev r4-eth1

配置完成后,可以从主机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。

Cisco-linux-4.png

图3:R1配置脚本

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

Cisco-linux-5.png

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

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

Cisco-linux-6.png

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

2.R3
在R3上配置SRv6。

Cisco-linux-7.png

图6:R3配置脚本

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

Cisco-linux-8.png

图7:R3上抓包-END操作

3.R4
在R4上配置SRv6。

Cisco-linux-9.png

图8:R4配置脚本

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

Cisco-linux-10.png

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

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

Cisco-linux-11.png

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

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

Cisco-linux-12.png

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

互通验证结果:

Cisco-linux-13.png

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

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

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

Cisco-linux-14.png

图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,图中报文上的数字表示数据包在网络中的转发顺序。

Cisco-linux-15.png

图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。

Cisco-linux-16.png

图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.下面我们启动拓扑

Java
sudo python topo2.py
1
sudo python topo2.py

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

Java
ip route add 10.0.2.0/24 encap seg6 mode encap segs fc00:3::a,fc00:4::a dev r1-eth1
1
ip route add10.0.2.0/24encap seg6 mode encap  segs fc00:3::a,fc00:4::adev r1-eth1

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

Java
ip -6 route add fc00:1::a/128 encap seg6local action End.DX4 nh4 10.0.0.1 dev r1-eth1
1
ip-6route add fc00:1::a/128encap seg6local action End.DX4 nh410.0.0.1dev r1-eth1

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

Java
ip -6 route add fc00:3::a/128 encap seg6local action End.B6.Encaps srh segs fc00:5::a,fc00:3::b dev r3-eth1
1
ip-6route add fc00:3::a/128encap seg6local action End.B6.Encaps srh segs fc00:5::a,fc00:3::bdev r3-eth1

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

Java
ip -6 route add fc00:3::b/128 encap seg6local action End.DX6 nh6 :: dev r3-eth1
1
ip-6route add fc00:3::b/128encap seg6local action End.DX6 nh6::dev r3-eth1

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

Java
ip -6 route add fc00:5::a/128 encap seg6local action End dev ids-eth0
1
ip-6route add fc00:5::a/128encap seg6local action Enddev ids-eth0

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

Java
ip -6 route add fc00:4::a/128 encap seg6local action End.DX4 nh4 10.0.2.1 dev r4-eth1
1
ip-6route add fc00:4::a/128encap seg6local action End.DX4 nh410.0.2.1dev r4-eth1

回程路由直接去往R1

Java
ip route add 10.0.0.0/24 encap seg6 mode encap segs fc00:1::a dev r4-eth1
1
ip route add10.0.0.0/24encap seg6 mode encap  segs fc00:1::adev r4-eth1

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

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

Cisco-linux-17.png

图16:R1配置脚本

2.R3
在R3上配置SRv6。

Cisco-linux-18.png

图17:R3配置脚本

3.IDS
在IDS上配置SRv6。

Cisco-linux-19.png

图18:IDS配置脚本

4.R4
在R4上配置SRv6。

Cisco-linux-20.png

图19:R4配置脚本

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

Cisco-linux-21.png

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

在R3上的抓包情况:

Cisco-linux-22.png

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

在IDS上的抓包情况:

Cisco-linux-23.png

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

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

Cisco-linux-24.png

图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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK