プロトコルを作成/使用する場合netlink
、netlink
属性は、プロトコルに将来の拡張性を可能にする明確な自己文書化レイアウトを与えることを目的としています。つまり、現在のプロトコルに既に存在するものに加えて別のデータ型を使用したい場合、コードは既存の操作を壊すことなく互換性があります。
「属性」はプロトコルに依存し、そのプロトコルを使用して送信される特定のメッセージに関連しています。
taskstats
インターフェースを例として使用します。
taskstat
属性:
enum {
TASKSTATS_CMD_ATTR_UNSPEC = 0,
TASKSTATS_CMD_ATTR_PID,
TASKSTATS_CMD_ATTR_TGID,
TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
__TASKSTATS_CMD_ATTR_MAX,
};
UNSPEC
これらの属性では、間にカスタム属性を追加し、MAX
その属性を必要な特定の機能または操作にマッピングすることで、簡単に「拡張」できます。
カーネル空間taskstat
ポリシー:
static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
[TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
プロトコルとインターフェイスstruct nlattr
を使用してこの構造体のフィールドをロードする例であるの定義を既にご覧になっていると思います。NETLINK_GENERIC
taskstats
struct nlattr na;
na.nla_type = CTRL_ATTR_FAMILY_NAME; // defined in linux/genetlink.h
na.nla_len = strlen(TASKSTATS_GENL_NAME) + 1 // defined in linux/taskstats.h
// note: you will need to copy/access nlattr data in the same way the NLMSG_DATA
// macro operates.
これらの属性を解析するときに、カーネル側で関連する関数が呼び出され、処理方法に関するアクションが意図されます。
あなたが投稿した図があなたをうんざりさせているかどうかはわかりませんが、少しズームアウトしてより広い視野を得るために:
カーネルソースv3.16 include/net/netlink.h
によると:
/* ========================================================================
* Netlink Messages and Attributes Interface (As Seen On TV)
* ------------------------------------------------------------------------
* Messages Interface
* ------------------------------------------------------------------------
*
* Message Format:
* <--- nlmsg_total_size(payload) --->
* <-- nlmsg_msg_size(payload) ->
* +----------+- - -+-------------+- - -+-------- - -
* | nlmsghdr | Pad | Payload | Pad | nlmsghdr
* +----------+- - -+-------------+- - -+-------- - -
* nlmsg_data(nlh)---^ ^
* nlmsg_next(nlh)-----------------------+
*
* Payload Format:
* <---------------------- nlmsg_len(nlh) --------------------->
* <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) ->
* +----------------------+- - -+--------------------------------+
* | Family Header | Pad | Attributes |
* +----------------------+- - -+--------------------------------+
* nlmsg_attrdata(nlh, hdrlen)---^
ここで、投稿したヘッダーとペイロードの図は、より大きなペイロードの一部に過ぎないことがわかります。struct nlmsghdr
そのセグメントは、メッセージ形式の a とともに続きます。
ポリシーでは、netlink メッセージを送信するとき、送信者はプロトコル形式に従う必要があります。メッセージの受信者はstruct nla_policy
、ペイロードにアクセスする前に属性を検証するために使用します。
「ファミリ」または識別子は、カーネルが通信する適切なプロトコル インターフェイスを追跡するために使用されます。これは、標準プロトコルまたはGeneric Netlinkのようなカスタム プロトコルに関係なく行われます。
「これを回避できますか?」と尋ねると、独自のカスタム汎用 netlink プロトコルを作成して netlink を拡張している場合、これらが存在するため、関連するすべての操作を実行したり、変更/修正したりすることなく、そのプロトコルを簡単に調整および維持できます。プロトコルが壊れているフラットアウト。長さや型が関連付けられていない、さまざまなデータ型のネストされたメッセージを解析することを他にどのように提案しますか? タイプと長さは、正しいアラインメントでメッセージを解析し、目的のアクションを実行できるようにするためにあります。ペイロードにラベルを付ける属性タイプがなければ、それをどのように解釈しますか、ペイロードは「何」ですか? 長さがなければ、「どのくらいの大きさ」をどのように知ることができますか ペイロードは?それぞれの長さが異なる複数のペイロードが存在する可能性があり、それらのサイズを区別するものがないため、一方の開始点と他方の終了点を区別する方法がありません。
libnl (netlink ソケットを操作するためのライブラリであり、強くお勧めします) ドキュメントの属性へのリンクは次のとおりです。