相信很多客户都经历过从 VPC Peering 到 TGW 的转换过程,因为在发展过程中,需要更多的扩展性,支持更多的 VPC 连接,包括传递路由、防火墙控制;同时也有很多客户具有关于核心路由的低延时、高效访问和流量的成本控制需要,从而有从 TGW 到 VPC Peering 的转换需求。但是无论哪种方法,都会在变更配置中,出现在一定时间内存在非对称路由的状态。
 
       变更前: 对称状态下的两种路由方式
 
        
        
       变更过程中:两种临时状态
 
        
        
       先说结论,只有最后一个场景下(Request 侧为 TGW,Response 侧为 VPC Peering)的非对称路由状态下,会发生超过 MTU 8500 的包丢包。下面是详细解释:
 
       故障现象:只有 MTU 超过 8500 的包会丢,通常是数据库的数据提交,或者应用的大包传递。而类似 ping 和 ssh 访问都完全不会有问题。而 scp 可以用于模拟这个故障现象。如果我们全程用 ping 来观察,是完全不会丢包的。可以用 Ping -s 9000 Target-IP 来进行探测故障现象。
 
       根本原因:VPC Peering Connection 支持的 MTU 是 9001, TGW 接受的 MTU 是 8500,在建立连接协商 MSS 的过程中,TGW 采用的 Clamping 的机制,本身不支持 PMTUD,从而在非对称路由情况下,产生 2 种不同的结果。
 
       非对称路由下从 172.16.8.100 到 172.17.8.100 的访问
 
       基本信息:
 
        
        - MSS 协商过程在 TCP 建立连接的 SYN 和 SYN,ACK 阶段。
  
        - Amazon Linux 默认是 9001 MTU。
  
        - AWS Transit Gateway 支持最大 8500 MTU; VPC Peering 支持最大 9001 MTU。
  
       
 
        
       我们可以分析一下整个流程:
 
       1:172.16.8.100 上发起访问 TCP 访问到 172.17.8.100,都是 Amazon linux 2023 的系统网卡的 MTU 都是 9001,所以去掉 IP 头部 20 字节,TCP 20 字节,所以就是 9001-40=8961。
 
       2:在通过 TGW 网关后,由于 AWS TGW 的 Clamping 的机制,所以在流经 TGW 的时候,就被直接降低为 8500-40=8460。
 
       3:172.17.8.100 收到 SYN,8460 后,发出了 SYN,ACK MSS=8961,这里不容易理解的是,为什么在已经收到 MSS 为 8460 后,仍然发出 8961 的 MSS 的值,实际上这就是 MSS 的协商机制,代表我能处理的最大的包,不管之前收到的多少。如果是对称情况下,SYN,ACK 过程中,会被 TGW 再次修改为 8460。
 
       4:流经 VPC Peering,由于能处理同等级别的 MTU,所以不会改变任何 MSS 的值。
 
       接下来才是真正问题所在,实例 172.16.8.100 就会认为链路上可以接受 8961 的 MSS,所以再发包的时候,就会以 MSS=8961 的进行发包,当再次流经 TGW 后,就会被 TGW Drop 掉所有超过 8500 的包。
 
        
       下面佐证上述的抓包信息。
 
       在 172.16.8.100 发起 SCP 传输到 172.17.8.100
 
       在 172.16.8.100 处抓包:
 
        
       在 172.17.8.100 处抓包:
 
        
       非对称路由下从 172.16.8.100 到 172.17.8.100 的访问:
 
        
       在这种场景下,MSS 最后流经 TGW,最后协商 MSS 就会是 8460,再建立连接后,MSS 就会满足所有中间传输过程所有的网关,也就不会有问题了。
 
       如上,在知道了故障原因后,就知道我们如何来避免这个问题,即尽量来减少对称路由持续的时间。
 
       我们迭代了 2 个版本的方式,下面会给大家做一个简单的介绍。最终测试可以做到时间在 2s 以内,而通常这种情况下,不会触发任何警报。
 
       解决方案
 
       方案 1. 采用 AWS CLI,同时对称执行每条命令
 
       这个方案的每个路由表操作清晰,可以很好地保留单条的回滚操作,但是执行时间稍长,取决于实际您的路由表条数。
 
       我们首先确认需要的变更信息表:
 
        
         
          
           |  
          Name |  
          Route table id |  
          Destination VPC CDIR |  
          Target Gateway ID |  
          Original Gateway |  
         
 
         
         
          
          | 172.16->172.17 |  
          A-sin-private-ap-southeast-1a |  
          rtb-xxxxxxxa01 |  
          172.17.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
          
           |  
          A-sin-private-ap-southeast-1b |  
          rtb-xxxxxxxa02 |  
          172.17.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
          
           |  
          A-sin-private-ap-southeast-1c |  
          rtb-xxxxxxxa03 |  
          172.17.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
          
          | 172.17->172.16 |  
          B-sin-private-ap-southeast-1a |  
          rtb-xxxxxxxb01 |  
          172.16.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
          
           |  
          B-sin-private-ap-southeast-1b |  
          rtb-xxxxxxxb02 |  
          172.16.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
          
           |  
          B-sin-private-ap-southeast-1c |  
          rtb-xxxxxxxb03 |  
          172.16.0.0/16 |  
          tgw-xxxxxxxxxxxxxxxxx |  
          pcx-xxxxxxxxxxxxxxxxx |  
         
 
         
       
 
        
        172.16:
