2013年12月15日日曜日

Tremaを試す ~simple-ruter その1~

サンプルプログラムの中にあるsimpel-routerのソースコードを見ていきたいと思います。

ただし、simple-routerのソースに入る前にルータが何をしているのかを調べておきます。

今回はルータやL3スイッチなどの動作の一つ、ルーティングおよびルーティングテーブルについてです。

ルーティングとはパケットを宛先まで送る際に、最適な経路の選択をする事を言います。
その経路を選択するのに使用するのがルーティングテーブルです。
ルーティングテーブルには宛先までの経路情報が記録されています。

ルータ等はパケットの宛先IPアドレスを元にルーティングテーブルを参照して、次はどこにパケットを送るかを決定します。
ルーティングテーブルから次のパケット転送先が特定出来ない場合、パケットは破棄されます。

■ルーティングテーブルには以下のような情報が記録されています。
宛先ネットワーク 宛先ネットワークアドレスとネットマスクの情報。
ルーティングをする際は宛先IPアドレスと宛先ネットワーク情報から経路を選択する
ネクストホップ 宛先ネットワークに到達する為に、次のパケット送り先となるネットワーク情報。
メトリック 宛先ネットワークへの経路が複数存在する場合の優先順位です。
出力インターフェイス ネクストホップのパケット出力先インターフェイス。
その他 経路を学習してからの経過時間や経路の情報源等

■ルーティングテーブルの作られ方
・スタティックルーティング(静的経路制御)
管理者の手でルート情報をルーティングテーブルに追加しておく方法です。

・ダイナミックルーティング(動的経路制御)
ルーティングプロトコルにより自動でルーティング追加・管理させる方法です。


以下はルーティングテーブルに関する動作についてです。

■ルート集約
ルーティングテーブルの複数の経路情報のエントリをまとめる事です。
エントリをまとめる理由は、宛先毎に経路情報を保持していくとルーティングテーブルのエントリーががどんどん多くなり、経路を見つけるまでの時間がかかるようになったり、大量のメモリが必要になるためです。

例えば以下の2つのルーティングは一つにまとめられます
宛先ネクストホップ 宛先ネクストホップ
192.168.0.0/24ルータ1 192.168.0.0/23ルータ1
192.168.1.0/24ルータ1

この例を2進数表示と合わせて表にすると以下のようになります。
まずは集約前のルーティングテーブルの状態です。
宛先(10進数)宛先(2進数)ネクストホップ
192.168.0.0/24 11000000.10101000.00000000.00000000ルータ1
192.168.1.0/24 11000000.10101000.00000001.00000000ルータ1

この2つの経路情報はネクストホップが同じであり、サブネットマスクを/24から/23にする事で両方のネットワークを表すことができるため、エントリを一つにまとめることができます。
サブネットマスク/24から/23にすると以下のようになります。

11111111.11111111.11111111.00000000
11111111.11111111.11111110.00000000

例のルーティングテーブルのサブネットマスクを/24→/23に変更したネットワークアドレスは以下のようになります。
宛先(10進数)ネットワークアドレス(2進数)ネクストホップ
192.168.0.0 11000000.10101000.0000000ルータ1
192.168.1.0 11000000.10101000.0000000ルータ1

このように全く同じ内容になるため、集約できるわけです。

■ロンゲストマッチ
宛先ネットワークへの経路が複数存在する場合、プレフィックス長が長い方を選択します。
例えば以下のルーティングテーブルを持つルータを経由して192.168.1.1へパケットを送る時は 2の経路が選択されます。

No宛先ネクストホップ
1192.168.0.0/16ルータ1
2192.168.1.0/24ルータ2

以上です。

2013年12月11日水曜日

rubyのモジュールとは何だ!?

今回はrubyのモジュール(module)について調べました。

調べたと言ってもかなり浅くでして、実はもっと奥が深いようです。

モジュールの書き方はクラスの定義と同じ様に「module モジュール名」で定義をします。
モジュールはクラスと違い、クラスからオブジェクトを作ったり継承する事は出来ません。

以下は簡単な例ですが、モジュールの使い方です。

(Test.rb)
module Hoge

  def hello
    p "Hello"
  end

end

class Test

  include Hoge

  def moge
    hello
  end

end

a=Test.new
a.hello
a.moge

実行すると以下のように表示されます。
$ ruby Test.rb
"Hello"
"Hello"

例のようにモジュールはクラスにincludeして使います。
includeすると関数のように使えます。

実行結果の1つ目の”Hello"はaクラスの関数のように実行しました。
2つ目はaクラスのmogeメソッドの中で実行しています。

今回はこのへんで。

2013年12月10日火曜日

ICMPとはなんだ!?

今回はtremaのsimple-routerにICMPが出てくるので調べました。

ICMPはIPアドレスで通信をするうえで欠かせないプロトコルです。
pingやtracerouteはICMPプロトコルを使用したものです。

