ネットワークアプリケーションとネットワークデバイスの一般的なエラーについて書くことにしました。Linuxスタックを例として使用して問題を説明しようと思います。そして、私はもっと抽象的に議論し、原理を説明しようとします。結局のところ、本質は同じですが、すべてのアプリケーションは異なります。(ビットを前後に転送します。)そして、各ネットワークアプリケーション、またはネットワークデバイスは、ミスを修正するために独自のアプローチを必要とします。
問題は、システムが交換するデータの小さなチャンクにあります。より正確には、これらの部分自体ではなく、それらがさらに収集および処理される方法です。
たとえば、あるシステムは「Hello World!「」
どうやってやるの?はい、何でも。TCP、MPTCP、UDPなどの任意のデータ転送プロトコルが選択されます。データはチャンクに分割され、これをパケットと呼びます。そして、それらは最終システムに送られます。(正確には?それはまったく問題ではありません。)
重要なことは、最終的なシステムが受信したデータをどのように(そしてどのように)処理するかです。文字列「HelloWorld!「2つのパッケージに分割されました:
「こんにちは」-これは最初のパッケージの内容です。
「世界!"-そしてこれは2番目のパッケージです。
, ( ) , (). ( . )
, . , , . , .. . — .
, . ,
«World !» - .
«Hello » - .
, , : «World !Hello ». ( , , « » «seq»).
: seq. , « ». , , . seq? , , «Hello World !»
Linux TCP ( Linux-5.10.7 ) net/ipv4/tcp_ipv4.c tcp_v4_fill_cb, . ,
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
skb->len - th->doff * 4);
end_seq — . ( , ( , )
: «Hello » - . 6 .
, seq = 0x1 end_seq = 0x7
«World !» - . 7 .
, seq = 0x7 end_seq = 0xe
«Hello World !»
, seq = 0x4 end_seq = 0xb
«Hello ld !»
«Wor» . ( , ) . tcp_rcv_nxt_update net/ipv4/tcp_input.c rcv_nxt struct tcp_sock. , end_seq ( ). ( rcv_nxt tcp )
: end_seq. , copied_seq struct tcp_sock. , ( ) , rcv_nxt end_seq. .
. : seq = 0xfffffff0 0x64 (100)
TCP_SKB_CB(skb)->end_seq = (0xfffffff0 + 0x1 + 0 + 0x140 - 0x40);
( doff = 5 tcp )
TCP_SKB_CB(skb)->end_seq = 0xfffffff0 + 0x65 = 0x100000055
. . , end_seq = 0x55 (85 ) rcv_nxt = 0xfffffff0 , . . .
, end_seq < seq ( 0x55 < 0xfffffff0 )
, , . ( , skb_len )
. seq = 0xfffffc6e 1000 (end_seq = 0x56 ) , URG . : 16- . , (urgent) .
, . , urg . . . ( TCP Offload Engine )
seq ( ), ( ), urg 0 - 0xffff,
rcv_nxt. . ( ) . .
, : after before. , "" , "" "".
, .
inline bool before(__u32 seq1, __u32 seq2)
{
return (__s32)(seq1-seq2) < 0;
}
#define after(seq2, seq1) before(seq1, seq2)
after( 0x80000000, 0x7fffffff ) = 1
after( 0x7fffffff, 0x80000000 ) = 0
after( 0x80000000, 0x80000000 ) = 0
before( 0x80000000, 0x7fffffff ) = 0
before( 0x7fffffff, 0x80000000 ) = 1
before( 0x80000000, 0x80000000 ) = 0
, , .
, , . , end_seq , .
end_seq < seq ( 0x55 < 0xfffffff0 )
, , __,
if(TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq >= __) {
__ } else { _ }
if(0x55 - 0xfffffff0 >= __)
if(0xffffff9 >= __)
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c .
handle_urg_ptr .
if (skb && tp->copied_seq - ULP_SKB_CB(skb)->seq >= skb->len)
chtls_free_skb(sk, skb);
: copied_seq, seq, skb->len .
(- , ULP_SKB_CB(skb)->seq ). (skb)->seq, seq, copied skb->len , , . ( , )
, : chtls_cm.c
chtls_recv_data
if (unlikely(hdr->urg))
handle_urg_ptr(sk, tp->rcv_nxt + ntohs(hdr->urg));
if (unlikely(tp->urg_data == TCP_URG_NOTYET &&
tp->urg_seq - tp->rcv_nxt < skb->len))
tp->urg_data = TCP_URG_VALID |
skb->data[tp->urg_seq - tp->rcv_nxt];
handle_urg_ptr(sk, tp->rcv_nxt + ntohs(hdr->urg)); : tp->rcv_nxt + ntohs(hdr->urg) .
rcv_nxt , hdr->urg . , __ handle_urg_ptr . , .
if (unlikely(tp->urg_data == TCP_URG_NOTYET &&
tp->urg_seq - tp->rcv_nxt < skb->len))
tp->urg_data = TCP_URG_VALID |
skb->data[tp->urg_seq - tp->rcv_nxt];
tp->urg_seq - tp->rcv_nxt < skb->len , , , ( ). skb->data[tp->urg_seq - tp->rcv_nxt];
, tp->urg_seq - tp->rcv_nxt. , - ???
tp->urg_seq - tp->rcv_nxt < skb->len
, skb->data
urg_seq - tp->rcv_nxt , .
skb->len,
tp->urg_seq - tp->rcv_nxt < skb->len
skb->data[0xffffffff];
skb->data[0xfffffff0];
skb->data[0xffffff00]; .
, . .
.
(, ). , , ( ). , .
, " " , .
tcp , / , . . , ( , .). , "" ( - ), , - . , ( ), . , . . , . , . . , , , .
, . .
, ( ) . . , . ( ) ( . , )
chtls_recv , .
void chtls_recv(struct chtls_dev *cdev,
struct sk_buff **skbs, const __be64 *rsp)
{
struct sk_buff *skb = *skbs;
unsigned int opcode;
int ret;
opcode = *(u8 *)rsp; //
__skb_push(skb, sizeof(struct rss_header));
skb_copy_to_linear_data(skb, rsp, sizeof(struct rss_header));
ret = chtls_handlers[opcode](cdev, skb); // ,
if (ret & CPL_RET_BUF_DONE)
kfree_skb(skb);
}
, .
opcode = *(u8 *)rsp; , .
, , seq urg, , .
ret = chtls_handlers[opcode](cdev, skb);
NULL. .
.
, TCP urg. , UDP (. , , ). , . , .
( ). , . . ( + , ) , , ) .
.