Jelajahi Sumber

fix: netdrv,napt,修正tcp连接被意外关闭的

Wendal Chen 3 bulan lalu
induk
melakukan
0d6544189b

+ 5 - 5
components/network/netdrv/include/luat_netdrv_napt.h

@@ -12,18 +12,18 @@
 #define NAPT_RET_INVALID_CTX -4    // NAPT上下文无效
 
 // 哈希表大小(用于加速查找)
-// 优化: 使用2的幂次方便模运算,保持负载因子约0.75平衡性能和内存
+// 根据压力测试结果优化:适应高并发场景,负载因子0.5-0.6
 #ifndef NAPT_HASH_TABLE_SIZE
 #if defined(TYPE_EC718HM)
-#define NAPT_HASH_TABLE_SIZE 8192   // 对应8K映射,负载因子1.0 (64KB)
+#define NAPT_HASH_TABLE_SIZE 16384  // 8K映射,负载因子0.5 (~131KB,两表共计)
 #elif defined(TYPE_EC718PM)
-#define NAPT_HASH_TABLE_SIZE 4096   // 对应4K映射,负载因子1.0 (32KB)
+#define NAPT_HASH_TABLE_SIZE 8192   // 4K映射,负载因子0.5 (~65KB)
 #else
-#define NAPT_HASH_TABLE_SIZE 2048   // 对应2K映射,负载因子1.0 (16KB)
+#define NAPT_HASH_TABLE_SIZE 4096   // 2K映射,负载因子0.5 (~33KB)
 #endif
 #endif
 #define NAPT_HASH_INVALID_INDEX 0xFFFF
-#define NAPT_HASH_MAX_PROBE 32      // 最大探测次数,防止满表时死循环
+#define NAPT_HASH_MAX_PROBE 96      // 提高到96,应对更高的冲突率
 
 // #define IP_NAPT_TIMEOUT_MS_TCP (30*60*1000)
 #define IP_NAPT_TIMEOUT_MS_TCP_DISCON (20*1000)

+ 95 - 9
components/network/netdrv/src/luat_netdrv_napt.c

@@ -129,7 +129,7 @@ __NETDRV_CODE_IN_RAM__ static int napt_hash_add_wan2lan(luat_netdrv_napt_ctx_t *
             return 0;
         }
     }
-    LLOGE("哈希表wan2lan已满,无法添加");
+    LLOGE("哈希表wan2lan已满,无法添加项 %d(冲突深度超过%d)", item_idx, NAPT_HASH_MAX_PROBE);
     return -1;
 }
 
@@ -147,7 +147,7 @@ __NETDRV_CODE_IN_RAM__ static int napt_hash_add_lan2wan(luat_netdrv_napt_ctx_t *
             return 0;
         }
     }
-    LLOGE("哈希表lan2wan已满,无法添加");
+    LLOGE("哈希表lan2wan已满,无法添加项 %d(冲突深度超过%d)", item_idx, NAPT_HASH_MAX_PROBE);
     return -1;
 }
 
@@ -166,7 +166,15 @@ __NETDRV_CODE_IN_RAM__ static int napt_hash_find_wan2lan(luat_netdrv_napt_ctx_t
             return -1;  // 遇到空槽说明不存在
         }
         
+        // 防御性检查:确保索引有效
+        if (idx >= ctx->item_last) {
+            LLOGE("哈希表wan2lan数据损坏,idx %d >= item_last %d", idx, ctx->item_last);
+            return -1;
+        }
+        
         luat_netdrv_napt_tcpudp_t *item = &ctx->items[idx];
+        if (item->is_vaild == 0) continue;  // 跳过已删除的项
+        
         if (item->wnet_ip == wnet_ip && item->wnet_port == wnet_port && item->wnet_local_port == wnet_local_port) {
             return idx;
         }
@@ -189,7 +197,15 @@ __NETDRV_CODE_IN_RAM__ static int napt_hash_find_lan2wan(luat_netdrv_napt_ctx_t
             return -1;  // 遇到空槽说明不存在
         }
         
+        // 防御性检查:确保索引有效
+        if (idx >= ctx->item_last) {
+            LLOGE("哈希表lan2wan数据损坏,idx %d >= item_last %d", idx, ctx->item_last);
+            return -1;
+        }
+        
         luat_netdrv_napt_tcpudp_t *item = &ctx->items[idx];
