专栏首页Serverless+使用 BPF 记录 TCP 重传和丢包记录
原创

使用 BPF 记录 TCP 重传和丢包记录

背景

在云函数的日常运营中,经常有用户提出要求协助排查网络问题。一般的手段就是使用 tcpdump 抓包,但是部署抓包往往是在问题发生之后,而且抓包后复现的时机也不确定,往往费时费力。本文讲述使用 BPF 记录 TCP 的重传和丢包记录,作为定位网络问题的一种辅助手段。

在 BPF 出现之前

BPF 出现之前,在 Linux 上我们也是可以解决这个问题的,只不过比较繁琐,需要对内核、调试器、编译器等许多基础知识有较深理解,参见这里

TCP 重传为例,我们使用 perf 工具来查找跟踪的点位:

$ sudo perf list 'tcp:*'

List of pre-defined events (to be used in -e):

  tcp:tcp_destroy_sock                               [Tracepoint event]
  tcp:tcp_probe                                      [Tracepoint event]
  tcp:tcp_rcv_space_adjust                           [Tracepoint event]
  tcp:tcp_receive_reset                              [Tracepoint event]
  tcp:tcp_retransmit_skb                             [Tracepoint event]
  tcp:tcp_retransmit_synack                          [Tracepoint event]
  tcp:tcp_send_reset                                 [Tracepoint event]


Metric Groups:

对于 TCP 重传,显然 tcp_retransmit_skb 是一个合适的跟踪点位。让我们来看看这个函数在内核代码中的签名:

int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs);

struct sock 的定义在这里,它包含了我们所需要的信息。这是一个庞大且复杂的结构体,而且对于 kprobe 来说,我们只能使用寄存器以及偏移来输出其值。

要知道这个结构体中每个字段的真实偏移,我们需要内核的符号表,使用 GDB 来确定其值:

$ sudo apt install linux-image-unsigned-5.8.0-37-generic-dbgsym
$ gdb /usr/lib/debug/boot/vmlinux-5.8.0-37-generic
(gdb) ptype struct sock
...
(gdb) print (int)&((struct sock*)0)->__sk_common.skc_dport
$1 = 12

除此之外,我们还需要了解 X86_64调用约定,诸如函数调用的第一个参数使用 di 寄存器传递等。

有了这些背景知识后,我们可以使用 kprobe 来达成这一目标,记录 TCP 重传的例子如下:

$ echo 'p:kprobes/tcp_retransmit tcp_retransmit_skb port=+12(%di):u16 dst=+0(%di):u32 state=+18(%di):u8' >> /sys/kernel/debug/tracing/kprobe_events
$ echo 1 > /sys/kernel/debug/tracing/events/kprobes/tcp_retransmit/enable

这个例子不仅晦涩难懂,而且不易开发及调试,好在现在我们有了 BPF

BPF 横空出世

BPF 是一项革命性技术,它能在内核中运行沙箱程序, 而无需修改内核源码或者加载内核模块。

对于上面的例子,一个等价的 BPF 程序如下:

#include <uapi/linux/ptrace.h>
#include <net/sock.h>

int log_tcp_retransmit(struct pt_regs *ctx, struct sock *sk) {
    u16 port = sk->__sk_common.skc_dport;
    u32 daddr = sk->__sk_common.skc_daddr;
    u8 state = sk->__sk_common.skc_state;
    bpf_trace_printk("tcp_retransmit port=%d dst=%d state=%d\n", port, daddr, state);
    return 0;
}

使用 C 编写,不需要理解 ABI 等细节,而且方便调试。你可以在这里找到完整的代码。对于 TCP 重传,也是一样的道理。

重传的日志记录在 /sys/kernel/debug/tracing/trace,下面是一些真实的记录:

$ sudo cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 103/103   #P:1
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
...
          <idle>-0       [000] ..s. 2621728.977959: 0: tcp_retransmit port=37897 dst=831376843 state=1
           <...>-3202753 [000] ..s. 2622104.077378: 0: tcp_retransmit port=37897 dst=831376843 state=1
...

转换一下格式,可以看到重传的目的地址及端口等信息:

2621728.977959 2021-03-05 19:48:18.959403       tcp_retransmit  203.205.141.49           2452   TCP_ESTABLISHED
2622104.077378 2021-03-05 19:54:34.058822       tcp_retransmit  203.205.141.49           2452   TCP_ESTABLISHED

结论

