前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >细说TCP的MSS选项(1)

细说TCP的MSS选项(1)

作者头像
glinuxer
发布2019-04-10 14:57:16
7.4K1
发布2019-04-10 14:57:16
举报
文章被收录于专栏:专注网络研发专注网络研发

前几天,我厂剑英和晓培同学在定位一个TCP通信失败问题时,发现原因是客户端发送的TCP数据过长(1460字节),导致数据包无法成功发送到服务端。但通过抓包发现,在三次握手时,双方协商的MSS就是1460。那么,应该是在这个连接的传输过程中,数据包的传输路径发生了变化,走了不同的中间设备,从而导致协商时的MSS大小已经超过了实际的传输路径限制。因为客户端已经发布,我们通过修改服务端的对外接口的MTU,暂时解决了这样的问题。

对于MSS选项,我以前曾经做个简单的研究,这次借着本厂遇到的这个问题,对MSS进行一个比较详细的技术总结。

MSS,全称为Max Segment Size。根据RFC的定义,MSS是一个TCP选项,并且只出现在TCP三次握手的SYN包中(包括SYN+ACK),用于通知对端本地最大可以接收的TCP报文数据大小(不包含TCP和IP报文首部) —— 注意这里是本地可以接收的大小。同一个TCP连接,两个方向上的MSS大小可以不同,并且发送方的TCP报文的最大数据长度不能超过对端声明的MSS大小。

明确了MSS的含义之后,就要问MSS的大小由什么决定?再次感谢开源的Linux内核,可以帮助我们解开这个秘密。

在函数tcp_syn_options中,

对TCP选项mss进行了赋值。接下来进入tcp_advertise_mss。

上图箭头所指的变量metric,个人认为起名不太明确,其值为dst_metric_advmss,实际上是得到的事dst的advmss大小。

其中dst_metric_raw取得对应dst的advmss属性 —— 通过ip route配置路由时,可以指定advmss选项。如果没有配置,则调用default_advmss。对于IPv4来说,就是ipv4_default_advmss。

也就是说,对于IPv4的dst advmss,其值一般为该接口的MTU减去TCP和IP的固定首部大小。

不要忘了前文中的tp->advmss,其值在函数tcp_connect_init中,由tcp_mss_clamp决定,即tp->advmss = tcp_mss_clamp(tp, dst_metric_advmss(dst))。

而user_mss由用户通过套接字选项TCP_MAXSEG配置。

综上所述,可以总结出影响TCP的MSS的因素:

  1. 路由设置的advmss选项;
  2. 出口路由的MTU减去40(TCP和IP报文的固定首部大小);
  3. IPv4的最高IPV4_MAX_PMTU-40(同上);

通常我们都不会设置路由的advmss选项,因此,TCP的MSS的值一般就为出口路由的MTU减去40。

TCP握手阶段的MSS,在内核代码中被称为advmss,即通告MSS。而在TCP的传输过程中,就像开头提到的那样,中间路由设备发生了变化,从而导致协商时的MSS大小不再适用于当前传输路径。那么这时就要引出PMTU了,留待后文分解。

专注Linux网络领域开发,坚持每周一更。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 LinuxerPub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档