+        if (item->is_vaild == 0) continue;  // 跳过已删除的项
+        
         if (item->inet_ip == inet_ip && item->inet_port == inet_port && 
             item->wnet_ip == wnet_ip && item->wnet_port == wnet_port) {
             return idx;
@@ -213,10 +229,50 @@ static void napt_hash_rebuild(luat_netdrv_napt_ctx_t *ctx) {
     
     // 重新添加所有有效映射
     for (size_t i = 0; i < ctx->item_last; i++) {
-        napt_hash_add_wan2lan(ctx, i, &ctx->items[i]);
-        napt_hash_add_lan2wan(ctx, i, &ctx->items[i]);
+        if (ctx->items[i].is_vaild == 0) continue;  // 跳过已删除的项
+        
+        if (napt_hash_add_wan2lan(ctx, i, &ctx->items[i]) != 0) {
+            LLOGE("哈希表wan2lan重建时添加失败,项 %d", i);
+        }
+        if (napt_hash_add_lan2wan(ctx, i, &ctx->items[i]) != 0) {
+            LLOGE("哈希表lan2wan重建时添加失败,项 %d", i);
+        }
+    }
+}
+
+// ============ 哈希表优化函数结束 ============
+
+// 统计哈希表使用情况(调试用)
+#ifdef NAPT_DEBUG
+static void napt_hash_stats(luat_netdrv_napt_ctx_t *ctx, const char* tag) {
+    if (ctx == NULL) return;
+    
+    size_t used_wan2lan = 0, used_lan2wan = 0, collisions_wan2lan = 0, collisions_lan2wan = 0;
+    
+    if (ctx->hash_table_wan2lan) {
+        for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+            if (ctx->hash_table_wan2lan[i].item_index != NAPT_HASH_INVALID_INDEX) {
+                used_wan2lan++;
+            }
+        }
     }
+    
+    if (ctx->hash_table_lan2wan) {
+        for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+            if (ctx->hash_table_lan2wan[i].item_index != NAPT_HASH_INVALID_INDEX) {
+                used_lan2wan++;
+            }
+        }
+    }
+    
+    double load_wan2lan = (double)used_wan2lan / NAPT_HASH_TABLE_SIZE * 100;
+    double load_lan2wan = (double)used_lan2wan / NAPT_HASH_TABLE_SIZE * 100;
+    
+    LLOGD("[%s] WAN2LAN: %d/%d (%.1f%%), LAN2WAN: %d/%d (%.1f%%)", 
+          tag, used_wan2lan, NAPT_HASH_TABLE_SIZE, load_wan2lan,
+          used_lan2wan, NAPT_HASH_TABLE_SIZE, load_lan2wan);
 }
+#endif
 
 // ============ 哈希表优化函数结束 ============
 
@@ -415,6 +471,11 @@ static int ctx_init(luat_netdrv_napt_ctx_t** ctx_ptrptr) {
         return -1;
     }
 
+#ifdef NAPT_DEBUG
+    LLOGD("NAPT初始化: 哈希表大小%d, 最大项%d, 最大端口数%d", 
+          NAPT_HASH_TABLE_SIZE, NAPT_TCP_MAP_ITEM_MAX, NAPT_PORT_COUNT);
+#endif
+
     *ctx_ptrptr = ctx;
     return 0;
 }
@@ -529,13 +590,18 @@ __NETDRV_CODE_IN_RAM__ static void mapping_cleanup(luat_netdrv_napt_ctx_t *napt_
     for (size_t i = 0; i < napt_ctx->item_last; i++) {
         flag = 0;
         it = &napt_ctx->items[i];
+        // 跳过已标记删除的映射项
+        if (!it->is_vaild) {
+            continue;
+        }
         tdiff = tnow - it->tm_ms;
         if (napt_ctx->ip_tp == IP_PROTO_TCP) {
             if (tdiff > NAPT_TCP_TIMEOUT_MS) { // TCP是20分钟
                 flag = 1;
             }
-            else if ((((it->finack1 && it->finack2) || !it->synack) && tdiff > NAPT_TCP_DISCON_TIMEOUT_MS)) {
-                // print_item("TCP链接已关闭,移除", it);
+            // 仅当连接明确关闭(FIN-ACK双向)或重置(RST)时才删除,避免误删活动连接
+            else if (((it->finack1 && it->finack2) || it->rst) && tdiff > NAPT_TCP_DISCON_TIMEOUT_MS) {
+                // print_item("TCP连接已关闭,移除", it);
                 flag = 1;
             }
         }
@@ -571,10 +637,19 @@ __NETDRV_CODE_IN_RAM__ static void mapping_cleanup(luat_netdrv_napt_ctx_t *napt_
     }
     // 全部标记完成了, 记录最后的位置
     // LLOGD("清理前后对比 %ld -> %ld", ctx->item_last, cur_index);
+    size_t removed_count = napt_ctx->item_last - cur_index;
     napt_ctx->item_last = cur_index;
     
     // 重建哈希表
     napt_hash_rebuild(napt_ctx);
+    
+    // 调试日志:输出清理和哈希表统计信息
+#ifdef NAPT_DEBUG
+    if (removed_count > 0) {
+        LLOGD("NAPT清理: 移除%d项,剩余%d项", removed_count, cur_index);
+        napt_hash_stats(napt_ctx, "清理后");
+    }
+#endif
 }
 
 
@@ -719,12 +794,23 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_tcp_lan2wan(napt_ctx_t* ctx, luat_ne
         }
         tmp.adapter_id = ctx->net->id;
         tmp.tm_ms = tnow;
+        tmp.is_vaild = 1;  // 标记映射为有效
         it = &napt_ctx->items[napt_ctx->item_last];
         memcpy(it, &tmp, sizeof(luat_netdrv_napt_tcpudp_t));
         
-        // 添加到哈希表
-        napt_hash_add_wan2lan(napt_ctx, napt_ctx->item_last, it);
-        napt_hash_add_lan2wan(napt_ctx, napt_ctx->item_last, it);
+        // 添加到哈希表(两个表都必须成功)
+        if (napt_hash_add_wan2lan(napt_ctx, napt_ctx->item_last, it) != 0) {
+            LLOGE("哈希表wan2lan添加失败,映射表满");
+            memset(it, 0, sizeof(luat_netdrv_napt_tcpudp_t));  // 清理未成功的项
+            ret = NAPT_RET_NO_MEMORY;
+            break;
+        }
+        if (napt_hash_add_lan2wan(napt_ctx, napt_ctx->item_last, it) != 0) {
+            LLOGE("哈希表lan2wan添加失败,映射表满");
+            memset(it, 0, sizeof(luat_netdrv_napt_tcpudp_t));  // 清理未成功的项
+            ret = NAPT_RET_NO_MEMORY;
+            break;
+        }
         
         napt_ctx->item_last ++;
         if (ctx->eth) {