UDP GSO原理及应用

2019年10月31日

一、需求

  1. 内核如何支持udp gso;
  2. 测试(包括性能);
  3. 用户如何使用udp gso;

 

二、背景

       针对上述问题,本小节展开一定的论述,基础知识就不再赘述了。

       Linux支持udp下的generic segmentation offload特性有两种实现方式,一种是在protocal stack做,一种是在NIC driver做。协议栈中做的udp gso我们亦可称为uso,基于协议栈支持的前提下,若硬件支持我们可称为udp gso offload或uso offload,顾名思义,后者基于前者再做offload。[注:udp gso容易和几年前开发的ufo混淆,ufo特性是做在NIC网卡driver上,而ufo问题频发导致很多NIC不再做支持。]

       2018年Willem de Bruijn公布了draft论文Optimizing UDP for Content Delivery with GSO, Pacing and Zerocopy ;2018年4月26日,社区合并了第一份uso的patchset(总共10个patch);  2018年11月14日举办了Linux Plumbers Conference论文的presentation。2018年12月3日youtube公开了对应的演讲视频

       2018年6月社区合并了第一个网卡driver(mlx5-core)的特性支持;2019年10月intel提供了自己的三块网卡(igb/ixgbe/i40e)的支持,但是暂未合并到主线。netdevconf的session的公开资料

       这里列出一些uso的基本原理:

       1. 下图的表示了ufo和uso切割packet时候的处理方式不同,uso是每一块都需要带上udp header头部(ipv4,8字节),而ufo不需要。

        2. 下图展示了三种情况,从左到右,1)正常upd发包流程,在proto协议栈层ip层分片,一路小包到NIC再到接收端大量小包;2)开启gso后,proto协议栈层不再做分片,一路大包到NIC网卡,在网卡发送前做分片;3)开启gso+gro(gro是接收端),在发送端同(2)一样,只是接收端在接收到大量小包后合包成大包;理论上加上测试数据来看,从左到右是性能上依次的升级。

        3. 下图展示了三种NIC前处理包情况,1)开启udp gso,如果packet正好是gso切割包大小的整数倍,则正常处理每一块并做好checksum,2)开启udp gso,如果packet不是gso的整数倍,则需要对最后一块做额外处理,3)开启udp gso,且支持gso partial(请注意和driver的gso partial不是一个),则可以将前面的若干包合并只是用一个header,最后一块作为non-gso块处理即可。做更细的理解,此gso partial的代码["mss *= skb_shinfo(segs)->gso_segs;"]中将MSS的值扩大成了gso_segs倍,也就是如前所说若干的小包合并为一个。

        注:driver层如mlx5-core的gso partial支持,只是为了在网卡特性开启(ethtool -K [网卡] xxx on/off)时能够区分开正常gso和udp gso offload功能而已,可以让用户能够支持gso的情况下开启或关闭udp gso offload,原始设计时候二者是混为一谈,用同一开关来控制。综上,此gso partial非上文提及的gso partial。

三、测试

       测试过程,请按如下准备:

1)两台机器client和server。可选在同一网段,并保证OS是linux4.18.0+系列。

2)两个内核代码。在两台机器分别下载对应版本的内核代码,并进入到tools/testing/selftests/net的目录下,make编译即可。

3)server端输入命令 ./udpgso_bench_rx 即可作为udp监听程序,如果加参数"-t"表示监听tcp程序。

4)client端输入命令 sudo perf stat -a -C 5 -e cycles ./udpgso_bench_tx -l 4 -4 -D {server ip addr} -S 即可开启uso功能,如果不加参数"-s"表示正常udp发包。

5)如想开启硬件支持uso offload,需查看网卡是否为mlx5-core,并且查看网卡特性是否在gso-partial下有udp-segmentation-offload开关。

