凯发app官方网站-凯发k8官网下载客户端中心 | | 凯发app官方网站-凯发k8官网下载客户端中心
  • 博客访问: 265370
  • 博文数量: 619
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5320
  • 用 户 组: 普通用户
  • 注册时间: 2022-03-07 15:28
个人简介

天翼云是中国电信倾力打造的云服务品牌,致力于成为领先的云计算服务提供商。提供云主机、cdn、云电脑、大数据及ai等全线产品和场景化凯发app官方网站的解决方案。

文章分类

全部博文(619)

文章存档

2024年(170)

2023年(247)

2022年(202)

我的朋友

分类: 信息化

2023-04-03 18:00:21

本文分享自天翼云开发者社区@《af_xdp技术简介》,作者: l****n

链接:

https://www.ctyun.cn/developer/article/356244563365957?track=|cp:cz_bk|tgdy:wenzhang|ttjh:bokeshequ|key:bw307|pf:pc

 

af-凯发app官方网站

af_xdp 是一项新增的,针对高性能数据包处理进行优化的地址族协议。
本文档假设读者已经熟悉 bpf 和 xdp。如果没有,可以参考开源cilium 项目在 ( )
通过xdp 的 xdp_redirect 操作,xdp程序可以使用 bpf_redirect_map() 函数将入口帧重定向到其他启用 xdp 的网络设备。af_xdp 套接字使 xdp 程序能够将帧重定向到用户程序中的一块内存缓冲区。


af_xdp 套接字 (以下简称xsk) 可以使用通用的socket() 系统调用创建。与每个 xsk 相关的有两个环:rx ring和 tx ring。套接字可以在 rx 环上接收数据包,也可以在 tx 环上发送数据包。这些环分别使用 setsockopts xdp_rx_ring 和 xdp_tx_ring 注册和调整大小。每个socket必须至少有一个这样的环。rx 或 tx 描述符环指向称为 umem中的数据缓冲区。rx 和 tx 可以共享相同的 umem,因此不必在 rx 和 tx 之间复制数据包。此外,如果一个数据包由于可能重新传输而需要保留一段时间,则可以将指向该数据包的描述符更改为指向另一个并立即重新使用。这避免了再次复制数据。


umem 由许多大小相同的块组成。环中的描述符通过引用其地址来引用帧。addr 只是整个 umem 区域内的偏移量。用户空间可以使用合适的任何方式(比如malloc、mmap、大页面等)为此 umem 分配内存。然后使用新的 setsockopt xdp_umem_reg 向内核注册此内存区域。umem 也有两个环:fill ring和 completion ring。应用程序使用 fill 环向下发送 addr 以供内核填充 rx 数据包。一旦收到每个数据包,对这些帧的引用就会出现在 rx 环中。另一方面,completion 环包含内核已完全传输的帧地址,现在可以由用户空间再次使用,用于 tx 或 rx。因此,出现在 completion 环中的帧地址是先前使用 tx 环传输的地址。总之,rx 和 fill 环用于 rx 路径,tx 和 completion 环用于 tx 路径。

 

套接字{banned}最佳终通过 bind() 系统调用和一个设备上的特定队列 id 绑定,绑定完成后,流量才开始流动。


如果需要,可以在进程之间共享 umem。如果一个进程想要这样做,它只需跳过 umem 的注册及其相应的两个环,在绑定调用中设置 xdp_shared_umem 标志并提交它想要共享 umem 的进程的 xsk 以及它自己的新创建 xsk 套接字。然后,新进程将在其自己的 rx 环中接收指向此共享 umem 的帧地址引用。请注意,由于环结构是单消费者/单生产者(出于性能原因),新进程必须创建自己的带有相关 rx 和 tx 环的套接字,因为它不能与其他进程共享。这也是每个 umem 只有一组 fill 和 completion 环的原因。处理 umem 是单个进程的责任。


