简体   繁体   English

XDP 程序未捕获所有入口数据包

[英]XDP program not capturing all ingress packets

The following XDP program does not capture all ingress XDP packets.以下 XDP 程序不会捕获所有入口 XDP 数据包。 I store the source IP in a hash table as the key and value as the number of times that IP is seen.我将源 IP 存储在 hash 表中作为键和值作为看到 IP 的次数。

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <arpa/inet.h>

struct addr_desc_struct {
    __u32 src_ip;
};

struct bpf_map_def SEC("maps") addr_map = {
    .type = BPF_MAP_TYPE_LRU_HASH,
    .key_size = sizeof(struct addr_desc_struct),
    .value_size = sizeof(long),
    .max_entries = 4096
};

SEC("collect_ips")
int xdp_ip_stats_prog(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;
    struct iphdr *iph = data + sizeof(struct ethhdr);

    if (data_end >= (void *) (eth + sizeof(struct ethhdr))) {
        if (eth->h_proto == htons(ETH_P_IP)) {
            struct addr_desc_struct addr_desc = {.src_ip = iph->saddr};
            long init_val = 1;
            long *value = bpf_map_lookup_elem(&addr_map, &addr_desc);

            if (value) {
                __sync_fetch_and_add(value, 1);
            } else {
                bpf_map_update_elem(&addr_map, &addr_desc, &init_val, BPF_ANY);
            }
        }
    }

    return XDP_PASS;
}

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

Setup:设置:

macOS host, VirtualBox guest running Lubuntu. macOS 主机,运行 Lubuntu 的 VirtualBox 来宾。 I have created a 'host only adapter' on the VM.我在虚拟机上创建了一个“仅主机适配器”。 Both the VM and macOS have an interface on the 192.168.56.x network, with IPs 192.168.56.102 and 192.168.56.1, respectively. VM 和 macOS 在 192.168.56.x 网络上都有一个接口,IP 分别为 192.168.56.102 和 192.168.56.1。 This XDP program loads successfully on the VM interface using the xdp-loader program.此 XDP 程序使用xdp-loader程序成功加载到 VM 接口上。

Test #1:测试#1:

Run a HTTP server on the VM on IP 192.168.56.102.在 IP 192.168.56.102 上的 VM 上运行 HTTP 服务器。 Curl this IP from macOS. Curl 这个来自 macOS 的 IP。

Observation: XDP program does not capture any packets.观察:XDP 程序没有捕获任何数据包。

Test #2:测试#2:

Run a HTTP server on macOS on the 192.168.56.1.在 192.168.56.1 的 macOS 上运行 HTTP 服务器。 Curl this IP from the VM. Curl 这个 IP 来自 VM。

Observation: XDP program captures some of the packets sent from macOS to the VM.观察:XDP 程序捕获了一些从 macOS 发送到 VM 的数据包。 Wireshark indicates more packets should have been received by XDP. Wireshark 表示 XDP 应该接收到更多的数据包。

Test #3:测试#3:

SSH from macOS into 192.168.56.102 on the VM. SSH 从 macOS 到 VM 上的 192.168.56.102。

Observation: No packets captured by XDP观察:XDP 没有捕获到数据包

In all tests I should expect to see packets processed by the XDP program.在所有测试中,我应该期望看到 XDP 程序处理的数据包。

Here's the updated function, as per Andrew's comments.根据 Andrew 的评论,这是更新的 function。 Main issue was with if (data_end >= (void *) (eth + sizeof(struct ethhdr))) , which results in overshooting the packet.主要问题是if (data_end >= (void *) (eth + sizeof(struct ethhdr))) ,这会导致数据包过冲。 I should have been casting to char * .我应该一直转换为char * Using data by itself is not as per standard, but works in clang because it adds bytes to a void * , not bytes*sizeof(some pointer) .单独使用data不符合标准,但可以在 clang 中使用,因为它将字节添加到void * ,而不是bytes*sizeof(some pointer)

SEC("collect_ips")
int xdp_ip_stats_prog(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;
    struct iphdr *iph = (char *) data + sizeof(struct ethhdr);

    // Without adding sizeof(struct iphdr) results in xdp-loader complaining about "invalid access to packet"
    if (data_end >= (void *) ((char *) data + sizeof(struct ethhdr) + sizeof(struct iphdr))) {
        if (eth->h_proto == htons(ETH_P_IP)) {
            struct addr_desc_struct addr_desc = {.src_ip = iph->saddr};
            long init_val = 1;
            long *value = bpf_map_lookup_elem(&addr_map, &addr_desc);

            if (value) {
                __sync_fetch_and_add(value, 1);
            } else {
                bpf_map_update_elem(&addr_map, &addr_desc, &init_val, BPF_ANY);
            }
        }
    }

    return XDP_PASS;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM