<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="http://gentoo-zh.org/extern.php?action=feed&amp;tid=871&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / Gentoo伯克利子系统之五:Systemtap BPF/BCC bpftrace 实践对比]]></title>
		<link>http://www.gentoo-zh.org/viewtopic.php?id=871</link>
		<description><![CDATA[Gentoo伯克利子系统之五:Systemtap BPF/BCC bpftrace 实践对比 最近发表的帖子。]]></description>
		<lastBuildDate>Sat, 13 Jul 2024 03:52:36 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Gentoo伯克利子系统之五:Systemtap BPF/BCC bpftrace 实践对比]]></title>
			<link>http://www.gentoo-zh.org/viewtopic.php?pid=991#p991</link>
			<description><![CDATA[<p>本篇文章通过一个案例，对systemtap、BPF/BCC、bpftrace三种不同类型的内核探测工具进行剖析和对比。这个程序就是简单对icmp_rcv函数，收到icmp报文，打印出对应的源IP地址和目的IP地址。</p><p>1. 使用BPF/BCC<br />1.1在centos8操作系统上安装对应的软件二进制包</p><div class="codebox"><pre><code>1）	安装kernel-devel包；
2）	安装dnf -y install bcc-tools</code></pre></div><p>1.2 源码包安装</p><p>dnf install -y bison cmake ethtool flex git iperf3 libstdc+±devel python3-netaddr python3-pip gcc gcc-c++ make zlib-devel elfutils-libelf-devel<br />dnf install -y clang clang-devel llvm llvm-devel llvm-static ncurses-devel<br />dnf -y install netperf<br />pip3 install pyroute2<br />ln -s /usr/bin/python3 /usr/bin/python<br />dnf -y install openssl<br />git clone <a href="https://github.com/iovisor/bcc.git" rel="nofollow">https://github.com/iovisor/bcc.git</a><br />mkdir bcc_build<br />cmake …/bcc -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_LLVM_SHARED=1<br />cd …/&amp;&amp; make -j10<br />make install<br />1.3 程序示例</p><p>使用bpf/bcc需要的内核版本最少是4.10以上。<br />使用下面的bcc代码，</p><br /><div class="codebox"><pre class="vscroll"><code>#!/usr/bin/env python3.6

from __future__ import print_function
from bcc import BPF
from bcc.utils import printb

bpf_text = &quot;&quot;&quot;
#include &lt;uapi/linux/ptrace.h&gt;
#include &lt;net/sock.h&gt;
#include &lt;bcc/proto.h&gt;
#include &lt;uapi/linux/icmp.h&gt;
#include &lt;linux/icmp.h&gt;
#include &lt;uapi/linux/ip.h&gt;
#include &lt;linux/ip.h&gt;


static inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb)
{
    // unstable API. verify logic in ip_hdr() -&gt; skb_network_header().
    return (struct iphdr *)(skb-&gt;head + skb-&gt;network_header);
}

int icmp_rcv_cb(struct pt_regs *ctx, struct sk_buff *skb)
{
            struct icmphdr *icmph ;
            struct iphdr *iph = skb_to_iphdr(skb);
            bpf_trace_printk(&quot;ipsrc:%pI4  ipdst:%pI4 \\n&quot;,&amp;iph-&gt;saddr, &amp;iph-&gt;daddr);
            icmph = (struct icmphdr *)skb-&gt;data;
            bpf_trace_printk(&quot;devname:%s ----- icmp_type:%d  \\n&quot;,skb-&gt;dev-&gt;name, icmph-&gt;type);
            return 0;
};
&quot;&quot;&quot;
# initialize BPF
b = BPF(text=bpf_text)
b.attach_kprobe(event=&quot;icmp_rcv&quot;, fn_name=&quot;icmp_rcv_cb&quot;)
#end format output
while 1:
    # Read messages from kernel pipe
    (task, pid, cpu, flags, ts, msg) = b.trace_fields()
    print(&quot;task:%s pid: %d %s &quot; % (task, pid, msg))
#b.trace_print()</code></pre></div><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/3230363645.png" alt="FluxBB bbcode 测试" /></span></p><p>2. Systemtap<br />2.1安装 systemtap</p><p>在centos8 上直接使用yum安装 yum install systemtap systemtap-runtime<br />2.2 Stap-prep</p><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/1950940485.png" alt="FluxBB bbcode 测试" /></span></p><p>通过在http://debuginfo.centos.org/8/x86_64/Packages/下载安装完debuginfo包后，执行stap-prep命令</p><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/736141600.png" alt="FluxBB bbcode 测试" /></span></p><p>简单测试可以运行成功</p><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/4473753.png" alt="FluxBB bbcode 测试" /></span></p><p>2.3 程序示例</p><p>下面是systemtap的方式对icmp_rcv函数的探测，对本机收到的ICMP报文打印出，对应的源IP和目的IP地址。</p><br /><div class="codebox"><pre class="vscroll"><code>stap -g icmp_systemtap.stp
#!/usr/bin/stap -g
%{
#include &lt;linux/kernel.h&gt;
#include &lt;linux/net.h&gt;
#include &lt;linux/skbuff.h&gt;
#include &lt;net/ip.h&gt;
#include &lt;linux/module.h&gt;
#include &lt;uapi/linux/if_packet.h&gt;
#include &lt;linux/fdtable.h&gt;
#include &lt;net/icmp.h&gt;

        static inline void ip2str(char *to,unsigned int from)
        {
                int size = snprintf(to,16,&quot;%pI4&quot;,&amp;from);
                to[size] = &#039;\0&#039;;
         }
%}
function get_icmp_packet_info:string(skb:long)
%{
        int ret = -1;
        struct sk_buff *skb = (struct sk_buff *)STAP_ARG_skb;
        struct iphdr *ip_header;
        unsigned int src_ip_1 = 0;
        unsigned int  dst_ip_1 = 0;
        char src_ip[16],dst_ip[16];
        struct icmphdr *icmph;

        if(!skb)
        {
                goto EXIT_F;
        }

        ip_header = (struct iphdr *)skb_network_header(skb);


        if(!ip_header)
        {
                goto EXIT_F;
        }

        src_ip_1 = (unsigned int)ip_header-&gt;saddr;
        dst_ip_1 = (unsigned int)ip_header-&gt;daddr;
        ip2str(src_ip,src_ip_1);
        ip2str(dst_ip,dst_ip_1);

        icmph = icmp_hdr(skb);
        if(icmph-&gt;type == 0)
        {

                goto ECHO_ICMP;
        }
        if(icmph-&gt;type == 8)
        {
                goto REPLY_ICMP;
        }

EXIT_F:
        snprintf(STAP_RETVALUE,MAXSTRINGLEN,&quot;ERROR:src_ip:%s dst_ip:%s&quot;,src_ip,dst_ip);
ECHO_ICMP:
        snprintf(STAP_RETVALUE,MAXSTRINGLEN,&quot;ECHO_ICMP:src_ip:%s dst_ip:%s&quot;,src_ip,dst_ip);
REPLY_ICMP:
        snprintf(STAP_RETVALUE,MAXSTRINGLEN,&quot;REPLY_ICMP:src_ip:%s dst_ip:%s&quot;,src_ip,dst_ip);
%}

global locations

probe begin { printf(&quot;Monitoring for recv icmp packets\n&quot;) }
probe end { printf(&quot;Stropping monitoring  packets\n&quot;) }

probe kernel.function(&quot;icmp_rcv&quot;).return
{
        printf(&quot;%s\n&quot;,get_icmp_packet_info($skb))
        iphdr = __get_skb_iphdr($skb)
        saddr = format_ipaddr(__ip_skb_saddr(iphdr), @const(&quot;AF_INET&quot;))
        daddr = format_ipaddr(__ip_skb_daddr(iphdr), @const(&quot;AF_INET&quot;))
        printf(&quot;src_ip:%s  dst_ip:=%s\n&quot;,saddr,daddr);

}

probe timer.sec(5)
{
        exit ()
}</code></pre></div><p>下面是运行后的测试结果：</p><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/3301897051.png" alt="FluxBB bbcode 测试" /></span></p><p>3. bpftrace<br />3.1 安装软件</p><p>yum -y install bpftrace<br />3.2 程序示例</p><p>bpftrace是使用自定义单行代码和简短脚本的临时工具的不错的选择，而BCC是复杂工具和守护程序的理想选择、bpftrace和BCC都是BPF的前端工具。</p><br /><div class="codebox"><pre class="vscroll"><code>在这里插入代码片#!/usr/bin/bpftrace

#include &lt;linux/skbuff.h&gt;
#include &lt;linux/ip.h&gt;
#include &lt;linux/udp.h&gt;
#include &lt;linux/socket.h&gt;

BEGIN
{
        printf(&quot;Tracing icmp rev.Hit  Ctrl-C end.\n&quot;);
}

kprobe:icmp_rcv
{
        $skb = (struct sk_buff *)arg0;

        $iph = (struct iphdr*)($skb-&gt;head + $skb-&gt;network_header);
        $src_ip = ntop(AF_INET,$iph-&gt;saddr);
        $dst_ip = ntop(AF_INET,$iph-&gt;daddr);

        printf(&quot;src_ip:%s  ----&gt; dst_ip:%s\n&quot;,$src_ip,$dst_ip);
}

END
{
        printf(&quot;OVER  bye!!&quot;)
}</code></pre></div><p>运行结果如下：</p><p><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/05/2335592397.png" alt="FluxBB bbcode 测试" /></span></p><p>4 总结</p><p>&#160; &#160; 使用systemtap工具跟踪内核需要安装和内核对应版本的debuginfo包，systemtap作为老牌的内核跟踪工具，可以支持比较老的内核版本，对于现有存量的内核定位跟踪有明显的优势。<br />&#160; &#160; BPF/BCC作为新的内核跟踪工具，需要较新的内核版本，最少是4.10版本，最好是4.19版本的内核。<br />&#160; &#160; 通过运行对比发现，编译和运行BPF/BCC的代码比systemtap的代码要快的多。<br />&#160; &#160; BPF有各类安全检查，避免在内核跟踪过程中产生panic，systemtap没有此类的安全检查，需要开发者在开发systemtap程序时，保证代码的安全性。<br />&#160; &#160; Bpftrace作为内核跟踪的一种工具，特别适合简单的内核跟踪，适合一条命令搞定的内核跟踪，bpftrace也有自己的一套语法体系可用。<br />&#160; &#160; 各种不同类型的内核探测跟踪技术，适合不同类型的场景，在实际使用中可选择适合自己的方式。</p><p>参考文献：<br /><a href="https://lwn.net/Articles/852112/" rel="nofollow">https://lwn.net/Articles/852112/</a></p>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Sat, 13 Jul 2024 03:52:36 +0000</pubDate>
			<guid>http://www.gentoo-zh.org/viewtopic.php?pid=991#p991</guid>
		</item>
	</channel>
</rss>
