2013年12月26日木曜日

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

今回はSimple-routerのソースを見ていきます。
simple-routerを元にプログラムを作れるようにしっかり理解していきたいところです。

本体のソースを見る前に、Simple-routerが初めに読み込む4つのプログラムの役割をざっくりと説明します。

arp-table.rb
arp情報を管理するクラスです
その名の通りIPアドレスからmacアドレスを調べるのに使います。
ソースは以前使ったFDBクラスとよく似ています

interface.rb
simple-routerのインターフェイス情報を管理するために使用するクラスです
macアドレスやIPアドレス、サブネットマスク、物理ポート番号を管理しています。

routing-table.rb
ルーティングテーブルの情報を保持するクラスです
ルーティングの追加などが行えます。

router-utils.rb
ICMPパケットやarpリクエストのパケットを作るといったルータの機能を実現するためのクラスが用意されています

ではソースの方を見ていきましょう。
  1  require "arp-table"
  2  require "interface"
  3  require "router-utils"
  4  require "routing-table"
  5  
  6  class SimpleRouter < Controller
  7    include RouterUtils
  8  
  9    def start
 10      load "simple_router.conf"
 11      @interfaces = Interfaces.new( $interface )
 12      @arp_table = ARPTable.new
 13      @routing_table = RoutingTable.new( $route )
 14    end
 15  
 16    def packet_in( dpid, message )
 17      return if not to_me?( message )
 18  
 19      if message.arp_request?
 20        handle_arp_request dpid, message
 21      elsif message.arp_reply?
 22        handle_arp_reply message
 23      elsif message.ipv4?
 24        handle_ipv4 dpid, message
 25      else
 26        # noop.
 27      end
 28    end
 29  
 30    private
 31  
 32    def to_me?( message )
 33      return true if message.macda.broadcast?
 34  
 35      interface = @interfaces.find_by_port( message.in_port )
 36      if interface and interface.has?( message.macda )
 37        return true
 38      end
 39    end
 40  
 41    def handle_arp_request( dpid, message )
 42      port = message.in_port
 43      daddr = message.arp_tpa
 44      interface = @interfaces.find_by_port_and_ipaddr( port, daddr )
 45      if interface
 46        arp_reply = create_arp_reply_from( message, interface.hwaddr )
 47        packet_out dpid, arp_reply, SendOutPort.new( interface.port )
 48      end
 49    end
 50  
 51    def handle_arp_reply( message )
 52      @arp_table.update message.in_port, message.arp_spa, message.arp_sha
 53    end
 54  
 55    def handle_ipv4( dpid, message )
 56      if should_forward?( message )
 57        forward dpid, message
 58      elsif message.icmpv4_echo_request?
 59        handle_icmpv4_echo_request dpid, message
 60      else
 61        # noop.
 62      end
 63    end
 64  
 65    def should_forward?( message )
 66      not @interfaces.find_by_ipaddr( message.ipv4_daddr )
 67    end
 68  
 69    def handle_icmpv4_echo_request( dpid, message )
 70      interface = @interfaces.find_by_port( message.in_port )
 71      saddr = message.ipv4_saddr.value
 72      arp_entry = @arp_table.lookup( saddr )
 73      if arp_entry
 74        icmpv4_reply = create_icmpv4_reply( arp_entry, interface, message )
 75        packet_out dpid, icmpv4_reply, SendOutPort.new( interface.port )
 76      else
 77        handle_unresolved_packet dpid, message, interface, saddr
 78      end
 79    end
 80  
 81    def forward( dpid, message )
 82      next_hop = resolve_next_hop( message.ipv4_daddr )
 83  
 84      interface = @interfaces.find_by_prefix( next_hop )
 85      if not interface or interface.port == message.in_port
 86        return
 87      end
 88  
 89      arp_entry = @arp_table.lookup( next_hop )
 90      if arp_entry
 91        macsa = interface.hwaddr
 92        macda = arp_entry.hwaddr
 93        action = create_action_from( macsa, macda, interface.port )
 94        flow_mod dpid, message, action
 95        packet_out dpid, message.data, action
 96      else
 97        handle_unresolved_packet dpid, message, interface, next_hop
 98      end
 99    end
