sendmsg + raw以太网+几帧

时间:2014-11-13 15:34:24

标签: c++ c linux

我使用linux 3.x和现代glibc(2.19)

我想发送几个以太网帧,而无需从内核/用户空间前后切换。

我有MTU = 1500,我想发送800 KB。 我这样初始化接收者地址:

struct sockaddr_ll socket_address;
socket_address.sll_ifindex = if_idx.ifr_ifindex;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_addr[0] = MY_DEST_MAC0;
//...

之后我可以调用sendto/sendmsg 800KB / 1500 ~= 500次,一切正常,但这需要用户空间<->内核协商每秒500 * 25次。我想避免它。

我尝试使用适当的信息init struct msghdr::msg_iov, 但得到错误“消息太长”,看起来msghdr::msg_iov无法用size > MTU描述某些内容。

因此,问题是可以立即从用户空间在Linux上发送许多原始以太网帧吗?

PS

我从文件中获取的数据(800KB),并将其读取到内存中。所以struct iovec对我有好处,我可以创建适当数量的以太网头,并且必须iovec per 1500 packet,一点指向数据,一点指向以太网报头。

1 个答案:

答案 0 :(得分:0)

哇。

我的上一家公司制作了实时的hidef视频编码硬件。在实验室中,我们不得不在粘合链路上爆炸200MB /秒,所以我对此有一些经验。以下是基于此。

在调整之前,您必须进行测量。你不想做多个系统调用,但你能用时间测量证明开销很重要吗?

我在clock_gettime周围使用了一个包装程序,它以毫微秒的精度(例如(tv_sec * 100000000) + tv_nsec)返回时间。称之为[此处]&#34; nanime&#34;。

因此,对于任何给定的系统调用,您需要进行测量:

tstart = nanotime();
syscall();
tdif = nanotime() - tstart;

对于send/sendto/sendmsg/write,这样做会产生小数据,因此您确定不会阻止[或使用O_NONBLOCK,如果适用]。这为您提供了系统调用开销

为什么要直接使用以太网帧? TCP [或UDP]通常足够快,现代NIC卡可以在硬件中进行信封包装/剥离。我想知道是否存在特定的情况需要以太网帧,或者您是否获得了所需的性能并且来了以此作为解决方案。记住,你的速度是800KB / s(~1MB / s),我的项目比TCP上的项目多100x-200x。

对套接字使用两个普通write调用怎么样?一个用于标题,一个用于数据[ all 800KB]。 write可以在套接字上使用,但不会出现EMSGSIZE错误或限制。

此外,为什么您需要将标头放在单独的缓冲区中?分配缓冲区时,只需执行:

datamax = 800 * 1024;  // or whatever
buflen = sizeof(struct header) + datamax;
buf = malloc(buflen);

while (1) {
    datalen = read(fdfile,&buf[sizeof(struct header)],datamax);
    // fill in header ...
    write(fdsock,buf,sizeof(struct header) + datalen);
}

即使对于以太网帧情况也是如此。

还可以使用setsockopt来增加套接字的内核缓冲区的大小。否则,您可以发送数据,但在接收器耗尽之前它将被丢弃在内核中。更多内容如下。

要测量电线的性能,请在标题中添加一些字段:

u64 send_departure_time;  // set by sender from nanotime
u64 recv_arrival_time;  // set by receiver when the packet arrives

因此,发件人设置出发时间并写入[只做这个测试的标题]。调用此数据包Xs。收件人在到达时盖章。接收方立即向发送方发送一条消息[称之为Xr],并带有Xs的内容。当发件人得到这个时,会用到达时间标记它。

以上我们现在有:

T1 -- time packet Xs departed sender
T2 -- time packet Xs arrived at receiver
T3 -- time packet Xr departed receiver
T4 -- time packet Xr arrived at sender

假设您在相对安静的连接上执行此操作,几乎没有其他流量,并且您知道链路速度(例如1 Gb / s),使用T1 / T2 / T3 / T4可以计算开销。

您可以重复TCP / UDP与ETH的测量。你可能会发现它并没有像你想象的那样多买你。再次,你能用精确的测量证明吗?

我&#34;发明了&#34;这个算法在上述公司工作时,只是发现它已经是通过100Gb以太网NIC卡发送原始视频的视频标准的一部分,并且NIC在硬件中进行时间戳。

您可能需要做的其他事情之一是添加一些油门控制。这类似于bittorrent的功能或PCIe总线的功能。

当PCIe总线节点首次启动时,它们会传达可用的空闲缓冲区空间,以便盲目写入&#34;也就是说,发件人可以自由地爆发,没有任何ACK消息。当接收器耗尽其输入缓冲区时,它会向发送方发送周期性的ACK消息,其中包含能够消耗的字节数。发送者可以将此值添加回盲写限制并继续。

出于您的目的,盲写限制是接收器的内核套接字缓冲区的大小。

<强>更新

根据您评论中的一些其他信息[实际的系统配置应该以更完整的形式,作为对底部问题的编辑]。

需要原始套接字并发送以太网帧。 可以通过ifconfig设置更大的MTU或使用ioctl进行SIOCSIFMTU调用来减少开销。我推荐ioctl。您可能不需要将MTU设置为800KB。您的CPU的NIC卡有实际限制。您可以轻松地将MTU从1500增加到15000。这会将系统调用开销减少10倍,这可能足够好&#34;。

您可能必须使用sendto/sendmsg。两个write调用基于转换为TCP / UDP。但是,我怀疑sendmsg msg_iov的开销会比sendto更多。如果您进行搜索,则会发现大多数示例代码都使用sendtosendmsg似乎对您的开销较小,但可能导致内核的更多开销。以下是使用sendtohttp://hacked10bits.blogspot.com/2011/12/sending-raw-ethernet-frames-in-6-easy.html

