что не так с вызовом функции bpf_csum_diff?

Хочу как-то перенаправить пакеты с помощью ebpf. Взял пример из документации Cilium: Реализация: прокси через bpf

вот пример моего макроса в bpf_helpers:

...
static int (*bpf_csum_diff)(void *from, __u64 from_size, void *to, __u64 to_size, __u64 seed) = (void*) // NOLINT
     BPF_FUNC_csum_diff;
...

вот код самого прокси-скрипта:

#include <linux/bpf.h>
#include "../main/bpf_helpers.h"
#include "../main/bpf_endian.h"
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <stdlib.h>
#include "../main/utils_helpers.h"
#include <stddef.h>
#include <linux/pkt_cls.h>

SEC("socket_filter")
int proxy(struct __sk_buff *skb)
{
    const __be32 cluster_ip = 0x846F070A; // 10.7.111.132
    const __be32 pod_ip = 0x0529050A;     // 10.5.41.5

    const int l3_off = ETH_HLEN;    // IP header offset
    const int l4_off = l3_off + 20; // TCP header offset: l3_off + sizeof(struct iphdr)
    __be32 sum;                     // IP checksum

    void *data = (void *)(long)skb->data;
    void *data_end = (void *)(long)skb->data_end;
    if (data_end < data + l4_off) { // not our packet
        return TC_ACT_OK;
    }

    struct iphdr *ip4 = (struct iphdr *)(data + l3_off);
    if (ip4->daddr != cluster_ip || ip4->protocol != IPPROTO_TCP /* || tcp->dport == 80 */) {
        return TC_ACT_OK;
    }

    // DNAT: cluster_ip -> pod_ip, then update L3 and L4 checksum
    sum = bpf_csum_diff((void *)&ip4->daddr, 4, (void *)&pod_ip, 4, 0);
    bpf_csum_diff((void *)&ip4->daddr, 4, (void *)&pod_ip, 4, 0);
    bpf_skb_store_bytes(skb, l3_off + offsetof(struct iphdr, daddr), (void *)&pod_ip, 4, 0);
    bpf_l3_csum_replace(skb, l3_off + offsetof(struct iphdr, check), 0, sum, 0);
    bpf_l4_csum_replace(skb, l4_off + offsetof(struct tcphdr, check), 0, sum, BPF_F_PSEUDO_HDR);

    return TC_ACT_OK;
}

char __license[] SEC("license") = "GPL";

Вот код самого прокси-скрипта:

...
2020/06/02 21:58:17 sf.Load(): %vebpf_prog_load() failed: 0: (b7) r2 = 86574346
1: (63) *(u32 *)(r10 -4) = r2
2: (61) r2 = *(u32 *)(r1 +80)
invalid bpf_context access off=80 size=4
processed 3 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
...

Подскажите, как правильно проксировать пакеты на другой порт и другой ip в докере?


person Alexandr Ershov    schedule 02.06.2020    source источник
comment
Это странно. Верификатор, кажется, жалуется на skb->data_end, что, насколько я вижу, верно. Как вы загрузили и подключили эту программу?   -  person pchaigno    schedule 02.06.2020
comment
Вы загружаете свою программу как socket_filter, у которого нет прямого пакетного доступа. См. этот вопрос и его ответ.   -  person Qeole    schedule 02.06.2020
comment
возможен пересчет контрольной суммы пакета bpf_csum_diff((void*)&ip4->daddr,4,(void*)&pod_ip,4,0); используя __sk_buff без доступа к пакету? Качаю программу с помощью goebpf, поэтому не могу загрузить программу в другой раздел.   -  person Alexandr Ershov    schedule 03.06.2020
comment
Я не уверен, что понял ваш вопрос. Почему бы не прикрепить вашу программу в качестве фильтра TC вместо фильтра сокетов? Вероятно, это было бы более гибким и, возможно, лучше подходящим для того, чего вы пытаетесь достичь?   -  person Qeole    schedule 03.06.2020