100  
101    def resolve_next_hop( daddr )
102      interface = @interfaces.find_by_prefix( daddr.value )
103      if interface
104        daddr.value
105      else
106        @routing_table.lookup( daddr.value )
107      end
108    end
109  
110    def flow_mod( dpid, message, action )
111      send_flow_mod_add(
112        dpid,
113        :match => ExactMatch.from( message ),
114        :actions => action
115      )
116    end
117  
118    def packet_out( dpid, packet, action )
119      send_packet_out(
120        dpid,
121        :data => packet,
122        :actions => action
123      )
124    end
125  
126    def handle_unresolved_packet( dpid, message, interface, ipaddr )
127      arp_request = create_arp_request_from( interface, ipaddr )
128      packet_out dpid, arp_request, SendOutPort.new( interface.port )
129    end
130  
131    def create_action_from( macsa, macda, port )
132      [
133        SetEthSrcAddr.new( macsa ),
134        SetEthDstAddr.new( macda ),
135        SendOutPort.new( port )
136      ]
137    end
138  end

では最初から見ていきます。

1~4行目
最初に説明した4つのソースプログラムを読み込み、使用できるようにしています。

7行目
simple-routerのプログラムからRouterUtils.rbに定義されたモジュールを使えるようにしています。

9~10行目
startメソッドは起動時に実行されます。
同じディレクトリにあるsimple_router.confファイルを読み込みます。
このファイルには$interface変数と$route変数が定義されます。

$interface変数にはsimple-routerのインターフェイス設定、$route変数にはsimple-routerで使うルーティングの初期値が書かれています。
先頭に$がついているのでグローバル変数になります。

11~13行目
クラスのオブジェクトを作成しています。
@interfaces変数はsimple-routerのインターフェイスの情報を保持します。
@arp_table変数にはsimple-routerのarp情報を格納します。
@routing_table変数はsimple-routerのルーティングテーブルとして使用します。

16~17行目
packet_inイベントハンドラはsimple-routerがパケットを受信すると実行されます。
to_me?メソッドは、受け取ったパケットがブロードキャストかsimple-router宛てのパケットの場合はtrueを返します。
ただし、ここではifの条件にnotがついているため、パケットがブロードキャストでもsimple-router宛てでもない場合はpacket_inメソッドから抜けます。

19~28行目
受け取ったパケットの種類により処理を行います。

arp_request?メソッドは、パケットがarpリクエストの場合にtrueを返します。
メソッドの結果がtrueの場合、handle_arp_requestメソッド実行します。
handle_arp_requestメソッドはarpリクエストに対しarpリプライを返します。

arp_reply?メソッドは、パケットがarpリプライの場合にtrueを返します。
メソッドの結果がtrueの場合、handle_arp_replyメソッドを実行します。
handle_arp_replyメソッドは受け取ったarpパケットを元にsimple-routerのarp情報を更新します。

ipv4?メソッドは、パケットがipv4パケットの場合にtrueを返します。
メソッドの実行結果がtrueの場合、handle_ipv4メソッドを実行します。
handle_ipv4メソッドはパケットの転送やicmpのリプライなどを行います。

これらにあてはまらないパケットの場合は何もしません。

32~39行目
to_me?メソッドはパケットの宛先がsimple-router宛てかを判定し、trueかfalseを返します。

パケットがブロードキャストの場合はtrueを返します。
ブロードキャストではない場合、Interfacesクラスのfind_by_portメソッドを実行し、パケットを受け取ったインターフェイス情報をinterface変数にセットします。
次に、そのインターフェイスのmacアドレスとパケットの宛先macアドレスが一致した場合はto_me?メソッドはtrueを返します。

41~49行目
handle_arp_requestメソッドはarpリプライを返すメソッドです。

port変数にはパケットを受け取った物理ポート番号をセットします。
addr変数にはパケットの宛先のIPアドレスをセットします。
interface変数にはパケットを受け取った物理ポート番号とIPアドレスが一致するインターフェイス情報をセットします。
interface変数にインターフェイス情報がセットされた場合、以下の処理でarpリプライを返します。

create_arp_reply_fromはarpリプライパケットを作るメソッドです。
引数にはarpリプライで返すハードウェアアドレスがセットされています。
packet_outメソッドでarpリプライを送ります

51~53行目
handle_arp_replyメソッドは、arp情報を更新するメソッドです。

受け取ったarpパケットからARPTableクラスのupdateメソッドを実行してarp情報を更新します。

