netperf 测试调研

本次调研的问题是,netperf测试,在不给额外参数时数据包的size是如何被确定的。
查看源码发现,send_size是作为发送数据的变量,lss_size与之有关系。

在nettest_omni.c中有这样一个函数:

static int
choose_send_size(int lss, int protocol) {

  int send_size;

  if (lss > 0) {
    send_size = lss_size;

    /* we will assume that everyone has IPPROTO_UDP and thus avoid an
       issue with Windows using an enum */
    if ((protocol == IPPROTO_UDP) && (send_size > UDP_LENGTH_MAX))
      send_size = UDP_LENGTH_MAX;

  }
  else {
    send_size = 4096;
  }
  return send_size;
}

可以看出如何当lss_size有值时,send_size会默认选择使用lss_size的值。
那么lss_size的值在哪里初始化呢?
在nettest_bsd.c文件中有如下代码:

  set_sock_buffer (temp_socket, SEND_BUFFER, lss_size_req, &lss_size);

这个函数是对其进行初始化的。
我摘抄一些代码:

int optname = (which == SEND_BUFFER) ? SO_SNDBUF : SO_RCVBUF;

  /* seems that under Windows, setting a value of zero is how one
     tells the stack you wish to enable copy-avoidance. Knuth only
     knows what it will do on other stacks, but it might be
     interesting to find-out, so we won't bother #ifdef'ing the change
     to allow asking for 0 bytes. Courtesy of SAF, 2007-05 raj
     2007-05-31 */
  if (requested_size >= 0) {
    if (setsockopt(sd, SOL_SOCKET, optname,
           (char *)&requested_size, sizeof(int)) < 0) {
      fprintf(where, "netperf: set_sock_buffer: %s option: errno %d\n",
          (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF",
          errno);
      fflush(where);
      exit(1);
    }
    if (debug > 1) {
      fprintf(where, "netperf: set_sock_buffer: %s of %d requested.\n",
          (which == SEND_BUFFER) ? "SO_SNDBUF" : "SO_RCVBUF",
          requested_size);
      fflush(where);
    }
  }

  /* the getsockopt() call that used to be here has been hoisted into
     its own routine to be used on those platforms where the socket
     buffer sizes might change from the beginning to the end of the
     run. raj 2008-01-15 */

  get_sock_buffer(sd, which, effective_sizep);

其思路是通过setsockopt系统调用设置socket的buffer size,再通过getsockopt系统调用读回来。并赋值给effective_sizep。

但是写入时使用的是-1这个是变量默认的值,但是当都会来时数值变为16384。这个过程匪夷所思。我决定继续研究。

首先查看setsockopt系统调用的代码:

SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
        char __user *, optval, int, optlen)
{
    int err, fput_needed;
    struct socket *sock;

    if (optlen < 0)
        return -EINVAL;

    sock = sockfd_lookup_light(fd, &err, &fput_needed);
    if (sock != NULL) {
        err = security_socket_setsockopt(sock, level, optname);
        if (err)
            goto out_put;

        if (level == SOL_SOCKET)
            err =
                sock_setsockopt(sock, level, optname, optval,
                        optlen);
        else
            err =
                sock->ops->setsockopt(sock, level, optname, optval,
                          optlen);
out_put:
        fput_light(sock->file, fput_needed);
    }
    return err;
}

其中专门有为SOL_SOCKET准备的函数:sock_setsockopt。这个函数的实现代码在net/core/sock.c中,代码比较长我只贴出主要部分:

    int val;
    int valbool;
    struct linger ling;
    int ret = 0;

    /*
     *  Options without arguments
     */

    if (optname == SO_BINDTODEVICE)
        return sock_setbindtodevice(sk, optval, optlen);

    if (optlen < sizeof(int))
        return -EINVAL;

    if (get_user(val, (int __user *)optval))
        return -EFAULT;

    valbool = val ? 1 : 0;

    lock_sock(sk);

    switch (optname) {
    case SO_DEBUG:
        if (val && !capable(CAP_NET_ADMIN))
            ret = -EACCES;
        else
   //。。。。。。。
   //ignore
   //。。。。。。。
    case SO_SNDBUF:
        /* Don't error on this BSD doesn't and if you think
         * about it this is right. Otherwise apps have to
         * play 'guess the biggest size' games. RCVBUF/SNDBUF
         * are treated in BSD as hints
         */
        val = min_t(u32, val, sysctl_wmem_max);
set_sndbuf:
        sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
        sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
        /* Wake up sending tasks if we upped the value. */
        sk->sk_write_space(sk);
        break;

    case SO_SNDBUFFORCE:
        if (!capable(CAP_NET_ADMIN)) {
            ret = -EPERM;
            break;
        }

在处理SO_SNDBUF时,使用了min_t宏求得,参数2和参数3的最小值(参数1作为类型参考),这时如何后者小于前者,val的值就变为sysctl_wmem_max的值,这个值可以通过sysctl命令通过用户空间配置。

在设置sk->sk_sndbuf时,又一次使用了max_t函数,进行比较交大者。这个表达式中交大者是这个变量返回的最终结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值