6)记录第(4)步骤结果,即可。

       测试结果,请阅读以下细节:

  1. TH-PUT即THROUGHPUT单位MB/s;
  2. CALLS单位calls/s;越小越好,带来cpu开销就越小;
  3. MESSAGES单位msg/s;
  4. 测试命令前可加入time命令,可测量SYS/USER的开销。
  5. perf测试尽可能不要使用多核,否则由于cpu调度会带来实验结果的不一致性,绑核一个cpu即可。

       如下是一组实测数据对比:

MACHINE

TYPE

TH-PUT

CALLS

MESSAGES

USER

SYS

client

udp

839

663894

14245

0m0.343s

0m3.385s

udp gso

1139

19333

19333

0m0.038s

0m2.018s

server

udp

932

663896

 

udp gso

1135

808258

       如下是作者公开数据:

Types

calls/s

Mcycles/s

Speed-up (%)

TCP

19040

618

487

UDP

812000

2801

100

UDP GSO

18248

1726

174

      上述的测试过程、方法及结果已找udp gso作者Willem de Bruijn确认。

  1. 开启gso后,client的calls次数相对于server降低40倍;而未开启的两端calls几乎一样。
  2. 开启gso后,USER开销方面,udp gso相对于gso提升了8倍。
  3. 开启gso后,SYS开销方面,udp gso相对于gso提升了0.67倍。

 

四、应用

  1. 开启内核支持

如下是最初需要的socket设置:

static void set_pmtu_discover(int fd, bool is_ipv4)

{

  int level, name, val;

 

  if (is_ipv4) {

    level = SOL_IP;

    name  = IP_MTU_DISCOVER;

    val = IP_PMTUDISC_DO;

  } else {

    level = SOL_IPV6;

    name  = IPV6_MTU_DISCOVER;

    val = IPV6_PMTUDISC_DO;

  }

 

  if (setsockopt(fd, level, name, &val, sizeof(val)))

    error(1, errno, "setsockopt path mtu");

}

 

如下是udp发包的过程:

static int send_udp_segment(int fd, char *data)

{

  char control[CMSG_SPACE(sizeof(cfg_mss))] = {0};

  struct msghdr msg = {0};

  struct iovec iov = {0};

  int ret;

 

  iov.iov_base = data;

  iov.iov_len = cfg_payload_len;

 

  msg.msg_iov = &iov;

  msg.msg_iovlen = 1;

 

  msg.msg_control = control;

  msg.msg_controllen = sizeof(control);

  send_udp_segment_cmsg(CMSG_FIRSTHDR(&msg));

 

  msg.msg_name = (void *)&cfg_dst_addr;

  msg.msg_namelen = cfg_alen;

 

  ret = sendmsg(fd, &msg, cfg_zerocopy ? MSG_ZEROCOPY : 0);

  if (ret == -1)

    error(1, errno, "sendmsg");

  if (ret != iov.iov_len)

    error(1, 0, "sendmsg: %u != %lu\n", ret, iov.iov_len);

 

  return 1;

}

确定测试或业务方使用的代码包括上面的socket设置部分和发包方式即可。

        仅作了解:

        开启gso后,大概流程如此:发包流程将延迟分片,本在ip层做分片(ipv4/output.c文件下ip_fragment()函数),而现在将分片推迟到NIC发送前一刻。

 

五、未来展望

目前在4.18.0 redhat8或centos8版本内核有如下问题:

  1. 在应用层代码中使用sendmsg(),而sendmmsg()是无法和uso一起工作。
  2. udp gso不支持MGS_ZEROCOPY。
  3. 使用udp gso offload代替udp gso是否会带来真正性能上的提升。
  4. 目前udp gso offload只有mlx5-core支持,而intel近一个月才提交patch还未进入upstream。
  5. udp gso设置packet size是否有最优值。

如上只是一些brainstorm,未来可做事情依然很多,但是技术方案并不成熟,最大的问题是兼容性。虽然合并到了upstream,但是不能代表能再生产环境稳定运行。

 

附录

  1. LPC presentation PPT
  2. NETCONF2017 PPT
  3. mlx5-core UDP GSO support
  4. intel系列网卡support
  5. LPC presentation video
  6. 世民谈云计算blog

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值