Linux カーネル ネットワーキングについてもっと学ぼうとしているときに... TCP 上で実行されるプロトコルを含むカーネル モジュールがあります。私が実験しているほとんどのアプリケーション層プロトコルです。呼び出しは、ユーザー空間から実行される通常のシステム コール インターフェイスを介して渡されます。
したがって、私の(TCPの上のレイヤー)モジュール内からのネットワーク呼び出しは、一般的に次のようになります...
ret = sock->ops->connect(sock, (struct sockaddr *) &myprot.daddr,
sizeof(myprot.daddr), flags);
KM 内で sendmsg/recvmsg を正常に使用して、クライアントからサーバーへ (2 つの別個のカーネル インスタンスから) データを送受信しました。KM 内の呼び出しは、通常、次のようになります。
ret = sock->ops->sendmsg(iocb, myprot.skt, &msg, sizeof(struct msghdr));
ret = sock->ops->recvmsg(iocb, sock, msg, total_len, flags);
私が今理解しようとしているのは、sk_buff を使用して同じことを行う方法とタイミングです。つまり、上記で使用したようなシステム コールをいつ使用するか、いつ sk_buff を介してネットワーク スタックに直接アクセスしてデータを送受信するかです。
sk_buff を使用してトランスポート レイヤー内からデータを送受信する方法の例を多数見つけましたが、カーネル モジュールにも含まれており、sk_buff を使用しているトランスポートより上のレイヤーからは何も見つかりませんでした。
明確にするために更新します。
struct proto_ops をオーバーライドし、ユーザー空間からのシステム コールに対応する、独自のプロトコルで使用するメンバー メソッドを置き換えました。sk_buff がカーネルのバッファ システムであり、パケットがキューに入れられる場所であることは理解しています。でも。ソケットとそれらにエンキューされたデータも処理する struct proto_ops のプロトコル固有の関数を使用できない理由はわかりません(より高いレベルではありますが)。したがって、アクセスしたい場所に応じて、sk_buffs にアクセスするには 2 つの方法があるように思えます。
トランスポート層で作業していて、ネットワーク スタック (トランスポート、IP、MAC など) 内のデータにアクセスしたい場合は、sk_buffs に直接アクセスできますが、トランスポート層の上で作業している場合は、抽象化されたプロトコルを使用します。システムコールに対応する特定のメンバー関数。結局のところ、どちらも最終的には sk_buffs で動作します。
私の混乱、または sk_buffs にアクセスするこれらの 2 つの方法とどこからのアクセスの違いを知ることによって、私が正しいか間違っているかを確認しようとしているのは... からのトランスポート経由でデータを送信している場合です。カーネル内の TCP ではなく、TCP に関連する proto_ops システム コールを利用することができます。より詳細な制御が必要な場合を除き、下位レベルの skb 関数を使用してキューを管理します。