文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

我们一起聊聊 TCP 跟踪点

2024-12-01 01:29

关注
# perf list 'tcp:*' 'sock:inet*'

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

tcp:tcp_destroy_sock [Tracepoint event]
tcp:tcp_probe [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]

sock:inet_sock_set_state [Tracepoint event]

这包括一个多功能的:袜子:inet_sock_set_state。它可用于跟踪内核何时更改 TCP 会话的状态,例如从TCP_SYN_SENT更改为TCP_ESTABLISHED。一个例子是我在开源bcc集合中的tcplife工具:

# tcplife
PID COMM LADDR LPORT RADDR RPORT TX_KB RX_KB MS
22597 recordProg 127.0.0.1 46644 127.0.0.1 28527 0 0 0.23
3277 redis-serv 127.0.0.1 28527 127.0.0.1 46644 0 0 0.28
22598 curl 100.66.3.172 61620 52.205.89.26 80 0 1 91.79
22604 curl 100.66.3.172 44400 52.204.43.121 80 0 1 121.38
22624 recordProg 127.0.0.1 46648 127.0.0.1 28527 0 0 0.22
3277 redis-serv 127.0.0.1 28527 127.0.0.1 46648 0 0 0.27
[...]

我在这个跟踪点存在之前编写了 tcplife,所以我不得不使用 tcp_set_state() 内核函数的 kprobes(内核动态跟踪)。这有效,但它依赖于各种内核实现细节,这些细节可能会从一个内核版本更改为下一个内核版本。为了保持 tcplife 正常工作,每次内核更改时都需要包含不同的代码,这将变得难以维护和增强。想象一下,需要在几个不同的内核版本上测试更改,因为 tcplife 为每个版本都有特殊的代码!

跟踪点被认为是一个“稳定的API”,因此它们的详细信息不应该从一个内核版本更改为下一个内核版本,从而使使用它们的程序更容易维护。我故意说“不应该”,因为我认为这些是“尽最大努力”而不是“一成不变的”。如果它们被认为是一成不变的,那么说服内核维护者接受新的跟踪点将更加困难(有充分的理由)。举个例子:tcp:tcp_set_state是在 4.15 中添加的,然后在 4.16 中添加了sock:inet_sock_set_state。由于袜子是超集,因此 tcp 在 4.16 中被禁用,将被移除。我们尽量避免像这样更改跟踪点,但在这种情况下,它是短暂的,并且在任何人使用它之前就被删除了。

无论如何,tcplife 并不是使用跟踪点的一个很好的例子,因为它在三个地方(tx 和 rx 字节,以及跟踪点上尽力而为的进程上下文)超出了跟踪点 API,因此它可能仍然需要一些维护。但这是对 kprobes 版本的一个很大的改进,其他工具只能坚持使用跟踪点 API。

显示sock:inet_sock_set_state的另一种方法是使用 Sasha Goldshtein 的 bcc 跟踪工具将其与 tcp_set_state() 上的 kprobes 进行比较。第一个命令使用 kprobes,第二个命令使用跟踪点:

# trace -t -I net/sock.h 'p::tcp_set_state(struct sock *sk) "%llx: %d -> %d", sk, sk->sk_state, arg2'
TIME PID TID COMM FUNC -
2.583525 17320 17320 curl tcp_set_state ffff9fd7db588000: 7 -> 2
2.584449 0 0 swapper/5 tcp_set_state ffff9fd7db588000: 2 -> 1
2.623158 17320 17320 curl tcp_set_state ffff9fd7db588000: 1 -> 4
2.623540 0 0 swapper/5 tcp_set_state ffff9fd7db588000: 4 -> 5
2.623552 0 0 swapper/5 tcp_set_state ffff9fd7db588000: 5 -> 7
^C
# trace -t 't:sock:inet_sock_set_state "%llx: %d -> %d", args->skaddr, args->oldstate, args->newstate'
TIME PID TID COMM FUNC -
1.690191 17308 17308 curl inet_sock_set_state ffff9fd7db589800: 7 -> 2
1.690798 0 0 swapper/24 inet_sock_set_state ffff9fd7db589800: 2 -> 1
1.727750 17308 17308 curl inet_sock_set_state ffff9fd7db589800: 1 -> 4
1.728041 0 0 swapper/24 inet_sock_set_state ffff9fd7db589800: 4 -> 5
1.728063 0 0 swapper/24 inet_sock_set_state ffff9fd7db589800: 5 -> 7
^C

两者都显示相同的输出。供参考:

1: TCP_ESTABLISHED

2: TCP_SYN_SENT

3: TCP_SYN_RECV

4: TCP_FIN_WAIT1 5: TCP_FIN_WAIT2 6: TCP_TIME_WAIT

7: TCP_CLOSE

8:TCP_CLOSE_WAIT

我知道,我知道,我应该把它添加为查找哈希,然后......过了一会儿,这是我刚刚为密件抄送贡献的一个新工具 - tcpstate,它进行翻译,并显示每个州的持续时间:

# tcpstates
SKADDR C-PID C-COMM LADDR LPORT RADDR RPORT OLDSTATE -> NEWSTATE MS
ffff9fd7e8192000 22384 curl 100.66.100.185 0 52.33.159.26 80 CLOSE -> SYN_SENT 0.000
ffff9fd7e8192000 0 swapper/5 100.66.100.185 63446 52.33.159.26 80 SYN_SENT -> ESTABLISHED 1.373
ffff9fd7e8192000 22384 curl 100.66.100.185 63446 52.33.159.26 80 ESTABLISHED -> FIN_WAIT1 176.042
ffff9fd7e8192000 0 swapper/5 100.66.100.185 63446 52.33.159.26 80 FIN_WAIT1 -> FIN_WAIT2 0.536
ffff9fd7e8192000 0 swapper/5 100.66.100.185 63446 52.33.159.26 80 FIN_WAIT2 -> CLOSE 0.006
^C

我在 Linux 4.16 上演示了这一点,此前 Yafang Shao 编写了一个增强功能来显示所有状态转换,而不仅仅是内核实现的状态转换。这是它在 4.15 上的样子:

 trace -I net/sock.h -t 'p::tcp_set_state(struct sock *sk) "%llx: %d -> %d", sk, sk->sk_state, arg2'
TIME PID TID COMM FUNC -
3.275865 29039 29039 curl tcp_set_state ffff8803a8213800: 7 -> 2
3.277447 0 0 swapper/1 tcp_set_state ffff8803a8213800: 2 -> 1
3.786203 29039 29039 curl tcp_set_state ffff8803a8213800: 1 -> 8
3.794016 29039 29039 curl tcp_set_state ffff8803a8213800: 8 -> 7
^C
# trace -t 't:tcp:tcp_set_state "%llx: %d -> %d", args->skaddr, args->oldstate, args->newstate'
TIME PID TID COMM FUNC -
2.031911 29042 29042 curl tcp_set_state ffff8803a8213000: 7 -> 2
2.035019 0 0 swapper/1 tcp_set_state ffff8803a8213000: 2 -> 1
2.746864 29042 29042 curl tcp_set_state ffff8803a8213000: 1 -> 8
2.754193 29042 29042 curl tcp_set_state ffff8803a8213000: 8 -> 7

回到 4.16,这是通过 bcc 的 tplist 工具提供的带有参数的当前跟踪点列表:

# tplist -v 'tcp:*'
tcp:tcp_retransmit_skb
const void * skbaddr;
const void * skaddr;
__u16 sport;
__u16 dport;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];
tcp:tcp_send_reset
const void * skbaddr;
const void * skaddr;
__u16 sport;
__u16 dport;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];
tcp:tcp_receive_reset
const void * skaddr;
__u16 sport;
__u16 dport;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];
tcp:tcp_destroy_sock
const void * skaddr;
__u16 sport;
__u16 dport;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];
tcp:tcp_retransmit_synack
const void * skaddr;
const void * req;
__u16 sport;
__u16 dport;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];
tcp:tcp_probe
__u8 saddr[sizeof(struct sockaddr_in6)];
__u8 daddr[sizeof(struct sockaddr_in6)];
__u16 sport;
__u16 dport;
__u32 mark;
__u16 length;
__u32 snd_nxt;
__u32 snd_una;
__u32 snd_cwnd;
__u32 ssthresh;
__u32 snd_wnd;
__u32 srtt;
__u32 rcv_wnd;
# tplist -v sock:inet_sock_set_state
sock:inet_sock_set_state
const void * skaddr;
int oldstate;
int newstate;
__u16 sport;
__u16 dport;
__u16 family;
__u8 protocol;
__u8 saddr[4];
__u8 daddr[4];
__u8 saddr_v6[16];
__u8 daddr_v6[16];

添加的第一个TCP跟踪点是Cong Wang(Twitter)的tcp:tcp_retransmit_skb。他引用了我来自perf-tools的基于kprobe的tcpretrans工具作为示例消费者。Song Liu(Facebook)又增加了五个跟踪点,包括tcp:tcp_set_state现在是sock:inet_sock_set_state。感谢 Cong 和 Song,以及 David S. Miller(网络维护者)接受这些内容,并对正在进行的 tcp 跟踪点工作提供反馈。

在开发过程中,我与 Song(和 Alexei Starovoitov)讨论了最近添加的内容,所以我已经知道了它们存在的原因及其用途。当前 TCP 跟踪点的一些粗略说明:

我可以想象这些 TCP 跟踪点将是多么有用,因为我多年前设计和使用了类似的跟踪点:我在CEC2006 上演示的DTrace TCP 提供程序。我最初将TCP状态更改拆分为每个状态的探针,但是当它合并时,它变成了一个单独的tcp:::状态更改探针,就像我们现在通过袜子跟踪点在Linux中一样。

下一步是什么?tcp:tcp_send和tcp:tcp_receive的跟踪点可能很方便,但必须特别注意它们可能增加的微小开销(启用和特别禁用),因为发送/接收可能是一个非常频繁的活动。错误条件的更多跟踪点也很有用,例如连接拒绝路径,这可能有助于分析 DoS 攻击。

如果您对添加 TCP 跟踪点感兴趣,我建议您首先编写一个 kprobe 解决方案作为概念验证,并获得一些生产经验。这就是我之前的kprobe工具所扮演的角色。kprobe 解决方案将显示跟踪点是否有用,如果是,则有助于将其包含在 Linux 内核维护者中。

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