Linux SRv6实战 服务链功能详解(第二篇)

2019-05-17 13:54:43 浏览数 (1)

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

摘要:本文基于Linux SRv6功能,结合Vagrant,Snort等工具,对SRv6服务链功能进行详细解析和验证。实现SRv6服务链上同时支持SR-aware服务和Non SR-aware服务。

本文所有代码见:

https://github.com/ljm625/srv6_Sandbox

一、SRv6服务链简介

如本文第一篇(《Linux SRv6实战:V**、流量工程和服务链(第一篇)》)所述,SR实现服务链本质上是基于自身的流量工程能力,事实上服务节点(或代理)本质上只是Segment列表中的一个Segment,这不但适用于SR-aware服务,也适用于Non SR-aware服务。除非特别说明,SR服务链解决方案同时适用于SR MPLS和SRv6,本文只以SRv6为例进行说明。

在本文第一篇中,我们使用Mininet等工具,验证了Linux SRv6的V**、流量工程和服务链(SR-aware服务)功能。在本篇中,我们将更进一步深入分析SRv6服务链功能,验证SRv6服务链对Non SR-aware服务的支持能力。

下面是SRv6服务链相关操作简介(更多SRv6操作介绍参见本文第一篇):

End.AD4:该操作要求SL不为0(不是最后一跳),是为了兼容Non SR-aware服务的服务链操作。核心思想是配置了此操作的节点作为SR代理(SR Proxy),即在把数据包转发给Non SR-aware服务处理之前,把外层的封装暂时去掉,再转发给服务进行处理,这样服务无需支持SRv6即可正常工作。End.AD4操作要求内层必须是一个IPv4数据包,此操作将更新外层报头的SL,去掉外层IPv6报头后发送给Non SR-aware服务;在服务处理完成后把数据包发回时,SR Proxy重新添加IPv6和SRH报头,继续转发。End.AD4操作需要为每条服务链维护一个动态的缓存,以封装服务发回的数据包。具体如下图所示:

图1:End.AD4操作

End.AD6:该操作和End.AD4基本一致,唯一区别是其要求内层是一个IPv6数据包。

End.AM:该操作要求SL不为0(不是最后一跳),也是为了兼容Non SR-aware服务的服务链操作。虽然同样是基于SR Proxy机制,但和End.AD操作不同,End.AM操作会将IPv6目的地址更新为SL=0时的Segment,即最终的IPv6目的地址,然后转发给服务;根据RFC8200规定,服务(中间节点)不会处理SRH而只是根据目的地址转发,这里假设服务可以处理跟在SRH之后的负载。服务把数据包发回后,End.AM节点把IPv6目的地址更新为SL指定的Segment,继续转发。End.AM操作不需要为每条服务链维护缓存,其规则适用于所有经由End.AM节点的服务链。End.AM这种实现机制只在SRv6上支持,SR MPLS不支持类似的机制。具体如下图所示

图2:End.AM操作

二、为什么使用Linux SRv6实现服务链?

在数据中心/云网络部署中,不少用户采用主机叠加网络(Host Overlay)的方式为租户提供服务。这种方式采用主机的虚拟交换机/FD.IO进行Host Overlay部署,实现不同主机上虚拟机或者容器之间的二三层互通,也常用于实现服务链。

RFC 7665提出了服务功能链(SFC)架构,RFC 8300提出网络服务头(NSH)作为实现SFC架构的封装。NSH携带了服务链路径和元信息(Metadata),这些信息可在不同的服务之间共享,利用NSH可实现动态的服务链配置,可在服务链形成后进行动态的路径和拓扑修改、插入新的服务,提供端到端可视化、OAM、性能管理能力。

但NSH目前实际应用很少,原因有三点:

1.NSH目前面临的最大问题是:网络设备、VNF、主机操作系统对NSH的支持非常有限。网络设备只有个别路由器例如思科ASR9000支持,大部分硬件交换机不支持;实现NSH所设计的功能依赖于服务链中的VNF对路径和元信息的操作能力,但很多VNF都不支持

2.NSH需要在每条服务链的所有服务设备上维持状态,这很大程度上限制了扩展性

3.NSH携带了服务链路径信息,但是流量在不同VNF之间的引导还需要通过其他隧道技术机制来实现(例如VxLAN、GRE等),没有实现Overlay和Underlay的融合。这造成解决方案的差异性不强,OVS Openflow等替代方案可以实现类似的功能且较简单

