乐趣区

关于linux:在云原生场景中nettrace-如何快速进行网络故障诊断

​在开源 Linux 操作系统 OpenCloudOS 8.6 中,减少了内核对网络工具 nettrace 的反对,容许开发者通过 bpf 进行网络丢包起因跟踪,内核也同时回合相干的丢包跟踪点。明天,就以 nettrace 为典型,介绍如何在 OpenCloudOS 中利用 nettrace 进行网络故障诊断。

一、工具简介

1. 背景

在一些场景下(特地是云原生场景),Linux 零碎中的网络部署变得越来越简单。一个 TCP 连贯,从客户端到服务端,两头可能要通过简单的 NAT、GRE、IPVS 等过程,网络报文在节点(主机)上的解决门路也变得越来越长。在产生网络故障(比方网络丢包)时,如何疾速、无效地定位出网络问题成为了一个难题。目前惯例的网络故障定位伎俩,如 tcpdump、dropwatch、ftrace、kprobe 等存在肯定的短板:

  • tcpdump:只能在链路层抓包,无奈定位内核协定栈中的问题,比方惯例的内核丢包问题
  • ftrace:只能跟踪内核函数,无奈进行报文过滤,且动手较难,须要对内核协定栈有肯定理解
  • kprobe:长期编写内核模块,效率和安全性低
  • BCC:性能繁多,长期编写 BCC 程序跟踪效率低,须要对内核有肯定理解,动手难
  • dropwatch:性能繁多,只能查看网络丢包问题,且无奈失去丢包起因和解决方案

在此背景下,笔者联合多年的 Kernel 网络协议栈故障定位教训,基于 eBPF 开发了 Linux 环境下网络故障定位工具集——nettrace。

2. 性能介绍

nettrace 是一款基于 eBPF 的集网络报文跟踪(故障定位)、网络故障诊断、网络异样监控于一体的网络工具集,旨在可能提供一种更加高效、易用的办法来解决简单场景下的网络问题。目前,其实现的性能包含:

  • 网络报文跟踪:跟踪网络报文从进入到内核协定栈到开释 / 抛弃的过程中在内核中所走过的门路,实现报文整个生命周期的监控,并采集生命周期各个阶段的事件、信息。通过观察报文在内核中的门路,对于有肯定内核协定栈教训的人来说能够疾速、无效地发现网络问题。
  • 网络故障诊断:将以往的教训集成到工具的知识库,通过常识匹配的形式来被动诊断以后网络故障,给出诊断后果以及修复倡议。该性能动手简略、易用性强,无需过多的网络教训即可进行网络问题定位。
  • 网络异样监控:常态化地部署到生产环境中,被动地发现、上报环境上的网络异样。
  • droptrace:用于跟踪、监控零碎中的丢包事件的工具,在文末链接中查看详情介绍。该性能已被遗弃,能够应用 nettrace –drop 实现雷同的性能。

二、装置办法

nettrace 是采纳 C 语言编写的基于 eBPF(libbpf)的命令行工具,在应用和装置时能够用编译好的 RPM 包和二进制程序。 留神 :本工具目前仅在 4.14 及以上的内核版本上进行过兼容性测试,因而请确保以后的零碎所应用的的内核版本在 4.14 以上。对于默认继承 yum 的 OpenCloudOS,本工具曾经上线到对应的软件仓库,能够方便快捷地间接应用 yum 命令来进行在线装置:

sudo yum install nettrace

也能够间接从 OpenCloudOS releases 页面中下载对应的 RPM/DEB 安装包,手动进行装置。

三、应用办法

nettrace 是用来跟踪内核报文和诊断网络故障的,在进行报文跟踪时能够应用肯定的过滤条件来跟踪特定的报文。其根本命令行参数为:

$ nettrace -h
nettrace: a tool to trace skb in kernel and diagnose network problem