ICMPには、大きく分けて「問い合わせ」と「エラー通知」の2種類のメッセージがあります。
pingやtracerouteは「問い合わせ」にあたります。

「エラー通知」はIP通信において経路上にエラーが発生した場合に、送信元にエラーの理由を返します。
なおエラー通知が無限ループにならないように、ICMP通知に対してはエラー通知の対象にならないようになっています。

ICMPのパケットの構造
ethernetヘッダー
IPヘッダー
ICMPメッセージ
 タイプ     機能コードの値が入る
 コード     詳細な機能コードが入る
 チェックサム エラーがないか確認する値が入る
 データ     ICMPメッセージごとに異なる

ICMPタイプ(抜粋)
タイプメッセージ説明
0Echo Replyエコー応答
3Destination Unreachable宛先到達不可
4Source Quench送出抑制要求
5Redirect経路変更要求
8Echo Requestエコー要求
11Time Exceeded時間超過
12Parameter Problem不正引数
13Timestamp Requestタイムスタンプ要求
14Timestamp Replyタイムスタンプ応答
15Information Request情報要求
16Information Reply情報応答
17Address Mask Requestアドレスマスク要求
18Address Mask Replyアドレスマスク応答

タイプ0、8はpingで使われています。

ICMPについては引き続きまとめます。

2013年12月8日日曜日

rubyのpackメソッドがわからない

標記の通りなんですが・・・。

packメソッドはsimple-routerのrouter-util.rbで使われています。
構文は「pack(template)->string」で、説明は「配列の内容をtemplateで指定された文字列にしたがってバイナリとしてパックした文字列を返す」と書いてありますが、いったい何がどうなるのでしょうか?

調べてわかったのは、packメソッドっというのはruby以外にPHPやperlにもある。
packではバイナリデータを出力するメソッドのようです。
構文のtemplateで型指定と長さを指定します。

それ以上の事はわかりませんでした。
とりあえず今回はtemplateの内容をまとめてみます。
(といってもリファレンスマニュアルからの抜粋ですが・・・)

template文字列説明
aASCII(足りない部分はnull文字を詰める)
AASCII(足りない部分はスペースを詰める)
Znull終端文字列(aと同じ)
bビットストリング(各バイトごとに下位ビットから上位ビット)
Bビットストリング(各バイトごとに上位ビットから下位ビット)
h16進数文字列(下位ニブルが先)
H16進数文字列(上位ニブルが先)
cchar(8bit符号付整数)
Cchar(8bit符号なし整数)
sshort(16bit符号付整数、エンディアンに依存)
Sunsigned short(16bit符号なし整数、エンディアンに依存)
iint(符号付整数、エンディアンとintのサイズに依存)
Iunsigned int(16bit符号なし整数、エンディアンとintのサイズに依存)
llong(32bit符号付整数、エンディアンに依存)
Lunsigned long(32bit符号付整数、エンディアンに依存)
qlong long(符号付整数、エンディアンとlong longのサイズに依存)
Qunsigned long long(符号なし整数、エンディアンとlong longのサイズに依存)
mbase64された文字列。60オクテッドごとに改行が付加される
Mquoted-printable encodingされた文字列
nネットワークバイトオーダーのunsigned short
Nネットワークバイトオーダーのunsigned long
v"VAX"バイトオーダーのunsigned short
V"VAX"バイトオーダーのunsigned long
f単精度浮動小数点数
d倍精度浮動小数点数
eリトルエンディアンの単精度浮動小数点数
Eリトルエンディアンの倍精度浮動小数点数
gビッグエンディアンの単精度浮動小数点数
Gビッグエンディアンの倍精度浮動小数点数
pナル終端の文字列へのポインタ
P構造体(固定長文字列)へのポインタ
uunencodeされた文字列
UUTF-8
wBER圧縮指数
xナルバイト
X1バイト後退
@絶対位置への移動

また何かわかったら載せたいと思います。

2013年12月5日木曜日

パケットとフレームの違い

SDNやtremaでは、よくパケットという単語を目にします。
パケットと言えばネットワークに流れるデータを指してそう呼んでいると思います。

ただ、パケットの他にもフレームという単語もあり、こちらも同様にネットワークを流れるデータを指しているようです。
今回はパケットとフレームの違いを調べてみました。

まずパケットやフレームというのは、OSI参照モデルの各レイヤのPDU(プロトコル・データ・ユニット)の呼び名という事でした。
PDUは各プロトコルごとに決められたデータ単位の事です。

パケットレイヤ3(ネットワーク層)のIPのPDU
フレームレイヤ2(データリンク層)のEthernetのPDU

他にもこんなのもあるみたいです。
セグメントレイヤ4(トランスポート層)のTCPのPDU
メッセージレイヤ5(セッション層)のPDU
セルレイヤ2のATM(Asynchronous Transfer Mode)のPDU

ただ、ネットワークに流れるデータをパケットと言ってしまっているケースもあるようです。