aws ec2 replace-route --route-table-id rtb-xxxxxxxa01 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa02 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa03 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name
172.17:
aws ec2 replace-route --route-table-id rtb-xxxxxxxb01  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb02  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb03  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name
 
         
       所以对应的回滚命令:
 
        
        172.16:
aws ec2 replace-route --route-table-id rtb-xxxxxxxa01 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa02 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa03 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
172.17:
aws ec2 replace-route --route-table-id rtb-xxxxxxxb01  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb02  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb03  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
 
         
       反之亦然。
 
       方案 2. 从指定对称账号下抓取指定 VPC 下所有的路由表,针对目标路由修改网关
 
       迭代为并发调用,可以在 1-2 秒级别完成整个对称操作,从而做到应用无感知的更新。
 
       整体方案仍然是:
 
       A:采集目标信息,Python 脚本,依据目标地址,获取所有匹配的 VPC 下的路由表,输出为 CSV,对比变更内容。
 
        
        $ python3 getAllRouteTableInfo.py
CSV file 'route_info.csv' has been created with the route information.
$ cat route_info.csv
vpc,route table id,dest vpc cidr,gateway
vpc-0b66cf51703b7d189,rtb-004257d2fe5ab16ab,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0b66cf51703b7d189,rtb-03e8ac66f8c002544,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0b66cf51703b7d189,rtb-0ed6c9acc69963302,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-05f7948acdf9149e1,172.16.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-0c8090b390f805219,172.16.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-04fd7e3c5c609634b,172.16.0.0/16,tgw-015dbf530ac9fb88c
 
         
       B:变更脚本,依据目标地址,获取每条记录,并发改匹配的所有路由表网关。程序本身是幂等的,每次可以通过脚步 A 保留执行结果。
 
        
        $ python3 changRouteTable.py
No matching route found in route table rtb-0d39482f555cd3818 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a588923eb2883c15 for CIDR 172.17.0.0/16
No matching route found in route table rtb-000b98350ab58a79d for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a16367cfbbb7e4de for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-04fd7e3c5c619d34b for CIDR 172.16.0.0/16
No matching route found in route table rtb-0aa7e8ec3768dbdb5 for CIDR 172.16.0.0/16
Task completed for route table rtb-04fd7e3c5c609d33b
No matching route found in route table rtb-0bd2d895b5e7a7d1c for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-05f7948acdf9199e1 for CIDR 172.16.0.0/16
Task completed for route table rtb-05f7948acdf9199e1
Route replaced successfully in route table rtb-0c8090b390f807219 for CIDR 172.16.0.0/16
Task completed for route table rtb-0c8090b390f807219
Route replaced successfully in route table rtb-004257d2fe5ab96ab for CIDR 172.17.0.0/16
Route replaced successfully in route table rtb-0ed6c9acc6996a302 for CIDR 172.17.0.0/16
Task completed for route table rtb-004257d2fe5ab96ab
Task completed for route table rtb-0ed6c9acc6996a302
Route replaced successfully in route table rtb-03e8ac66f8c005544 for CIDR 172.17.0.0/16
Task completed for route table rtb-03e8ac66f8c005544
All tasks completed.
 
         
       C:回滚脚本, 依据目标地址,获取每条记录,并发改匹配的所有路由表网关。
 
        
        $ python3 restoreRouteTable.py
No matching route found in route table rtb-0d39482f555cd3818 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a588923eb2883c15 for CIDR 172.17.0.0/16
No matching route found in route table rtb-000b98350ab58a79d for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a16367cfbbb7e4de for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-0ed6c9acc6996a312 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0aa7e8ec3768dbdb5 for CIDR 172.16.0.0/16
No matching route found in route table rtb-0bd2d895b5e7a7d1c for CIDR 172.16.0.0/16
Task completed for route table rtb-0ed6c9acc6996a312
Route replaced successfully in route table rtb-04fd7e3c5c609d31b for CIDR 172.16.0.0/16
Task completed for route table rtb-04fd7e3c5c609d31b
Route replaced successfully in route table rtb-004257d2fe5ab96ab for CIDR 172.17.0.0/16
Task completed for route table rtb-004257d2fe5ab96ab
Route replaced successfully in route table rtb-05f7948acdf9199e1 for CIDR 172.16.0.0/16
Task completed for route table rtb-05f7948acdf9199e1
Route replaced successfully in route table rtb-03e8ac66f8c005544 for CIDR 172.17.0.0/16
Task completed for route table rtb-03e8ac66f8c005544
Route replaced successfully in route table rtb-0c8090b390f807219 for CIDR 172.16.0.0/16
Task completed for route table rtb-0c8090b390f807219
All tasks completed.
 
         
       代码在 Github 的位置如下:
 
       https://github.com/JasonB9527/Route-Table-Changes-Between-TGW-and-VPC-Peering
 
       就在文章发布之际,公司发布了新的特性,目前 TGW 已经支持 PMTUD,以后不会再出现这个异步路由情况下丢包的场景了。
 
       https://aws.amazon.com/about-aws/whats-new/2024/11/aws-transit-gateway-cloud-wan-visibility-metrics-path-mtu/
 
       相关文档
 
       https://docs.aws.amazon.com/vpc/latest/peering/vpc-peering-basics.html (关键字: MTU/MSS)
 
       https://docs.aws.amazon.com/vpc/latest/tgw/transit-gateway-quotas.html (关键字: MSS/Clamping)
 
       https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-mtu.html (关键字: MTU/MSS)
 
       本篇作者