今日も秋田で IoT

旧 Trema 日記

C 言語で packet_in ハンドラを書く (その3)

今回は packet_in ハンドラにどのような情報が渡ってくるかについて解説します。

packet_in ハンドラに引数として渡ってくる packet_in 構造体は、以下のように定義されています。

typedef struct {
  uint64_t datapath_id;
  uint32_t transaction_id;
  uint32_t buffer_id;
  uint16_t total_len;
  uint16_t in_port;
  uint8_t reason;
  const buffer *data;
  void *user_data;
} packet_in;

datapath_id と in_port は、packet_in の契機となったスイッチの datapath_id と受信ポート番号です。その他の各フィールドは、OpenFlow 1.0 Spec 中の ofp_packet_in 中にある書くフィールドの値が、ホストバイトオーダーで格納されています。user_data には、set_packet_in_handler() で登録された値が格納されています。

packet_in で送られてくるパケット本体は、packet_in 構造体の data のフィールドに格納されています。data の型である buffer 構造体は、buffer.h 内で以下のように定義されています。

typedef struct buffer {
  void *data;
  size_t length;
  void *user_data;
  void ( *user_data_free_function )( struct buffer *buffer );
} buffer;

この中の data にパケットの本体が、length にその長さが格納されています。再び data が出てきてややこしいですが、パケット本体を覗きたい場合には、buffer 構造体のメンバー data を参照すればよいということになります。

Trema ではパケットの中身をユーザが覗かなくてもよいよう、予め parse した結果を buffer 構造体中の user_data
に格納しています。user_data の中身は packet_info 型ですので、キャストして参照してください。ここに格納されている値は、すべてホストバイトオーダーに変換してあるので、オーダーを気にせずに使用することができます。

typedef struct {
  uint32_t format;
  
  uint8_t eth_macda[ ETH_ADDRLEN ];
  uint8_t eth_macsa[ ETH_ADDRLEN ];
  uint16_t eth_type;
  ... 
} packet_info;

packet_info 構造体の定義は、packet_info.h にありますので、詳しくはそちらをご参照ください。

次回は、packet_info 中の値を使った packet_in ハンドラの作り方について紹介します。