的示例

除了改善系统调用开销之外,更大的MTU 可能提高&#34; wire&#34;的效率,即使这在您的用例中似乎不是问题。我有CPU + FPGA系统的经验以及它们之间的通信,但我仍然对你的一条评论感到困惑,因为它没有使用电线&#34;。连接到CPU的以太网引脚的FPGA我得到了 - 有点像。更准确地说,您是指 FPGA引脚连接到CPU的卡/芯片的以太网引脚&#34;

同一PC板上的CPU / NIC和FPGA引脚是否通过PC板走线连接?否则,我不明白&#34;不使用电线&#34;。

  

但是,我必须再次说明,必须能够在盲目地尝试改进之前衡量您的表现。< / p>

您是否运行了我建议用于确定 syscall 开销的测试用例?如果它足够小,尝试优化它可能值得它并且这样做可能实际上在其他领域严重损害了更多的性能你开始的时候并没有意识到。

作为一个例子,我曾经研究过一个存在严重性能问题的系统,这样系统就无法运行。我怀疑串口驱动程序很慢,所以我从高级语言(例如C语言)重新编码为汇编程序。

我将驱动程序性能提高了2倍,但它对系统的性能提升不到5%。事实证明,真正的问题是其他代码正在访问不存在的内存,这只会导致总线超时,从而可以显着降低系统速度[它确实不< / em>生成一个中断,可以很容易地在现代系统上找到它。

当我了解测量的重要性时。我基于受过教育的 guess 而不是硬数据完成了我的优化。之后:吸取教训!

如今,我从不尝试大量优化,直到我可以先测量。在某些情况下,我添加了一个优化,我确定&#34;确定&#34;会让事情变得更好(例如内联函数)。当我测量它[和因为可以测量它]时,我发现新代码实际上更慢我必须恢复变化。但是,重点是:我可以通过 hard 性能数据证明/反驳这一点。

你使用的是什么CPU:x86,arm,mips等。什么时钟频率? DRAM多少钱?多少个核心?

您使用的是什么FPGA(例如Xilinx,Altera)?具体型号/部件号是什么?什么是最大时钟频率? FPGA是完全专注于逻辑还是你内部还有一个CPU,如microblaze,nios,arm? FPGA是否可以访问它自己的[以及多少DRAM]?

如果增加MTU,FPGA可以从缓冲区/空间角度或时钟速度的角度来处理吗?如果你增加MTU,你可能需要像我在原帖中所建议的那样添加一个ack / sync协议。

目前,CPU正在对数据执行写操作,希望FPGA可以处理它。这意味着CPU和FPGA之间存在开放竞争条件。

这可以减轻,纯粹是发送小数据包的副作用。如果你过多地增加MTU,你可能会淹没FPGA。换句话说,这是您尝试优化的开销,这使FPGA能够跟上数据速率。

这就是我所说的盲目优化的意外后果。它可能会产生意想不到的副作用。

发送到FPGA的数据的性质是什么?您发送800KB,但多久一次?

由于某些原因,我假设它是 FPGA固件本身。你说固件已经快满了[它正在接收以太网数据]。此外,通常通过I2C总线,ROM或FPGA编程器加载固件。那么,我是对的吗?

您正在从文件向FPGA发送数据。这意味着它只在CPU的应用程序启动时被发送一次。那是对的吗?如果是这样,则不需要优化,因为它的初始/启动成本对正在运行的系统几乎没有影响。

所以,我必须假设文件被多次加载,每次可能是一个不同的文件。那是对的吗?如果是这样,您可能需要考虑read系统调用的影响。不仅来自 syscall 开销,还有最佳读取长度。例如,IIRC,磁盘到磁盘或文件到文件复制/传输的最佳传输大小为64KB,具体取决于文件系统或底层磁盘特性。

因此,如果您希望减少开销,那么从文件中读取数据可能远远超过应用程序生成数据[如果可能的话]。

内核 syscall 接口的开销非常低。内核程序员[我碰巧是一个]花了很多时间来确保开销很低。

你说你的系统正在为其他事物利用大量的CPU时间。你可以衡量其他事情吗?您的申请是如何构建的?有多少个进程?多少线程?他们如何沟通?什么是延迟/吞吐量?您可能能够找到[很可能找到]更大的瓶颈并重新编码这些瓶颈,并且超过最大值的CPU使用率将全面降低让您从MTU调整中获益。

尝试优化系统调用开销可能就像我的串口优化一样。很多努力,但总体结果令人失望。

在考虑性能时,从整体系统角度考虑它非常重要。在您的情况下,这意味着CPU,FPGA和其他任何内容。

你说CPU正在做很多事情。其中一些算法可以/应该进入FPGA吗?他们之所以不是因为FPGA几乎没有空间,否则你会这样做? FPGA固件是100%完成的吗?或者,是否有更多的RTL要写?如果您在FPGA中占用90%的空间,并且您需要更多的RTL,您可能希望考虑使用具有更多逻辑空间的FPGA部件,可能具有更高的时钟速率。 / p>

在我的视频公司,我们使用了FPGA。我们使用了FPGA供应商拥有的最大/最快的最先进部件。我们还使用了几乎100%的空间用于逻辑,并且需要部件的最大时钟频率。供应商告诉我们,我们是全球任何客户公司的最大FPGA资源消费者。因此,我们正在使供应商开发工具紧张。布局和布线经常会失败,必须重新运行才能获得正确的布局并满足时机要求。

因此,当FPGA几乎充满逻辑时,布局和布线很难实现。这可能是考虑更大部分[如果可能]

的原因