Почему моя программа BPF_PROG_TYPE_CGROUP_SKB не работает в контейнере?

Я написал следующую программу eBPF для подсчета пакетов:

#include <linux/version.h>
#include <uapi/linux/bpf.h>

#include "include/bpf_map.h"
#include "include/bpf_helpers.h"

struct bpf_map_def SEC("maps/count") count_map = {
    .type = BPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(int),
    .value_size = sizeof(__u64),
    .max_entries = 1024,
};

SEC("cgroup/skb")
int count_packets(struct __sk_buff *skb) {
    char debug[] = "count_packets\n";
    bpf_trace_printk(debug, sizeof(debug));

    int packets_key = 0;
    __u64 *packets = 0;

    packets = bpf_map_lookup_elem(&count_map, &packets_key);
    if (packets == 0)
        return 0;

    *packets += 1;

    // allow access
    return 1;
}

char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;

У меня также есть компонент пользовательского пространства, который загружает программу как BPF_PROG_TYPE_CGROUP_SKB, прикрепляет ее к контрольной группе v2 (/sys/fs/cgroup/unified/foo), используя тип подключения BPF_CGROUP_INET_EGRESS, добавляет свой собственный PID в эту контрольную группу и начинает создавать сетевой трафик.

Когда я запускаю этот компонент пользовательского пространства вне контейнера, он работает, как и ожидалось, и я вижу, что моя программа вызывается, выполняя cat /sys/kernel/debug/tracing/trace_pipe.

Однако, когда я запускаю свою программу в контейнере, я не вижу никакого вывода.

Я запускаю контейнер следующим образом:

docker run -it \
        --privileged \
        --pid=host \
        --net=host \
        -v /sys/fs/cgroup/unified:/sys/fs/cgroup/unified \
        ${IMAGE}

Я использую хост-сеть и пространства имен PID, чтобы избежать любых потенциальных проблем, которые они могли бы вызвать в противном случае.

Почему моя программа не работает из контейнера?

uname -a: Linux ubuntu-bionic 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Вт, 12 февраля, 13:35:51 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux


person dippynark    schedule 12.04.2019    source источник


Ответы (1)


Это произошло потому, что докер использовал контроллеры net_prio и net_cls, которые перезаписывали данные, используемые для сопоставления cgroup2. Из здесь

В то время как userland может начать использовать net_prio или net_cls в любое время, после их использования сопоставление cgroup2 больше не работает.

Мое решение состояло в том, чтобы отключить эти контроллеры с помощью флага загрузки: cgroup_no_v1=net_prio,net_cls. Лучшим решением было бы просто запретить докеру их использовать, но я не мог понять, как это сделать.

person dippynark    schedule 13.04.2019
comment
Спасибо, столкнулся с такой же проблемой - person SPYFF; 04.08.2019