linux socket recv buffer packet甚至为“pktcount * pktsize”< SO_RCVBUF

时间:2013-03-29 16:09:00

标签: linux networking

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

sfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);

我有getsockopt SO_RCVBUF:262142 .i.e 262KB 如果一个数据包需要84个字节(包括IP,100字节在线),则rcv缓冲区应该能够保持 262142/84 = 3120包

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

但是有10多滴。

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

接收主机上的数据包在ehtereal中正确显示。

当我设置:

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

为什么会这样?

行动中排队很少。

  1. 网卡环缓冲区。
  2. nic to kernel que
  3. 每个套接字rcv缓冲区
  4. 我猜net.core.rmem_max只会改变每个套接字rcv缓冲区。

    正确方向的任何链接。

    Platform Linux suse10/x86
    

    NIC:Intel Corporation PRO / Wireless 2200BG

    - 添加更多

    我禁用了所述无线接口并开始使用有线接口 以太网控制器:Broadcom Corporation NetXtreme BCM5705M_2千兆以太网(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个约170个 用默认值200的ethtool -G改变了rx,tx但是没有效果。

    然后我更改了每个套接字rcv buffer max

    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);
     }
    

2 个答案:

答案 0 :(得分: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 =预期1000分中有127分。

我得到的是170,距离预期不远。

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

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

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

  • Surinder

答案 1 :(得分:-2)

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