分12rx_droppedの値を表示する次にrx_droppedの内容を表示してみましょう。SystemTapではいくつかのローカル変数にアクセスできます。dropラベル付近の変数であれば,次のように確認できます。sk_buff*」の変数にアクセスできるわけです。@cast()を使うことで,特定の変数を指定した構造体にキャストしてそのメンバーにアクセスしたり,その値を読むことが可能です。具体的に見ていきましょう。sk_buff」であるという情報を与えた上で,そのdevメンバーにアクセスしています。net_deviceであり,そのrx_droppedメンバーの値を「atomic_long_read()」でdropped変数に保存,表示しています。実際に実行してみると次のような結果になります。2どうやら値が読めているようです。showの結果と比べてみると,dropped1の値は1つ少ないことがわかります。これは「dropラベル」でrx_droppedカウンターの内容を見てしまっているためです。コードをよく見るとわかりますが,rx_droppedはdropラベルにジャンプしたあとに更新されるので,本来は更新されたあとにチェックする必要があります。ラベルのある箇所と違って,コード上の任意の場所をプローブポイントにするのは少し調整が必要です。-L」コマンドを実行したときに,ラベルのある具体的なコードの箇所が表示されていました。今回はその表示を元にコードの行番号をkfree_skb(skb);が実行される4528行目「付近の」プローブポイントに設定してみましょう。STPスクリプトの末尾に,次のコードブロックを追加してください。dropped)}「statement("関数名@ファイル名:行番号").nearest」を使うと,指定した行番号付近のもっとも近いところをプローブポイントに設定してくれます。期待通りの場所になるとは限りませんが,うまくプローブポイントを指定できないときに役に立つでしょう。4dropped2のほうは,きちんと「増えたあと」のrx_droppedが表示されましたね。関数を定義するSystemTapではfunctionを指定することで自前の関数を定義します。さきほどの例ではrx_droppedの増加前後で同じようなコードをコピーしていたので,関数化してしまいましょう。"dropped2")}これだけです。説明するまでもないぐらいわかりやすいですね。MACアドレスを表示する最後にMACアドレスを表示してみましょう。*)でEthernetフレームのヘッダーを示すポインタを取り出します。そのメンバーであるh_destとh_sourceが送信先・送信元のMACアドレスです。実はSystemTapのスクリプトの中でC言語の関数を呼び出すことも可能です。先に完成形のスクリプトを提示しておきましょう。get_ethhdr($skb))}最初のポイントはC言語の部分は「%{...%}」でかこうことです。C言語部分については別途カーネルヘッダーが必要になりますので,明示的に必要なヘッダーファイルをインクルードしています。get_ethhdr()では,skbのポインタを渡して,Ethernetフレームのヘッダーを示すポインターに変換し,文字列として送信元・送信先のMACアドレスとEtherTypeを保存します。STAP_ARG_fooはSTPスクリプト上の変数をC言語で解釈するためのマクロであり,STAP_RETVALUEは関数から値を返すためのマクロです。カーネルのprintf関連のフォーマットには便利なフォーマット変換子(上記で言うとMACアドレス表記にする%pMなど)があるため,C言語側で文字列に変換しています。「MAXSTRINGLEN」は128バイトと小さめなので,もしいろいろ出力するなら別途調整したほうが良いでしょう。あとは作成した文字列をそのまま出力しているだけです。実際の出力結果は次のようになります。proto=0x4321stapコマンドは「-g」オプションを付けることでguruモードで動作します。C言語を埋め込む場合はその内容によって「-g」が必要になるようです。errframe.pyで設定した値に従って,MACアドレスやEtherTypeが設定されていることがわかります。