我没有使用 XDP_TX 接收数据包
I'm not receiving packets using XDP_TX
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__))
static inline __u16 csum_fold_helper(__u64 csum) {
int i;
#pragma unroll
for (i = 0; i < 4; i++) {
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__))
static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) {
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__))
static inline void ipv4_l4_csum(void* data_start, __u32 data_size,
__u64* csum, struct iphdr* iph) {
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md* ctx)
{
void* data_end = (void*)(long)ctx->data_end;
void* data = (void*)(long)ctx->data;
struct ethhdr* eth = data;
if (data + sizeof(*eth) > data_end) {
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP)) {
struct iphdr* iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end) {
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP) {
return XDP_PASS;
}
struct tcphdr* tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end) {
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000) {
return XDP_DROP;
}
if (tcph->dest == htons(65535)) {
unsigned char gateway[ETH_ALEN];
gateway[0] = 0x92; gateway[1] = 0x10;
gateway[2] = 0x95; gateway[3] = 0x86;
gateway[4] = 0x26; gateway[5] = 0xbf;
__builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
__builtin_memcpy(eth->h_dest, gateway, ETH_ALEN);
bpf_debug("MAC Source: %i:%i:%i", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
bpf_debug("%i:%i:%i\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);
bpf_debug("MAC Destin: %i:%i:%i", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
bpf_debug("%i:%i:%i\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
奇怪的是,我没有在目标服务器上接收到 TCP 数据包 *(147.135.76.254 | 4266428307),而且在本地服务器上,数据包也没有出现在 tcpdump -i eth0 dst port 65535
我做错了什么吗?如果是,我该如何修复代码。
目的是:在服务器端口 LOCAL:65535 上接收数据包,并重定向到 DESTINATION:65535
更新:
程序似乎运行正常,我收到消息“收到!”在猫 /sys/kernel/debug/tracing/trace_pipe
数据包没有到达目标服务器
在目标服务器 (Windows) 中,我是 运行 Wireshark,禁用了 TCP 校验和验证,这意味着中间没有阻止数据包的过滤器校验和无效,例如:
在源服务器 (linux) 上,我发送 hping3 147.135.76.254 -p 65535 --
badcksum 并在 wireshark(目标服务器)中接收所有数据包(具有无效校验和)
在源服务器 (XDP) 中,当我执行:tcpdump -i eth0 tcp 端口 65535 时,我没有收到任何数据包。
注意:我使用 ethtool -K eth0 tx off 来禁用卸载/chksum
如果我将 XDP_TX 更改为 XDP_PASS 我可以在 tcpdump 中接收此数据包(上面的命令):
14:38:10.964195 IP d2-2-us-east-va-1.39698 > 147.135.76.254.65535: Flags [S], seq 3962643128, win 14600, options [mss 1460,sackOK,TS val 2414158903 ecr 0, nop,wscale 9], 长度 0
在 ethtool -S eth0 中正确显示 rx/tx
如果我从“XDP_TX”更改为“XDP_PASS”,我会在 tcpdump 中收到此响应:135.148.232.155.58062 > 147.135.76.254.65535:Flags [ S]、cksum 0x41c3(正确)、seq 2996104997、win 14600、options [mss 1460、sackOK、TS val 2614058020 ecr 0、nop、wscale 9]、长度 0,这意味着我的 TCP 校验和和 IP 计算正常工作
我更新了正确通知 MAC 地址,但问题仍然存在。
执行的命令:
[root@d2-2-us-east-va-1 ~]# arp -a
_gateway (135.148.232.1) at 92:10:95:86:26:bf [ether] on eth0
[root@d2-2-us-east-va-1 ~]#猫/sys/class/net/eth0/address
fa:16:3e:0e:cf:a4
[root@d2-2-us-east-va-1 ~]# ifconfig
...(确认 mac 地址)
您没有更新以太网层的源和目标 MAC 地址。如果源 MAC 与配置的 NIC MAC 不匹配,某些 NIC,尤其是虚拟化的 NIC 将丢弃传出数据包。
如果您将数据包反射回本地网络上的同一台物理机器(本地机器或 router/default 网关),您可以简单地交换 src 和 dst 地址。
我更新了您的代码以添加此内容:
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum)
{
int i;
#pragma unroll
for (i = 0; i < 4; i++)
{
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__)) static inline void ipv4_csum(void *data_start, int data_size, __u64 *csum)
{
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__)) static inline void ipv4_l4_csum(void *data_start, __u32 data_size,
__u64 *csum, struct iphdr *iph)
{
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
{
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP))
{
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
{
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP)
{
return XDP_PASS;
}
struct tcphdr *tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end)
{
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000)
{
return XDP_DROP;
}
if (tcph->dest == htons(65535))
{
bpf_debug("Checksum Old: %i | %i\n", iph->check, tcph->check);
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
更改的行是:
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
请注意,如果您正在切换数据包(将其发送到不同的物理设备),这将不起作用,在这种情况下,您需要使用 ARP 来获得正确的 MAC 或对其进行硬编码。
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__))
static inline __u16 csum_fold_helper(__u64 csum) {
int i;
#pragma unroll
for (i = 0; i < 4; i++) {
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__))
static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) {
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__))
static inline void ipv4_l4_csum(void* data_start, __u32 data_size,
__u64* csum, struct iphdr* iph) {
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md* ctx)
{
void* data_end = (void*)(long)ctx->data_end;
void* data = (void*)(long)ctx->data;
struct ethhdr* eth = data;
if (data + sizeof(*eth) > data_end) {
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP)) {
struct iphdr* iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end) {
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP) {
return XDP_PASS;
}
struct tcphdr* tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end) {
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000) {
return XDP_DROP;
}
if (tcph->dest == htons(65535)) {
unsigned char gateway[ETH_ALEN];
gateway[0] = 0x92; gateway[1] = 0x10;
gateway[2] = 0x95; gateway[3] = 0x86;
gateway[4] = 0x26; gateway[5] = 0xbf;
__builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
__builtin_memcpy(eth->h_dest, gateway, ETH_ALEN);
bpf_debug("MAC Source: %i:%i:%i", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
bpf_debug("%i:%i:%i\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);
bpf_debug("MAC Destin: %i:%i:%i", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
bpf_debug("%i:%i:%i\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
奇怪的是,我没有在目标服务器上接收到 TCP 数据包 *(147.135.76.254 | 4266428307),而且在本地服务器上,数据包也没有出现在 tcpdump -i eth0 dst port 65535
我做错了什么吗?如果是,我该如何修复代码。
目的是:在服务器端口 LOCAL:65535 上接收数据包,并重定向到 DESTINATION:65535
更新:
程序似乎运行正常,我收到消息“收到!”在猫 /sys/kernel/debug/tracing/trace_pipe
数据包没有到达目标服务器
在目标服务器 (Windows) 中,我是 运行 Wireshark,禁用了 TCP 校验和验证,这意味着中间没有阻止数据包的过滤器校验和无效,例如:
在源服务器 (linux) 上,我发送 hping3 147.135.76.254 -p 65535 -- badcksum 并在 wireshark(目标服务器)中接收所有数据包(具有无效校验和)
在源服务器 (XDP) 中,当我执行:tcpdump -i eth0 tcp 端口 65535 时,我没有收到任何数据包。
注意:我使用 ethtool -K eth0 tx off 来禁用卸载/chksum
如果我将 XDP_TX 更改为 XDP_PASS 我可以在 tcpdump 中接收此数据包(上面的命令):
14:38:10.964195 IP d2-2-us-east-va-1.39698 > 147.135.76.254.65535: Flags [S], seq 3962643128, win 14600, options [mss 1460,sackOK,TS val 2414158903 ecr 0, nop,wscale 9], 长度 0在 ethtool -S eth0 中正确显示 rx/tx
如果我从“XDP_TX”更改为“XDP_PASS”,我会在 tcpdump 中收到此响应:135.148.232.155.58062 > 147.135.76.254.65535:Flags [ S]、cksum 0x41c3(正确)、seq 2996104997、win 14600、options [mss 1460、sackOK、TS val 2614058020 ecr 0、nop、wscale 9]、长度 0,这意味着我的 TCP 校验和和 IP 计算正常工作
我更新了正确通知 MAC 地址,但问题仍然存在。
执行的命令:
[root@d2-2-us-east-va-1 ~]# arp -a _gateway (135.148.232.1) at 92:10:95:86:26:bf [ether] on eth0
[root@d2-2-us-east-va-1 ~]#猫/sys/class/net/eth0/address fa:16:3e:0e:cf:a4
[root@d2-2-us-east-va-1 ~]# ifconfig ...(确认 mac 地址)
您没有更新以太网层的源和目标 MAC 地址。如果源 MAC 与配置的 NIC MAC 不匹配,某些 NIC,尤其是虚拟化的 NIC 将丢弃传出数据包。
如果您将数据包反射回本地网络上的同一台物理机器(本地机器或 router/default 网关),您可以简单地交换 src 和 dst 地址。
我更新了您的代码以添加此内容:
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum)
{
int i;
#pragma unroll
for (i = 0; i < 4; i++)
{
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__)) static inline void ipv4_csum(void *data_start, int data_size, __u64 *csum)
{
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__)) static inline void ipv4_l4_csum(void *data_start, __u32 data_size,
__u64 *csum, struct iphdr *iph)
{
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
{
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP))
{
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
{
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP)
{
return XDP_PASS;
}
struct tcphdr *tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end)
{
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000)
{
return XDP_DROP;
}
if (tcph->dest == htons(65535))
{
bpf_debug("Checksum Old: %i | %i\n", iph->check, tcph->check);
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
更改的行是:
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
请注意,如果您正在切换数据包(将其发送到不同的物理设备),这将不起作用,在这种情况下,您需要使用 ARP 来获得正确的 MAC 或对其进行硬编码。