はじめに
Linux 4.6でマージされたKernel Connection Mulitplexor (KCM)を使ったプログラムを書くときに、あらかじめ知っておいた方が良さそうなことをまとめます。
書いたプログラム
A sample program of KCM に書いたプログラムがあります。
やってることは適当なプロトコルを作って、KCMを使ってC/Sで簡単なメッセージのやりとりをしているだけです。プロトコルといっても、文字列を渡すだけのもので、メッセージのヘッダに文字列のサイズが書かれているだけです。BPFがメッセージのヘッダを解釈して、メッセージ毎に分割してユーザプログラムに返してくれます。
KCMのプログラムを書くときに知っておくと良いこと
とりあえず、以前私が書いた Kernel Connection Mulitplexor (KCM) - Qiita を読むと概要がわかります
- BPFの命令を書く時は libbcc を使うと楽
-
bpf(2)を読むと自分でBPF命令を一命令ずつ記述することになっているが、libbccはC (+ヘルパ関数)で書ける
-
bpf_module_create_c
,bpf_module_create_c_from_string
,bpf_prog_load
といったライブラリ関数を使う
-
- Fedora 23だと
libbcc
という名前のパッケージがあるのでこれをインストールする - コンパイルするときに
-bcc
を付ける
-
bpf(2)を読むと自分でBPF命令を一命令ずつ記述することになっているが、libbccはC (+ヘルパ関数)で書ける
-
socket(AF_KCM, ...)
とそれをクローン(ioctl(kcmfd, SIOCKCMCLONE, ...)
)したファイルディスクリプタは同等の関係である- なんとなく親子関係があって、実際の通信にはクローンしたファイルディスクリプタを使うものだと思っていたけど、それは間違い
- socketで作ったものが0番目のディスクリプタでクローンしたものが1番目というだけ
- なのでクローンしなくてもKCMは使える
- 特殊なことをしなければ最初にメッセージが届くのは0番目のディスクリプタなので、1番目で受信しようとすると(2個以上メッセージを投げないと)永遠にメッセージが届かなくてハマる...
-
ioctl(kcmfd, SIOCKCMATTACH, ...)
に渡す(TCP)ソケットは、accept
した後のもの - BPFプログラムが返す値は、メッセージ全体のサイズ
- ヘッダを含んだサイズ
- BPFプログラムのサンプルにある
load_word
は64bitの値を返す- 32bitの場合は
load_half
- 注:アーキテクチャ依存かもしれない
- 32bitの場合は
- BPFプログラムの
load_half(skb, 0)
の意味はsk_buff
にあるデータのオフセット0から32bitを読み込む - プロトコルヘッダ内のメッセージサイズは(当然)ネットワークバイトオーダーで書く
-
/proc/net/kcm
,/proc/net/kcm_stats
というKCMの状態を出力するprocfsのファイルがある-
/proc/net/kcm
が生成されたTCMインスタンス毎の状態,/proc/net/kcm_stats
がシステムグローバルの統計情報を返す - デバッグするときは、
/proc/net/kcm
のRX-Msgs
やRX-Bytes
の値を見て、どのソケット(tcmやpsock)にメッセージが何個届いているか確認することになる
-
おわりに
簡単ですが、私がサンプルプログラムを書くときにハマった所を書いてみました。これからKCMを使ってプログラムを書く人の助けになれば良いなと思います。
なお、使い方を完全に理解しているわけではないので、上記内容には間違いがあるかもしれません。もしあれば間違いを指摘していただけるとありがたいです。