Usage:
    -s, --saddr      filter source ip address
    --saddr6         filter source ip v6 address
    -d, --daddr      filter dest ip address
    --daddr6         filter dest ip v6 address
    --addr           filter source or dest ip address
    --addr6          filter source or dest ip v6 address
    -S, --sport      filter source TCP/UDP port
    -D, --dport      filter dest TCP/UDP port
    -P, --port       filter source or dest TCP/UDP port
    -p, --proto      filter L3/L4 protocol, such as 'tcp', 'arp'
    --pid            filter by current process id(pid)
    -t, --trace      enable trace group or trace
    --ret            show function return value
    --detail         show extern packet info, such as pid, ifname, etc
    --date           print timestamp in date-time format
    --basic          use 'basic' trace mode, don't trace skb's life
    --diag           enable 'diagnose' mode
    --diag-quiet     only print abnormal packet
    --diag-keep      don't quit when abnormal packet found
    --hooks          print netfilter hooks if dropping by netfilter
    --drop           skb drop monitor mode, for replace of 'droptrace'
    --drop-stack     print the kernel function call stack of kfree_skb

    -v               show log information
    --debug          show debug information
    -h, --help       show help information

其中,参数 s/d/addr/S/D/port/p/pid 用于进行报文的过滤,能够通过 IP 地址、端口、协定等属性进行过滤。其余参数的用处包含:

  • t/trace:要启用的跟踪模块,默认启用所有
  • ret:跟踪和显示内核函数的返回值
  • detail:显示跟踪详细信息,包含以后的过程、网口和 CPU 等信息
  • date:以工夫格局打印(以 2022-10-24 xx:xx:xx.xxxxxx 格局打印),而不是工夫戳
  • basic:启用 basic 跟踪模式。默认状况下,启用的是生命周期跟踪模式。启用该模式后,会间接打印出报文所通过的内核函数 /tracepoint。
  • diag:启用诊断模式
  • diag-quiet:只显示呈现存在问题的报文,不显示失常的报文
  • diag-keep:继续跟踪。diag 模式下,默认在跟踪到异样报文后会进行跟踪,应用该参数后,会继续跟踪上来。
  • hooks:联合 netfilter 做的适配,详见下文
  • drop:进行零碎丢包监控,取代原先的 droptrace
  • drop-stack: 打印 kfree_skb 内核函数的调用堆栈

上面咱们首先来看一下默认模式下的工具应用办法。

1. 生命周期

默认状况下,nettrace 会跟踪报文从进入到内核协定栈到来到(销毁)的过程。对于有肯定内核网络教训的人来说,能够通过报文的内核门路来疾速推断出以后的网络问题,达到疾速定位的目标。

1.1 跟踪 ping 报文

sudo ./nettrace -p icmp
begin trace...
***************** ffff889be8fbd500,ffff889be8fbcd00 ***************
[1272349.614564] [dev_gro_receive] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614579] [__netif_receive_skb_core] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614585] [ip_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614592] [ip_rcv_core] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614599] [skb_clone] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614616] [nf_hook_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614629] [nft_do_chain] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614635] [ip_rcv_finish] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614643] [ip_route_input_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614647] [fib_validate_source] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614652] [ip_local_deliver] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614658] [nf_hook_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614663] [ip_local_deliver_finish] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614666] [icmp_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614671] [icmp_echo] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614675] [icmp_reply] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614715] [consume_skb] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614722] [packet_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220
[1272349.614725] [consume_skb] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 48220

***************** ffff889be8fbde00 ***************
[1272349.614681] [nf_hook_slow] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614688] [ip_output] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614690] [nf_hook_slow] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614693] [ip_finish_output] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614697] [ip_finish_output2] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614705] [__dev_queue_xmit] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272349.614709] [dev_hard_start_xmit] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220
[1272351.286866] [consume_skb] ICMP: 172.27.0.6 -> 169.254.128.15 ping reply, seq: 48220

下面的 * 两头的示意以后所跟踪的 skb 的地址,因为以后的报文被克隆过,因而以后跟踪上下文存在两个报文。

1.2 指定过滤条件