数据包是如何从 xdp 程序分发到 xsk 的呢?有一个称为 xskmap(bpf_map_type_xskmap)的 bpf 映射。用户空间应用程序可以将 xsk 放置在此映射中的任意位置。然后 xdp 程序可以将数据包重定向到此映射中的特定索引,xdp 验证该映射中的 xsk 确实绑定到该设备和环号。如果不是,则丢弃该数据包。如果映射在该索引处为空,则数据包也将被丢弃。


af_xdp 可以在两种不同的模式下运行:xdp_skb 和 xdp_drv。如果驱动程序不支持 xdp,或者在加载 xdp 程序时显式选择了 xdp_skb,则采用 xdp_skb 模式,该模式将 skb复制到用户空间,适用于任何网络设备的后备模式,该模式在协议栈开始处运行。另一方面,如果驱动程序支持 xdp,af_xdp 代码将使用它来提供更好的性能,但仍有一份数据复制到用户空间。该模式在驱动处运行,性能比xdp_skb模式好。
文章来源:英文翻译(

为了使用 af_xdp 套接字,需要设置许多关联对象。这些对象及其选项将在以下部分中进行说明。
有关 af_xdp 工作原理的概述,您还可以查看 2018 年有关该主题的 linux plumbers 论文:http: //vger.kernel.org/lpc_net2018_talks/lpc18_paper_af_xdp_perf-v2.pdf。不要查阅 2017 年关于“af_packet v4”的论文,这是 af_xdp 的{banned}中国第一次尝试。从那以后,几乎一切都发生了变化。jonathan corbet 还写了一篇关于 lwn 的优秀文章,“使用 af_xdp 加速网络”。它可以在找到。

umem

umem 是一个虚拟的连续内存区域,被分成大小相等的帧。umem 与 netdev 和该 netdev 的特定队列 id 相关联。它是通过使用 xdp_umem_reg setsockopt 系统调用创建和配置的(块大小、headroom、起始地址和大小)。umem 通过 bind() 系统调用绑定到 netdev 和该netdev的队列 id。


一个 af_xdp 是连接到单个 umem 的套接字,但一个 umem 可以有多个 af_xdp 套接字。要共享套接字 a 创建的 umem,下一个套接字 b 可以通过在 struct sockaddr_xdp 成员 sxdp_flags 中设置 xdp_shared_umem 标志并将 a 的文件描述符传递给 struct sockaddr_xdp 成员 sxdp_shared_umem_fd 来实现。
umem 有两个单生产者/单消费者环,用于在内核和用户空间应用程序之间转移 umem 帧的所有权。


rings

有四种不同类型的环:fill、completion、rx 和 tx。所有环都是单生产者/单消费者,因此用户空间应用程序需要显式同步多个进程/线程正在读取/写入它们。
umem 使用两个环:fill 和 completion。每个与 umem 关联的套接字必须有一个 rx 队列、tx 队列或两者兼有。
这些环是基于头部(生产者)/尾部(消费者)的环。生产者将数据写入struct xdp_ring生产者成员指向的索引处,并增加生产者索引。消费者读取struct xdp_ring消费者成员指向的索引处的数据环,并增加消费者索引。
环是通过 _ring setsockopt 系统调用配置和创建的,然后使用 mmap() 的适当偏移量(xdp_pgoff_rx_ring、xdp_pgoff_tx_ring、xdp_umem_pgoff_fill_ring 和 xdp_umem_pgoff_completion_ring)映射到用户空间。
注:环的大小需要是 2 的大小幂。


umem fill ring

fill 环用于将 umem 的所有权从用户空间转移到内核空间。umem 地址在环中传递。例如,如果 umem 是 64k 并且每个块是 4k,那么 umem 有 16 个块并且可以传递 0 到 64k 之间的地址。
传递给内核的帧用于入口路径(rx 环)。
用户应用程序为该环生成 umem 地址。请注意,如果以对齐的块模式运行应用程序,内核将屏蔽传入的地址。例如,对于 2k 的块大小,addr 的 log2(2048) lsb 将被屏蔽掉,这意味着 2048、2050 和 3000 指的是同一个块。如果用户应用程序在未对齐的块模式下运行,那么传入的 addr 将保持不变。


umem completion ring

completion ring 用于将 umem 的所有权从内核空间转移到用户空间。就像 fill 环一样,使用 umem 索引。
从内核传递到用户空间的帧是已经发送的帧(tx 环),可以再次被用户空间使用。
用户应用程序消费此环中的 umem 地址。


rx ring

rx 环是套接字的接收端。环中的每个条目都是一个 struct xdp_desc 描述符。描述符包含 umem 偏移量 (addr) 和数据长度 (len)。
如果没有帧通过 fill 环传递给内核,则没有描述符出现在 rx 环上。
用户应用程序消费此环中的 struct xdp_desc 描述符。


tx ring

tx 环用于发送帧。struct xdp_desc 描述符被填充(索引、长度和偏移量)并传递到环中。
要开始传输,需要 sendmsg() 系统调用。未来可能会放宽。
用户应用程序为、在此环生产struct xdp_desc 描述符。

使用 af_xdp 套接字,有两个部分是需要的。用户空间应用程序和 xdp 程序。有关完整的设置和使用示例,请参阅示例应用程序。用户空间端是 xdpsock_user.c,xdp 端是 libbpf 的一部分。
tools/lib/bpf/xsk.c 中包含的 xdp 代码示例如下:
sec("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
{
    int index = ctx->rx_queue_index;

    // a set entry here means that the corresponding queue_id
    // has an active af_xdp socket bound to it.
    if (bpf_map_lookup_elem(&xsks_map, &index))
        return bpf_redirect_map(&xsks_map, index, 0);

    return xdp_pass;
}
一个简单但性能不高的 ring dequeue 和 enqueue 可能如下所示:
// struct xdp_rxtx_ring {
//     __u32 *producer;
//     __u32 *consumer;
//     struct xdp_desc *desc;
// };

// struct xdp_umem_ring {
//     __u32 *producer;
//     __u32 *consumer;
//     __u64 *desc;
// };

// typedef struct xdp_rxtx_ring ring;
// typedef struct xdp_umem_ring ring;

// typedef struct xdp_desc ring_type;
// typedef __u64 ring_type;

int dequeue_one(ring *ring, ring_type *item)
{
    __u32 entries = *ring->producer - *ring->consumer;

    if (entries == 0)
        return -1;

    // read-barrier!

    *item = ring->desc[*ring->consumer & (ring_size - 1)];
    (*ring->consumer) ;
    return 0;
}

int enqueue_one(ring *ring, const ring_type *item)
{
    u32 free_entries = ring_size - (*ring->producer - *ring->consumer);

    if (free_entries == 0)
        return -1;

    ring->desc[*ring->producer & (ring_size - 1)] = *item;

    // write-barrier!

    (*ring->producer) ;
    return 0;
}

 

下面是一个 xdpsock测试应用程序,演示如何将 af_xdp 套接字与私有 umem 一起使用。假设你希望来自端口 4242 的 udp 流量{banned}最佳终进入队列 16,使用 ethtool启用 af_xdp:
ethtool -n p3p2 rx-flow-hash udp4 fn
ethtool -n p3p2 flow-type udp4 src-port 4242 dst-port 4242 \
    action 16
然后可以使用以下命令在 xdp_drv 模式下运行 rxdrop 基准测试:
samples/bpf/xdpsock -i p3p2 -q 16 -r -n
对于 xdp_skb 模式,使用开关“-s”而不是“-n”。

原文链接:

作者:kernel development community,如需转载,请联系作者。

阅读(239) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
")); function link(t){ var href= $(t).attr('href'); href ="?url=" encodeuricomponent(location.href); $(t).attr('href',href); //setcookie("returnouturl", location.href, 60, "/"); }
网站地图