XDP上的线程安全操作
我可以从文档中确认BPF_MAP_UPDATE_ELEM如果在hash_maps上完成,则是原子操作。来源( https://man7.org/linux/man-man-pages/ man2/bpf.2.html )。 [cite:map_update_elem()在原子上替代了现有元素]
我的问题是2倍。
如果元素不存在,MAP_UPDATE_ELEM仍然是原子吗?
XDP操作BPF_MAP_DELETE_ELEM线程免受用户空间程序的安全?
该地图是hash_map。
I was able to confirm from the documentation that bpf_map_update_elem is an atomic operation if done on HASH_MAPs. Source (https://man7.org/linux/man-pages/man2/bpf.2.html). [Cite: map_update_elem() replaces existing elements atomically]
My question is 2 folds.
What if the element does not exist, is the map_update_elem still atomic?
Is the XDP operation bpf_map_delete_elem thread safe from User space program?
The map is a HASH_MAP.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Atomic OPS,种族条件和线程安全在EBPF中很复杂,因此我会做出广泛的答案,因为很难从您的问题中判断您的目标是什么。
是的,
BPF_MAP_UPDATE_ELEM
通过SYSCALL和辅助函数命令和辅助函数更新地图“ atmomomylines thimomomomomy”',在这种情况下,如果我们从value a'a'tore'tore'tore'b't'tore'b',请始终看到“ a”或“ b”不是两个组合(例如,“ b”的第一个字节和“ a”的最后一个字节)。所有地图类型都是如此。对于所有映射修改SYSCALL命令(包括BPF_MAP_DELETE_ELEM
),这是正确的。但是,这并不能使比赛条件变得不可能,因为地图的值可能在
map_lookup_elem
和更新时发生了变化。请记住的是,
map_lookup_elem
syscall命令(用户空间)的工作方式与助手函数(kernelspace)的作用不同。 SYSCALL将始终返回不可变形的数据副本。但是,辅助功能将返回一个指针,转换为存储地图值的内核内存中的位置,您可以以这种方式直接更新地图值,而无需使用map_update_elem
helper。这就是为什么您经常看到使用的哈希地图,例如:请注意,在此示例,
__ sync_fetch_and_add
用于更新地图值的部分。我们需要执行此操作,因为更新它,例如value-> packet ++;
或value-> packet+= 1
将导致竞赛条件。__ sync_fetch_and_add
发出原子CPU指令,在这种情况下,该指令获取,添加和写回一个指令。同样,在此示例中,两个结构字段已在原子上进行了更新,但不是在一起,
数据包
仍然可以增加,但是bytes
尚未。如果要避免这种情况,则需要使用Spinlock(使用bpf_spin_lock
和bpf_spin_unlock
helpers )。完全避开问题的另一种方法是使用
_PER_CPU
地图的变体,在此您可以权衡交通拥堵/速度和内存使用。Atomic ops, race conditions and thread safety are sort of complex in eBPF, so I will make a broad answer since it is hard to judge from your question what your goals are.
Yes, both the
bpf_map_update_elem
command via the syscall and the helper function update the maps 'atmomically', which in this case means that if we go from value 'A' to value 'B' that the program always sees either 'A' or 'B' not some combination of the two(first bytes of 'B' and last bytes of 'A' for example). This is true for all map types. This holds true for all map modifying syscall commands(includingbpf_map_delete_elem
).This however doesn't make race conditions impossible since the value of the map may have changed between a
map_lookup_elem
and the moment you update it.What is also good to keep in mind is that the
map_lookup_elem
syscall command(userspace) works differently from the helper function(kernelspace). The syscall will always return a copy of the data which isn't mutable. But the helper function will return a pointer to the location in kernel memory where the map value is stored, and you can directly update the map value this way without using themap_update_elem
helper. That is why you often see hash maps used like:Note that in this example,
__sync_fetch_and_add
is used to update parts of the map value. We need to do this since updating it likevalue->packets++;
orvalue->packets += 1
would result in a race condition. The__sync_fetch_and_add
emits a atomic CPU instruction which in this case fetches, adds and writes back all in one instruction.Also, in this example, the two struct fields are atomically updated, but not together, it is still possible for the
packets
to have incremented butbytes
not yet. If you want to avoid this you need to use a spinlock(using thebpf_spin_lock
andbpf_spin_unlock
helpers).Another way to sidestep the issue entirely is to use the
_PER_CPU
variants of maps, where you trade-off congestion/speed and memory use.