55~63行目
handle_ipv4メソッドはパケットの転送処理やicmpパケットの返信処理を行います。

should_forward?メソッドは、パケットの宛先IPアドレスがsimple-routerのインターフェイスに振られているIPアドレスかを調べます。
simple-routerのインターフェイスにそのIPアドレスが無い場合はtrueになり、forwardメソッドを実行してパケットの転送を行います。
パケットの宛先IPアドレスがsimple-router宛ての場合はfalseで、かつパケットがicmpパケットだった場合は、handle_icmpv4_echo_requestメソッドを実行してicmpに返信を返します。

それ以外の場合は何もしません。

65~67行目
should_forward?メソッドはパケットの宛先IPアドレスがsimple-routerのインターフェイスに振られれているIPアドレスかを調べるメソッドです。
パケットを転送するか判断するのに使用します。

Interfaceクラスのfind_by_ipaddrメソッドを実行し、simple-routerにIPアドレスが一致するインターフェイスがある場合はfalseを返します。

69~79行目
handle_icmpv4_echo_requestメソッドはicmpパケットに返信を返すメソッドです。

interface変数には、Interfacesクラスのfind_by_portメソッドを実行し、パケットを受け取った物理ポートのインターフェイス情報をセットします。
saddr変数には、パケット送信元のIPアドレスをセットします。
arp_entry変数には、ARPTableクラスのlookupメソッド実行し、送信元のIPアドレスを元に@arp_table変数からarp情報を取得しセットします。

arp_entry変数にarp情報がセットされた場合、create_icmpv4_replyメソッドを実行して返信するパケットを作成し、packe_outメソッドで送信元に返します。

@arp_table変数からarp情報が取得できなかった場合は、handle_unresolved_packetメソッドを実行してarp情報を取得します。

81~87行目
forwardメソッドはパケットの転送処理を行います。

next_hop変数には、resolve_next_hopメソッドでパケットの次の転送先IPアドレスを取得してセットします。
interface変数には、Interfacesクラスのfind_by_prefixメソッドを実行しsimple-routerの出力先ポートをセットします。
出力先インターフェイスが見つからないか、出力先ポートがパケットを受け取ったポートだった場合はforwardメソッドを終了します。

89~99行目
arp_entry変数には、next_hop変数を元にlookupメソッドでarp情報を取得しセットします。
arp情報が取得できた場合、macsa変数にはsimple-routerの出力インターフェイスのmacアドレスをセットします。
macda変数にはarp情報から取得したパケットの送信先のmacアドレスをセットします。
action変数には、create_action_fromメソッドでパケットを送る時のaction(処理)を作成します。
flow_modメソッドでフローエントリを追加し、packet_outメソッドでパケットを送信します。

arp情報が取得できなかった場合は、handle_unresolved_packetメソッドでnext_hopに指定されているIPアドレスに対してarpリクエストを送ります。

101~108行目
resolve_next_hopメソッドはパケットの転送先のIPアドレスを取得します。

まず、送信先IPアドレスを元にSimple-routerのインターフェイスの中からIPアドレスのネットワーク部分が一致するインターフェイスを探します。
simple-routerに送信先IPアドレスのネットワークと一致するインターフェイスがある場合、メソッドは送信先IPアドレスを返します。
一致するIPアドレスがな無い場合はルーティングテーブルから次の転送先を取得します。
RoutingTableクラスのlookupメソッドでパケットの次の転送先のIPアドレスを取得します。

110~116行目
flow_mod_メソッドはフローテーブルにフロールールを追加するメソッドです。
引数のdpid、message、actionを元にフローエントリを追加します。

118~124行目
packe_outメソッドはパケットを送信するメソッドです。
引数のdpid、packet、actionを元にパケットを送信します。

126~129行目
handle_unresolved_packetメソッドはarpリクエストを送るメソッドです。
arp_request変数にcreate_arp_request_fromメソッドでarpパケットを作ります。
packet_outメソッドでarpリクエストを送ります。

131~137行目
create_action_fromメソッドはflowエントリを追加する時や、パケットを送る時のactionを作成します。

長かったですね。
今度はsimple-routerで使われている他のソースも見て行きたいと思います。

以上です。

2013年12月24日火曜日

気になるSDN関連ニュース VPNサービス

