読者です 読者をやめる 読者になる 読者になる

TenForward

技術ブログ。はてなダイアリーから移転しました

Linux kernel ソースの netlink の connector のサンプルを動かす(2)

Linux

前に書いたエントリ の続編.とは言っても途中経過をメモするだけで,このエントリで何かが出来るのは示せません.というか良く分からないままだけど,とりあえずやった所までメモしておこう,という感じですね.

Linux ソースの Documentation/connector 以下にサンプルプログラムと connector.txt という簡単なドキュメントがあります.このサンプルは,カーネルモジュールとユーザ空間のプログラムの間で情報をやりとりするサンプルになっているのですが,「カーネル→ユーザ」方向と「ユーザ→カーネル」方向の両方のサンプルが含まれていて,"if (0)" とか "#if 0" とかで無効化されていたりして,ややこしいです (いや,ちょっと見たらそんなにややこしく無いのですが,どういうサンプルかの説明がまったくないので...).その辺りをちょこちょこいじって,動かしてみるというものですね.

カーネル→ユーザ」方向は,がばっと関係無いところを削除すると,普通に動きます (多分).

「ユーザ→カーネル」方向 (サンプルをまったくいじらずに make するとこちらになる) は,実はそのままでは何も起きません (エラーにもならないけど).それを少し何か起こるようにしたのが 前に書いたエントリ です.ヒントは connector.txt にあります.

後半の "Userspace usage" という section で以下のような記述があります.

2.6.14 has a new netlink socket implementation, which by default does not allow to send data to netlink groups other than 1. So, if to use netlink socket (for example using connector) with different group number userspace application must subscribe to that group.

(中略)

2.6.14 netlink code only allows to select a group which is less or equal to the maximum group number, which is used at netlink_kernel_create() time. In case of connector it is CN_NETLINK_USERS + 0xf, so if you want to use group number 12345, you must increment CN_NETLINK_USERS to that number. Additional 0xf numbers are allocated to be used by non-in-kernel users.

(間違っている可能性の高い翻訳:p) 2.6.14 は Netlink ソケットの実装が新しくなりました.デフォルトでは 1 以外の Netlink グループに対してデータを送る事が許可されていないものです.なので,もし 異なるグループ番号の Netlink ソケットを使う場合 (例えば connector を使う場合),ユーザ空間のアプリケーションはこのグループを購読しなければなりません.

(中略)

2.6.14 Netlink コードは,グループ番号の最大値以下のグループのみ選択出来ます.これは netlink_kernel_create() 時に使われます.connector の場合,これは CN_NETLINK_USERS + 0xf です.なのでもしグループ番号 12345 を使いたい場合は,この番号まで CN_NETLINK_USERS を増やさなければなりません.0xf がカーネル内でないユーザーのために使うために足されます.

というわけで,前のエントリのように,cn_test.c (カーネルモジュール) の cn_test_id を

static struct cb_id cn_test_id = { 0x1, 0x456 };

に,ucon.c の方で l_local.nl_group の値を

l_local.nl_groups = 0x1;

という風にすれば動きます.これは "0x1" という値が include/linux/connector.h で

#define CN_IDX_PROC                     0x1
    : (略)
#define CN_NETLINK_USERS                6

という風になっており,さらに 0x1 を使うカーネルモジュールがカーネルの標準で付属しているからだと思います (多分).ちなみにここの値を 0x2 にしても動きます.0x3 以上だと動きません.

ここで3つ疑問.

  1. 値を 0x1 にして動くのはなぜか? (→標準モジュールがあるので,どこかで動くような処理が行われている? "by default does not allow to send data to netlink groups other than 1." という記述があるが,このグループとプログラム中の group は同じ? これとしたら,次の 0x2 で動くのが謎.)
  2. 値を 0x2 にしても動くのはなぜか? (→謎.0x2 は connector.h で定義はされているが,標準カーネル内で使われてはいない感じ.Google Codesearch しても定義しか出てこないし,それ以外は Perl のソースが引っかかる)
  3. 値を 0x3 以上にして動かないのはなぜか? (→ 0x3, 0x4, 0x5 は少なくとも標準カーネルでは connector.h で定義はされている.多分使ってないからどこでもコレを動かす処理が行われておらず,指定しても動かないと想像するが,じゃあ 0x2 が動くのが謎)

ここで 0x3 以上のグループでもメッセージの受信が出来るようにするには,connector.txt で示されているように setsockopt を使用します (サンプルプログラムでは if(0) で無効化されている).

{
    int on = l_local.nl_groups;
    setsockopt(s, 270, 1, &on, sizeof(on));
}

ここで on に 0x3 とか 0x5 とか入れると,ちゃんとユーザ空間のプログラムでカーネルモジュールからのメッセージを受け取れます.ここで指定するグループは,前述の connector.txt の引用によると,

2.6.14 netlink code only allows to select a group which is less or equal to
the maximum group number, which is used at netlink_kernel_create() time.
In case of connector it is CN_NETLINK_USERS + 0xf,

という制限を受けるような気がします.これを確認してみました.グループに指定する数を徐々に増やしていくと,0x20 までは OK でした.0x21 はダメ.でも上記説明だと "less or equal to the maximum group number" とあるので,CN_NETLINK_USERS が include/linux/connector.h および /usr/include/linux/connector.h で 6 と指定されているので,0x15 のような...

試しに connector.h での値を 7 に増やしてみたけど,相変わらず 0x21 はダメでした.

ここで最後の疑問.

  1. グループ番号として 0x20 まで OK で,それ以上ダメなのはなぜ?
  2. CN_NETLINK_USERS を増やしても,変化がないのはなぜ?

という疑問を今後調べて行こうかな〜,と.英文の解釈を間違っているかも知れないのと,netlink の基本が分かってれば自明な問題なのかもしれないという気も少ししてますが... (^_^;)

ちなみに driver/connector/connector.c には,確かに

        dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
                                         CN_NETLINK_USERS + 0xf,
                                         dev->input, NULL, THIS_MODULE);

という部分があり,"CN_NETLINK_USERS + 0xf" してます (この引数の意味も分かってませんが ^^;).

(追記)

  • 0x21 指定したときの setsockopt のエラーは EINVAL (Invalid argument) でした.
  • CN_NETLINK_USERS を 0x123 とか増やしたら,0x21 でもエラー出ず.何なんだ?