Bläddra i källkod

update: netdrv,napt,将线性查表改成hash表

Wendal Chen 3 månader sedan
förälder
incheckning
82154e1244

+ 23 - 0
components/network/netdrv/include/luat_netdrv_napt.h

@@ -11,6 +11,19 @@
 #define NAPT_RET_LOCK_FAIL   -3    // 加锁失败
 #define NAPT_RET_INVALID_CTX -4    // NAPT上下文无效
 
+// 哈希表大小(用于加速查找)
+// 根据最大映射数自动调整,保持负载因子约0.5以获得最佳性能
+#ifndef NAPT_HASH_TABLE_SIZE
+#if defined(TYPE_EC718HM)
+#define NAPT_HASH_TABLE_SIZE 16384  // 对应8K映射,内存充足时使用大哈希表
+#elif defined(TYPE_EC718PM)
+#define NAPT_HASH_TABLE_SIZE 8192   // 对应4K映射
+#else
+#define NAPT_HASH_TABLE_SIZE 4096   // 对应2K映射
+#endif
+#endif
+#define NAPT_HASH_INVALID_INDEX 0xFFFF
+
 // #define IP_NAPT_TIMEOUT_MS_TCP (30*60*1000)
 #define IP_NAPT_TIMEOUT_MS_TCP_DISCON (20*1000)
 #ifndef NAPT_TCP_MAP_ITEM_MAX
@@ -74,6 +87,12 @@ typedef struct luat_netdrv_napt_llist
     luat_netdrv_napt_tcpudp_t item;
 }luat_netdrv_napt_llist_t;
 
+// 哈希表项,用于加速查找
+typedef struct {
+    uint16_t item_index;  // 映射项在items数组中的索引,NAPT_HASH_INVALID_INDEX表示空槽
+    uint16_t next_index;  // 链表下一个索引(用于处理哈希冲突)
+} napt_hash_entry_t;
+
 typedef struct luat_netdrv_napt_ctx{
     uint32_t ip_tp;
     size_t clean_tm;
@@ -82,6 +101,10 @@ typedef struct luat_netdrv_napt_ctx{
     luat_netdrv_napt_tcpudp_t items[NAPT_TCP_MAP_ITEM_MAX];
     luat_rtos_mutex_t lock;
     uint32_t *port_used;
+    // 哈希表用于加速查找(WAN->LAN方向)
+    napt_hash_entry_t *hash_table_wan2lan;  // 按(wnet_ip, wnet_port, wnet_local_port)索引
+    // 哈希表用于加速查找(LAN->WAN方向)
+    napt_hash_entry_t *hash_table_lan2wan;  // 按(inet_ip, inet_port, wnet_ip, wnet_port)索引
 }luat_netdrv_napt_ctx_t;
 
 int luat_napt_icmp_handle(napt_ctx_t* ctx);

+ 208 - 26
components/network/netdrv/src/luat_netdrv_napt.c

@@ -61,6 +61,162 @@ static void check_it(const char* tag, luat_netdrv_napt_llist_t* it, luat_netdrv_
     }
 }
 
+// ============ 哈希表优化函数 ============
+
+// WAN->LAN方向的哈希函数:基于(wnet_ip, wnet_port, wnet_local_port)
+__NETDRV_CODE_IN_RAM__ static inline uint32_t napt_hash_wan2lan(uint32_t wnet_ip, uint16_t wnet_port, uint16_t wnet_local_port) {
+    // 简单的FNV-1a哈希变种
+    uint32_t hash = 2166136261U;
+    hash ^= wnet_ip;
+    hash *= 16777619U;
+    hash ^= ((uint32_t)wnet_port << 16) | wnet_local_port;
+    hash *= 16777619U;
+    return hash % NAPT_HASH_TABLE_SIZE;
+}
+
+// LAN->WAN方向的哈希函数:基于(inet_ip, inet_port, wnet_ip, wnet_port)
+__NETDRV_CODE_IN_RAM__ static inline uint32_t napt_hash_lan2wan(uint32_t inet_ip, uint16_t inet_port, uint32_t wnet_ip, uint16_t wnet_port) {
+    uint32_t hash = 2166136261U;
+    hash ^= inet_ip;
+    hash *= 16777619U;
+    hash ^= ((uint32_t)inet_port << 16) | wnet_port;
+    hash *= 16777619U;
+    hash ^= wnet_ip;
+    hash *= 16777619U;
+    return hash % NAPT_HASH_TABLE_SIZE;
+}
+
+// 初始化哈希表
+static void napt_hash_init(luat_netdrv_napt_ctx_t *ctx) {
+    if (ctx->hash_table_wan2lan == NULL) {
+        ctx->hash_table_wan2lan = luat_heap_malloc(NAPT_HASH_TABLE_SIZE * sizeof(napt_hash_entry_t));
+        if (ctx->hash_table_wan2lan) {
+            for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+                ctx->hash_table_wan2lan[i].item_index = NAPT_HASH_INVALID_INDEX;
+                ctx->hash_table_wan2lan[i].next_index = NAPT_HASH_INVALID_INDEX;
+            }
+        }
+    }
+    if (ctx->hash_table_lan2wan == NULL) {
+        ctx->hash_table_lan2wan = luat_heap_malloc(NAPT_HASH_TABLE_SIZE * sizeof(napt_hash_entry_t));
+        if (ctx->hash_table_lan2wan) {
+            for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+                ctx->hash_table_lan2wan[i].item_index = NAPT_HASH_INVALID_INDEX;
+                ctx->hash_table_lan2wan[i].next_index = NAPT_HASH_INVALID_INDEX;
+            }
+        }
+    }
+}
+
+// 向哈希表添加映射(WAN->LAN)
+__NETDRV_CODE_IN_RAM__ static void napt_hash_add_wan2lan(luat_netdrv_napt_ctx_t *ctx, uint16_t item_idx, luat_netdrv_napt_tcpudp_t *item) {
+    if (ctx->hash_table_wan2lan == NULL) return;
+    
+    uint32_t hash = napt_hash_wan2lan(item->wnet_ip, item->wnet_port, item->wnet_local_port);
+    napt_hash_entry_t *entry = &ctx->hash_table_wan2lan[hash];
+    
+    if (entry->item_index == NAPT_HASH_INVALID_INDEX) {
+        // 空槽,直接放置
+        entry->item_index = item_idx;
+        entry->next_index = NAPT_HASH_INVALID_INDEX;
+    } else {
+        // 冲突,使用线性探测找下一个空槽
+        for (size_t i = 1; i < NAPT_HASH_TABLE_SIZE; i++) {
+            uint32_t probe = (hash + i) % NAPT_HASH_TABLE_SIZE;
+            if (ctx->hash_table_wan2lan[probe].item_index == NAPT_HASH_INVALID_INDEX) {
+                ctx->hash_table_wan2lan[probe].item_index = item_idx;
+                ctx->hash_table_wan2lan[probe].next_index = NAPT_HASH_INVALID_INDEX;
+                entry->next_index = probe;
+                break;
+            }
+        }
+    }
+}
+
+// 向哈希表添加映射(LAN->WAN)
+__NETDRV_CODE_IN_RAM__ static void napt_hash_add_lan2wan(luat_netdrv_napt_ctx_t *ctx, uint16_t item_idx, luat_netdrv_napt_tcpudp_t *item) {
+    if (ctx->hash_table_lan2wan == NULL) return;
+    
+    uint32_t hash = napt_hash_lan2wan(item->inet_ip, item->inet_port, item->wnet_ip, item->wnet_port);
+    napt_hash_entry_t *entry = &ctx->hash_table_lan2wan[hash];
+    
+    if (entry->item_index == NAPT_HASH_INVALID_INDEX) {
+        entry->item_index = item_idx;
+        entry->next_index = NAPT_HASH_INVALID_INDEX;
+    } else {
+        for (size_t i = 1; i < NAPT_HASH_TABLE_SIZE; i++) {
+            uint32_t probe = (hash + i) % NAPT_HASH_TABLE_SIZE;
+            if (ctx->hash_table_lan2wan[probe].item_index == NAPT_HASH_INVALID_INDEX) {
+                ctx->hash_table_lan2wan[probe].item_index = item_idx;
+                ctx->hash_table_lan2wan[probe].next_index = NAPT_HASH_INVALID_INDEX;
+                entry->next_index = probe;
+                break;
+            }
+        }
+    }
+}
+
+// 从哈希表查找映射(WAN->LAN)
+__NETDRV_CODE_IN_RAM__ static int napt_hash_find_wan2lan(luat_netdrv_napt_ctx_t *ctx, uint32_t wnet_ip, uint16_t wnet_port, uint16_t wnet_local_port) {
+    if (ctx->hash_table_wan2lan == NULL) return -1;
+    
+    uint32_t hash = napt_hash_wan2lan(wnet_ip, wnet_port, wnet_local_port);
+    napt_hash_entry_t *entry = &ctx->hash_table_wan2lan[hash];
+    
+    while (entry->item_index != NAPT_HASH_INVALID_INDEX) {
+        luat_netdrv_napt_tcpudp_t *item = &ctx->items[entry->item_index];
+        if (item->wnet_ip == wnet_ip && item->wnet_port == wnet_port && item->wnet_local_port == wnet_local_port) {
+            return entry->item_index;
+        }
+        if (entry->next_index == NAPT_HASH_INVALID_INDEX) break;
+        entry = &ctx->hash_table_wan2lan[entry->next_index];
+    }
+    return -1;
+}
+
+// 从哈希表查找映射(LAN->WAN)
+__NETDRV_CODE_IN_RAM__ static int napt_hash_find_lan2wan(luat_netdrv_napt_ctx_t *ctx, uint32_t inet_ip, uint16_t inet_port, uint32_t wnet_ip, uint16_t wnet_port) {
+    if (ctx->hash_table_lan2wan == NULL) return -1;
+    
+    uint32_t hash = napt_hash_lan2wan(inet_ip, inet_port, wnet_ip, wnet_port);
+    napt_hash_entry_t *entry = &ctx->hash_table_lan2wan[hash];
+    
+    while (entry->item_index != NAPT_HASH_INVALID_INDEX) {
+        luat_netdrv_napt_tcpudp_t *item = &ctx->items[entry->item_index];
+        if (item->inet_ip == inet_ip && item->inet_port == inet_port && 
+            item->wnet_ip == wnet_ip && item->wnet_port == wnet_port) {
+            return entry->item_index;
+        }
+        if (entry->next_index == NAPT_HASH_INVALID_INDEX) break;
+        entry = &ctx->hash_table_lan2wan[entry->next_index];
+    }
+    return -1;
+}
+
+// 重建哈希表(在清理后调用)
+static void napt_hash_rebuild(luat_netdrv_napt_ctx_t *ctx) {
+    if (ctx->hash_table_wan2lan) {
+        for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+            ctx->hash_table_wan2lan[i].item_index = NAPT_HASH_INVALID_INDEX;
+            ctx->hash_table_wan2lan[i].next_index = NAPT_HASH_INVALID_INDEX;
+        }
+    }
+    if (ctx->hash_table_lan2wan) {
+        for (size_t i = 0; i < NAPT_HASH_TABLE_SIZE; i++) {
+            ctx->hash_table_lan2wan[i].item_index = NAPT_HASH_INVALID_INDEX;
+            ctx->hash_table_lan2wan[i].next_index = NAPT_HASH_INVALID_INDEX;
+        }
+    }
+    
+    // 重新添加所有有效映射
+    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 !defined(LUAT_USE_PSRAM) && !defined(LUAT_USE_NETDRV_NAPT)
 __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_pkg_input(int id, uint8_t* buff, size_t len) {
     return 0;
@@ -245,6 +401,11 @@ static int ctx_init(luat_netdrv_napt_ctx_t** ctx_ptrptr) {
     memset(ctx->port_used, 0, port_len);
     ctx->clean_tm = 1;
     ctx->item_max = NAPT_TCP_MAP_ITEM_MAX;
+    
+    // 初始化哈希表
+    ctx->hash_table_wan2lan = NULL;
+    ctx->hash_table_lan2wan = NULL;
+    napt_hash_init(ctx);
 
     *ctx_ptrptr = ctx;
     return 0;
@@ -273,6 +434,14 @@ void luat_netdrv_napt_disable(void) {
             luat_heap_free(g_napt_tcp_ctx->port_used);
             g_napt_tcp_ctx->port_used = NULL;
         }
+        if (g_napt_tcp_ctx->hash_table_wan2lan) {
+            luat_heap_free(g_napt_tcp_ctx->hash_table_wan2lan);
+            g_napt_tcp_ctx->hash_table_wan2lan = NULL;
+        }
+        if (g_napt_tcp_ctx->hash_table_lan2wan) {
+            luat_heap_free(g_napt_tcp_ctx->hash_table_lan2wan);
+            g_napt_tcp_ctx->hash_table_lan2wan = NULL;
+        }
         luat_rtos_mutex_delete(g_napt_tcp_ctx->lock);
         luat_heap_free(g_napt_tcp_ctx);
         g_napt_tcp_ctx = NULL;
@@ -284,6 +453,14 @@ void luat_netdrv_napt_disable(void) {
             luat_heap_free(g_napt_udp_ctx->port_used);
             g_napt_udp_ctx->port_used = NULL;
         }
+        if (g_napt_udp_ctx->hash_table_wan2lan) {
+            luat_heap_free(g_napt_udp_ctx->hash_table_wan2lan);
+            g_napt_udp_ctx->hash_table_wan2lan = NULL;
+        }
+        if (g_napt_udp_ctx->hash_table_lan2wan) {
+            luat_heap_free(g_napt_udp_ctx->hash_table_lan2wan);
+            g_napt_udp_ctx->hash_table_lan2wan = NULL;
+        }
         luat_rtos_mutex_delete(g_napt_udp_ctx->lock);
         luat_heap_free(g_napt_udp_ctx);
         g_napt_udp_ctx = NULL;
@@ -387,6 +564,9 @@ __NETDRV_CODE_IN_RAM__ static void mapping_cleanup(luat_netdrv_napt_ctx_t *napt_
     // 全部标记完成了, 记录最后的位置
     // LLOGD("清理前后对比 %ld -> %ld", ctx->item_last, cur_index);
     napt_ctx->item_last = cur_index;
+    
+    // 重建哈希表
+    napt_hash_rebuild(napt_ctx);
 }
 
 
@@ -448,20 +628,19 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_tcp_wan2lan(napt_ctx_t* ctx, luat_ne
         napt_ctx->clean_tm = tsec;
         // LLOGD("完成映射关系清理 %ld %ld", tsec, napt_ctx->clean_tm);
     }
-    // size_t c_all = 0;
-    for (size_t i = 0; i < napt_ctx->item_last; i++) {
-        it = &napt_ctx->items[i];
-        // 远程ip(4 byte), 远程端口(2 byte), 本地映射端口(2 byte)
-        if (memcmp(&tmp.wnet_ip, &it->wnet_ip, 8) == 0) {
-            it->tm_ms = tnow;
-            memcpy(mapping, it, sizeof(luat_netdrv_napt_tcpudp_t));
-            ret = 0;
-            if (napt_ctx->ip_tp == IP_PROTO_TCP) {
-                update_tcp_stat_wnet(tcp_hdr, it);
-            }
-            break;
+    
+    // 使用哈希表快速查找
+    int idx = napt_hash_find_wan2lan(napt_ctx, tmp.wnet_ip, tmp.wnet_port, tmp.wnet_local_port);
+    if (idx >= 0 && idx < (int)napt_ctx->item_last) {
+        it = &napt_ctx->items[idx];
+        it->tm_ms = tnow;
+        memcpy(mapping, it, sizeof(luat_netdrv_napt_tcpudp_t));
+        ret = NAPT_RET_OK;
+        if (napt_ctx->ip_tp == IP_PROTO_TCP) {
+            update_tcp_stat_wnet(tcp_hdr, it);
         }
     }
+    
     luat_rtos_mutex_unlock(napt_ctx->lock);
     return ret;
 }
@@ -503,19 +682,17 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_tcp_lan2wan(napt_ctx_t* ctx, luat_ne
         mapping_cleanup(napt_ctx);
         napt_ctx->clean_tm = tsec;
     }
-    for (size_t i = 0; i < napt_ctx->item_last; i++) {
-        it = &napt_ctx->items[i];
-        c_all ++;
-        // 本地ip(4 byte), 本地端口(2 byte), 远程ip(4 byte), 远程端口(2 byte)
-        if (memcmp(&tmp.inet_ip, &it->inet_ip, 6 + 6) == 0) {
-            it->tm_ms = tnow;
-            ret = 0;
-            memcpy(mapping, it, sizeof(luat_netdrv_napt_tcpudp_t));
-            // 映射关系找到了,那就关联一下情况
-            if (napt_ctx->ip_tp == IP_PROTO_TCP) {
-                update_tcp_stat_inet(tcp_hdr, it);
-            }
-            break;
+    
+    // 使用哈希表快速查找
+    int idx = napt_hash_find_lan2wan(napt_ctx, tmp.inet_ip, tmp.inet_port, tmp.wnet_ip, tmp.wnet_port);
+    if (idx >= 0 && idx < (int)napt_ctx->item_last) {
+        it = &napt_ctx->items[idx];
+        it->tm_ms = tnow;
+        ret = NAPT_RET_OK;
+        memcpy(mapping, it, sizeof(luat_netdrv_napt_tcpudp_t));
+        // 映射关系找到了,那就关联一下情况
+        if (napt_ctx->ip_tp == IP_PROTO_TCP) {
+            update_tcp_stat_inet(tcp_hdr, it);
         }
     }
     while (ret != 0) {
@@ -537,6 +714,11 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_tcp_lan2wan(napt_ctx_t* ctx, luat_ne
         tmp.tm_ms = tnow;
         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);
+        
         napt_ctx->item_last ++;
         if (ctx->eth) {
             memcpy(it->inet_mac, ctx->eth->src.addr, 6);
@@ -545,7 +727,7 @@ __NETDRV_CODE_IN_RAM__ int luat_netdrv_napt_tcp_lan2wan(napt_ctx_t* ctx, luat_ne
             memset(it->inet_mac, 0, 6);
         }
         memcpy(mapping, it, sizeof(luat_netdrv_napt_tcpudp_t));
-        ret = 0;
+        ret = NAPT_RET_OK;
         break;
     }