【问题标题】:Enforce max threshold of tracked connections in eBPF在 eBPF 中强制跟踪连接的最大阈值
【发布时间】:2021-05-28 02:58:19
【问题描述】:

我有一个跟踪许多活动 TCP 连接的 kprobe ebpf 程序。为了减少开销,我对可以同时跟踪的 TCP 连接数设置了一个上限。因此,我必须在 ebpf 程序中维护一个计数器,以便在建立新连接时,如果低于限制,则增加计数器,当连接完成时,减少计数器。由于程序是可重入的,所以计数器的操作应该是原子的。

我尝试了 bpf_spin_lock。但是它不能用于跟踪程序(例如 kprobe)。 ebpf 也很少有原子操作。我知道一个操作__sync_fetch_and_add。但是仅仅实现这里的逻辑是不够的。

我在网上找到了一些讨论https://lists.iovisor.org/g/iovisor-dev/topic/bpf_concurrency/74407447?p=,,,20,0,0,0::recentpostdate%2Fsticky,,,20,2,20,74407447。在没有任何可行的解决方案的情况下,讨论仍在进行中。

有现成的解决方案吗?非常感谢!

【问题讨论】:

  • 如果目标只是限制开销,为什么不使用 per-cpu 阵列来维护每个核心的计数?
  • per-cpu array 只能限制每个cpu的数量。可能会出现以下情况:cpu A 达到其限制,连接被拒绝,而 cpu B 仍有空闲插槽。我需要的是一个全局计数器。
  • 如果有问题的开销是 CPU 周期,那么它也是每个核心的开销,所以我看不出有每个核心阈值的问题。您将如何决定什么是好的全局计数器?
  • 每个 cpu 计数器的一个问题如下。在一个 kprobe 中,我在建立连接时增加计数器。在另一个 kprobe 中,当连接完成时,我会减少计数器。然而,这两个 kprobe 可以由不同的 cpu 内核运行。这导致计数器在一个 cpu 上增加,而在另一个 cpu 上减少。换句话说,计数器计数不正确。有没有办法解决这个问题?
  • 啊,说得好!我假设您必须有一个哈希图来跟踪已建立的连接。如果您只是将该哈希图的 max_entries 设置为全局计数器值怎么办?然后,如果 hashmap 更新失败,则意味着您已达到最大连接数。

标签: counter bpf ebpf


【解决方案1】:

在 cmets 进行了一些讨论后,我们得出结论,最好的解决方案可能是依靠地图的 max_entries 参数来强制限制跟踪的连接数

使用这种方法,BPF 程序将如下所示:

// Update an existing connection or insert a new one.
res = bpf_map_update_elem(&conntrack, &tuple, &connection, 0);
if (res == -E2BIG) {
    // The map is full. The max. threshold for tracked connections was reached.
} else if (res != 0) {
    // The map update failed for some other reason.
} else {
    // The map update was successful.
}

在 BPF 中访问哈希映射是一个原子操作,因此即使在并发访问的情况下,映射也永远不会包含比 max_entries 更多的元素。请注意,对特定地图元素的访问不是原子的。


我们丢弃了 per-CPU 数组以维护 per-CPU 计数器,因为不能保证关闭连接的事件(例如 TCP FIN)将在与打开它的事件(例如 TCP SYN)相同的 CPU 上处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-04
    • 2014-02-08
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多