前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TF虚拟网络流量排错:在正确的时刻使用正确的工具

TF虚拟网络流量排错:在正确的时刻使用正确的工具

原创
作者头像
Tungsten Fabric
修改2021-02-05 14:44:10
6930
修改2021-02-05 14:44:10
举报

我们总是希望一切都能如期进行。不过残酷的现实是,大多数时候,总会出现问题。

在排除网络故障时,第一个碰到的问题总是这个——“流量在哪里?”

事情变得有点“复杂”

对于虚拟网络来说,也依然如此!即使是在Tungsten Fabric集群内部,按理说,我们在故障排除环节的第一步,也会进行某种流量嗅探或流量识别。

那么……和传统的物理网络有什么不同呢?从概念上讲,没有什么不同……但是,在实践当中,事情会更复杂一些。我们所说的复杂,并不是指难以理解无从下手。所谓复杂,是指有更多的变数在起作用,但这并不一定意味着故障排除会非常难。相反,从另一个角度来看,这意味着我们可以使用更多的工具来更好地了解网络中发生的事情。

回到Tungsten Fabric集群,或者说是一般的虚拟环境,我们的目标是检查/监控进出某个虚拟机的流量。与传统的物理设备相比,如前所述,环境更加复杂。有了物理设备,就像有了一台一体化设备。但当移动到虚拟环境时,一体化设备就不存在了!你有物理服务器(计算)和连接到DC架构的NIC,你有管理程序,最后,你有虚拟机。虚拟机的流量会经过所有这些层次。在每个层次,都有工具可以用来检查/监控流量。这就是我说的“更复杂的场景”的意思,但也是为什么说,从另一个角度来看,这意味着有很多有用的武器可以满足我们的需求。

因此,了解在每个层面可以使用哪些工具是很重要的。我们必须掌握复杂性,并利用它!

让我们用一个例子来解决这个问题。例如有一个IP为192.168.10.3的虚拟机(VM1),这个虚拟机运行在compute1上。在compute2上,有另一个IP为192.168.10.4的虚拟机(VM2)。让我们从VM1 ping到VM2:

代码语言:javascript
复制
$ ping 192.168.10.4
PING 192.168.10.4 (192.168.10.4): 56 data bytes
64 bytes from 192.168.10.4: seq=0 ttl=64 time=44.812 ms
64 bytes from 192.168.10.4: seq=1 ttl=64 time=32.076 ms
64 bytes from 192.168.10.4: seq=2 ttl=64 time=6.418 ms
^C
--- 192.168.10.4 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 6.418/27.768/44.812 ms
$

Ping成功了!现在,我们要做的是识别和监控这些流量。

三个层次,三套工具

首先,正如之前预想的那样,我们必须掌握复杂性。在处理Tungsten Fabric集群时,我们可以识别3个层次:VNF,hypervisor和vRouter。

107d6934-d6ff-4c1d-9314-c1302d8edb54-image.png
107d6934-d6ff-4c1d-9314-c1302d8edb54-image.png

现在来看一下整个流程。

在VNF层面,我们拥有VNF提供的所有工具,可能有类似tcpdum的命令,或者如果VNF是一个防火墙,有一些东西可以查看流表内容。由于这个级别取决于厂商/VNF,这里不打算详细介绍。

再来看看vRouter。vRouter是Tungsten Fabric解决方案的核心,它提供并管理计算节点内部的所有虚拟网络。此外,它还提供了一系列不错的工具,可以用来了解集群内的流量是如何流动的。

要访问这套工具,首先要访问vRouter容器,通过连接到计算节点并使用知名的docker命令来实现。

代码语言:javascript
复制
[root@compute1 ~]# docker ps | grep vrouter
c1f441949cb5        hub.juniper.net/contrail/contrail-vrouter-agent:1911.31       "/entrypoint.sh /usr…"   8 days ago          Up 8 days                               vrouter_vrouter-agent_1
4333e1b1cf92        hub.juniper.net/contrail/contrail-nodemgr:1911.31             "/entrypoint.sh /bin…"   8 days ago          Up 8 days                               vrouter_nodemgr_1
[root@compute1 ~]# docker exec -it vrouter_vrouter-agent_1 bash
(vrouter-agent)[root@compute1 /]$

