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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2023-08-13 ovn打通跨网段和同网段通信