eBPF 代答arp请求

eBPF代答veth口arp请求

在cilium中,eBPF tc ingress负责代答容器网卡的arp请求,回复的mac地址是容器网卡对端veth口mac地址,与当前逻辑类似,这里只是回复了假mac。
在kube-ovn中,ovs br-int网桥上xxx_h负责响应容器网卡的arp请求,没有geneve arp请求场景。

Ubuntu 23.10/6.5.0-44-generic

1. 创建包含容器网卡的veth对

ip netns add ns
ip link add veth0 type veth peer name veth1
ip link set veth1 netns ns
ip netns exec ns ip addr add 1.1.1.1/24 dev veth1
ip netns exec ns ip link set dev veth1 up
ip link set dev veth0 up

2. 加载eBPF程序到veth口

clang -c arp/arp-resp.c -o arp/arp-resp.o -target bpf -O2 -g
tc qdisc del dev veth0 clsact
tc qdisc add dev veth0 clsact
tc filter add dev veth0 ingress bpf da obj arp/arp-resp.o sec tc

clsact是假qdisc,只用于执行加载的filter eBPF程序。
tc上加上da表示tc eBPF程序根据TC_ACT_OK等返回值决定转发逻辑,而不是由action关键字来决定。

failed to resolve CO-RE relocation <byte_off> [24] struct arphdr.arp_data.arp_tha.addr_bytes (0:5:2:0 @ offset 20)

原因是参考的dpdk-stable-20.11.1中arp数据结构与内核不匹配。
dpdk-stable-20.11.1 lib/librte_net/rte_arp.h

参考cilium,提取关键部分

headers/arp.h

#include "vmlinux.h"
#define ETH_ALEN 6
#ifndef __packed
# define __packed __attribute__((packed))
#endif
struct arp_eth {
unsigned char ar_sha[ETH_ALEN];
__be32 ar_sip;
unsigned char ar_tha[ETH_ALEN];
__be32 ar_tip;
} __packed;

arp/arp-resp.c

#include "../headers/arp.h"
#include "../headers/bpf_endian.h"
#include "../headers/bpf_helpers.h"
#define TC_ACT_SHOT 2
#define TC_ACT_OK 0
#define ETH_P_IP 0x0800
#define ETH_P_ARP 0x0806
#define ETH_ALEN 6
#define ARPOP_REQUEST 1
#define ARPOP_REPLY 2
#ifndef memcpy
#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n))
#endif
char __license[] SEC("license") = "Dual MIT/GPL";
SEC("tc")
int tc_resp_arp(struct __sk_buff *skb)
{
void *data_end = (void *)(long)skb->data_end;
void *data = (void *)(long)skb->data;
struct ethhdr *eth_hdr = data;
if ((void *)eth_hdr + sizeof(*eth_hdr) > data_end)
{
return TC_ACT_OK;
}
if (eth_hdr->h_proto != bpf_htons(ETH_P_ARP))
{
return TC_ACT_OK;
}
struct arphdr *arp_hdr = (void *)eth_hdr + sizeof(*eth_hdr);
if ((void *)arp_hdr + sizeof(*arp_hdr) > data_end)
{
return TC_ACT_OK;
}
if (arp_hdr->ar_op != bpf_htons(ARPOP_REQUEST))
{
return TC_ACT_OK;
}
struct arp_eth *arpe = (void *)arp_hdr + sizeof(*arp_hdr);
if ((void *)arpe + sizeof(*arpe) > data_end)
{
return TC_ACT_OK;
}
// 请求改成响应
arp_hdr->ar_op = bpf_htons(ARPOP_REPLY);
// 交换源ip和目的ip
__u32 tmp = arpe->ar_sip;
arpe->ar_sip = arpe->ar_tip;
arpe->ar_tip = tmp;
// 更新以太网头和arp头mac
unsigned char mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xee};
for (int i = 0; i < ETH_ALEN; i++)
{
eth_hdr->h_dest[i] = eth_hdr->h_source[i];
eth_hdr->h_source[i] = mac[i];
arpe->ar_tha[i] = eth_hdr->h_source[i];
arpe->ar_sha[i] = mac[i];
}
// skb发回veth口
return bpf_redirect(skb->ifindex, BPF_ANY);
}

arp请求报文

3. 测试arp请求和响应

ip netns exec ns arping 1.1.1.2

posted on   王景迁  阅读(47)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2023-08-13 ovn打通跨网段和同网段通信
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示