一旦我们进行到这里,就可以开始寻找流量了。

首先,确定VM的虚拟机接口(vif)。通过使用“vif”实用程序,匹配端口IP地址(192.168.10.3)来实现:

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ vif --list | grep -B 1 -A 1 192.168.10.3
vif0/3      OS: tapcae84676-cb NH: 33
            Type:Virtual HWaddr:00:00:5e:00:01:00 IPaddr:192.168.10.3
            Vrf:2 Mcast Vrf:2 Flags:PL3L2DEr QOS:-1 Ref:6

在这里,我们学到了很多有用的东西。

接口属于Vrf 2,这是一种路由表索引。虚拟接口索引是3(vif0/3)。最后,对应的tap接口是tapcae84676-cb。

下一个工具,我们可以使用rt。记住,我们要ping的是地址为192.168.10.4的远程虚拟机。

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ rt --get 192.168.10.4/32 --vrf 2
Match 192.168.10.4/32 in vRouter inet4 table 0/2/unicast

Flags: L=Label Valid, P=Proxy ARP, T=Trap ARP, F=Flood ARP
vRouter inet4 routing table 0/2/unicast
Destination           PPL        Flags        Label         Nexthop    Stitched MAC(Index)
192.168.10.4/32         0           LP         23             20        2:e7:fd:ee:27:78(148824)

上面的输出结果告诉我们流量将被发送到下一跳20。此外,它还说到将使用标签23。这表明,为了到达目的地,流量将不得不离开计算节点,并被封装成一个MPLSoUDP(或MPLSoGRE)包。这个标签就是将要推送的服务标签。

我们来检查下一跳:

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ nh --get 20
Id:20         Type:Tunnel         Fmly: AF_INET  Rid:0  Ref_cnt:6          Vrf:0
              Flags:Valid, MPLSoUDP, Etree Root,
              Oif:0 Len:14 Data:56 68 ac c3 28 02 56 68 ac c3 28 04 08 00
              Sip:192.168.200.3 Dip:192.168.200.4

正如想象的那样,下一跳是一个MPLSoUDP隧道,将流量从compute1(vhost0地址192.168.200.3)发送到compute2(vhost0地址192.168.200.4)。

请注意输出中的“Vrf:0”字段,这告诉我们,流量将通过VRF 0发送出去(如前所述,VM在VRF 2中)。Vrf 0是“fabric network”,连接计算节点和underlay的网络。此外,发送到下一跳20的流量将通过接口0(Oif 0)发送到Vrf 0(如前所述)。Oif 0是连接计算和底层的物理接口接口:

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ vif --get 0
Vrouter Interface Table
vif0/0      OS: ens3f1 (Speed 1000, Duplex 1) NH: 4
            Type:Physical HWaddr:56:68:ac:c3:28:04 IPaddr:0.0.0.0
            Vrf:0 Mcast Vrf:65535 Flags:TcL3L2VpEr QOS:-1 Ref:7
            RX packets:738213  bytes:47096090 errors:0
            TX packets:808295  bytes:42533041 errors:0
            Drops:30

这是vhost0所在的接口。Oif 0会“看到”封装的数据包。

综上所述,我们的虚拟机的流量属于VRF 2,在这个VRF里面,发生了查找(lookup)动作。在那里,通过Oif 0接口(物理接口),流量将被封装成MPLSoUDP数据包,然后发送到另一个计算节点。

下一个有用的工具,是“流(flow)”。vRouter默认是基于流的(可以通过将vmis设置为数据包模式来选择性地禁用每个vmi的流模式)。

让我们根据目的地来匹配流量:

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ flow --match 192.168.10.4
Listing flows matching ([192.168.10.4]:*)

    Index                Source:Port/Destination:Port                      Proto(V)
