3

我将 icmp echo 发送到 C 程序中的 250 个节点。套接字是这样创建的

sfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);

我有getsockopt SO_RCVBUF :262142 .ie 262KB 因为一个数据包需要84字节(包括IP,100字节在线),rcv缓冲区应该能够容纳262142/84 = 3120个数据包

sysctl parameters  (defaults)
net.core.rmem_max     = 131071
net.core.rmem_default = 113664

但是有10+滴。

我正在发送所有回显请求,然后使用 recvfrom() 获取数据包。很明显,replypacks 是在 socket 的 rcv 缓冲区中积累起来的,但是 rcv 缓冲区足够大,可以容纳 3120 个数据包。

数据包在接收主机上以 ehteral 正确显示。

当我设置:

sysctl -w net.core.rmem_max=1048576
and SO_RCVBUF to 2MB, the drops were 0.

为什么会这样?

很少有队列在行动。

  1. 网卡环形缓冲区。
  2. nic 到内核 que
  3. 每个套接字 rcv 缓冲区

我猜 net.core.rmem_max 只会改变每个套接字 rcv 缓冲区。

任何指向正确方向的链接。

Platform Linux suse10/x86

网卡:英特尔公司 PRO/无线 2200BG

-- 添加更多

我禁用了上述无线接口并开始使用有线接口以太网控制器:Broadcom Corporation NetXtreme BCM5705M_2 Gigabit Ethernet (rev 03) 情况发生了显着变化。

net.core.netdev_budget = 300
net.core.netdev_max_backlog = 1000
net.core.rmem_max = 131071
net.core.wmem_max = 131071

getsockopt SO_RCVBUF :262142
getsockopt SO_SNDBUF :262142
# ethtool -g eth1
Current hardware settings:
RX:             200
TX:             200
#

eth1 txqueuelen:1000

现在它就像每 250 个数据包 0 丢包和每 1000 个更改 rx,tx 大约 170 次,使用 ethtool -G 从默认值 200 但这没有效果。

然后我更改了每个套接字 rcv 缓冲区最大值

sysctl -w net.core.rmem_max=1024000

这允许每 6000 滴 0 滴和每 7000 滴 500 滴

进一步增加 per-socket-rcv-buffer-max

sysctl -w net.core.rmem_max=2048000

每 7000 个数据包 0 丢包

有线网络给出了更加一致和合作的结果。

但是当 262142 字节缓冲区可以容纳 3000 个大小为 84 的数据包(带有 IP 标头)时,问题仍然存在,为什么在 1000 个数据包时会发生丢包。即使在线数据包最大为 100 字节,262142 也可以容纳 2600 个数据包。

ethereal 大部分时间都能够获取数据包,并且 ifconfig 计数器显示没有丢弃,因此这是 nic 驱动程序将数据包提供给内核之后的事情。

ethereal 也错过了一些数据包,但这种情况较少发生。

通过仅更改上述这些

sysctl -w net.core.rmem_max=1024000

掉落 96/1000 掉落 0/6000

下降 500/7000

sysctl -w net.core.rmem_max=2048000

掉落 0/7000

sysctl -w net.core.rmem_max=512000
sysctl -w net.core.netdev_max_backlog=3000

掉落 0/3000

sysctl -w net.core.rmem_max=256000
sysctl -w net.core.netdev_max_backlog=3000

下降 1400/3000

hold = 2 * 1024 * 1024;
setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));

for(;;) 
...
 if(recvfrom(sfd,(char *)packet, packlen, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
    rcvcount++;
    process_packet(packet,packlen);
 }
4

2 回答 2

2

(从 nntp:comp.os.linux.networking 转发我的答案)

以下代码回答了我的问题。

http://lxr.linux.no/#linux+v3.8.7/net/core/sock.c#L689

708set_rcvbuf:
709             sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
710             /*
711              * We double it on the way in to account for
712              * "struct sk_buff" etc. overhead.   Applications
713              * assume that the SO_RCVBUF setting they make will
714              * allow that much actual data to be received on that
715              * socket.
716              *
717              * Applications are unaware that "struct sk_buff" and
718              * other overheads allocate from the receive buffer
719              * during socket buffer allocation.
720              *
721              * And after considering the possible alternatives,
722              * returning the value we actually used in getsockopt
723              * is the most desirable behavior.
724              */
725              sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
726              break;

由于我的数据包低于 100 字节数据,因此 sk_buff 开销会相当高。从视觉上看 sk_buff,对于 32 位系统,sk_buff 的大小似乎在 200 字节左右。

对于 100 字节在线数据包,这意味着只有三分之一的 rcvbuf 保存数据包数据。2/3 是 sk_buff 开销。

所以对于 SO_RCVBUF :262142,

262142/3 = 87380 字节可用于数据包数据。

87380/100 = 873 是可以容纳在其中的数据包数。

预计 1000 - 873 = 127 次下降(1000 次)。

我得到的是170,与预期相差不远。

以下章节/书籍真的很有帮助。

[1] Christian Benvenuti 理解 Linux 网络内部
第三部分:传输和接收

[2] Sreekrishnan Venkateswaran
第 15 章的基本 Linux 设备驱动程序。网络接口卡

  • 苏林德
于 2013-04-15T04:11:51.320 回答
-2

这是一个很长的镜头,但由于您没有显示完整的代码,它可能与防火墙有关。一些恶意软件变种使用 ICMP 数据包风暴,因此如果有防火墙软件正在运行,则可能会阻碍其运行。

于 2013-03-29T16:14:53.847 回答