sudo ./nettrace -p icmp --saddr 169.254.128.15
begin trace...
***************** ffff889be8fbc700,ffff889be8fbdc00 ***************
[1273445.360831] [dev_gro_receive] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360844] [__netif_receive_skb_core] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360847] [ip_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360850] [ip_rcv_core] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360854] [skb_clone] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360861] [nf_hook_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360868] [nft_do_chain] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360875] [ip_rcv_finish] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360878] [ip_route_input_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360882] [fib_validate_source] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360887] [ip_local_deliver] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360890] [nf_hook_slow] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360895] [ip_local_deliver_finish] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360899] [icmp_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360903] [icmp_echo] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360908] [icmp_reply] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360922] [consume_skb] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360930] [packet_rcv] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754
[1273445.360933] [consume_skb] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 54754

1.3 显示详细信息

sudo ./nettrace -p icmp --saddr 169.254.128.15 --detail
begin trace...
***************** ffff889be8fbcd00,ffff889be8fbcc00 ***************
[1273732.110173] [ffff889be8fbcd00][dev_gro_receive][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110185] [ffff889be8fbcd00][__netif_receive_skb_core][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110189] [ffff889be8fbcd00][ip_rcv][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110192] [ffff889be8fbcd00][ip_rcv_core][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110196] [ffff889be8fbcd00][skb_clone][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110204] [ffff889be8fbcc00][nf_hook_slow][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110211] [ffff889be8fbcc00][nft_do_chain][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110222] [ffff889be8fbcc00][ip_rcv_finish][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110229] [ffff889be8fbcc00][ip_route_input_slow][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110234] [ffff889be8fbcc00][fib_validate_source][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110240] [ffff889be8fbcc00][ip_local_deliver][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110243] [ffff889be8fbcc00][nf_hook_slow][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110252] [ffff889be8fbcc00][ip_local_deliver_finish][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110255] [ffff889be8fbcc00][icmp_rcv][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110260] [ffff889be8fbcc00][icmp_echo][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110267] [ffff889be8fbcc00][icmp_reply][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110283] [ffff889be8fbcc00][consume_skb][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110291] [ffff889be8fbcd00][packet_rcv][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464
[1273732.110294] [ffff889be8fbcd00][consume_skb][cpu:40][ens5][pid:0][swapper/40] ICMP: 169.254.128.15 -> 172.27.0.6 ping request, seq: 56464

能够看到,每个报文的地址、所在 CPU、网口和过程信息都被打印了进去。

1.4 NAT 跟踪

在对报文进行跟踪时,一旦报文被跟踪起来(命中过滤条件),那么这个报文即便内容产生了变动也会继续被跟踪,晓得报文被开释。上面是 NAT 场景下的跟踪,能够看到报文的源地址由 192.168.122.8 通过 SNAT 被批改成了 9.135.224.89,然而报文仍然被跟踪到了:

$ sudo ./nettrace -p icmp --addr 192.168.122.8
begin tracing......
<------------------- skb: ffff88818f02f900 ---------------------->
463697.331957: [__netif_receive_skb_core]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.331972: [nf_hook_slow]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.331985: [nf_hook_slow]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.331990: [__netif_receive_skb_core]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.331994: [ip_rcv]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.331998: [ip_rcv_core]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332001: [nf_hook_slow]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332004: [ip_rcv_finish]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332010: [ip_forward]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332014: [nf_hook_slow]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332024: [ip_output]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332027: [nf_hook_slow]: ICMP: 192.168.122.8 -> 10.123.119.98, ping request   , seq: 0
463697.332037: [ip_finish_output]: ICMP: 9.135.224.89  -> 10.123.119.98, ping request   , seq: 0
463697.332039: [ip_finish_output2]: ICMP: 9.135.224.89  -> 10.123.119.98, ping request   , seq: 0
463697.332042: [dev_queue_xmit]: ICMP: 9.135.224.89  -> 10.123.119.98, ping request   , seq: 0
463697.332046: [dev_hard_start_xmit]: ICMP: 9.135.224.89  -> 10.123.119.98, ping request   , seq: 0
463697.332060: [consume_skb]: ICMP: 9.135.224.89  -> 10.123.119.98, ping request   , seq: 0

2. 诊断模式

应用形式与下面的统一,加个 diag 参数即可应用诊断模式。上文的生命周期模式对于使用者的要求比拟高,须要理解内核协定栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在生命周期模式的根底上,提供了更加丰盛的信息,使得没有网络开发教训的人也可进行简单网络问题的定位和剖析。

2.1 根本用法

上面是应用诊断模式进行报文跟踪的用法,能够看进去相比于一般模式,诊断模式提供了更多的可供参考的信息,包含以后报文通过了 iptables 的哪些表和哪些链、报文产生了 NAT、报文被克隆了等。诊断模式设置了三种提醒级别:

  • INFO:失常的信息提醒
  • WARN:正告信息,该报文可能存在肯定的问题,须要关注
  • ERROR:异样信息,报文产生了问题(比方被抛弃)。
./nettrace -p icmp --diag --saddr 192.168.122.8
begin trace...
***************** ffff889fad356200 ***************
[3445.575957] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.575978] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[3445.575990] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:nat, chain:PREROUT* *packet is accepted*
[3445.576005] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *bridge in chain: PRE_ROUTING*
[3445.576014] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576024] [ip_rcv] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576029] [ip_rcv_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576040] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[3445.576044] [ip_rcv_finish] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576052] [ip_route_input_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576061] [fib_validate_source] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576080] [ip_forward] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576084] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: FORWARD*
[3445.576087] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:filter, chain:FORWARD* *packet is accepted*
[3445.576107] [ip_output] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[3445.576113] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: POST_ROUTING*
[3445.576116] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:nat, chain:POSTROU* *packet is accepted*
[3445.576131] [nf_nat_manip_pkt] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *NAT happens (packet address will change)*
[3445.576148] [ip_finish_output] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0
[3445.576152] [ip_finish_output2] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0
[3445.576158] [__dev_queue_xmit] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0
[3445.576165] [netdev_core_pick_tx] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0
[3445.576177] [dev_hard_start_xmit] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0
[3445.576215] [consume_skb] ICMP: 192.168.255.10 -> 10.123.119.98 ping request, seq: 0 *packet is freed (normally)*
---------------- ANALYSIS RESULT ---------------------
[1] WARNING happens in nf_nat_manip_pkt(netfilter):
        NAT happens (packet address will change)