-----------------------------------------------------------------------------------
   512500518060       192.168.10.3:49409                                  1 (2)
                         192.168.10.4:0
(Gen: 1, K(nh):33, Action:F, Flags:, QOS:-1, S(nh):33,  Stats:4/392,  SPort 54199,
 TTL 0, Sinfo 3.0.0.0)

   518060512500       192.168.10.4:49409                                  1 (2)
                         192.168.10.3:0
(Gen: 1, K(nh):33, Action:F, Flags:, QOS:-1, S(nh):20,  Stats:4/392,  SPort 65513,
 TTL 0, Sinfo 192.168.200.4)

到目前为止,我们只看到了控制面信息:接口索引、路由表、下一跳。

这是第一次确认流量真的在虚拟机之间流动。

我们有2个流,因为每个流都是单向的。

这个输出有这么多信息!流量是流动的,因为Action被设置为F,也就是转发。

我们还知道,流量是ICMP,因为proto等于1。Proto旁边有“(V)”。这代表了VRF id,不出意外的话,它等于2!

最后,看到K(NH)和S(NH):这些是Key和Source(RPF)的下一跳。下一跳20我们已经看到了。此外,我们还看到下一跳33,它指向我们的本地虚拟机(vif 3):

代码语言:javascript
复制
(vrouter-agent)[root@compute1 /]$ nh --get 33 | grep Oif
              EncapFmly:0806 Oif:3 Len:14

我们可以从vRouter内部使用的东西就到这里了。

最后,我们进入到hypervisor层。我所说的“hypervisor层”指的是虚拟机和外界之间的那个中间层。这是虚拟机接口与物理网卡连接的地方。在这个层面我们能做的主要是嗅探流量。

先退出vRouter容器。

当使用vif时,我们能够定位到与该端口相关的tap接口“tapcae84676-cb”。

可以使用标准的tcpdump:

代码语言:javascript
复制
[root@compute1 ~]# tcpdump -i tapcae84676-cb -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tapcae84676-cb, link-type EN10MB (Ethernet), capture size 262144 bytes
09:24:55.082119 IP 192.168.10.3 > 192.168.10.4: ICMP echo request, id 49409, seq 688, length 64
09:24:55.107621 IP 192.168.10.4 > 192.168.10.3: ICMP echo reply, id 49409, seq 688, length 64
09:24:56.082344 IP 192.168.10.3 > 192.168.10.4: ICMP echo request, id 49409, seq 689, length 64
09:24:56.092153 IP 192.168.10.4 > 192.168.10.3: ICMP echo reply, id 49409, seq 689, length 64
^C
4 packets captured
10 packets received by filter
0 packets dropped by kernel

是的,这里就是我们的流量。

其次,可以直接在物理接口上嗅探流量。这里,我们将看到封装的流量。

在这个接口上,我们可能会看到许多不同类型的流量:到计算节点2的流量,到其它计算节点的流量,到控制节点的流量。此外,并非所有的流量都是MPLSoUDP。我们可以有VXLAN(L2虚拟化)流量或普通IP流量(XMPP)。出于这个原因,适当地过滤流量可能是有用的。

MPLSoUDP的流量可以通过6635端口过滤udp流量来缩小范围;VXLAN可以通过设置4789端口过滤udp流量。此外,我们还可以在目的主机IP上进行过滤,如之前学习的使用“rt”和“nh”,流量被发送到192.168.200.4:

代码语言:javascript
复制
[root@compute1 ~]# tcpdump -i ens3f1 -nn udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens3f1, link-type EN10MB (Ethernet), capture size 262144 bytes
09:33:24.394590 IP 192.168.200.3.54199 > 192.168.200.4.6635: UDP, length 102
09:33:24.395915 IP 192.168.200.4.56128 > 192.168.200.3.6635: UDP, length 102
09:33:25.395362 IP 192.168.200.3.54199 > 192.168.200.4.6635: UDP, length 102
09:33:25.398488 IP 192.168.200.4.56128 > 192.168.200.3.6635: UDP, length 102
09:33:26.395541 IP 192.168.200.3.54199 > 192.168.200.4.6635: UDP, length 102
09:33:26.399384 IP 192.168.200.4.56128 > 192.168.200.3.6635: UDP, length 102
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

