
# 定制TCP重传策略
#### 背景说明
TCP报文重传遵循指数退避原则，在弱网场景下丢包率较高，时延较高。因此新增通过编程接口定制TCP重传策略的能力，包括定制线性退避次数、最大重传次数、最大重传间隔时间，以优化弱网场景的丢包率和时延。
#### 接口说明
- 通过sysctl设置TCP重传策略功能。 net.ipv4.tcp_sock_retrans_policy_custom，用于控制定制TCP重传策略功能是否开启。
  0：关闭定制TCP重传策略功能。
  1：开启定制TCP重传策略功能。
  ```
  sysctl -w net.ipv4.tcp_sock_retrans_policy_custom=1
  ```
  
 
- 调用setsockopt针对指定socket定制TCP重传策略。
  - 接口
    ```
    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
    int getsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
    ```
    optname传递枚举，optval传递结构体起始地址。
    
  
  - 枚举
    ```
    TCP_SOCK_RETRANS_POLICY_CUSTOM 100
    ```
    
  
  - 结构体
    ```
    struct tcp_sock_retrans_policy {
        uint8_t tcp_linear_timeouts_times; /* number of times linear backoff */
        uint8_t tcp_retries_max; /* maximum retransmission times */
        uint8_t tcp_rto_max; /* maximum RTO time, unit:second */
        uint8_t unused;
    };
    ```
    其中
    1. tcp_linear_timeouts_times表示线性退避次数，范围：取值是在0到32之间。 0：使用默认策略（指数退避）。
       非0：定制线性退避次数。
       ![](https://support.huaweicloud.com/usermanual-hce/public_sys-resources/note_3.0-zh-cn.png)
       - 指数退避：发生报文重传时，RTO值直接翻倍。
       
       - 线性退避：发生报文重传时，RTO值保持不变。
         
    
    2. tcp_retries_max表示最大重传次数，范围：取值是在0到64之间。 0：使用系统配置的最大重传次数（默认15次）。
       非0：定制最大重传次数。
       最大重传次数需要大于sysctl选项net.ipv4.tcp_retries1（最小重传次数，默认3次）。
       
    
    3. tcp_rto_max表示最大重传间隔时间，单位为秒，不允许设置小数，范围：取值是0或者在20到120之间。 0：使用默认最大重传间隔时间（120秒）。
       非0：定制最大重传间隔时间。
       
     
   
#### 使用说明
- 开启TCP重传策略定制能力。通过如下命令，将net.ipv4.tcp_sock_retrans_policy_custom配置为1：
  ```
  [root@localhost ~]# sysctl -w net.ipv4.tcp_sock_retrans_policy_custom=1
  ```
  
- 设置线性退避4次，最大重传10次，最大重传间隔时间20秒：
  ```
  tcp_sock_retrans_policy policy = {0};
  policy.tcp_linear_timeouts_times = 4; 
  policy.tcp_retries_max = 10; 
  policy.tcp_rto_max = 20; 
  setsockopt(sockfd, SOL_TCP, TCP_SOCK_RETRANS_POLICY_CUSTOM, (const void*)&policy, sizeof(struct tcp_sock_retrans_policy));
  ```
  
- 恢复为默认策略：
  ```
  tcp_sock_retrans_policy policy = {0};
  setsockopt(sockfd, SOL_TCP, TCP_SOCK_RETRANS_POLICY_CUSTOM, (const void*)&policy, sizeof(struct tcp_sock_retrans_policy));
  ```
  
- 关闭TCP重传策略定制能力：
  ```
  [root@localhost ~]# sysctl -w net.ipv4.tcp_sock_retrans_policy_custom=0
  ```
  ![](https://support.huaweicloud.com/usermanual-hce/public_sys-resources/caution_3.0-zh-cn.png)
  定制TCP重传策略功能在HCEOS版本内核进行修改，在HCEOS版本glibc中使用该功能，需要在用户态代码中添加TCP_SOCK_RETRANS_POLICY_CUSTOM 宏以及对应的结构体tcp_sock_retrans_policy。
  
 
#### 约束限制
1. 只针对ESTABLISHED状态的TCP链接生效。
2. 支持IPv4和IPv6，由于历史原因，TCP相关sysctl选项都挂在net.ipv4下，实际以net.ipv4.tcp打头的sysctl选项，对IPv4和IPv6均生效。
3. 应用级TCP重传策略优先级高于其他全局级TCP重传配置。
4. 定制TCP重传策略可能会增加系统负载，需要根据系统资源合理定制，建议定制的线性退避次数不超过6次。
5. 如果定制的最大重传次数小于net.ipv4.tcp_retries1（默认值3），则将无法触发网络探测，可能导致部分网络变更场景报文不通。
6. 如果定制的最大重传次数非0，则其必须大于等于线性退避次数，否则返回错误。
7. 如果只定制最大重传间隔时间，不定制最大重传次数，那么实际最大重传次数可能会大于net.ipv4.tcp_retries2（默认值15，描述最大重传次数或时间，下简称R2）。RFC6069规定，如果R2使用次数描述，则必须换算成时间。为避免使能本功能后TCP过早断连，该换算过程使用系统默认TCP_RTO_MAX（120s）而不是定制的最大重传时间，因此对外表现为实际重传次数多于R2。
8. 由于TCP-TLP算法，未收到ACK的尾包可能会被Loss Probe定时器选中做一次重传，用于后续触发快速重传。该次重传不计入本功能定制的重传次数内。
 