如果以后报文存在 ERROR,那么工具会给出肯定的诊断修复倡议,并终止以后诊断操作。通过增加 diag-keep 能够在产生 ERROR 事件时不退出,持续进行跟踪剖析。上面是产生异样时的日志:

./nettrace -p icmp --diag --saddr 192.168.122.8
begin trace...
***************** ffff889fb3c64f00 ***************
[4049.295546] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295566] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[4049.295578] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:nat, chain:PREROUT* *packet is accepted*
[4049.295594] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *bridge in chain: PRE_ROUTING*
[4049.295612] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295624] [ip_rcv] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295629] [ip_rcv_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295640] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[4049.295644] [ip_rcv_finish] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295655] [ip_route_input_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295664] [fib_validate_source] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295683] [ip_forward] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[4049.295687] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: FORWARD* *packet is dropped by netfilter (NF_DROP)*
[4049.295695] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:filter, chain:FORWARD* *packet is dropped by iptables/iptables-nft*
[4049.295711] [kfree_skb] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *packet is dropped by kernel*
---------------- ANALYSIS RESULT ---------------------
[1] ERROR happens in nf_hook_slow(netfilter):
        packet is dropped by netfilter (NF_DROP)
    fix advice:
        check your netfilter rule

[2] ERROR happens in nft_do_chain(netfilter):
        packet is dropped by iptables/iptables-nft
    fix advice:
        check your iptables rule

[3] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        nf_hook_slow+0x96
    drop reason:
        NETFILTER_DROP

analysis finished!

end trace...