本文讲述使用 BPF 带来的可观测性能力,获取 TCP 的重传及丢包记录,作为辅助定位网络问题的手段。与传统的 kprobe 方式相比, BPF 带来的可编程性极大地提升了开发效率,既没有增加系统的复杂度,也不会牺牲执行效率和安全性。

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Cilium架构 (Cilium 2)

    译自:http://docs.cilium.io/en/stable/architecture/

    charlieroro
  • FFShark-一种可以监控全世界网络的100G可编程智能NIC

    最近几天,老美又加大了对华为的约束,几乎将华为逼上绝路。老美之所以费尽心机的制裁华为,最重要的原因就是以5G为代表的网络战略地位的抢夺。网络,已不仅仅是数据通...

    网络交换FPGA
  • 一种可以监控全世界网络的可编程智能NIC

    最近几天,老美又加大了对华为的约束,几乎将华为逼上绝路。老美之所以费尽心机的制裁华为,最重要的原因就是以5G为代表的网络战略地位的抢夺。网络,已不仅仅是数据通...

    网络交换FPGA
  • 连接跟踪(conntrack):原理、应用及 Linux 内核实现

    本文介绍连接跟踪(connection tracking,conntrack,CT)的原理,应用,及其在 Linux 内核中的实现。

    我是阳明
  • Linux阅码场 - Linux内核月报(2020年08月)

    Linux阅码场内核月报栏目,是汇总当月Linux内核社区最重要的一线开发动态,方便读者们更容易跟踪Linux内核的最前沿发展动向。

    Linux阅码场
  • 你的第一个TC BPF 程序

    https://github.com/nevermosby/linux-bpf-learning

    nevermosby
  • Kubernetes 中的 eBPF

    BPF (Berkeley Packet Filter) 最早是用在 tcpdump 里面的,比如 tcpdump tcp and dst port 80 这样...

    黑光技术
  • 如何使用BPF将SSH会话转换为结构化事件

    Teleport 4.2引入了一个名叫增强型会话记录(Enhanced Session Recording)的新功能,该功能可以接收一个非结构化的SSH会话,并...

    FB客服
  • 利用 ebpf sockmap/redirection 提升 socket 性能(2020)

    本文翻译自 2020 年的一篇英文博客 How to use eBPF for accelerating Cloud Native applications[1...

    米开朗基杨
  • 性能工具之 Goreplay 安装及入门使用

    只需要在生产服务器上启动一个 gor 进程,它负责所有的工作包括监听、过滤和转发。它的设计遵循 Unix 设计哲学:一切都是由管道组成的,各种输入将数据复用为输...

    高楼Zee
  • 深入理解 Cilium 的 eBPF 收发包路径

    本文翻译自 2019 年 DigitalOcean 的工程师 Nate Sweet 在 KubeCon 的一篇分享: Understanding (and Tr...

    米开朗基杨
  • 张亦鸣 : eBPF 简史 (上篇)

    数日之前,笔者参加某一技术会议之时,为人所安利了一款开源项目,演讲者对其性能颇为称道,称其乃基于近年在内核中炙手可热的 eBPF 技术。

    Linuxer
  • 使用 BPF 自定义安全组

    上一篇文章阅读量比较多,看起来网络的主题比较受欢迎。这一篇文章我们继续探索 BPF 在网络领域的应用:使用 BPF 来实现安全组。

    ritchiechen
  • Iptables 介绍与使用

    连接跟踪是许多网络应用的基础。例如,Kubernetes Service、ServiceMesh sidecar、 软件四层负载均衡器 LVS/IPVS、Doc...

    Se7en258
  • 实例:面对未知环境的MySQL性能问题,如何诊断

    内容来源:2018 年 5 月 20 日,爱可生技术服务总监洪斌在“PHPCon China 2018 技术峰会”进行《MySQL性能诊断方法与实践》演讲分享。...

    IT大咖说
  • [译] 利用 eBPF 支撑大规模 K8S Service

    K8S 当前重度依赖 iptables 来实现 Service 的抽象,对于每个 Service 及其 backend pods,在 K8s 里会生成很多 ip...

    我是阳明
  • [译] 利用 eBPF 支撑大规模 K8s Service

    K8S 当前重度依赖 iptables 来实现 Service 的抽象,对于每个 Service 及其 backend pods,在 K8s 里会生成很多 ip...

    CNCF
  • BPF的可移植性和CO-RE (Compile Once – Run Everywhere)

    在上一篇文章中介绍了提高socket性能的几个socket选项,其中给出了几个源于内核源码树中的例子,如果选择使用内核树中的Makefile进行编译的话,可能会...

    charlieroro
  • 使用Cilium增强Istio|通过Socket感知BPF程序

    8月1日凌晨,Istio 1.0发布,已生产就绪! Cilium社区感谢所有Istio贡献者为此付出的巨大努力。我们很幸运能够参与社区活动,为Istio做出贡献...

    CNCF

扫码关注云+社区

领取腾讯云代金券