2013年12月4日水曜日

simple-routerとARP

前回、ARPについて書きましたが、実はtremaのsimple-routerで使っているrouter-utils.rbに関係があります。
router-utils.rbのソースコードにARPPacketというクラスがあります。
以下がそのソースになります。

(router-utils.rbから抜粋)
 1  class ARPPacket
 2    attr_accessor :type, :tha, :sha, :tpa, :spa
 3  
 4    def initialize type, tha, sha, tpa, spa
 5      @type = type
 6      @tha = tha
 7      @sha = sha
 8      @tpa = tpa
 9      @spa = spa
10    end
11  
12    def pack
13      eth_header = EthernetHeader.new( @tha, @sha, 0x0806 )
14  
15      # arp
16      arp = [ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, @type ]
17      arp += @sha.to_a + @spa.to_a + @tha.to_a + @tpa.to_a
18  
19      while arp.length < 46 do
20        arp += [ 0x00 ]
21      end
22  
23      eth_header.pack + arp.pack( "C*" )
24    end
25  end


今回は詳しく見ませんが、以下の部分はARPパケットの中身そのものです。

16      arp = [ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, @type ]
17      arp += @sha.to_a + @spa.to_a + @tha.to_a + @tpa.to_a

16行目は、ARPパケットの制御情報と動作コードを配列にセットしています。

0x0001         ネットワーク種類(Ethernet)
0x0800         プロトコル(IP)
0x06          ハードウェアアドレス長さ
0x04          プロトコルアドレス長さ
0x0001 または 0x0002  動作コード(ARPリクエスト/ARPリプライ)

17行目はARPパケットの送信元、目標の情報をarp変数の配列に追加しています。

sha           送信元のMACアドレス
spa           送信元のIPアドレス
tha           目標のMACアドレス
tpa           目標のIPアドレス

ARPパケットについて知らずにソースを見てもよくわかりませんでしたが、ARPパケットの中身が分かってから見ると意味がわかる気がしますね。

2013年12月3日火曜日

ARPとは何だ!?

今回はARP(Address Resolution Protocol)についてです。

ARP自体は少し調べてみればなんとなくわかる思いますが、ザックリとまとめてみました。
要するにTCP/IPで通信するにはIPアドレスの他にMACアドレスが必要で、IPアドレスからMACアドレスを調べるためにARPというプロトコルがあります。

ARPには以下の2種類があります。
・ARPリクエスト(要求)
・ARPリプライ(応答)

ARPの仕組みは、ARPリクエストをするノード(※1)は同一ネットワーク上の全てのノードに対してARPリクエストを送ります(※2)。
ARPリクエストを受け取ったノードは、ARPパケットの目標IPが自分宛てだった場合、ARPリクエストをしたノードにだけARPリプライを送ります(※3)。
ARPパケットの目標IPが自分宛てではなかったノードはパケットを破棄します
 ※1:ノードとはネットワークを構成するコンピュータや通信機器の事
 ※2:ブロードキャスト
 ※3:ユニキャスト

ARPパケットの中身はこんな感じです。

■ARPリクエスト
【イーサネットヘッダ】
宛先MACアドレス    ブロードキャスト(「FF:FF:FF:FF:FF:FF」)
送信元MACアドレス   ARPリクエストしたノードのMACアドレス
フレームタイプ     0x0806(固定)→ARPを示す
 【ARPパケット】
 制御情報        プロトコル等<ネットワーク種類:0x0001(固定)→Ethernet/プロトコル:0x0800→IP/ハードウェアアドレス(MAC)長さ:0x06固定/プロトコルアドレス(IP)長さ:0x04(固定)>
 動作コード       0001(固定)→ARPリクエストを示す
 送信元MACアドレス   ARPリクエストしたノードのMACアドレス
 送信元IPアドレス    ARPリクエストしたノードのIPアドレス
 目標MACアドレス    わからないため「00:00:00:00:00:00」や「FF:FF:FF:FF:FF:FF」にしておく
 目標IPアドレス     調べたいノードのIPアドレス

■ARPリプライ
【イーサネットヘッダ】
宛先MACアドレス    ARPリクエストしたノードのMACアドレス
送信元MACアドレス   ARPリプライしたノードのMACアドレス
フレームタイプ     0x0806固定→ARPを示す
 【ARPパケット】
 制御情報        プロトコル等<ネットワーク種類:0x0001(固定)→Ethernet/プロトコル:0x0800→IP/ハードウェアアドレス(MAC)長さ:0x06固定/プロトコルアドレス(IP)長さ:0x04(固定)>
 動作コード       0x0002(固定)→ARPリプライを示す
 送信元MACアドレス   ARPリプライしたノードのMACアドレス
 送信元IPアドレス    ARPリプライしたノードのIPアドレス
 目標MACアドレス    ARPリクエストしたノードのMACアドレス
 目標IPアドレス     ARPリクエストしたノードのIPアドレス


以上です。