从这里的日志能够看出,在报文通过 iptables 的 filter 表的 forward 链的时候,产生了丢包。在诊断后果里,会列出所有的异样事件,一个报文跟踪可能会命中多条诊断后果。这里的诊断倡议是让用户查看 iptables 中的规定是否存在问题。其中,kfree_skb 这个跟踪点是对 drop reason 内核个性做了适配的,能够了解为将 droptrace 的性能集成到了这里的诊断后果中,这里能够看出其给出的对包起因是 NETFILTER_DROP。

2.2 netfilter 反对

网络防火墙是网络故障、网络不同产生的重灾区,因而 netfilter 工具对 netfilter 提供了完满适配,包含老版本的 iptables-legacy 和新版本的 iptables-nft。诊断模式下,nettrace 可能跟踪报文所通过的 iptables 表和 iptables 链,并在产生因为 iptables 导致的丢包时给出肯定的提醒,下面的示例充沛展现出了这部分。除了对 iptables 的反对,nettrace 对整个 netfilter 大模块也提供了反对,可能显示在通过每个 HOOK 点时对应的协定族和链的名称。除此之外,为了应答一些注册到 netfilter 中的第三方内核模块导致的丢包问题,nettrace 还能够通过增加参数 hooks 来打印出以后 HOOK 上所有的的钩子函数,从而深入分析问题:

./nettrace -p icmp --diag --saddr 192.168.122.8 --hooks
begin trace...
***************** ffff889faa054500 ***************
[5810.702473] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702491] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: PRE_ROUTING*
[5810.702504] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *iptables table:nat, chain:PREROUT* *packet is accepted*
[5810.702519] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *bridge in chain: PRE_ROUTING*
[5810.702527] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702535] [ip_rcv] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702540] [ip_rcv_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702546] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: PRE_ROUTING*
[5810.702551] [ip_rcv_finish] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702556] [ip_route_input_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702565] [fib_validate_source] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702579] [ip_forward] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943
[5810.702583] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: FORWARD* *packet is dropped by netfilter (NF_DROP)*
[5810.702586] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *iptables table:filter, chain:FORWARD* *packet is dropped by iptables/iptables-nft*
[5810.702599] [kfree_skb] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 *packet is dropped by kernel*
---------------- ANALYSIS RESULT ---------------------
[1] ERROR happens in nf_hook_slow(netfilter):
        packet is dropped by netfilter (NF_DROP)

    following hook functions are blamed:
        nft_do_chain_ipv4

    fix advice:
        check your netfilter rule

[2] ERROR happens in nft_do_chain(netfilter):
        packet is dropped by iptables/iptables-nft
    fix advice:
        check your iptables rule

[3] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        nf_hook_slow+0x96
    drop reason:
        NETFILTER_DROP

analysis finished!

end trace...

能够看出,下面 following hook functions are blamed 中列出了导致以后 netfilter 丢包的所有的钩子函数,这里只有 iptables 一个钩子函数。

2.3 其余场景

因为对 drop reason 内核个性进行了适配,因而对于反对 drop reason 的零碎,基于 drop reason 本工具能够诊断 70+ 种丢包问题。nettrace 通过将网络诊断教训翻译成规定存储到规定库的形式来进行诊断剖析,通过裁减规定配置文件的形式可能一直加强其诊断性能。目前,本工具曾经集成了 20+ 典型网络故障诊断性能,并且在实践中不断完善知识库(规定库)。端口未监听导致的丢包:

./nettrace --diag --diag-quiet
begin trace...
***************** ffff888f97730ee0 ***************
[365673.326016] [ip_output] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326026] [ip_finish_output] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326029] [ip_finish_output2] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326032] [__dev_queue_xmit] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326039] [dev_hard_start_xmit] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326042] [enqueue_to_backlog] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326051] [__netif_receive_skb_core] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326059] [ip_rcv] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326061] [ip_rcv_core] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326068] [ip_rcv_finish] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326072] [ip_local_deliver] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326075] [ip_local_deliver_finish] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326078] [tcp_v4_rcv] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326084] [__inet_lookup_listener] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S *tcp port is not listened*
[365673.326090] [tcp_v4_send_reset] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S
[365673.326125] [kfree_skb] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S *packet is dropped by kernel*
---------------- ANALYSIS RESULT ---------------------
[1] WARNING happens in __inet_lookup_listener(tcp-in):
        tcp port is not listened
    fix advice:
        check your target tcp port