2013年12月10日にNTTコミュニケーションズが、新VPNサービス「Arcstar Universal One Virtual」を発表しました。
手軽にVPNが使えますよって製品ですかね。
これはサービス開始は来春からです。

SDN技術を活用とありますがどこに使われているんでしょうね?
既存のVPN製品「Arcstar Universal One」にSDNでユーザごとに仮想ネットワークを構築する感じ?

2014年秋からNFVも提供予定のようです。

◆報道資料
http://www.ntt.com/release/monthNEWS/detail/20131210_2.html
◆関連トピック
http://www.ntt.com/a_virtual/
http://itpro.nikkeibp.co.jp/article/NEWS/20131210/523779/

2013年12月20日金曜日

rubyの演算子(>>、~、&)

rubyのソースを見ていてわからない記号があったので調べました。
今回わからなかったのは「>>」「~」「&」の3つです。

以下のような式で使われていました。
val >> 4
~val
val & 0xffff

それぞれ意味は以下のようです。

「>>」(右シフト演算)
これは左辺の値を右辺のビット数だけ右にシフトさせます。
符号ビットは保持されます。
ビットを右に1つシフトすると値は1/2になります。2つシフトすると1/4です。

以下の例は1234を右に4つシフトするので1/16になります。
p 1234 >> 4
=> 77

2進数で表現すると以下のようになります。
010011010010
     ↓
000001001101

同じ様な物に、<<(左シフト演算)があります。
こちらは逆に左に1つシフトすると2倍、2つシフトすると4倍です。

「~」(ビット反転)
ビットの「1」と「0」を反転させます。
1234のビットを反転させると-1235になります。

p ~1234
=> -1235

2進数で表現すると以下のようになります。
010011010010
     ↓
101100101101

符号付きの2進数のため、-1235になります。

「&」(ビット論理積)
右辺と左辺のビットの両方が「1」の場合は「1」、片方が「0」の場合は「0」になります。

これはサブネットマスクの計算の時に使ったやつですね。
以下の2進数の表現のようにビット列を上下に並べて上下とも「1」だったら「1」、片方が「0」だったら「0」になるやつです。

p 1234 & 0xffff
=> 1234

2進数で表現すると以下のようになります。

  0000010011010010
  1111111111111111
------------------
  0000010011010010

0xffffだとそのままなので分かりにくいかもしれません。
他の例を見てみましょう。
p 21 & 11
=> 1

2進数で表現すると以下のように1になります。

  10101
  01011
-------
  00001

以上です。

2013年12月18日水曜日

気になるSDN関連ニュース HPのSDN製品

ヒューレット・パッカードからSDN製品が発売されたというニュースをキャッチしました。

SDNコントローラの「HP Virtual Application Network SDN Controller」
ネットワーク統合管理ソフトウェアのプラグイン「HP IMC VAN SDN Manager」、「HP IMC VAN Fabric Manager」
仮想環境で稼働するソフトウェアルータ「HP Virtual Services Router」

コントローラはソフトウェアみたいですね。
アプリケーション開発者向けのSDK等が無償で提供されるみたいです。

主にデータセンターやクラウド環境などがターゲットのようですね。
うーん、特に触る機会はないかもしれません。

◆報道資料
http://www8.hp.com/jp/ja/hp-news/press-release.html?id=1549428
◆関連トピック
http://itpro.nikkeibp.co.jp/article/NEWS/20131217/525482/?ST=openflow

2013年12月16日月曜日

気になるSDN関連ニュース SDNコントローラ

SDN関連のニュースなんかも取り上げていきたいと思います。

2013年11月28日の内容ですが、NTTコムウェアがソフトウェアのSDNコントローラ「SmartSDN Controller」を発表、29日に発売したようです。

サーバにコントローラインストールして使うもので、サポートするサーバはRed Hat Enterprise Linux 6.4、スイッチはOpenFlow1.2以上です。

報道資料などを見る限り、単体のソフトウェアコントローラのようですね。
ソフト単体で1,000万から!?ってマジか。

果たして他のベンダーが追随し、SDNが本格化してくるのだろうか・・・?

◆報道資料
http://www.nttcom.co.jp/news/pr13112801.html
◆関連トピック
http://itpro.nikkeibp.co.jp/article/NEWS/20131128/521363/
http://itpro.nikkeibp.co.jp/article/Interview/20131204/522726/?k3

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アドレス


以上です。