IT课程

 新网工在YESLAB   

IT技术专业学习平台
IT人才专业服务提供商

 

VUE考试注册预约电话:010-82608710

全国热线:400-004-8626

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

首页    思科专题    Linux SRv6实战(第一篇):VPN、流量工程和服务链

一、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 内核中原生支持的功能进行验证。

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 列表为(逆序排列)

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 常用操作,测试结果令人满意。由于条件所限,本文并未进行性能测试。

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

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

【参考文献】
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

2019年2月19日 15:04
浏览量:0
收藏