[2] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        tcp_v4_rcv+0x4a

XDP 导致的丢包(XDP 转发会给提醒):

./nettrace -p icmp --diag --diag-quiet 
begin trace...
***************** ffff889f015acc00 ***************
[18490.607809] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[18490.607828] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[18490.607840] [nft_do_chain] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *iptables table:nat, chain:PREROUT* *packet is accepted*
[18490.607855] [nf_hook_slow] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *bridge in chain: PRE_ROUTING*
[18490.607874] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0
[18490.607882] [netif_receive_generic_xdp] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *packet is dropped by XDP program*
[18490.607888] [kfree_skb] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 *packet is dropped by kernel*
---------------- ANALYSIS RESULT ---------------------
[1] ERROR happens in netif_receive_generic_xdp(link-in):
        packet is dropped by XDP program
    fix advice:
        check your XDP eBPF program

[2] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        netif_receive_generic_xdp+0x259
    drop reason:
        NOT_SPECIFIED

analysis finished!

3. 丢包监控

应用命令 nettrace –drop 能够对系统中的丢包事件进行监控,对于反对内核个性 skb drop reason 的内核,这里还会打印出丢包起因。能够通过查看 /tracing/events/skb/kfree_skb/format 来判断以后零碎是否反对该个性:

cat /tracing/events/skb/kfree_skb/format 
name: kfree_skb
ID: 1524
format:
        field:unsigned short common_type;       offset:0;       size:2; signed:0;
        field:unsigned char common_flags;       offset:2;       size:1; signed:0;
        field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
        field:int common_pid;   offset:4;       size:4; signed:1;

        field:void * skbaddr;   offset:8;       size:8; signed:0;
        field:void * location;  offset:16;      size:8; signed:0;
        field:unsigned short protocol;  offset:24;      size:2; signed:0;
        field:enum skb_drop_reason reason;      offset:28;      size:4; signed:0;

print fmt: "skbaddr=%p protocol=%u location=%p reason: %s", REC->skbaddr, REC->protocol, REC->location, __print_symbolic(REC->reason, { 1, "NOT_SPECIFIED"}, {2, "NO_SOCKET"}, {3, "PKT_TOO_SMALL"}, {4, "TCP_CSUM"}, {5, "SOCKET_FILTER"}, {6, "UDP_CSUM"}, {7, "NETFILTER_DROP"}, {8, "OTHERHOST"}, {9, "IP_CSUM"}, {10, "IP_INHDR"}, {11, "IP_RPFILTER"}, {12, "UNICAST_IN_L2_MULTICAST"}, {13, "XFRM_POLICY"}, {14, "IP_NOPROTO"}, {15, "SOCKET_RCVBUFF"}, {16, "PROTO_MEM"}, {17, "TCP_MD5NOTFOUND"}, {18, "TCP_MD5UNEXPECTED"}, {19, "TCP_MD5FAILURE"}, {20, "SOCKET_BACKLOG"}, {21, "TCP_FLAGS"}, {22, "TCP_ZEROWINDOW"}, {23, "TCP_OLD_DATA"}, {24, "TCP_OVERWINDOW"}, {25, "TCP_OFOMERGE"}, {26, "TCP_RFC7323_PAWS"}, {27, "TCP_INVALID_SEQUENCE"}, {28, "TCP_RESET"}, {29, "TCP_INVALID_SYN"}, {30, "TCP_CLOSE"}, {31, "TCP_FASTOPEN"}, {32, "TCP_OLD_ACK"}, {33, "TCP_TOO_OLD_ACK"}, {34, "TCP_ACK_UNSENT_DATA"}, {35, "TCP_OFO_QUEUE_PRUNE"}, {36, "TCP_OFO_DROP"}, {37, "IP_OUTNOROUTES"}, {38, "BPF_CGROUP_EGRESS"}, {39, "IPV6DISABLED"}, {40, "NEIGH_CREATEFAIL"}, {41, "NEIGH_FAILED"}, {42, "NEIGH_QUEUEFULL"}, {43, "NEIGH_DEAD"}, {44, "TC_EGRESS"}, {45, "QDISC_DROP"}, {46, "CPU_BACKLOG"}, {47, "XDP"}, {48, "TC_INGRESS"}, {49, "UNHANDLED_PROTO"}, {50, "SKB_CSUM"}, {51, "SKB_GSO_SEG"}, {52, "SKB_UCOPY_FAULT"}, {53, "DEV_HDR"}, {54, "DEV_READY"}, {55, "FULL_RING"}, {56, "NOMEM"}, {57, "HDR_TRUNC"}, {58, "TAP_FILTER"}, {59, "TAP_TXFILTER"}, {60, "ICMP_CSUM"}, {61, "INVALID_PROTO"}, {62, "IP_INADDRERRORS"}, {63, "IP_INNOROUTES"}, {64, "PKT_TOO_BIG"}, {65, "MAX"})

