0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SO_REUSEADDR 与 SO_REUSEPORT是什么?

Linux爱好者 来源:187J3X1 作者:187J3X1 2020-12-11 16:38 次阅读

SO_REUSEPORT选项在Linux 3.9被引入内核,在这之前也有一个很像的选项SO_REUSEADDR。

如果你不太清楚这两者的区别和联系,建议搜索 How do SO_REUSEADDR and SO_REUSEPORT differ?。

如果不想读,那么下面这一节算是为懒人准备的。

SO_REUSEADDR 与 SO_REUSEPORT 是什么?

TCP/UDP用五元组唯一标识一个连接。

任何时候,两条连接的五元组都不能完全相同,否则当收到一个报文时,协议栈没办法判断它是属于哪个连接的。

五元组{, , , , }

五元组里,protocol在创建socket时确定,在bind()时确定,在connect()时确定。

当然,bind()和connect()在一些时候并不需要显式使用,不过这不在本文的讨论范围里。

那么,如果对socket设置了SO_REUSEADDR和SO_REUSEPORT选项,它们什么时候起作用呢?

答案是bind(),也就在确定时。

不同操作系统内核对待SO_REUSEADDR和SO_REUSEPORT的行为有少许差异,但它们都源自BSD

因此,接下来就以BSD的实现为标准进行说明。

SO_REUSEADDR

假设我现在需要bind()将socketA绑定到A:X,将socketB绑定到B:Y(不考虑X=0或者Y=0,因为0表示让内核自动分配端口,一定不会冲突)。

如果X!=Y,那么无论A和B的关系如何,两个bind()都会成功。但如果X==Y,那么结果会是下面这样:

SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON/OFF 192.168.0.1:21 192.168.0.1:21 Error (EADDRINUSE) ON/OFF 192.168.0.1:21 10.0.0.1:21 OK ON/OFF 10.0.0.1:21 192.168.0.1:21 OK OFF 0.0.0.0:21 192.168.1.0:21 Error (EADDRINUSE) OFF 192.168.1.0:21 0.0.0.0:21 Error (EADDRINUSE) ON 0.0.0.0:21 192.168.1.0:21 OK ON 192.168.1.0:21 0.0.0.0:21 OK ON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE)

第一列表示是否设置SO_REUSEADDR注,最后一列表示后绑定的socket是否能绑定成功。

注:这里设置的对象是指后绑定的socket(也就是说不关心前一个是否设置)

可以看出,BSD的实现中SO_REUSEADDR可以让一个使用通配地址(0.0.0.0),一个使用指定地址(192.168.1.0)的socket同时绑定成功。

SO_REUSEADDR还有一种应用情景:在TCP中存在一个TIME_WAIT状态,它是指主动关闭的一端最后停留的阶段。

假设socketA绑定到A:X,在完成TCP通信后主动使用close(),进入TIME_WAIT,此时,如果socketB也去绑定A:X,那么同样会得到EADDRINUSE错误,但如果socketB设置了SO_REUSEADDR,那么就可以绑定成功。

SO_REUSEPORT

如果理解了SO_REUSEADDR,那么SO_REUSEPORT就很好理解了,它让两个socket可以绑定完全相同的

SO_REUSEPORT socketA socketB Result --------------------------------------------------------------------- ON 192.168.0.1:21 192.168.0.1:21 OK

提醒一下,以上的结果都是BSD的结果,Linux内核有一些不一样的地方,具体表现为

3.9版本支持SO_REUSEPORT,作为Server的TCP Socket一旦绑定到了具体的端口,启动了LISTEN,即使它之前设置过SO_REUSEADDR, 也不会生效。这一点Linux比BSD更加严格

SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON/OFF 192.168.0.1:21 0.0.0.0:21 Error (EADDRINUSE)

3.9版本之前,作为Client的Socket,SO_REUSEADDR选项具有BSD中的SO_REUSEPORT的效果。这一点Linux又比BSD更加宽松。

SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON 192.168.0.2:55555 192.168.0.2:55555 OK

