vpp開啟nat,分片包丟包問題分析與解決

現象描述

兩個網口都開啟nat?output-feature,路由模式進行大包轉發,網絡不同,小包轉發沒問題。

通過trace發現,在nat44-ed-in2out-output-slowpath節點丟包。

Packet 503:50:43:447292: handoff_traceHANDED-OFF: from thread 2 trace index 5
03:50:43:447292: nat44-ed-out2inNAT44_OUT2IN_ED_FAST_PATH: sw_if_index 2, next index 12search key local 192.168.93.146:1 remote 192.168.1.123:1 proto ICMP fib 0 thre
ad-index 0 session-index 0no reason for slow path
03:50:43:447304: ip4-inaclINACL: sw_if_index 2, next_index 1, table_index -1, offset -1no table
03:50:43:447311: ip4-lookupfib 0 dpo-idx 15 flow hash: 0x00000000ICMP: 192.168.93.146 -> 192.168.1.123tos 0x00, ttl 64, length 1300, checksum 0x4f79 dscp CS0 ecn NON_ECNfragment id 0x2612, flags MORE_FRAGMENTSICMP echo_reply checksum 0x4ff2 id 1
03:50:43:447318: ip4-rewritetx_sw_if_index 1 dpo-idx 15 : ipv4 via 192.168.1.123 eth0: mtu:2026 next:8 fla
gs:[features ] 0019e0772dfb9409d30081280800 flow hash: 0x0000000000000000: 0019e0772dfb9409d3008128080045000514261220003f015079c0a85d92c0a800000020: 017b00004ff2000102cf6162636465666768696a6b6c6d6e6f707172
03:50:43:447325: nat44-in2out-output-worker-handoffNAT44_IN2OUT_WORKER_HANDOFF OUTPUT-FEATURE: next-worker 1 trace index 4
03:50:43:447335: nat44-ed-in2out-outputNAT44_IN2OUT_ED_FAST_PATH: sw_if_index 2, next index 5search key local 69.0.5.20:0 remote 38.18.32.0:0 proto IL fib 0 thread-index 0session-index 0
03:50:43:447341: nat44-ed-in2out-output-slowpathNAT44_IN2OUT_ED_SLOW_PATH: sw_if_index 2, next index 0
03:50:43:447355: error-droprx:eth1
03:50:43:447358: dropip4-input: input ACL session deny drops

在函數nat44_ed_in2out_slow_path_node_fn_inline中加調試信息發現vnet_buffer (b0)->ip.reass.save_rewrite_length值為2,正常應該是14。

在重組節點(ip4-sv-reassembly-feature),添加調試,發現下面的代碼后ip.reass.save_rewrite_length會被修改成2。

分析了下vnet_buffer_opaque_t結構,終于明白了原因。

原因總結

vnet_buffer_opaque_t 結構中 ip.reass.owner_thread_index 和 ip.reass.save_rewrite_length內存重疊。修改兩者中的一個,另一個的值必然會被修改。

/* reassembly */union{/* group input/output to simplify the code, this way* we can handoff while keeping input variables intact */struct{/* input variables */struct{u32 next_index;	/* index of next node - used by custom apps */u32 error_next_index;	/* index of next node if error - used by custom apps */};/* handoff variables */struct{u16 owner_thread_index;};};/* output variables */struct{union{/* shallow virtual reassembly output variables */struct{u16 l4_src_port;	/* tcp/udp/icmp src port */u16 l4_dst_port;	/* tcp/udp/icmp dst port */u32 tcp_ack_number;u8 save_rewrite_length;u8 ip_proto;	/* protocol in ip header */u8 icmp_type_or_tcp_flags;u8 is_non_first_fragment : 1;u8 l4_layer_truncated : 7;u32 tcp_seq_number;};/* full reassembly output variables */struct{u16 estimated_mtu;	/* estimated MTU calculated during reassembly */};};};/* internal variables used during reassembly */struct{u16 fragment_first;u16 fragment_last;u16 range_first;u16 range_last;u32 next_range_bi;u16 ip6_frag_hdr_offset;};} reass;

當同一組分片包被投放到不同線程時(nat handoff會將數據包投遞到會話所在的線程),在重組節點(ip4-sv-reassembly-feature)會將線程ID記錄到ip.reass.owner_thread_index中,如下圖:


這時ip.reass.save_rewrite_length就會被修改。這就是為什么 ip.reass.save_rewrite_length 值為 2的原因,2是線程 id。

當數據包到達后續nat節點時,會通過ip.reass.save_rewrite_length獲取IP頭,這時獲取的IP頭時錯誤的,代碼中無法識別3層協議而丟包。

嘗試解決

修改 ip.reass.owner_thread_index?的位置,添加占位符 u8 _pad[6],使其不再和ip.reass.save_rewrite_length內存重疊。如下:

修改后還是會和tcp_seq_number有內存重疊,但TCP一般不會有分片包,問題不大。

經過上面的修改后,測試大包還是不通,又有了新的問題。O__O "…

新的問題

通過 trace 信息發現分片包(按照分片會話)沒有按照預期被投遞到別的線程(分片會話所在線程),并且進入ip4-sv-reassembly-feature(重組)節點,而是直接進入到后續的nat處理節點中,然后被丟包。丟包原因是ICMP?type?無效。

分片包的ip.reass的icmp_type_or_tcp_flags等信息需要匹配到會話,然后被賦值(從分片會話中獲取)。數據包沒有再次進入p4-sv-reassembly-feature(重組)節點,就無法完成這一步。

當數據包到達后續nat節點時,因為icmp_type_or_tcp_flags無效被丟包。

繼續找原因

通過?ip4_sv_reass_inline?函數代碼發現,如果 error0 不為?IP4_ERROR_NONE 時會查feature來確定下一個節點,從而直接走后面的feature。

如上圖中 next0 會被修改為nat44-out2in-worker-handoff節點,而分片包被投遞到分片會話所在的線程,這一操作是在節點 ip4-sv-reass-feature-hoff 中完成的。next0?在 handoff 處會被指定為IP4_SV_REASSEMBLY_NEXT_HANDOFF,數據包就會走到ip4-sv-reass-feature-hoff節點。該節點中會按照 ip.reass.owner_thread_index?記錄的值將數據包投遞到相應的線程。

嘗試修改2

經過上面的分析,解決方法就是在 handoff 處需要將error0賦值為非IP4_ERROR_NONE的值。如下:

經過上面的修改后,測試大包還是不通,又有了新的問題。O__O "………

新的問題2? ??

數據包成功被投遞到分片會話所在的線程,但在數據包在重組節點,即ip4_sv_reass_inline函數中被丟包。丟包位置如下:

進一步加調試信息,發現IP頭的獲取是有誤的,分析代碼發現是下面的問題

當數據包第二次進入 ip4_sv_reass_inline?函數時 is_output_feature?是為 0 的。

經過分析 ip4-sv-reass-feature-hoff?節點代碼,發現數據包的下一個節點會被固定指定為ip4-sv-reassembly(在函數ip4_sv_reass_init_function初始化指定),該節點在調用?ip4_sv_reass_inline?時會指定 is_output_feature?為 0。

這時的數據包處理是在路由后進行,正確的處理應該是在 ip4-sv-reass-feature-hoff?節點指定下一個節點為?ip4-sv-reassembly-output-feature。

嘗試修改3

按照上面的分析進行如下修改:

  • 為函數ip4_sv_reass_handoff_node_inline添加參數 bool is_output_feature,然后新增節點 ip4-sv-reass-feature-hoff-output-feature,該節點在調用函數 ip4_sv_reass_handoff_node_inline?時指定參數 is_output_feature 為 1。? ? ? ?

/* *INDENT-OFF* */
VLIB_NODE_FN (ip4_sv_reass_feature_handoff_node_output_feature) (vlib_main_t * vm,vlib_node_runtime_t *node,vlib_frame_t * frame)
{return ip4_sv_reass_handoff_node_inline (vm, node, frame, true /* is_feature */, false /* is_custom_context */, true);
}
/* *INDENT-ON* *//* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip4_sv_reass_feature_handoff_node_output_feature) = {.name = "ip4-sv-reass-feature-hoff-output-feature",.vector_size = sizeof (u32),.n_errors = ARRAY_LEN(ip4_sv_reass_handoff_error_strings),.error_strings = ip4_sv_reass_handoff_error_strings,.format_trace = format_ip4_sv_reass_handoff_trace,.n_next_nodes = 1,.next_nodes = {[0] = "error-drop",},
};
/* *INDENT-ON* */
  • 修改ip4-sv-reassembly-output-feature節點的next_node,當 is_output_feature?為 1?時,讓數據包走新增的節點 ip4-sv-reass-feature-hoff-output-feature。

  • 在 ip4_sv_reass_handoff_node_inline?函數中,如果 is_output_feature 為 1,則指定數據包的下一個節點為 ip4-sv-reassembly-output-feature。

  • 在函數 ip4_sv_reass_inline?中的 handoff 處,如果 is_output_feature 為 1,則指定數據包的下一個節點為 ip4-sv-reass-feature-hoff-output-feature。

rm->fq_index_output_feature 和?rm->fq_feature_index 在函數 ip4_sv_reass_init_function?中初始化,如下:

總結

vpp對于分片的處理支持的并不是很好,本次遇到問題主要是兩方面的原因:

  1. vnet_buffer_opaque_t?聯合體的設計,導致變量內存重,進而導致互相影響。
  2. nat?handoff?選擇線程與重組 handoff 選擇線程的算法不同,導致數據包被多次從一個線程投遞到其他線程。
  3. 而重組?handoff?對于數據包的處理存在一定的問題,即上面遇到的后兩個問題。

所有的修改總結如下:

  • 修改結構體vnet_buffer_opaque_t?中?ip.reass.owner_thread_index?的位置,添加占位符 u8 _pad[6],使其不再和ip.reass.save_rewrite_length內存重疊。
  • ip4_sv_reass_inline?中的 handoff 處,進行兩處修改。如果 is_output_feature 為 1,則指定數據包的下一個節點為 ip4-sv-reass-feature-hoff-output-feature;指定error0 = IP4_ERROR_REASS_INTERNAL_ERROR;

  • 新增?ip4-sv-reass-feature-hoff-output-feature?節點,讓數據包在路由后正確被處理。詳細見上面的修改3.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94962.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94962.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94962.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入解析交換機端口安全:Sticky MAC的工作原理與應用實踐

深入解析交換機端口安全:Sticky MAC的工作原理與應用實踐在當今企業網絡環境中,未授權設備接入是常見的安全威脅之一,而Sticky MAC技術正是解決這一問題的利器。在網絡安全管理中,端口安全是保護網絡基礎設施的第一道防線。Sticky…

AI接管瀏覽器:Anthropic發布Claude for Chrome,是效率革命還是安全噩夢?

AI智能體(Agent)的競賽,正在以超乎想象的速度進入白熱化階段。 就在上個月,OpenAI剛剛憑借ChatGPT Agent,向世界展示了AI在云端遠程操作電腦、制作PPT的強大能力。而現在,它的老對手Anthropic,…

LFI-labs靶場通關教程

目錄 CMD01-06 pass01 pass02 pass03 pass04 pass05 pass06 HDR-1 hdr-1 LFI-01-14 pass01 pass02 pass03 pass04 pass05 pass06 pass07 pass08 pass09 pass10 pass11 pass12 pass13 pass14 CMD01-06 pass01 看看源碼, 這里顯示的是一個get參數cmd,并…

隨機森林的 “Bootstrap 采樣” 與 “特征隨機選擇”:如何避免過擬合?(附分類 / 回歸任務實戰)

隨機森林的 “Bootstrap 采樣” 與 “特征隨機選擇”:如何避免過擬合?(附分類 / 回歸任務實戰) 第一部分:揭開隨機森林的神秘面紗 1.1 告別“過擬合”,擁抱更強大的模型 在機器學習的旅程中,…

Java開發 - 緩存

一、RedisUtil封裝package com.qj.redis.util;import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component;import javax.annotation.Resource; import java.util.Set; import java.util.…

光伏發多少電才夠用?匹配家庭用電需求

在“雙碳”目標推動下,新能源產業迎來爆發式增長,家庭屋頂光伏憑借清潔環保、能降低電費的優勢,成為越來越多家庭的選擇。但很多家庭在安裝前都會陷入一個核心困惑:到底裝多大容量的光伏系統,發多少電才能剛好滿足自家…

如何管理跨境電商多語種素材?數字資產本地化指南

核心要點: 問題: 多語言內容管理真的那么難嗎?多語種內容素材雜亂、反復翻譯浪費預算、上線延遲影響市場窗口期,跨境電商如何高效管理全球素材? 答案: 借助 AI 驅動的數字資產管理系統,跨境品…

Git 8 ,git 分支開發( 切換分支開發,并設置遠程倉庫默認分支 )

目錄 前言 一、📍環境背景 二、💻 完整流程 三、📝 順序總覽 四、🔹關系圖例 五、?暫存警告 六、?? 默認分支 七、🟣更多操作 前言 在團隊開發或多人協作的項目中,Git 是最常用的版本管理工具。一個常見…

如何在mysql中執行創建數據庫的腳本文件?

1、先準備好腳本文件,.sql擴展名的把腳本文件放在某個盤的根目錄(也可以不是根目錄,根目錄的話路徑會簡單一些),這里我放在C盤的根目錄下。腳本文件內容如下:/* SQLyog Community v13.1.1 (32 bit) MySQL - 5.7.26 : D…

《AI智脈速遞》2025 年 8 月22 日 - 29 日

歐盟 AI 法案正式生效:禁止社會評分,規范生成式 AI 內容標注 8 月 21 日,歐盟《人工智能法案》全面實施,明確禁止社會評分、實時面部識別等高風險 AI 應用,要求生成式 AI 內容必須標注來源。該法案被視為全球最嚴格的 …

iOS 審核 4.3a【二進制加固】

我們應該知道,面對iOS 上架 遇到4.3a的問題或者制作馬甲包.最基礎的操作就是混淆代碼尤其是我們專業做上架的,需要對各種語言的編譯模式,產物,以及ipa構成都需要非常了解, 每種語言開發的App的編譯產物不同,針對不同的編譯產物做不同的處理方式有一些經驗的開發者, 應該知道 目…

使用Python腳本執行Git命令

說明:本文介紹如何使用Python腳本在某個目錄下執行Git命令 編碼 直接上代碼 import os import subprocessdef open_git_bash_and_run_command(folder_path, git_command):# 檢查文件夾路徑是否存在if not os.path.exists(folder_path):print(f"錯誤&#xff1a…

2025docker快速部署Nginx UI可視化管理平臺

1、nginx-ui簡介 Nginx UI 是一個開源項目,旨在為著名的 Web 服務器和反向代理軟件 Nginx 提供一個基于網頁的圖形化用戶界面(GUI)。它的核心目標是讓 Nginx 的配置和管理變得可視化、簡單化和自動化,從而降低其使用門檻&#xf…

數據防泄與最小可見:ABP 統一封裝行級安全(RLS)+ 列級脫敏

數據防泄與最小可見:ABP 統一封裝行級安全(RLS) 列級脫敏 TL;DR:把“誰能看到哪些行、字段可見到哪一位”下沉到數據庫強制層(PostgreSQL:RLS 安全視圖;SQL Server:RLS DDM&#x…

網絡編程 04:TCP連接,客戶端與服務器的區別,實現 TCP 聊天及文件上傳,Tomcat 的簡單使用

一、概述 記錄時間 [2025-08-29] 前置文章: 網絡編程 01:計算機網絡概述,網絡的作用,網絡通信的要素,以及網絡通信協議與分層模型 網絡編程 02:IP 地址,IP 地址的作用、分類,通過 …

最小生成樹——Kruskal

標題什么是生成樹? 對于一張無向圖,由nnn個頂點和n?1n-1n?1條邊構成地聯通子圖,叫做這個無向圖 生成樹 最小生成樹就是指邊權之和最小的生成樹 如何求最小生成樹? Kruskal 介紹: 存圖時只存每條邊地起點、終點,…

ADFS 和 OAuth 的區別

ADFS 和 OAuth 的區別 ADFS(Active Directory Federation Services)和 OAuth 都是身份認證與授權領域的技術,但它們的設計目標、應用場景和實現方式有顯著區別。以下從核心定義、技術特性、應用場景等方面詳細對比: 核心定義與設計目標 技術 核心定義 設計目標 ADFS 微軟…

神經網絡參數量計算詳解

1. 神經網絡參數量計算基本原理 1.1 什么是神經網絡參數 神經網絡的參數主要包括: 權重(Weights):連接不同神經元之間的權重矩陣偏置(Bias):每個神經元的偏置項批歸一化參數:BatchNo…

手寫鏈路追蹤

1. 什么是鏈路追蹤 鏈路追蹤是指在分布式系統中,將一次請求的處理過程進行記錄并聚合展示的一種方法。目的是將一次分布式請求的調用情況集中在一處展示,如各個服務節點上的耗時、請求具體到達哪臺機器上、每個服務節點的請求狀態等。這樣就可以輕松了解…

從零開始的python學習——常量與變量

? ? ? ? ? づ?ど 🎉 歡迎點贊支持🎉 個人主頁:勵志不掉頭發的內向程序員; 專欄主頁:python學習專欄; 文章目錄 前言 一、常量和表達式 二、變量類型 2.1、什么是變量 2.2、變量語法 (1&a…