该模式下应用的成果与原先的 droptrace 完全相同,如下所示:

nettrace --drop
begin trace...
[142.097193] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AR, reason: NOT_SPECIFIED, tcp_v4_rcv+0x81
[142.331798] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:A, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83
[142.331857] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AP, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83
[146.136576] TCP: 127.0.0.1:43582 -> 127.0.0.1:9999 seq:3819454691, ack:0, flags:S, reason: NO_SOCKET, tcp_v4_rcv+0x81
[146.220414] TCP: 169.254.0.138:8186 -> 172.27.0.6:40634 seq:8486084, ack:2608831141, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126
[146.533728] TCP: 127.0.0.1:36338 -> 127.0.0.1:56100 seq:1110580666, ack:1951926207, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126
[147.255946] TCP: 20.44.10.122:443 -> 192.168.255.10:42878 seq:2950381253, ack:211751623, flags:A, reason: NOT_SPECIFIED, tcp_rcv_state_process+0xe9

同样能够应用 man dropreason 命令来查看对应的丢包起因的具体解释。对于不反对 skb drop reason 个性的内核,该模式下将不会打印丢包起因字段,成果如下所示:

nettrace --drop
begin trace...
[2016.965295] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:AR, tcp_v4_rcv+0x50
[2017.201315] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:A, tcp_v4_do_rcv+0x70
[2019.041344] TCP: 176.58.124.134:37441 -> 172.27.0.6:443 seq:1160140493, ack:0, flags:S, tcp_v4_rcv+0x50
[2021.867340] TCP: 127.0.0.1:34936 -> 127.0.0.1:9999 seq:1309795878, ack:0, flags:S, tcp_v4_rcv+0x50
[2024.997146] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AR, tcp_v4_rcv+0x50
[2025.235953] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:A, tcp_v4_do_rcv+0x70
[2025.235967] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AP, tcp_v4_do_rcv+0x70

四、小结

nettrace 工具自上线 OpenCloud 社区以来,受到了业界的宽泛关注,并在 OpenCloudOS 的网络故障诊断中失去了大量利用。特地是简单的云原生网络环境中,nettrace 工具通过报文跟踪、网络诊断的形式为用户解决了屡次疑难网络问题。

同时,nettrace 与 OpenCloudOS 进行了完满的兼容和适配,并上架了 OpenCloudOS 的软件仓库,使得 OpenCloudOS 用户能够很不便地间接应用 yum 命令来进行装置和应用。

本月,OpenCloudOS 源社区 2301 版本已公布,领有更多技术新个性,欢送开发者下载应用。OpenCloudOS ISO 下载地址

如果在应用过程中遇到技术问题,扫描下方二维码,退出社区用户群,即可理解 OpenCloudOS 最新动静,获取技术相干的反对,分享交换应用体验。

  • droptrace
  • OpenCloudOS release 页面
  • OpenCloudOS 社区官网
退出移动版