linux-kernel - bpf_csum_diff 函数调用有什么问题?
问题描述
我想以某种方式使用 ebpf 重定向数据包。从 Cilium 文档中举了一个例子:Implementation: proxy via 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
...
告诉我如何正确地将数据包代理到 docker 中的另一个端口和另一个 ip?
解决方案
推荐阅读
- vue.js - 如何以编程方式向 Vue 组件添加道具?
- vue.js - 如何删除vue表中的整列?
- php - 如何获取我在表中选择的数据行的 ID?
- jenkins - jenkins如何将liferay7 portlet部署到远程服务器?
- visual-c++ - 由于 -Ot 标志导致的 Visual C++ 2017 链接错误?
- sql - 如何在 django 中使用 sql 语句?
- python - 连接到松弛
- .net-core - 在没有 nuget.org 的情况下确定 nuget 包是否与 .net 核心兼容的最佳方法是什么?
- php - Laravel 5.3:违反完整性约束(适用于某些设置)
- r - R:函数在返回 NULL 时改变打印行为