4

関連する (私にとって) ネットワーク情報が変更されるたびに通知する平和なコードを作成しました (主に RTM_NEWADDR、RTM_DELADDR、RTM_NEWLINK、および RTM_DELLINK をリッスンします)。唯一の問題は、コードを初めて起動したときに、現在のステータス全体 (RTM_GETLINK と RTM_GETADDR) を取得したいことです。

RTM_GETLINK または RTM_GETADDR のいずれかをリクエストできます。

memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETLINK;  /* link information              */
req.nlmsghdr.nlmsg_seq   = 1;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &addr;
msghdr.msg_namelen = sizeof(addr);

/*
** TODO: check for number of sent characters
**       on error display errno
*/
sendmsg(nls, &msghdr, 0);

/* do listening stuff... */

しかし、両方を同時にリクエストした場合:

req.nlmsghdr.nlmsg_type  = RTM_GETLINK | RTM_GETADDR;

IP情報しか取得できません。

リクエスト用とリッスン用に 2 つの異なるソケットを使用することになっていますか、それとも同じソケットですべてを行うことは可能ですか?

リクエストごとに送信を実行しようとしましたが、seq を使用して (2 番目のリクエストではそれを増やしています)、2 番目の応答の長さが 40 バイトしかないことがわかりました:(

memset(&kms.addr, 0, sizeof(kms.addr));
kms.addr.nl_family = AF_NETLINK;

/* prepare request */
memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP /*| NLM_F_ACK*/; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETLINK;                /* link information                     */
req.nlmsghdr.nlmsg_seq   = 1;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &kms.addr;
msghdr.msg_namelen = sizeof(kms.addr);

/*
** TODO: check for number of sent characters
**       on error display errno
*/
sendmsg(kms.nls, &msghdr, 0);

memset(&req, 0, sizeof(req));
req.nlmsghdr.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP /*| NLM_F_ACK*/; /* request to dump all kernel subsystem */
req.nlmsghdr.nlmsg_type  = RTM_GETADDR;                /* link information                     */
req.nlmsghdr.nlmsg_seq   = 2;
req.nlmsghdr.nlmsg_pid   = pid;
req.rtgenmsg.rtgen_family = AF_UNSPEC;

iovec.iov_base = &req;
iovec.iov_len  = req.nlmsghdr.nlmsg_len;

memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_iov     = &iovec;
msghdr.msg_iovlen  = 1;
msghdr.msg_name    = &kms.addr;
msghdr.msg_namelen = sizeof(kms.addr);

/* do listening stuff... */

もう少し分析すると、NLMSG_ERROR メッセージ タイプが表示されるようです。エラー コード -16 は、「デバイスまたはリソースがビジー状態」を意味します。

送信するたびにソケットを読み取れば、問題は発生しません。しかし、私はすべてのリクエストを実行してから、すべての返信を収集できるようにしたいと考えています...

4

2 に答える 2

2

ユーザースペースは、次のリクエストをネットリンクソケットに送信する前に、NLMSG_DONE ネットリンク制御メッセージを待つ必要があります。つまり、複数の netlink リクエストを続けて送信する場合、シーケンスは次のようになります。

  1. req1 を送信
  2. NLMSG_DONE を待つ
  3. req2 を送信
  4. NLMSG_DONE を待つ
  5. ...
于 2015-10-08T07:48:04.077 に答える
0

ここに私が見つけた答えがあります http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html

オプションで、カーネルは構成変更の通知を送信して、ユーザー空間が頻繁にポーリングする代わりに変更をリッスンできるようにすることができます。通知は通常、既存のメッセージ タイプを再利用し、別のソケットを使用してリクエストと通知を区別するアプリケーションに依存しますが、別のメッセージ タイプを指定することもできます。

しかし、これが何を意味するのかわかりません:

ただし、別のメッセージ タイプを指定することもできます。

于 2014-03-20T22:01:12.420 に答える