【ndnSIM】Interest・DataパケットをIPのパケットに詰め込んだり、元に戻したり

モチベーション

Information Centric Networking(ICN)のシミュレーションで、ルーティング周りの処理を弄ってトラフィック量の計測がしたい。一番研究が盛んなNDNをベースにして、ちゃんとInterest & Dataパケットは使いたいし、ndnSIM または ndn-cxx + NFD で実装したい。
しかし、ndnSIMにしろndn-cxx + NFDにしろアプリケーション層の研究開発向けっぽくて、ルーティング周りを弄ろうとすると内部実装書き換える必要あるっぽいので、技術力のない自分にはキツい。
仮にアプリケーション層でやりたいことを実装して、中間地点に設置したノードにインストールしても、元々のルーティング処理が良い感じに処理してしまうのでアプリケーション層まで届けられずに転送されてしまう。
そこで、Interest & DataパケットをIPパケットに詰め込んでソケットで送ってしまえばNDNのルーティング処理を通さないので,上位層の自前のコードで色々と処理出来て計測結果取れるよね、みたいな話(日本語が壊滅的に下手すぎてダメ)

どうするのか

ndn::Interestクラス・ndn::Dataクラス双方にwireEncodeというメソッドが存在する。これはNDNパケットをTLVフォーマットで表現したndn::Block型に変換して返してくれるという優れものである。
ここからさらにuint8_t型定数ポインタに変換してくれるwireというメソッドを使えば良い。ここまで変換すれば、Packet型にPayloadとしてぶち込むことが可能になる。

実際のコード (Interestパケットの場合)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 適当にInterestパケットを作成する
ndn::Interest interest(ndn::Name("/ndn.com"));
interest.setInterestLifetime(ndn::time::milliseconds(100000));
interest.setMustBeFresh(true);

// Block型に変換する
ndn::Block block = interest.wireEncode();

// Packetにぶち込む
ns3::Packet packet(block.wire(), (uint32_t)block.size());

// Packetからデータを取り出す
uint8_t *buffer = new uint8_t[packet.GetSize()];
packet.CopyData(buffer, packet.GetSize());

// Block型に復元する
ndn::Block block_restored(buffer, packet.GetSize ());

// Interestパケットに復元する
ndn::Interest interest_restored(block_restored);

// 以下の2行は出力が同じになります
std::cout << interest << std::endl;
std::cout << interest_restored << std::endl;

ndn::DataクラスでもwireEncodeメソッドがあるので、Dataパケットでも同様に出来ます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 適当にDataパケットを作成する
std::shared_ptr<ndn::Data> data = std::make_shared<ndn::Data>();
data->setName(ndn::Name("/ndn.com/content01.html"));
data->setFreshnessPeriod(ndn::time::seconds(10));
static const std::string content = "hogehogeclub";
data->setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.size());
ndn::security::v2::KeyChain m_keyChain;
m_keyChain.sign(*data);

// Block型に変換する
ndn::Block block = data->wireEncode();

// Packetにぶち込む
ns3::Packet packet(block.wire(), (uint32_t)block.size());

// Packetからデータを取り出す
uint8_t *buffer = new uint8_t[packet.GetSize()];
packet.CopyData(buffer, packet.GetSize());

// Block型に復元する
ndn::Block block_restored(buffer, packet.GetSize ());

// Dataパケットに復元する
ndn::Data data_restored(block_restored);

// 以下の2行は出力が同じになります
std::cout << *data << std::endl;
std::cout << data_restored << std::endl;

keyChain.sign()をやっておかないとエラーが出るので注意!
この後はNS-3のSocketとか使って良い感じに指定したノードに送ってあげましょう。