如本文第一篇所述, Linux内核从4.10版本(2017年2月)就开始支持SRv6,支持丰富的SRv6操作,通过开源的Linux内核模块SREXT(https://github.com/netgroup/SRv6-net-prog/)支持更多的操作,其中包括对服务链功能的增强。通过把不同的SRv6 Segment组合起来,Linux SRv6能够完美地整合Overlay、Underlay和服务链,其性能通过应用DPDK或者FD.IO/VPP也可以得到极大的提升。

SRv6可以与现有不支持SRv6的IPv6网络无缝互操作,基于SRv6的服务链也可以同时支持SR-aware和Non SR-aware的服务,因此基于Linux SRv6的服务链具有很高的实用性,基本上可以部署在任何支持IPv6的网络上。

三、准备工作

验证环境基于Vagrant,可在Windows/Linux/Mac 下进行,需要提前自行安装好Virtualbox和Vagrant,这里不再赘述这两个软件的安装过程。容器内的软件如下

  • Linux,内核版本高于4.14
  • Snort,开源IDS软件,我们会使用两个版本的Snort:SR-aware版本以及Non SR-aware版本

3.1 拓扑说明

图3 SRv6服务链拓扑

拓扑如图3所示,有三台支持SRv6的路由器。其中R2连接配置了End.AD4操作的SR Proxy,SR Proxy下挂Non SR-aware版本的Snort(Service1);R3连接了SR-aware版本的Snort(Service2)。

主机a和主机b只通过IPv4连接到路由器R1以及R3,默认情况下它们无法通讯。路由器之间只有IPv6地址和路由。

主机a发送给主机b的数据包,经由R1、R2,然后发往Service1;接着经由R3,发往Service2;最后发给主机b。

3.2 部署脚本说明

在Vagrant File里面我们定义了拓扑结构,每个节点的镜像文件和配置信息,当我们执行“Vagrant up”命令的时候,会自动根据Vagrant的描述文件进行虚拟机的创建、启动及配置。

图4 Vagrant 配置示例

上图是Vagrant的配置文件中定义的一个节点。包括以下部分的内容:

1.镜像信息

其中“vm.box”定义了我们使用的镜像,“vm.box_version”定义了所使用镜像的版本,在vagrant启动虚拟机的时候,如果本地找不到这个镜像,会去vagrant的镜像仓库下载,这一点和docker的镜像下载机制基本相同。

2.虚拟网络

接着定义了该虚拟机的网络,这部分就是用来定义Vagrant的网络拓扑的相关配置,其中“virtualbox_intnet”定义了不同的私网,对于IP地址,这里可以设置v4或者v6地址,但如果是IPv6地址,建议手动设置子网掩码,会避免很多问题。

3.内存、网卡状态、抓包等信息

“memory”定义虚拟机的内存大小,由于是测试用途,256MB即可满足需求。

“nictrace”则是配置通过网卡实时抓包,并保存为pcap文件。我们设置了在所有的网卡上进行实时的抓包存储,这样方便测试和理解。

“cableconnected”定义了网卡的连接状态。读者可能有一个疑问是我们只定义了2个网络,为什么会有3张网卡?其实第一个网卡是系统默认定义的NAT网卡,用于连接互联网。此外,Virtualbox具有每台虚拟机最多支持4张网卡的限制,因此所定义的虚拟机,除了默认的NAT网络,如果有多于3个网络,那么多出的网卡将不会被正确添加。

4.Day0配置

“vm.provision” 定义了当虚拟机启动之后运行的Day0自动配置脚本,在脚本里我们配置了默认路由,启用SRv6以及安装一些测试用的软件,相关的配置会在后面章节中说明。

四、安装教程

由于本次使用的是Vagrant安装方案,所以宿主机可以是Windows/Mac/Linux,只需要按照官网的教程安装git、Vagrant以及Virtualbox即可。

在完成安装git、Vagrant以及Virtualbox之后,就可以启动测试环境了。

接着Vagrant会自动下载镜像,启动拓扑里面的主机,以及完成Day0的配置。需要注意的是单台虚拟机的内存为256MB,因此电脑需要256*6=1.5GB的空闲内存空间。

这里用的镜像是定制过的Debian image,已经包含了4.14的Kernel以及最新版的iproute2,因此无需重新安装iproute2或者更新内核。

下面对每台设备的Day0启动脚本关键部分进行解析。

1.R1

对路由器R1的配置主要是把IPv4数据包封装入SRv6并转发;同时对回程数据包指定与End.DX4操作对应的Segment,解封装后发给主机a(10.0.0.1),具体可以参考本文第一篇。

2.R2

对路由器R2的配置对指定与End操作对应的Segment,此操作更新SL并更新数据包的IPv6 目的地址。

3.R3

对路由器R3的配置和R1的配置基本相同,对回程数据包指定与End.DX4操作对应的Segment,解封装并转发给主机b(10.0.1.1),实现主机a和主机b的通信;并对主机b的回程数据包封装,添加SRH报头。

4.SR Proxy

SR Proxy的配置包含3部分:

  • 使用Linux Network Namespace(Linux自带的网络虚拟化)机制,创建一个名字为”snort”的 VNF,相当于SR Proxy下挂了一个新的主机,突破了Vagrant单机只能有最多4张网卡的限制。这部分使用了一键脚本进行配置,VNF的2张网卡IP分别为192.168.1.2和192.168.2.2,VNF会对传入的流量进行处理,然后从192.168.2.2发出。
  • 在SR Proxy的VNF内安装并配置Snort,实现IDS功能,即上图中的Service1。
  • 在SR Proxy下安装SREXT内核模块,这个内核模块扩展了Linux内核所支持的SRv6操作,使其能够支持End.AD4、End.AD6以及End.AM等操作,从而在服务链上支持Non SR-aware服务。

安装完毕之后配置SR Proxy。

5.Service2

Service2的配置相比SR Proxy要简单很多,因为上面运行的是支持SRv6的服务。所以Service2只需要配置一个End操作即可,以更新SL和IPv6目的地址。

五、验证Linux SRv6高级服务链功能

5.1 概述

图5 验证所用拓扑

本验证所用拓扑及验证场景如图5所示。在该拓扑中,默认情况IPv4主机a和主机b之间通过SRv6 End.DX4操作实现V**互通,流量路径是R1->R2->R3。通过修改R1的SRv6策略,我们使流量在去往主机b之前,先被引导至SR Proxy下Non SR-aware版本的Snort(Service1),再被引导至Service2的SR-aware版本的Snort,最后到达主机b实现互通。

5.2 具体步骤

5.2.1 验证SR Proxy上的Non SR-aware服务(Service1)

在本次的验证中,我们已经默认实现了主机a与主机b之间的IPv4互访,这一步骤的细节参见本文第一篇。

当所有环境通过vagrant up启动之后,我们登陆到主机a。

图6 主机a可以正常ping通主机b

如图6所示,主机a与主机b可以正常互通。

在默认情况下,我们在R1配置的SRv6 Policy是经由R1->R2->R3进行转发,并没有经过Service1/Service2。

我们可以通过Wireshark打开R1的eth2接口的抓包文件予以确认(默认为trace12.pcap文件)。

图7 R1上抓包结果-数据包被加上了SRH

如图7所示,从主机a(10.0.0.1)去往主机b(10.0.1.1)的数据包,加上SRH,Segment列表指定了数据包经由R2、R3进行转发。

现在登陆到R1上,查看当前的SRv6 Policy:

图8 R1上当前的SRv6 Policy

然后,我们修改SRv6 Policy,加入2个新的Segment,引导流量至Service1和Service2上的Snort进行监测。主要注意的是,Service1对应的Segment其实是SR Proxy配置的End.AD4,而不是实际提供服务的VNF的地址(192.168.1.2)。

再次查看抓包文件trace12.pcap,可以看到数据包的下一跳被重定向到了Service1。

图9 R1上抓包结果-修改SR Policy后

接着,登陆到SR Proxy这台主机,名字叫“server1”。

图10 SR Proxy上配置的End.AD4操作

可以看到SR Proxy配置了End.AD4操作。由于使用了SREXT模块,因此需要使用srconf命令。

如前所述,在SR Proxy上配置End.AD4操作的命令为(包含在Day0脚本中):

其中fc00: a::a1为End.AD4对应的Segment,192.168.1.2为Non SR-aware服务的地址。

在这里我们添加服务的方法是使用Linux Network Namespace虚拟出一个名字为”snort”的VNF,此VNF包含有2个接口veth0和veth1,接口地址设置见图3。在VNF内安装Non SR-aware版本的Snort。

首先通过tcpdump,在veth0抓包

图11 VNF内tcpdump的抓包结果

如图11所示,在我们新建的VNF上收到的数据包已经没有了IPv6报头,而只有内层的IPv4报头。

接下来检查Snort上的规则。

图12 VNF内的Snort配置的规则

本验证所使用的Snort规则如图12所示,该规则针对所有ICMP包都会发出一个告警,并显示详细信息。

接下来运行Snort,并查看Snort日志:

图13 VNF内的Snort监测日志

可以看到不支持SRv6的Snort能够正常地监测到ICMP包的源地址、目的地址以及协议,这是因为数据包原有的外层IPv6报头在执行End.AD4 操作时已经被SR Proxy去除了,此时Snort收到的是内层的IPv4数据包。

我们再看一下SR Proxy处理之后继续转发的数据包,使用wireshark打开traceserver1.pcap

图14 SR Proxy上抓包结果-经过SR Proxy处理之后的数据包

如图14所示,可以看到经过End.AD4处理之后的数据包,在发回SR Proxy的时候,SR Proxy会自动加回IPv6报头以及SRH,其中SL和IPv6目的地址都已经更新。

下表总结了数据包经过SR Proxy前后的变化情况。

表1 数据包经过SR Proxy前后的对比

5.2.2 验证SR Proxy上的Non SR-aware服务(iptables)

在这里我们继续做个测试,使用Linux iptables实现一个简单的防火墙功能。官方版本的Linux iptables目前是Non SRv6-aware的。

使用命令查看iptables的状态,如下图:

图15 在VNF添加iptables规则后的统计信息

如图15所示,可以看到所添加的iptables规则成功匹配到了从10.0.0.0去往10.0.1.0的ICMP包,并实施了丢弃(DROP)操作。

图16 在VNF添加丢弃ICMP防火墙规则后,主机a无法ping通主机b

回到主机a,我们可以看到已经ping不通主机b了,再次证明了SR可以实现包含Non SR-aware服务的服务链。

现在删除这条防火墙规则,继续接下来的测试。

5.2.3 验证Server2上的SR-aware服务(Service2)

数据包会被继续引导至Service2,即SR-aware版本的Snort。

登陆到Service2所在的主机,名字叫“server2”。

图17 在Server2主机上的tcpdump抓包结果

如图17所示,在Server2上抓到的数据包是带有IPv6和SRH报头的。若使用官方版本的Snort将无法监测到内层的IPv4数据包内容。

因此我们需要运行修改过的SR-aware版本的Snort。

图18 在Server2上运行SR-aware版本的Snort的监测结果

支持SRv6的Snort会跳过SRH报头直接读取内层的IPv4数据包内容,从而实现服务链,这里不需要配置End.AD这类操作。

5.2.4 验证Server2上的Non SR-aware服务(iptables)

新建一条与5.2.2小节中一样的iptables规则进行对比。

图19 在Server2添加iptables规则后的统计信息

如图19所示,可以看到INPUT和OUTPUT都统计到了数据包,但因为数据包最外层具有IPv6报头,因此iptables规则没能匹配成功,ping流量也不会被丢弃。

六、总结与展望

在本文第一篇的基础上,本篇对Linux SRv6服务链进行了详细的解析和验证,基于开源的Linux内核模块SREXT,实现了服务链上同时支持SR-aware服务和Non SR-aware服务。

从结果来看,Linux内核模块SREXT已经能比较好地支持服务链的操作。SR实现服务链本质上是基于自身的流量工程能力,服务节点(或代理)本质上只是Segment列表中的一个Segment,因此我们可以采用SR流量工程的 OAM手段来管理服务链,这极大地降低了服务链本身的管理开销。

在本文第三篇中,我们将会介绍用FD.IO/VPP来实现SRv6,以提供高性能的Linux SRv6解决方案,同时还会把FD.IO/VPP与物理网络设备通过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.SR Service Programming draft:

https://tools.ietf.org/html/draft-xuclad-spring-sr-service-programming-01

4.Segment Routing的相关资料:

https://segment-routing.net

5.SRv6 Linux的相关资料/教程:

https://segment-routing.org

6.SREXT的相关资料/教程:

https://github.com/netgroup/SRv6-net-prog

7.SR-SFC-DEMO的相关资料:

https://github.com/SRouting/SR-sfc-demo

0 人点赞