正如你所看到的,我们在这些计算节点之间有双向的MPLSoUDP流量。无论如何,还不能确定这真的是我们的流量。为了确定这一点,我们可以将捕获到的数据保存到一个文件中,然后用wireshark打开,wireshark能够解码MPLSoUDP。

根据配置的封装优先级,可能VXLAN是用于计算到计算的流量。事实上,VXLAN是VN内部流量的默认选择,除非MPLSoUDP被配置在优先级列表中的第一位(无论如何,现在这并不重要……)。

我们只能说,我们必须期望处理不同类型的overlay流量。

其实VXLAN更方便用户使用,因为tcpdump可以显示内部数据包的内容:

代码语言:javascript
复制
[root@compute1 ~]# tcpdump -i ens3f1 -nn udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens3f1, link-type EN10MB (Ethernet), capture size 262144 bytes
09:36:24.478515 IP 192.168.200.3.54199 > 192.168.200.4.4789: VXLAN, flags [I] (0x08), vni 5
IP 192.168.10.3 > 192.168.10.4: ICMP echo request, id 49409, seq 1377, length 64
09:36:24.479659 IP 192.168.200.4.56128 > 192.168.200.3.4789: VXLAN, flags [I] (0x08), vni 5
IP 192.168.10.4 > 192.168.10.3: ICMP echo reply, id 49409, seq 1377, length 64
09:36:25.478920 IP 192.168.200.3.54199 > 192.168.200.4.4789: VXLAN, flags [I] (0x08), vni 5
IP 192.168.10.3 > 192.168.10.4: ICMP echo request, id 49409, seq 1378, length 64
09:36:25.480214 IP 192.168.200.4.56128 > 192.168.200.3.4789: VXLAN, flags [I] (0x08), vni 5
IP 192.168.10.4 > 192.168.10.3: ICMP echo reply, id 49409, seq 1378, length 64
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel
[root@compute1 ~]#

在这里,我们可以看到实际的VM ICMP数据包。这样就可以确定是否为我们的流量。

只要我们的计算节点是在内核模式下,使用tcpdump就是可能的。如果我们有一个dpdk vRouter,那么就不能在主机上使用tcpdump,因为dpdk会“吃掉接口”,使它们对内核不可见(tcpdump在内核可见的接口上工作)。在这种情况下,hypervisor层消失了,我们必须依靠vRouter层。

一旦我们进入vRouter容器,一个至今没有见过的工具就成了基础:vifdump。Vifdump就像tcpdump一样,只是它工作在DPDK接口上,只能在vRouter容器内部运行。

要嗅探一个虚拟机接口:

代码语言:javascript
复制
vifdump -i vif0/3 -nn icmp

要嗅探一个物理接口:

代码语言:javascript
复制
vifdump -i vif0/0

总结

就是这样!让我们总结一下所有的可能性——

在VNF层面,使用厂商/VNF特定的工具。

在vRouter层面(工具要在vRouter容器内运行):

  • vif,列出虚拟接口
  • nh,了解流量计算一个特定的nexth-hop索引是在哪里发送的
  • flow,查看vRouter上的活动流量
  • rt,查看vRouter路由表内部

在hypervisor层面,使用tcpdump来嗅探虚拟接口和物理接口上的数据包。

最后,如果节点是DPDK节点,那么主机级的tcpdump就没有用了,用vRouter容器里面运行的“vifdump”代替。

现在没有秘密了吧?一句话,在正确的层面上使用正确的工具~


作者:Umberto Manferdini 译者:TF编译组 原文链接: https://iosonounrouter.wordpress.com/2020/04/13/troubleshooting-contrail-vms-traffic-the-right-tool-at-the-right-moment/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 事情变得有点“复杂”
  • 三个层次,三套工具
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档