使用ovs+dpdk進行數據面轉發可以提供很高的轉發性能,但是在處理分片包的邏輯上會比較耗性能, 是在使用ovs自帶的ct模塊的時候, 由于分片包沒有4層頭,會匹配不到ct,所以需要進行報文的聚合(這里不會真的聚合成一個包,只是將分片包一起處理), 然后進行ct匹配,完成報文轉發。
這里聚合完成的一個判斷邏輯是這樣的, 不是最后一個報文的報文長度不能小于min_v4_frag_size:
conntrack_execute-》ipf_preprocess_conntrack-》ipf_extract_frags_from_batch-》ipf_is_valid_v4_frag
bool lf = ipf_is_last_v4_frag(pkt);
if (OVS_UNLIKELY(!lf && dp_packet_l3_size(pkt) < min_v4_frag_size_)) {
ipf_count(ipf, false, IPF_NFRAGS_TOO_SMALL);
goto invalid_pkt;
}
min_v4_frag_size在ipf_init時候設置為IPF_V4_FRAG_SIZE_MIN_DEF (1200), 小于mtu, 大部分報文(vpn報文去掉加密頭一般也會大于1200)分片非最后一個包都大于1200, 并且這個參數可以通過命令設置, 最小可以設置成400
ovs-appctl dpctl/ipf-set-min-frag netdev@ovs-netdev v4 400
設置最小分片的目的是防止fraglist過大, 影響ct中frag聚合效率低,導致性能下降影響轉發,比如惡意的構造分片都是400字節的包,一個大包可以分成近160個分片包,這樣會導致ovs聚合消耗很多cp性能。
ipf-set-min-frag [dp] v4|v6 minfrag
Sets the minimum fragment size (L3 header and data) for non-fi‐
nal fragments to minfrag. Either v4 or v6 must be specified.
For enhanced DOS security, higher minimum fragment sizes can
usually be used. The default IPv4 value is 1200 and the clamped
minimum is 400. The default IPv6 value is 1280, with a clamped
minimum of 400, for testing flexibility. The maximum fragment
size is not clamped, however, setting this value too high might
result in valid fragments being dropped. Only supported for
userspace datapath.
但是大包在復雜鏈路上可能被多次分片,會出現非最后一個包的長度較小,在通過網關轉發的場景里,
公網大于1500的報文比如1600長度的,進入網關上可能是分成了1500和100字節的報文, 如果需要將報文封裝vxlan隧道
第一個包l3長度會變成1550, 所以需要對1500的報文分片,變成一個1450, 50, 100的3個包, 第二包到了ovs會認為是非法的,
導致3個包在ct中處理不了, 最終會被ipf_frag超時處理丟棄掉
可以通過修改ovs代碼的IPF_V4_FRAG_SIZE_LBOUND來支持多次分片的小包, 比如修改成70=50(paylaod)+20(ipheader), 這樣就可以解決分片聚合失敗的問題