#tcp #mib #kprobe #bcc-bpf
#tcp #МиБ #kprobe #bcc-bpf
Вопрос:
Здесь я попытался написать программу (kprobe) для включения enum tcp mib, например @tcp_states, в книге BPF Performance Tools bpftrace. Перечисляемый mib tcp находится в / 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: %dn", comm, pid);
printf("n");
printf("$ib: %un", $ib->miss[6]);
$mib_s = $ib->mibs[TCP_MIB_MAX];
$mib_str = @mib[$mib_s];
printf("TCP mib is: %sn", $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?
Ответ №1:
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];
};
(включить /uapi/linux/snmp.h и включить /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
? Итак, если счетчик равен 10 кб, вы пытаетесь взять 10000-ю ячейку массива размером 16? Я полагаю, в вашем случае значение равно 0, поэтому вы делаете $mib_str = @mib[0]
, что, вероятно, является пустой строкой, потому что вы никогда не устанавливали значение @mib[0]
.
Чтобы исправить все это, я бы начал с использования правильных индексов (от 0 до 15) для @mib
массива, чтобы избежать путаницы. Тогда вам, вероятно, нужно переосмыслить то, что вы пытаетесь точно напечатать, но я не уверен, что две строки выше — это то, что вы хотите.