返回

如何解决使用 eBPF TC 程序处理 IPv6 数据包的 MSS 问题

Linux

解决使用 eBPF TC 程序处理 IPv6 数据包的 MSS 问题

简介

使用 eBPF 技术优化网络性能时,有时会出现意想不到的问题。本文将重点讨论一个常见问题:当使用 eBPF TC 程序处理 IPv6 出站数据包时,如果最大段大小 (MSS) 大于 1424,则数据包可能会被丢弃。本文将深入探讨这个问题,并提供分步指南来解决它。

问题陈述

在具有 1500 MTU 的网络中,如果使用 eBPF TC 程序向 IPv6 数据包添加扩展头,同时 MSS 大于 1424,则这些数据包可能会被丢弃。这是因为内核会尝试使用 MSS 重新计算 IP 和 TCP 校验和,但这会导致校验和错误。

解决方案

要解决这个问题,我们需要采取以下步骤:

  1. 调整 MSS: 将 MSS 调整到小于 MTU 的值。对于 1500 MTU 的网络,建议将 MSS 设置为 1460。
  2. 更新 eBPF 程序: 在 eBPF 程序中使用 bpf_skb_set_tc_flags 函数设置 TC_OFFSET_MANGLE 标志。这将指示内核在重新计算校验和之前更新偏移量。

示例代码

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(u32),
    .value_size = sizeof(u32),
    .max_entries = 1024,
};

static __always_inline int handle_ipv6(struct __sk_buff *skb)
{
    struct ethhdr *eth = (struct ethhdr *)skb->data;
    struct ipv6hdr *ip6 = (struct ipv6hdr *)(eth + 1);
    struct tcphdr *tcp = (struct tcphdr *)(ip6 + 1);
    u32 key = ip6->saddr.s6_addr32[3];
    u32 *value;

    value = bpf_map_lookup_elem(&my_map, &key);
    if (!value) {
        value = bpf_map_lookup_elem(&my_map, &key);
        if (!value)
            return TC_ACT_SHOT;
    }

    tcp->check = bpf_csum_diff(tcp->check, htons(tcp->check),
                               htons(tcp->seq), htons(tcp->seq + *value),
                               sizeof(tcp->seq));
    return TC_ACT_OK;
}

static __always_inline int handle_tcp(struct __sk_buff *skb)
{
    struct ethhdr *eth = (struct ethhdr *)skb->data;
    struct ipv6hdr *ip6 = (struct ipv6hdr *)(eth + 1);

    if (ip6->nexthdr != IPPROTO_TCP)
        return TC_ACT_OK;

    return handle_ipv6(skb);
}

SEC("tc")
int tc_prog(struct __sk_buff *skb)
{
    struct ethhdr *eth = (struct ethhdr *)skb->data;

    if (eth->h_proto != htons(ETH_P_IPV6))
        return TC_ACT_OK;

    return handle_tcp(skb);
}

结论

通过遵循本文中概述的步骤,你可以解决 eBPF TC 程序在处理具有较大 MSS 的 IPv6 出站数据包时丢弃数据包的问题。调整 MSS 和更新 eBPF 程序对于确保数据包能够顺利通过网络至关重要。

常见问题解答

  1. 为什么 MSS 大于 1424 时会出现问题?
    因为内核会使用 MSS 重新计算 IP 和 TCP 校验和,但当 MSS 大于 MTU 时,这会导致校验和错误。

  2. 如何调整 MSS?
    你可以使用bpf_set_tc_mpls_hdr()函数来调整 MSS。

  3. 如何更新 eBPF 程序以设置 TC_OFFSET_MANGLE 标志?
    你可以使用bpf_skb_set_tc_flags()函数来设置 TC_OFFSET_MANGLE 标志。

  4. 我需要在代码中做哪些其他更改才能解决这个问题?
    除了调整 MSS 和更新 eBPF 程序外,你可能还需要修改 eBPF 程序以处理扩展头。

  5. 实施这些更改后,还有什么其他需要注意的事项?
    确保在部署任何更改之前对其进行彻底测试。此外,监视网络以确保这些更改不会对性能或稳定性产生负面影响。