流解析器 (strparser)¶
簡介¶
流解析器 (strparser) 是一個用於解析執行在資料流上的應用層協議訊息的工具。流解析器與核心中的上層協同工作,為應用層訊息提供核心支援。例如,核心連線複用器 (KCM) 使用流解析器透過 BPF 程式解析訊息。
strparser 工作在兩種模式之一:接收回調模式或通用模式。
在接收回調模式下,strparser 從 TCP 套接字的 data_ready 回撥中被呼叫。訊息在套接字上接收時被解析和傳遞。
在通用模式下,一系列 skb 從外部源輸入到 strparser。訊息在序列處理時被解析和傳遞。這種模式允許 strparser 應用於任意資料流。
介面¶
該 API 包括一個上下文結構、一組回撥、實用函式以及用於接收回調模式的 data_ready 函式。回撥包括一個用於執行解析的 parse_msg 函式(例如 KCM 情況下的 BPF 解析),以及一個在完整訊息完成時呼叫的 rcv_msg 函式。
函式¶
strp_init(struct strparser *strp, struct sock *sk, const struct strp_callbacks *cb)用於初始化流解析器。strp 是一個由上層分配的 strparser 型別的結構體。sk 是與流解析器關聯的 TCP 套接字,用於接收回調模式;在通用模式下,此引數設定為 NULL。回撥由流解析器呼叫(回撥列表如下)。
void strp_pause(struct strparser *strp)臨時暫停流解析器。訊息解析暫停,並且沒有新訊息傳遞給上層。
void strp_unpause(struct strparser *strp)取消暫停已暫停的流解析器。
void strp_stop(struct strparser *strp);呼叫 strp_stop 以完全停止流解析器操作。當流解析器遇到錯誤時,此函式會在內部被呼叫;它也會從上層被呼叫以停止解析操作。
void strp_done(struct strparser *strp);呼叫 strp_done 以釋放流解析器例項持有的任何資源。此函式必須在流處理器停止後呼叫。
int strp_process(struct strparser *strp, struct sk_buff *orig_skb, unsigned int orig_offset, size_t orig_len, size_t max_msg_size, long timeo)在通用模式下,呼叫 strp_process 讓流解析器解析一個 sk_buff。返回處理的位元組數或負錯誤碼。請注意,strp_process 不會消耗 sk_buff。max_msg_size 是流解析器將解析的最大大小。timeo 是完成訊息的超時時間。
void strp_data_ready(struct strparser *strp);當底層套接字上資料準備就緒供 strparser 處理時,上層呼叫 strp_tcp_data_ready。此函式應從套接字上設定的 data_ready 回撥中呼叫。請注意,最大訊息大小受限於接收套接字緩衝區,訊息超時受限於套接字的接收超時時間。
void strp_check_rcv(struct strparser *strp);呼叫 strp_check_rcv 以檢查套接字上的新訊息。這通常在流解析器例項初始化時或在 strp_unpause 之後呼叫。
回撥¶
有七個回撥
int (*parse_msg)(struct strparser *strp, struct sk_buff *skb);呼叫 parse_msg 以確定流中下一條訊息的長度。上層必須實現此函式。它應該將 sk_buff 解析為包含流中下一條應用層訊息的頭部。
輸入 skb 中的 skb->cb 是一個 struct strp_msg。在 parse_msg 中只有 offset 欄位是相關的,它提供了訊息在 skb 中開始的偏移量。
此函式的返回值包括:
>0
表示成功解析訊息的長度
0
表示需要接收更多資料才能解析訊息
-ESTRPIPE
當前訊息不應由核心處理,將套接字控制權返回給使用者空間,使用者空間可以自行讀取訊息
其他 < 0
解析錯誤,將控制權返回給使用者空間,假定同步已丟失且流不可恢復(應用程式應關閉 TCP 套接字)
如果返回錯誤(返回值小於零)且解析器處於接收回調模式,則它將在 TCP 套接字上設定錯誤並喚醒它。如果 parse_msg 返回 -ESTRPIPE 並且流解析器之前已為當前訊息讀取了一些位元組,則附加套接字上設定的錯誤是 ENODATA,因為在這種情況下流是不可恢復的。
void (*lock)(struct strparser *strp)當 strparser 執行非同步操作(例如處理超時)時,呼叫 lock 回撥來鎖定 strp 結構。在接收回調模式下,預設函式是 lock_sock 用於關聯的套接字。在通用模式下,回撥必須設定正確。
void (*unlock)(struct strparser *strp)呼叫 unlock 回撥以釋放由 lock 回撥獲得的鎖。在接收回調模式下,預設函式是 release_sock 用於關聯的套接字。在通用模式下,回撥必須設定正確。
void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);當接收到完整訊息併入隊時,呼叫 rcv_msg。被呼叫者必須消耗 sk_buff;它可以呼叫 strp_pause 以防止在 rcv_msg 中接收任何進一步的訊息(參見上面的 strp_pause)。此回撥必須設定。
輸入 skb 中的 skb->cb 是一個 struct strp_msg。此結構體包含兩個欄位:offset 和 full_len。offset 是訊息在 skb 中開始的位置,full_len 是訊息的長度。skb->len - offset 可能大於 full_len,因為 strparser 不會截斷 skb。
int (*read_sock)(struct strparser *strp, read_descriptor_t *desc, sk_read_actor_t recv_actor);如果提供了 read_sock 回撥,strparser 將使用它而不是 sock->ops->read_sock。
int (*read_sock_done)(struct strparser *strp, int err); read_sock_done is called when the stream parser is done reading the TCP socket in receive callback mode. The stream parser may read multiple messages in a loop and this function allows cleanup to occur when exiting the loop. If the callback is not set (NULL in strp_init) a default function is used. :: void (*abort_parser)(struct strparser *strp, int err); This function is called when stream parser encounters an error in parsing. The default function stops the stream parser and sets the error in the socket if the parser is in receive callback mode. The default function can be changed by setting the callback to non-NULL in strp_init.
統計¶
每個流解析器例項都維護著各種計數器。這些計數器位於 strp_stats 結構體中。strp_aggr_stats 是一個方便的結構體,用於累積多個流解析器例項的統計資訊。save_strp_stats 和 aggregate_strp_stats 是用於儲存和聚合統計資訊的輔助函式。
訊息組裝限制¶
流解析器提供了限制訊息組裝所消耗資源的機制。
當新訊息開始組裝時,會設定一個定時器。在接收回調模式下,訊息超時時間取自關聯 TCP 套接字的 rcvtime。在通用模式下,超時時間作為引數傳遞給 strp_process。如果定時器在組裝完成前觸發,流解析器將被中止,並且如果在接收回調模式下,TCP 套接字上將設定 ETIMEDOUT 錯誤。
在接收回調模式下,訊息長度受限於關聯 TCP 套接字的接收緩衝區大小。如果 parse_msg 返回的長度大於套接字緩衝區大小,則流解析器將中止,並在 TCP 套接字上設定 EMSGSIZE 錯誤。請注意,這使得帶有流解析器的套接字的接收 skbuff 的最大大小為 TCP 套接字的 2*sk_rcvbuf。
在通用模式下,訊息長度限制作為引數傳遞給 strp_process。