如何在kprobe程序中使用enum tcp mib定义?

问题描述

在这里,我试图编写一个程序(kprobe)以在BPF Performance Tools bpftrace一书中包含枚举tcp mib(如@tcp_states)。枚举tcp mib位于'/include/uapi/linux/snmp.h'中:

#!/usr/local/bin/bpftrace

#include <net/net_namespace.h>
#include <net/netns/mib.h>
#include <net/snmp.h>
#include <uapi/linux/snmp.h>

#define TCP_MIB_MAX              __TCP_MIB_MAX

kprobe:sk_alloc
{
        $net = (struct net *)arg0;
        $mi = (struct netns_mib *)$net->mib;
        $ib = (struct tcp_mib *)$mi;
        
        @mib[1] = "TCP_MIB_NUM";
        @mib[2] = "TCP_MIB_RTOALGORITHM";
        @mib[3] = "TCP_MIB_RTOMIN";
        @mib[4] = "TCP_MIB_RTOMAX;
        @mib[5] = "TCP_MIB_MAXCONN";        
        @mib[6] = "TCP_MIB_ACTIVEOPENS";
        @mib[7] = "TCP_MIB_PASSIVEOPENS";
        @mib[8] = "TCP_MIB_ATTEMPTFAILS";
        @mib[9] = "TCP_MIB_ESTABRESETS";
        @mib[10] = "TCP_MIB_CURRESTAB";
        @mib[11] = "TCP_MIB_INSEGS";
        @mib[12] = "TCP_MIB_OUTSEGS";
        @mib[13] = "TCP_MIB_RETRANSSEGS";
        @mib[14] = "TCP_MIB_INERRS";
        @mib[15] = "TCP_MIB_OUTRSTS";
        @mib[16] = "TCP_MIB_CSUMERRORS";

        printf("-------------------------------\n");
        time();
        printf("sk_alloc: %s pid: %d\n",comm,pid);
        printf("\n");
        printf("$ib: %u\n",$ib->miss[6]);

        $mib_s = $ib->mibs[TCP_MIB_MAX];
        $mib_str = @mib[$mib_s];

        printf("TCP mib is: %s\n",$mib_str);

        clear(@mib);
}
      

当我尝试运行它时,输出为:

the index 94779518808448 is out of bounds for array of size 16

然后我尝试代替TCP_MIB_MAX放置特定的数组位置,例如5,(我修改了上面的代码):

$mib_s = $ib->mibs[5];

当我尝试运行它时,输出为:

...

-----------------------------
21:40:15
sk_alloc: systemd-logind pid: 920

$ib: 1516359680
TCP mib is:

-----------------------------
21:40:15
sk_alloc: systemd-logind pid: 920

$ib: 1516359680
TCP mib is:

...

为什么不显示TCP mib?并在输出中什么也不显示? 如何正确使用数组显示@mib?

解决方法

TCP_MIB_MAX__TCP_MIB_MAX等于16,等于内核中struct tcp_mib的大小:

enum
{
    TCP_MIB_NUM = 0,TCP_MIB_RTOALGORITHM,/* RtoAlgorithm */
    TCP_MIB_RTOMIN,/* RtoMin */
    TCP_MIB_RTOMAX,/* RtoMax */
    TCP_MIB_MAXCONN,/* MaxConn */
    TCP_MIB_ACTIVEOPENS,/* ActiveOpens */
    TCP_MIB_PASSIVEOPENS,/* PassiveOpens */
    TCP_MIB_ATTEMPTFAILS,/* AttemptFails */
    TCP_MIB_ESTABRESETS,/* EstabResets */
    TCP_MIB_CURRESTAB,/* CurrEstab */
    TCP_MIB_INSEGS,/* InSegs */
    TCP_MIB_OUTSEGS,/* OutSegs */
    TCP_MIB_RETRANSSEGS,/* RetransSegs */
    TCP_MIB_INERRS,/* InErrs */
    TCP_MIB_OUTRSTS,/* OutRsts */
    TCP_MIB_CSUMERRORS,/* InCsumErrors */   // == 15
    __TCP_MIB_MAX                                    // == 16
};

#define TCP_MIB_MAX __TCP_MIB_MAX
struct tcp_mib {
    unsigned long   mibs[TCP_MIB_MAX];
};

(include / uapi / linux / snmp.h和include / net / snmp.h)

但是,由于数组是从0开始索引的,因此在索引TCP_MIB_MAX - 1时只能上移到$ib->mibs。这就是为什么您抱怨越界索引的原因。

然后,当您选择较小的索引时,可以按预期访问数组项。但我不确定您要做什么:

        $mib_s = $ib->mibs[5];
        $mib_str = @mib[$mib_s];

在我看来,您似乎正在从MIB($ib->mibs[TCP_MIB_ACTIVEOPENS])中读取值,该值可能提供任何值,可能很大,并且可能为null(我怀疑这里就是这种情况)。然后您将该值用作...在@mib中的索引?因此,如果计数器为10k,则尝试获取16个大小的数组的第10,000个单元格?我想在您的情况下,该值为0,所以您正在做$mib_str = @mib[0],这很可能是空字符串,因为您从未为@mib[0]设置值。

要解决所有这些问题,我将从为@mib数组使用正确的索引(从0到15)开始,以避免任何混乱。然后,您可能需要重新考虑要打印的内容,但是我不确定上面的两行是您想要的。