专栏首页专注网络研发RPS与RFS实现分析

RPS与RFS实现分析

RPS和RFS是google贡献的两个补丁,在2.6.35版本中,正式被合并入了内核。这两个补丁总体来说,并不算复杂,实际上很多网络设备厂商早已在自己的产品中,有了类似的应用。但这个涉及到厂商的主营业务,所以不会做任何开源。

前几天在画RPS和RFS的流程图时,发现关于RPS和RFS的实现分析并不多,大部分都是设置和性能对比。所以,今天就炒炒冷饭,聊聊RPS与RFS的实现。

下面是较为完整的RPS&RFS的流程图。

因为微信会压缩图片,看不清楚的同学还是请访问https://raw.githubusercontent.com/gfreewind/kernel_skb_path/master/kernel_skb_path.jpg。

首先,我们要看为什么要有RPS和RFS?在没有它们的年代,网卡触发了接收中断之后,由一个CPU进行处理硬中断,接着在软中断里将数据包向上传递给协议栈。也就是说,哪个CPU响应了网卡中断,就由哪个CPU对该数据包进行全部的处理工作。在单核的时代,这样是没有问题的,但随着多核时代的到来,这就要求硬件必须较为均衡的将中断分发给不同的CPU。这对硬件提出了要求,莫说普通的单队列网卡,就是多队列网卡,也经常碰到在某些主板上,多个队列的中断都被发给一个CPU处理。这时,就需要在软件上做进一步均衡,也就是RPS的目的。

RPS全称为Receive Packet Steering,以TCP报文为例,RPS根据三层协议的IP报文的源地址和目的地址,四层协议的源端口和目的端口,进行hash运算后,确定由哪个CPU处理该报文。这样就弥补了硬件的不足,即使硬中断负载不均,通过RPS再处理,尽力保证各CPU的负载均衡。

而RFS是在RPS基础上更进一步,其全称是Receive Flow Steering,顾名思义RPS只针对数据包,没有对会话做任何考虑,而RFS则尽力保证同一会话仍然由“上次”的CPU处理,这样可以保证cache的热度,提高cache的命中率。

RPS的设置,通过/sys/class/net/eth0/queues/rx-0/rps_cpus设置CPU掩码,每一位对应一个CPU ID,RPS会将数据包在这几个CPU之间进行分发。RFS则略为复杂,既要通过/proc/sys/net/core/rps_sock_flow_entries设置全局的表项大小,也要通过/sys/class/net/eth0/queues/rx-0/rps_flow_cnt设置网卡接收队列的表项大小。

下面将从源码角度,分析RPS和RFS的实现。get_rps_cpu是RPS和RFS处理的入口函数。本文不对其做全面的分析,只对几个重要的关键点做一些分享。

1. 数据包的hash运算

目前很多网卡支持了receive-hashing,即由硬件对数据包做hash运算,驱动会调用skb_set_hash设置结果。这时skb的l4_hash就被设置为true,然后直接返回skb->hash结果。但有时会遇到硬件hash结果有问题,即hash结果比较集中,不分散,从而导致RPS的效果不好。这时就需要关闭网卡的receive-hashing功能。至于软件如何根据数据包计算hash,有兴趣的同学自行研究__skb_get_hash的实现即可。—— BTW,由于支持的协议越来越多,这部分代码也越来越复杂。(再吹个牛,PPTP的RPS支持,是我贡献的:))

2. RFS的全局表项匹配

要看懂这段代码,就要理解RFS的表项ents的结构。

每个ent,由2部分组成。前半部分,是表项对应的CPU,后半部分是hash结果。因此((ident ^ hash) & ~rps_cpu_mask)实际上就是用来匹配后面的hash ident结果。如果匹配,其值为0,如果不匹配,即没有对应RFS表项,则直接使用RPS获取对应的CPU。

3. RFS切换CPU的条件

next_cpu是RFS计算得来的本次sbk需要由哪个cpu处理,tcpu保存的是该flow上次由哪个cpu处理。当两者不一致时,即要切换处理flow的cpu。切换的条件如下:

1) tcpu != next_cpu —— 这个无需多言:)

2) tcp >= nr_cpu_ids,即没有设置处理该flow的cpu;

3)!cpu_online(tcpu),即tcpu已经不在线;

4)per_cpu(softnet_data, tcpu).input_queue_head - rflow->last_qtail >= 0,这个稍微隐晦些。input_queue_head是tcpu当前处理数据包的序号,而rflow->last_qtail记录的是上次该flow在tcpu上待处理的skb的序号。前者大于等于后者时,意味着在tcpu上,属于该flow的skb数据包已经被tcpu处理完毕。之所以要有这个条件,就是为了保证RFS在切换CPU时,也要保证flow的数据包不会被乱序处理。

当切换条件不满足时,RFS仍然会选择上次的cpu,即tcpu。

4. cpu记录RFS表项

既然RFS要保证局部性,所以在CPU开始处理该flow的数据包时,就要记录RFS表项,如在tcp_v4_do_rcv中,调用sock_rps_record_flow_hash来记录是当前CPU处理了该flow。

好了,通过流程图和几个关键点的分析,我相信大家对RPS和RFS已经比较清晰了。

PS:阅读内核代码,除了可以了解OS内部运行机制,还可以锻炼对大型软件的掌控,提高自己对复杂工程的分析能力。

本文分享自微信公众号 - LinuxerPub(LinuxerPub),作者:glinuxer

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-05-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • TCP接收窗口的实现(一)

    TCP首部中的Window字段,表示当前套接字的接收窗口,即目前可以接收的数据大小,对端不会发送超过接收窗口大小的数据。如果在三次握手时,两端都支持Window...

    glinuxer
  • 避免遗忘UNLOCK的小技巧

    C++程序可以通过封装来实现RAII,从而避免一切资源泄漏,包括忘记unlock。当时就为了这点,我就特别想推动用C++写C代码,C++只做封装...

    glinuxer
  • TCP接收窗口的实现(二)

    上篇介绍了TCP接收窗口的初始化,本篇将分析TCP在传输过程中的动态接收窗口大小,由什么决定。

    glinuxer
  • 如何使用java代码通过JDBC连接Impala(附Github源码)

    访问Impala的方式很多(如:impala-shell、ODBC、JDBC、Beeline),也可以通过Hue的来访问。关于Beeline方式连接Impala...

    Fayson
  • 从百度在传统业务上的“沉沦”看互联网营销的未来趋势

    原创作者:宋星 本文长度为5500字 ,建议阅读25分钟。 作者系iCDO创始人,网站分析在中国创始人,宋星 这篇文章部分图表来自宋星在澳大利亚悉尼“Acc...

    iCDO互联网数据官
  • Windows认证 | Windows本地认证

    Windows的登陆密码是储存在系统本地的SAM文件中的,在登陆Windows的时候,系统会将用户输入的密码与SAM文件中的密码进行对比,如果相同,则认证成功。

    信安本原
  • 黑客黑产攻防:1秒定生死的幽灵战

    黑客黑产攻防:1秒定生死的幽灵战; 你在前端秒杀,他们在后台博弈; 犯案模式更简单粗暴,随着国内互联网金融、人工智能和大数据等产业继续深化发展,互联网为实体产业...

    企鹅号小编
  • 如何科学减肥?这款小程序,教你边吃边瘦

    不过在加强运动的同时,我们也不能忽视饮食这个更为重要的因素,比如说控制食物摄入的热量。

    知晓君
  • AI综述专栏|神经科学启发的人工智能

    在科学研究中,从方法论上来讲,都应先见森林,再见树木。当前,人工智能科技迅猛发展,万木争荣,更应系统梳理脉络。为此,我们特别精选国内外优秀的综述论文,开辟“综述...

    马上科普尚尚
  • 平庸前端码农之蜕变 — AST

    首先,先说明下该文章是译文,原文出自《AST for JavaScript developers》。很少花时间特地翻译一篇文章,咬文嚼字是件很累的事情,实在是这...

    Nealyang

扫码关注云+社区

领取腾讯云代金券