Linux中reuseport的演进

Linux < 3.9

下面看看具体是怎么做的: 内核socket使用skc_reuse字段表示是否设置了SO_REUSEADDR

struct sock_common { /* omitted */ unsigned char skc_reuse; /* omitted */ } int sock_setsockopt(struct socket *sock, int level, int optname,... { ...... case SO_REUSEADDR: sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); break; }

inet_bind_bucket表示一个绑定的端口。

struct inet_bind_bucket { /* omitted */ unsigned short port; signed short fastreuse; int num_owners; struct hlist_node node; struct hlist_head owners; };

上面结构中的fastreuse表示该端口是否支持共享,所有共享该端口的socket挂到owner成员上。在用户使用bind()时,内核使用TCP:inet_csk_get_port(),UDP:udp_v4_get_port()来绑定端口。

/* inet_connection_Sock.c: inet_csk_get_port() */ tb_found: if (!hlist_empty(&tb->owners)) { ...... if (tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN && smallest_size == -1) { goto success;

所以,当该端口支持共享,且socket也设置了SO_REUSEADDR并且不为LISTEN状态时,此次bind()可以成功。

3.9 =< Linux < 4.5

3.9版本内核增加了对SO_REUSEPORT的支持,listener可以绑定到相同的了。

这个时候,当Server收到Client发送的SYN报文时,会选择其中一个socket进行响应。

具体到实现,3.9版本扩展了sock_common,将原来记录skc_reuse进行了拆分.

struct sock_common { unsigned short skc_family; volatile unsigned char skc_state; - unsigned char skc_reuse; + unsigned char skc_reuse:4; + unsigned char skc_reuseport:4; @@ int sock_setsockopt(struct socket *sock, int level, int optname, case SO_REUSEADDR: sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); break; + case SO_REUSEPORT: + sk->sk_reuseport = valbool; + break;

然后对inet_bind_bucket也相应进行了扩展

struct inet_bind_bucket { /* omitted */ unsigned short port; - signed short fastreuse; + signed char fastreuse; + signed char fastreuseport; + kuid_t fastuid;

而在绑定端口时,增加了一个队reuseport的通过条件

/* inet_connection_sock.c: inet_csk_get_port() */ tb_found: if (sk->sk_reuse == SK_FORCE_REUSE) goto success; - if (tb->fastreuse > 0 && - sk->sk_reuse && sk->sk_state != TCP_LISTEN && + if (((tb->fastreuse > 0 && + sk->sk_reuse && sk->sk_state != TCP_LISTEN) || + (tb->fastreuseport > 0 && + sk->sk_reuseport && uid_eq(tb->fastuid, uid))) && smallest_size == -1) { goto success;

而当Client的SYN报文到达时,Server会首先根据本地端口(SYN报文的)计算出一条hash冲突链,然后遍历该链表上的所有Socket,根据四元组匹配程度进行打分;

如果使能了reuseport,那么可能有多个Socket都将拿到最高分,此时内核将随机选择一个进行后续处理。

/* inet_hashtables.c */ struct sock *__inet_lookup_listener(struct......) { struct sock *sk, *result; unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; // 根据本地端口找到hash冲突链 /* code omitted */ result = NULL; hiscore = 0; sk_nulls_for_each_rcu(sk, node, &ilb->head) { score = compute_score(sk, net, hnum, daddr, dif); // 根据匹配程度进行打分 if (score > hiscore) { result = sk; hiscore = score; reuseport = sk->sk_reuseport; if (reuseport) { phash = inet_ehashfn(net, daddr, hnum, saddr, sport); matches = 1; // 如果是reuseport 则累计多少个socket满足 } } else if (score == hiscore && reuseport) { matches++; if (reciprocal_scale(phash, matches) == 0) result = sk; phash = next_pseudo_random32(phash); } } /* * if the nulls value we got at the end of this lookup is * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ return result; }

举个栗子,假设内核有4条listening socket的hash冲突链,然后用户建立了4个Server:A、B、C、D,监听的地址和端口如下图所示,A和B使能了SO_REUSEPORT。

冲突链是以端口为Key的,因此A、B、D会挂到同一条冲突链上。

如果此时收到对端一个SYN报文<192.168.10.1, 21>,那么内核会遍历listening_hash[0],为上面的7个socket进行打分,而由于B监听的是精确的地址,所以B的得分会比A高,内核最终选择出一个SocketB进行后续处理。

89f4964a-2eb2-11eb-a64d-12bb97331649.png

4.5 < Linux

从上面的例子可以看出,当收到SYN报文时,内核一定会遍历一条完整hash冲突链,为每一个socket进行打分,这稍微有些多余。

因此,在4.5版本中,内核引入了reuseport groups,它将绑定到同一个IP和Port,并且设置了SO_REUSEPORT选项的socket组织到一个group内部。

8a34dac0-2eb2-11eb-a64d-12bb97331649.png

--- a/include/net/sock.h +++ b/include/net/sock.h @@ -318,6 +318,7 @@ struct cg_proto; * @sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE) * @sk_backlog_rcv: callback to process the backlog * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 + * @sk_reuseport_cb: reuseport group container */ struct sock { /* @@ -453,6 +454,7 @@ struct sock { int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void (*sk_destruct)(struct sock *sk); + struct sock_reuseport __rcu *sk_reuseport_cb; };

这个特性在4.5版本只支持UDP,而在4.6版本开始支持TCP(patch)。

这样在查找listen socket时,内核将不用再遍历整个冲突链,而是在找到一个合格的socket时,如果它设置了SO_REUSEPORT,就直接找到它所属的reuseport group,从中选择一个进行后续处理。

@@ -215,6 +217,7 @@ struct sock *__inet_lookup_listener(struct net *net, unsigned int hash = inet_lhashfn(net, hnum); struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; int score, hiscore, matches = 0, reuseport = 0; + bool select_ok = true; u32 phash = 0; rcu_read_lock(); @@ -230,6 +233,15 @@ begin: if (reuseport) { phash = inet_ehashfn(net, daddr, hnum, saddr, sport); + if (select_ok) { + struct sock *sk2; + sk2 = reuseport_select_sock(sk, phash, + skb, doff); + if (sk2) { + result = sk2; + goto found; + } + } matches = 1; } }

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    3

    文章

    1372

    浏览量

    40294
  • Linux
    +关注

    关注

    87

    文章

    11306

    浏览量

    209555

原文标题:Linux 内核中 reuseport 的演进

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    TEA2376DT恩智浦PFC控制器驱动芯片

    - SO10/SO14的交错PFC▪相移,为优秀的PF/THD▪先进的频率控制,效率高▪添加/脱落/BM▪高灵活性和易于通过GUI设计最小包装,SO10和SO14通过MTP实现高可配置
    发表于 12-23 17:13 0次下载

    3PEAK最新物料选型总表(包含MPQ、最新LT交期情况

    TPA3662-VS1R MSOP8 3000 10 OPATPA3664-SO2R SOP14 2500 24 OPATPM1525-SO1R-S SOP8 4000 10
    发表于 12-10 12:35 0次下载

    恒温箱内的敏锐气体侦探-氧化锆氧传感器SO-E2-250、SO-E2-960

    恒温箱作为生物学、微生物学和医疗保健领域的关键工具,为细胞、组织和微生物样本的生长和培养提供了必要的控制条件。在这些应用中,准确监测和调整培养环境中的氧水平非常重要,氧化锆氧传感器SO
    的头像 发表于 12-04 01:07 169次阅读
    恒温箱内的敏锐气体侦探-氧化锆氧传感器<b class='flag-5'>SO</b>-E2-250、<b class='flag-5'>SO</b>-E2-960

    氧化锆氧传感器SO-E2-XXX在恒温箱内的应用

    SO-E2-XXX正是实现这一目标的重要工具。 氧测量传感器如何有益于细胞培养箱? 细胞培养箱中的氧测量传感器,如氧化锆氧传感器SO-E2-XXX,通过精确监测和调节氧水平,确保了细胞生长所需的理想环境。细胞在分化、增殖和存活等关键过程中
    的头像 发表于 11-07 13:43 154次阅读
    氧化锆氧传感器<b class='flag-5'>SO</b>-E2-XXX在恒温箱内的应用

    IGBT 和 MOSFET 驱动器-延展型 SO-6 封装,实现紧凑设计、快速开关和高压

    最新 IGBT 和 MOSFET 驱动器 器件峰值输出电流高达 4 A 工作温度高达 +125 °C,传播延迟低至 200 ns Vishay 推出两款采用紧凑、高隔离延展型 SO-6 封装
    的头像 发表于 11-03 13:42 254次阅读
    IGBT 和 MOSFET 驱动器-延展型 <b class='flag-5'>SO</b>-6 封装,实现紧凑设计、快速开关和高压

    请问OPA2378有没有SO-8封装的呢?

    请问OPA2378 有没有SO-8封装的呢? Tks!
    发表于 09-26 07:45

    ADS114S06和ADS114S08与低成本ADS114S06B和ADS114SO8B的比较

    电子发烧友网站提供《ADS114S06和ADS114S08与低成本ADS114S06B和ADS114SO8B的比较.pdf》资料免费下载
    发表于 09-10 10:34 2次下载
    ADS114S06和ADS114S08与低成本ADS114S06B和ADS114<b class='flag-5'>SO</b>8B的比较

    麻烦厂家发一份CS1237-SO的驱动程序给我STC版本的

    麻烦厂家发一份CS1237-SO的驱动程序给我STC版本的741891100@qq.com
    发表于 08-23 14:48

    STM32MP157运行glmark2提示没有openEGL.so,为什么?

    使用weston相关的应用,运行glmark2提示没有openEGL.so。请问一下这是为什么呢?这些应用和动态库应该都是在根文件系统啊。****
    发表于 07-23 08:19

    【飞凌嵌入式OK527N-C开发板体验】终章-传感器数据互通

    , SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror(\"setsockopt\"
    发表于 07-10 22:16

    如何在ROS中调用.so文件

    的是 liblibdaq-2.0.0.so这个文件,下面以ROS为例子怎么调用.so文件。 结合cmake的使用 新建工作空间,功能包等流程不再赘述,网上已经有很多教程了。着重讲cmakelist的配置
    发表于 07-02 14:44

    如何在ROS中调用.so文件

    设备笔者有一个需求,需要结合ROS做模拟量采集。有一种解决方法是ADC芯片+STM32主控,通过串口的方式与上位机通信,但串口通信速度很慢,达不到要求遂放弃。也考虑过使用NI的数据采集卡,貌似NI没有给ubuntu作配套,也放弃了。在淘宝上找到一款凌智电子的DAQ,价格便宜,也能满足使用需求,故做记录。系统环境ubuntu20.04+ROSnoetic硬件设
    的头像 发表于 06-30 08:23 539次阅读
    如何在ROS中调用.<b class='flag-5'>so</b>文件

    使用IAR和STlink,stm8 so disco的板子,提示Failed to set option byte: 怎么解决?

    使用IAR和STlink,stm8 so disco的板子,提示 Failed to set option byte: 写保护应该是取消了的,有没有前辈遇到这个问题
    发表于 04-16 08:03

    STM32MP157无法使用weston相关的应用,运行glmark2提示没有openEGL.so,为什么?

    使用weston相关的应用,运行glmark2提示没有openEGL.so。请问一下这是为什么呢?这些应用和动态库应该都是在根文件系统啊。
    发表于 03-15 07:47

    SO14;SMD卷轴包,13“;Q1/T1产品定位包装信息

    电子发烧友网站提供《SO14;SMD卷轴包,13“;Q1/T1产品定位包装信息.pdf》资料免费下载
    发表于 02-22 09:30 0次下载
    <b class='flag-5'>SO</b>14;SMD卷轴包,13“;Q1/T1产品定位包装信息