2014年8月 2日 (土)

◆単純なブリッジに仮想インターフェースを追加【OpenFlow1.0をTremaの土管として使う】

Trema のプログラムにより、ICMP Echo に応答する仮想のインタフェーフェースを作成してみました。
以下の2つの理由により少ないコード数で実現することができました。
1. Trema の PacketIn メッセージには ARP の解析結果が含まれている。
(Trema の PacketIn http://rubydoc.info/github/trema/trema/master/Trema/PacketIn )
2. Trema の前提としている Pio ライブラリを使用することで ARP と ICMP Echo パケットのエンコード/デコードが簡単にできる。

※注意:不正なパケットを受信した場合の処理はあまり考えていません。

■確認環境
  ・OS: Lubuntu 13.04 Desktop (i386)
  ・Ruby 1.9.3p194
  ・Trema 0.4.7
  ・Pio 0.7.0
  ・bindata 2.1.0

■テスト構成
  OpenFlow コントローラである Trema 側のプログラムにより仮想のインターフェースには図のように MAC アドレスと IP アドレスを割り振ってあります。

Photo

■プログラムコード

以前の記事「◆ 単純なブリッジの実装その4~Open vSwitch対策~【OpenFlow1.0をTremaの土管として使う】」のコードを改造して作成しました。

require 'pio'

class VirtualIP1 < Controller
  MIN_PACKET_DATA_LEN = 60

  def start
    @port_list = [ 1, 2, 3 ]    # all port numbers

    @VIF_mac = Pio::Mac.new("02:00:00:00:00:01")
    @VIF_ipv4addr = Pio::IPv4Address.new("192.168.0.251")
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def flood( datapath_id, in_port, data )
    actions = [ ]
    @port_list.each do | port |
      if ( in_port != port )
        actions.push( SendOutPort.new( port ) )
      end
    end

    send_packet_out( datapath_id,
      :in_port => in_port,
      :data => data,
      :actions => actions )
  end

  def handle_icmpv4_echo_request( datapath_id, message )
    return if ( message.ipv4_daddr != @VIF_ipv4addr )

    begin
      icmpv4_echo_req = Pio::Icmp.read( message.data )
    rescue => ex
      return
    end

    icmpv4_echo_reply = Pio::Icmp::Reply.new(
      :destination_mac => message.macsa,
      :source_mac => message.macda,
      :ip_source_address => message.ipv4_daddr,
      :ip_destination_address => message.ipv4_saddr,
      :identifier => icmpv4_echo_req.icmp_identifier,
      :sequence_number => icmpv4_echo_req.icmp_sequence_number,
      :echo_data => icmpv4_echo_req.echo_data)

    flood( datapath_id, OFPP_NONE, icmpv4_echo_reply.to_binary)
  end

  def handle_arp( datapath_id, message )
    return if ( message.arp_tpa != @VIF_ipv4addr )

    begin
      arp_req = Pio::Arp.read( message.data )
    rescue => ex
      return
    end

    arp_reply = Pio::Arp::Reply.new(
      :source_mac => @VIF_mac,
      :destination_mac => message.macsa,
      :sender_protocol_address => message.arp_tpa,
      :target_protocol_address => message.arp_spa
    )

    flood( datapath_id, OFPP_NONE, arp_reply.to_binary )
  end

  def handle_virtualIF( datapath_id, message )
    if ( message.arp_request? )
      handle_arp( datapath_id, message )
    end

    if ( message.icmpv4_echo_request? )
      handle_icmpv4_echo_request( datapath_id, message )
    end
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    # padding. length of sending data must be >= 60
    data_len = message.data.length
    if ( data_len < MIN_PACKET_DATA_LEN )
      data = message.data + "\x00" * ( MIN_PACKET_DATA_LEN - data_len )
    else
      data = message.data
    end

    # Flooding
    flood( datapath_id, message.in_port, data )

    # Virutal Interface
    if ( message.macda == @VIF_mac or message.macda.broadcast? )
      handle_virtualIF( datapath_id, message )
    end

  end

end

青字のところ:フラッディング処理を関数にまとめました。
赤字のところ:今回の仮想インターフェース用に追加したコードです。ARP Request への応答、ICMP Echo Request への応答のコードを追加しています。
仮想インターフェースの MAC アドレスと IPアドレスは、あらかじめ @VIF_mac と @VIF_ipv4addr の変数に入れています。Pio のライブラリを使っているのは、Trema側のPacketIn メッセージで  Pio を使うようになっていたため合わせました。(どこかのバージョンで Pio を使うように Trema の実装が変更されたようです。)

作成したデータを送信する際にイーサネットのフレームとしての最少バイト数を確保するようにしないといけないのですが、to_binary メソッドを見るとそのための処理が入っていたので今回のコードでは何もしていません。
ARP: https://github.com/trema/pio/blob/develop/lib/pio/arp/format.rb
ICMP : https://github.com/trema/pio/blob/develop/lib/pio/icmp/format.rb

■テスト用仮想ネットワークのコード

trema run 実行時に -c オプションで渡す仮想ネットワークのコードを以下に示します:

vswitch ( "vswitch1" ) {
  datapath_id 0x01
}

1.upto(3) do | each |
    netns ( "vhost#{ each }" ) {
      ip "192.168.0.#{ each }"
      netmask "255.255.255.0"
    }

    link "vswitch1", "vhost#{ each }"
end

仮想ネットワークのコードでは Ruby のプログラムが使えるので、3つの仮想ホストの生成のコードをまとめるようにしています。仮想ホスト vhost1 ~ vhost3 に 192.168.0.1 ~ 192.168.0.3 の IP を割り当てています。
仮想ホストは netns を使ってネットワークネームスペースとして生成します(仮想ホスト上で ping などのコマンドを使いたいため)。

■テスト結果

(1) vhost1 にて ARP キャッシュを確認します。
起動直後なので何も入っておらず何も表示されません。

$ sudo ip netns exec vhost1 arp

(2) vhost1 から vhost2 へ ping を実行したのち、ARP キャッシュを確認します。
vhost2 の IP アドレスに対応した MAC アドレスが学習されたことが確認できます。

$ ip netns exec vhost1 ping -c 3 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_req=1 ttl=64 time=28.8 ms
64 bytes from 192.168.0.2: icmp_req=2 ttl=64 time=25.9 ms
64 bytes from 192.168.0.2: icmp_req=3 ttl=64 time=26.2 ms

--- 192.168.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 25.950/27.013/28.849/1.303 ms
$ $ sudo ip netns exec vhost1 arp アドレス               HWタイプ  HWアドレス         フラグ マスク インタフェース 192.168.0.2           ether    1e:29:d4:1a:c0:24   C                 trema0-1

(3) vhost1 から今回作成した仮想インターフェースに対して ping を実行したのち ARP キャッシュを確認します。

$ sudo ip netns exec vhost1 ping -c 3 192.168.0.251
PING 192.168.0.251 (192.168.0.251) 56(84) bytes of data.
64 bytes from 192.168.0.251: icmp_req=1 ttl=128 time=60.0 ms
64 bytes from 192.168.0.251: icmp_req=2 ttl=128 time=44.2 ms
64 bytes from 192.168.0.251: icmp_req=3 ttl=128 time=38.9 ms

--- 192.168.0.251 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 38.967/47.745/60.010/8.940 ms
$
$ sudo ip netns exec vhost1 arp アドレス               HWタイプ  HWアドレス         フラグ マスク インタフェース 192.168.0.251         ether    02:00:00:00:00:01   C                 trema0-1 192.168.0.2           ether    1e:29:d4:1a:c0:24   C                 trema0-1

ping にきちんと応答が返ってきているので当たり前ですが、ARP キャッシュには 192.168.0.251 に対して MAC アドレス 02:00:00:00:00:01 が学習されています。


参考: Pio について

概要は以下あたりが参考になります:
http://www.slideshare.net/ssuser6d53d5/trema-day4-pio-trema

ソースやサンプルなどはこちら:
https://github.com/trema/pio

2014年7月27日 (日)

◆サポート期限切れの Lubuntu 13.04 を新規インストール

新規に Lubuntu 13.04 Desktop (i386) をインストールしたところ、インストールの最後の再起動後のログインで以下のダイアログボックスが出てきてインストールが不完全だといわれました。

01

ここですぐに「この操作を今すぐ実行する」ボタンを押して、セットアップを進めていくと以下のエラーが出てしまい失敗します。

02

原因は、先の記事「◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処」に書いたように apt-get install ができない状態になっていたるためだと思い先の記事の対処を先に実施してから「この操作を今すぐ実行する」ボタンを押しすようにしたところエラーが出ずに完了しました。

◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処

数週間前から Lubuntu 13.04 で apt-get install をしようとすると「404  Not Found」が出てインストールに失敗するようになってしまいました。
Ubuntu 13.04 が EOL(End of Life) に達したため、パッケージのファイルの置き場のサイトが old-releases.ubuntu.com に変わったためのようです。

参考:
https://help.ubuntu.com/community/EOLUpgrades

■確認環境

  Lubuntu 13.04 Desktop (i386)

■ 対処方法

1. /etc/apt/sources.list の中の URL のサイトを old-releases.ubuntu.com に変更します。

以下のコマンドで一括変換してしまいます。
(実行前に /etc/apt/sources.list をどこかにコピーして変更前の内容を退避しておくと良いでしょう)

$ sudo sed -i -e 's|//.*ubuntu.com/|//old-releases.ubuntu.com/|' /etc/apt/sources.list

2. 以下のコマンドで情報を更新します。

$ sudo apt-get update

実行すると以下が出力されました。

取得:1 http://old-releases.ubuntu.com raring Release.gpg [933 B]    
取得:2 http://old-releases.ubuntu.com raring-updates Release.gpg [933 B]
取得:3 http://old-releases.ubuntu.com raring-backports Release.gpg [933 B]
取得:4 http://old-releases.ubuntu.com raring-security Release.gpg [933 B]
取得:5 http://old-releases.ubuntu.com raring Release [40.8 kB]
取得:6 http://old-releases.ubuntu.com raring-updates Release [40.8 kB]
取得:7 http://old-releases.ubuntu.com raring-backports Release [40.8 kB]       
取得:8 http://old-releases.ubuntu.com raring-security Release [40.8 kB]        
取得:9 http://old-releases.ubuntu.com raring/main Sources [963 kB]             
取得:10 http://old-releases.ubuntu.com raring/restricted Sources [5,987 B]     
取得:11 http://old-releases.ubuntu.com raring/universe Sources [5,837 kB]      
取得:12 http://old-releases.ubuntu.com raring/multiverse Sources [171 kB]      
取得:13 http://old-releases.ubuntu.com raring/main i386 Packages [1,168 kB]    
取得:14 http://old-releases.ubuntu.com raring/restricted i386 Packages [9,623 B]
取得:15 http://old-releases.ubuntu.com raring/universe i386 Packages [5,404 kB]
取得:16 http://old-releases.ubuntu.com raring/multiverse i386 Packages [131 kB]
取得:17 http://old-releases.ubuntu.com raring/main Translation-ja [356 kB]     
取得:18 http://old-releases.ubuntu.com raring/main Translation-en [673 kB]     
取得:19 http://old-releases.ubuntu.com raring/multiverse Translation-ja [8,722 B]
取得:20 http://old-releases.ubuntu.com raring/multiverse Translation-en [98.4 kB]
取得:21 http://old-releases.ubuntu.com raring/restricted Translation-ja [480 B]
取得:22 http://old-releases.ubuntu.com raring/restricted Translation-en [2,767 B]
取得:23 http://old-releases.ubuntu.com raring/universe Translation-ja [1,085 kB]
取得:24 http://old-releases.ubuntu.com raring/universe Translation-en [3,737 kB]
取得:25 http://old-releases.ubuntu.com raring-updates/main Sources [90.4 kB]   
取得:26 http://old-releases.ubuntu.com raring-updates/restricted Sources [14 B]
取得:27 http://old-releases.ubuntu.com raring-updates/universe Sources [83.0 kB]
取得:28 http://old-releases.ubuntu.com raring-updates/multiverse Sources [2,797 B]
取得:29 http://old-releases.ubuntu.com raring-updates/main i386 Packages [220 kB]
取得:30 http://old-releases.ubuntu.com raring-updates/restricted i386 Packages [14 B]
取得:31 http://old-releases.ubuntu.com raring-updates/universe i386 Packages [170 kB]
取得:32 http://old-releases.ubuntu.com raring-updates/multiverse i386 Packages [4,813 B]
取得:33 http://old-releases.ubuntu.com raring-updates/main Translation-en [108 kB]
取得:34 http://old-releases.ubuntu.com raring-updates/multiverse Translation-en [2,212 B]
取得:35 http://old-releases.ubuntu.com raring-updates/restricted Translation-en [14 B]
取得:36 http://old-releases.ubuntu.com raring-updates/universe Translation-en [86.0 kB]
取得:37 http://old-releases.ubuntu.com raring-backports/main Sources [902 B]   
取得:38 http://old-releases.ubuntu.com raring-backports/restricted Sources [14 B]
取得:39 http://old-releases.ubuntu.com raring-backports/universe Sources [7,145 B]
取得:40 http://old-releases.ubuntu.com raring-backports/multiverse Sources [1,403 B]
取得:41 http://old-releases.ubuntu.com raring-backports/main i386 Packages [565 B]
取得:42 http://old-releases.ubuntu.com raring-backports/restricted i386 Packages [14 B]
取得:43 http://old-releases.ubuntu.com raring-backports/universe i386 Packages [8,489 B]
取得:44 http://old-releases.ubuntu.com raring-backports/multiverse i386 Packages [1,345 B]
取得:45 http://old-releases.ubuntu.com raring-backports/main Translation-en [269 B]
取得:46 http://old-releases.ubuntu.com raring-backports/multiverse Translation-en [1,040 B]
取得:47 http://old-releases.ubuntu.com raring-backports/restricted Translation-en [14 B]
取得:48 http://old-releases.ubuntu.com raring-backports/universe Translation-en [6,390 B]
取得:49 http://old-releases.ubuntu.com raring-security/main Sources [58.3 kB]  
取得:50 http://old-releases.ubuntu.com raring-security/restricted Sources [14 B]
取得:51 http://old-releases.ubuntu.com raring-security/universe Sources [14.3 kB]
取得:52 http://old-releases.ubuntu.com raring-security/multiverse Sources [2,262 B]
取得:53 http://old-releases.ubuntu.com raring-security/main i386 Packages [154 kB]
取得:54 http://old-releases.ubuntu.com raring-security/restricted i386 Packages [14 B]
取得:55 http://old-releases.ubuntu.com raring-security/universe i386 Packages [53.7 kB]
取得:56 http://old-releases.ubuntu.com raring-security/multiverse i386 Packages [3,858 B]
取得:57 http://old-releases.ubuntu.com raring-security/main Translation-en [79.9 kB]
取得:58 http://old-releases.ubuntu.com raring-security/multiverse Translation-en [1,826 B]
取得:59 http://old-releases.ubuntu.com raring-security/restricted Translation-en [14 B]
取得:60 http://old-releases.ubuntu.com raring-security/universe Translation-en [32.1 kB]
無視 http://old-releases.ubuntu.com raring/main Translation-ja_JP              
無視 http://old-releases.ubuntu.com raring/multiverse Translation-ja_JP
無視 http://old-releases.ubuntu.com raring/restricted Translation-ja_JP
無視 http://old-releases.ubuntu.com raring/universe Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-updates/main Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-updates/main Translation-ja
無視 http://old-releases.ubuntu.com raring-updates/multiverse Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-updates/multiverse Translation-ja
無視 http://old-releases.ubuntu.com raring-updates/restricted Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-updates/restricted Translation-ja
無視 http://old-releases.ubuntu.com raring-updates/universe Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-updates/universe Translation-ja
無視 http://old-releases.ubuntu.com raring-backports/main Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-backports/main Translation-ja
無視 http://old-releases.ubuntu.com raring-backports/multiverse Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-backports/multiverse Translation-ja
無視 http://old-releases.ubuntu.com raring-backports/restricted Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-backports/restricted Translation-ja
無視 http://old-releases.ubuntu.com raring-backports/universe Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-backports/universe Translation-ja
無視 http://old-releases.ubuntu.com raring-security/main Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-security/main Translation-ja
無視 http://old-releases.ubuntu.com raring-security/multiverse Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-security/multiverse Translation-ja
無視 http://old-releases.ubuntu.com raring-security/restricted Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-security/restricted Translation-ja
無視 http://old-releases.ubuntu.com raring-security/universe Translation-ja_JP
無視 http://old-releases.ubuntu.com raring-security/universe Translation-ja
21.0 MB を 3分 47秒 で取得しました (92.2 kB/s)
パッケージリストを読み込んでいます... 完了
W: Duplicate sources.list entry http://old-releases.ubuntu.com/ubuntu/ raring/main i386 Packages (/var/lib/apt/lists/old-releases.ubuntu.com_ubuntu_dists_raring_main_binary-i386_Packages)
W: これらの問題を解決するためには apt-get update を実行する必要があるかもしれません

■ 参考:apt-get install でのエラー出力の具体的内容

先の記事「◆【改訂】OpenFlow フレームワーク Trema 0.4 のインストール手順【0.4.7対応】」で書いた Trema 0.4.7 のインストールのための前提のパッケージを apt-get install した場合、以下が出力されました:

$ sudo apt-get install gcc make git ruby rubygems ruby-dev libpcap-dev libsqlite3-dev libglib2.0-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の特別パッケージがインストールされます:
  binutils build-essential dpkg-dev fakeroot g++ g++-4.7 gcc-4.7 git-man
  libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl
  libc-dev-bin libc6-dev libdpkg-perl liberror-perl libfile-fcntllock-perl
  libgcc-4.7-dev libgomp1 libitm1 libpcap0.8-dev libpcre3-dev libpcrecpp0
  libruby1.8 libruby1.9.1 libstdc++6-4.7-dev libyaml-0-2 linux-libc-dev
  manpages-dev pkg-config ruby1.8 ruby1.8-dev ruby1.9.1 ruby1.9.1-dev
  zlib1g-dev
提案パッケージ:
  binutils-doc debian-keyring g++-multilib g++-4.7-multilib gcc-4.7-doc
  libstdc++6-4.7-dbg gcc-multilib autoconf automake1.9 libtool flex bison gdb
  gcc-doc gcc-4.7-multilib libmudflap0-4.7-dev gcc-4.7-locales libgcc1-dbg
  libgomp1-dbg libitm1-dbg libquadmath0-dbg libmudflap0-dbg binutils-gold
  git-daemon-run git-daemon-sysvinit git-doc git-el git-arch git-cvs git-svn
  git-email git-gui gitk gitweb glibc-doc libglib2.0-doc sqlite3-doc
  libstdc++6-4.7-doc make-doc ri ruby1.8-examples ri1.8 ruby-switch
  ruby1.9.1-examples ri1.9.1 graphviz
以下のパッケージが新たにインストールされます:
  binutils build-essential dpkg-dev fakeroot g++ g++-4.7 gcc gcc-4.7 git
  git-man libalgorithm-diff-perl libalgorithm-diff-xs-perl
  libalgorithm-merge-perl libc-dev-bin libc6-dev libdpkg-perl liberror-perl
  libfile-fcntllock-perl libgcc-4.7-dev libglib2.0-dev libgomp1 libitm1
  libpcap-dev libpcap0.8-dev libpcre3-dev libpcrecpp0 libruby1.8 libruby1.9.1
  libsqlite3-dev libstdc++6-4.7-dev libyaml-0-2 linux-libc-dev make
  manpages-dev pkg-config ruby ruby-dev ruby1.8 ruby1.8-dev ruby1.9.1
  ruby1.9.1-dev rubygems zlib1g-dev
アップグレード: 0 個、新規インストール: 43 個、削除: 0 個、保留: 0 個。
48.3 MB のアーカイブを取得する必要があります。
この操作後に追加で 140 MB のディスク容量が消費されます。
続行しますか [Y/n]?
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libgomp1 i386 4.7.3-1ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libitm1 i386 4.7.3-1ubuntu1
  404  Not Found
取得:1 http://jp.archive.ubuntu.com/ubuntu/ raring/main libpcrecpp0 i386 1:8.31-2 [17.1 kB]
取得:2 http://jp.archive.ubuntu.com/ubuntu/ raring/main libyaml-0-2 i386 0.1.4-2build1 [55.3 kB]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main binutils i386 2.23.2-2ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring-updates/main libc-dev-bin i386 2.17-0ubuntu5.1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libgcc-4.7-dev i386 4.7.3-1ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main gcc-4.7 i386 4.7.3-1ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main gcc i386 4:4.7.3-1ubuntu10
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libstdc++6-4.7-dev i386 4.7.3-1ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main g++-4.7 i386 4.7.3-1ubuntu1
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main libc-dev-bin i386 2.17-0ubuntu5.1
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main g++ i386 4:4.7.3-1ubuntu10
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main make i386 3.81-8.2ubuntu2
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libdpkg-perl all 1.16.10ubuntu1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main dpkg-dev all 1.16.10ubuntu1
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main linux-libc-dev i386 3.8.0-35.50
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main build-essential i386 11.6ubuntu4
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main fakeroot i386 1.18.4-2ubuntu1
  404  Not Found
取得:3 http://jp.archive.ubuntu.com/ubuntu/ raring/main liberror-perl all 0.17-1 [23.8 kB]
エラー http://security.ubuntu.com/ubuntu/ raring-security/main libc6-dev i386 2.17-0ubuntu5.1
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main git-man all 1:1.8.1.2-1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main git i386 1:1.8.1.2-1
  404  Not Found
取得:4 http://jp.archive.ubuntu.com/ubuntu/ raring/main libalgorithm-diff-perl all 1.19.02-3 [50.0 kB]
取得:5 http://jp.archive.ubuntu.com/ubuntu/ raring/main libalgorithm-diff-xs-perl i386 0.04-2build3 [13.1 kB]
取得:6 http://jp.archive.ubuntu.com/ubuntu/ raring/main libalgorithm-merge-perl all 0.08-2 [12.7 kB]
取得:7 http://jp.archive.ubuntu.com/ubuntu/ raring/main libfile-fcntllock-perl i386 0.14-2 [15.8 kB]
取得:8 http://jp.archive.ubuntu.com/ubuntu/ raring/main libpcre3-dev i386 1:8.31-2 [261 kB]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main pkg-config i386 0.26-1ubuntu3
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main zlib1g-dev i386 1:1.2.7.dfsg-13ubuntu2
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libglib2.0-dev i386 2.36.0-1ubuntu2
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libpcap0.8-dev i386 1.3.0-1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libpcap-dev all 1.3.0-1
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring-updates/main libruby1.8 i386 1.8.7.358-7ubuntu1.2
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main libsqlite3-dev i386 3.7.15.2-1ubuntu1
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main libruby1.8 i386 1.8.7.358-7ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main manpages-dev all 3.44-0ubuntu1
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main libruby1.9.1 i386 1.9.3.194-8.1ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main ruby all 4.9
  404  Not Found
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main ruby-dev all 4.9
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main ruby1.9.1 i386 1.9.3.194-8.1ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
エラー http://jp.archive.ubuntu.com/ubuntu/ raring/main rubygems all 1.8.24-1ubuntu1
  404  Not Found
エラー http://security.ubuntu.com/ubuntu/ raring-security/main ruby1.9.1-dev i386 1.9.3.194-8.1ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
エラー http://security.ubuntu.com/ubuntu/ raring-security/main ruby1.8 i386 1.8.7.358-7ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
エラー http://security.ubuntu.com/ubuntu/ raring-security/main ruby1.8-dev i386 1.8.7.358-7ubuntu1.2
  404  Not Found [IP: 91.189.91.13 80]
449 kB を 11秒 で取得しました (39.6 kB/s)
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/libgomp1_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/libitm1_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/b/binutils/binutils_2.23.2-2ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://security.ubuntu.com/ubuntu/pool/main/e/eglibc/libc-dev-bin_2.17-0ubuntu5.1_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://security.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_3.8.0-35.50_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://security.ubuntu.com/ubuntu/pool/main/e/eglibc/libc6-dev_2.17-0ubuntu5.1_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/libgcc-4.7-dev_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/gcc-4.7_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-defaults/gcc_4.7.3-1ubuntu10_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/libstdc++6-4.7-dev_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-4.7/g++-4.7_4.7.3-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/gcc-defaults/g++_4.7.3-1ubuntu10_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/m/make-dfsg/make_3.81-8.2ubuntu2_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/d/dpkg/libdpkg-perl_1.16.10ubuntu1_all.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/d/dpkg/dpkg-dev_1.16.10ubuntu1_all.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/b/build-essential/build-essential_11.6ubuntu4_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/f/fakeroot/fakeroot_1.18.4-2ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/git/git-man_1.8.1.2-1_all.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/git/git_1.8.1.2-1_i386.deb の取 得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/p/pkg-config/pkg-config_0.26-1ubuntu3_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/z/zlib/zlib1g-dev_1.2.7.dfsg-13ubuntu2_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/g/glib2.0/libglib2.0-dev_2.36.0-1ubuntu2_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/libp/libpcap/libpcap0.8-dev_1.3.0-1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/libp/libpcap/libpcap-dev_1.3.0-1_all.deb の取得に失敗しました  404  Not Found
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.8/libruby1.8_1.8.7.358-7ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.9.1/libruby1.9.1_1.9.3.194-8.1ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://jp.archive.ubuntu.com/ubuntu/pool/main/s/sqlite3/libsqlite3-dev_3.7.15.2-1ubuntu1_i386.deb の取得に失敗しました  404  Not Found
http://jp.archive.ubuntu.com/ubuntu/pool/main/m/manpages/manpages-dev_3.44-0ubuntu1_all.deb の取得に失敗しました  404  Not Found
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.9.1/ruby1.9.1_1.9.3.194-8.1ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://jp.archive.ubuntu.com/ubuntu/pool/main/r/ruby-defaults/ruby_4.9_all.deb  の取得に失敗しました  404  Not Found
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.9.1/ruby1.9.1-dev_1.9.3.194-8.1ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://jp.archive.ubuntu.com/ubuntu/pool/main/r/ruby-defaults/ruby-dev_4.9_all.deb の取得に失敗しました  404  Not Found
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.8/ruby1.8_1.8.7.358-7ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://security.ubuntu.com/ubuntu/pool/main/r/ruby1.8/ruby1.8-dev_1.8.7.358-7ubuntu1.2_i386.deb の取得に失敗しました  404  Not Found [IP: 91.189.91.13 80]
http://jp.archive.ubuntu.com/ubuntu/pool/main/r/rubygems/rubygems_1.8.24-1ubuntu1_all.deb の取得に失敗しました  404  Not Found
E: いくつかのアーカイブを取得できません。apt-get update を実行するか --fix-missing オプションを付けて試してみてください。

2014年7月13日 (日)

◆ 単純なブリッジの実装その4~Open vSwitch対策~【OpenFlow1.0をTremaの土管として使う】

以前書いた記事『◆ 単純なブリッジの実装その3~より完璧な土管化~【OpenFlow1.0をTremaの土管として使う】』の保守リリースです。

Open vSwitch と接続した場合に、イーサネットの最低フレーム長に満たないデータが packet_in に入ってくる現象が発生し、そのまま転送しようとすると Trema が終了してしまうので対策することにしました。
こういうケースを想定した処理は堅牢なプログラムにするためには必要でしたね。

■発生環境
  ・OS: Lubuntu 13.04 Desktop (i386)
  ・Trema: 0.4.7
  ・OpenFlowスイッチ: Open vSwitch 1.9.0 (※同OS上に apt-get でインストール)
  ・仮想ホストとして、ネットワークネームスペース

※記事『◆ Lubuntu 13.04 に Open vSwitch をインストールした時のログ

 作成方法詳細は後述します。

■現象
  以下のメッセージを出力して Trema が停止する。

The length of the provided Ethernet frame is shorter than the minimum length of an Ethernet frame (= 64 bytes).

■原因
  送信データが、イーサネットの最小フレームサイズ(64バイト)に満たないため。

  ARP パケットを受け取った時に packet_in に入ってくる PacketIn メッセージの data のサイズが 42 バイトで渡ってくる。これをそのまま send_packet_out で送ろうとすると、
  42 + 4(FCS分) = 46 バイト
となり、64バイトに満たない。

■対策
  send_packet_out に渡すデータのデータ長の最低長が、64 から FCS分の4バイトを除いた 60 バイトとなるようにする。
  send_packet_out で送る data が 60 バイトに満たない場合、後ろを 0 で埋めて 60 バイトにする。

■ソースコード
赤字が変更箇所です。

class SimpleBridge4 < Controller
  MIN_PACKET_DATA_LEN = 60

  def start
    @port_list = [ 1, 2, 3 ]    # all port numbers
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    # padding. length of sending data must be >= 60
    data_len = message.data.length
    if ( data_len < MIN_PACKET_DATA_LEN )
      data = message.data + "\x00" * ( MIN_PACKET_DATA_LEN - data_len )
    else
      data = message.data
    end

    actions = [ ]
    @port_list.each do | port |
      if ( message.in_port != port )
        actions.push( SendOutPort.new( port ) )
      end
    end

    send_packet_out( datapath_id,
      :in_port => message.in_port,
      :data => data,
      :actions => actions )   end end

■再現環境

Photo_2

(1)再現環境の作り方
以下のコマンドを実行します。当然、すでに Open vSwitch がインストール済であることが前提です。

sudo ovs-vsctl add-br ofs1
sudo ovs-vsctl set-fail-mode ofs1 secure

sudo ip netns add vhost1
sudo ip link add name vlink1-0 type veth peer name vlink1-1
sudo ip link set vlink1-1 netns vhost1
sudo ip netns exec vhost1 ifconfig vlink1-1 up 192.168.0.1
sudo ip link set vlink1-0 up
sudo ovs-vsctl add-port ofs1 vlink1-0

sudo ip netns add vhost2
sudo ip link add name vlink2-0 type veth peer name vlink2-1
sudo ip link set vlink2-1 netns vhost2
sudo ip netns exec vhost2 ifconfig vlink2-1 up 192.168.0.2
sudo ip link set vlink2-0 up
sudo ovs-vsctl add-port ofs1 vlink2-0

sudo ovs-vsctl set-controller ofs1 tcp:127.0.0.1:6653
sudo ovs-vsctl set controller ofs1 connection-mode=out-of-band
sudo ovs-vsctl set controller ofs1 inactivity-probe=180

(2)現象を発生させるコマンド
192.168.0.2 への ARP キャッシュを消して、必ず ARP リクエストが生じるようにしてから ping を実行します。
あらかじめ Trema を実行させておきスイッチと接続が完了したことを確認した上で、以下のコマンドを実行します。1つ目のコマンド実行時に、ARPエントリがありません、といったメッセージがでるかもしれませんが構いません。

 sudo ip netns exec vhost1 arp -d 192.168.0.2
 sudo ip netns exec vhost1 ping -c 10 192.168.0.2

(3)再現環境の削除の仕方

 sudo ovs-vsctl del-br ofs1
 sudo ip netns delete vhost1
 sudo ip netns delete vhost2

以上

2014年7月 5日 (土)

◆ ポートベースVLANの作成【OpenFlow1.0をTremaの土管として使う】

[注意: 本記事は、OpenFlow の適切な使い方ではありません。単にパケットの出し入れの道具として利用しています。]

前回のブリッジのコードをもとにしてポートベースVLAN を実装し、動かしてみました。

■確認環境
  OS: Lubuntu 13.04 Desktop (i386)
  Trema: 0.4.7

■構成
  スイッチは、4ポート。
  ポート1,2で VLAN1 を構成。
  ポート3、4で VLAN2 を構成。

  各ポートにはホストを接続。

  Trema の仮想ネットワーク構成ファイル(h4s1.conf)は以下の通り:

vswitch ( "vswitch1" ) {
  datapath_id 0x01
}

vhost ( "vhost1" ) {
  mac "02:00:00:00:00:01"
  ip "192.168.1.1"
  netmask "255.255.255.0"
}

vhost ( "vhost2" ) {
  mac "02:00:00:00:00:02"
  ip "192.168.1.2"
  netmask "255.255.255.0"
}

vhost ( "vhost3" ) {
  mac "02:00:00:00:00:03"
  ip "192.168.1.3"
  netmask "255.255.255.0"
}

vhost ( "vhost4" ) {
  mac "02:00:00:00:00:04"
  ip "192.168.1.4"
  netmask "255.255.255.0"
}

link "vswitch1", "vhost1"
link "vswitch1", "vhost2"
link "vswitch1", "vhost3"
link "vswitch1", "vhost4"

図にすると:
Photo_2
※注意!!
Trema の仮想ネットワークではスイッチのポート番号と仮想ホストの対応を指定できません。上記の図における仮想ホストが接続されるポートのポート番号は今回テストした時にたまたまこうだったというだけで、必ずこうなるわけではありません。

■Trema のコード(PortBasedVLAN1.rb)
基本となるコードは前回のブリッジのコードです。

class PortBasedVLAN1 < Controller

  def start
    @port_list = [ 1, 2, 3, 4 ]    # all port numbers

    @port_list_of_vlan = {
      1 => [ 1, 2 ],
      2 => [ 3, 4 ]
    }

    @vlan_id_of_port = { }
    @port_list_of_vlan.each do | vlan_id, vlan_port_list |
      vlan_port_list.each do | port |
        @vlan_id_of_port[ port ] = vlan_id
      end
    end

    @port_of_mac = { }
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    learned_port = @port_of_mac[ message.macsa.to_i ]
    if learned_port == nil or learned_port != message.in_port
      info "MAC[%s] is found at Port #{ message.in_port }." % message.macsa.to_s
      @port_of_mac[ message.macsa.to_i ] = message.in_port
    end

    vlan_id = @vlan_id_of_port[ message.in_port ]
    vlan_port_list = @port_list_of_vlan[ vlan_id ]

    actions = [ ]
    vlan_port_list.each do | port |
      if ( message.in_port != port )
        actions.push( SendOutPort.new( port ) )
      end
    end

    send_packet_out( datapath_id,
      :in_port => message.in_port,
      :data => message.data,
      :actions => actions )
  end

end

緑のところ:
ポート数を4つに増やしています。

青いところ:
仮想ホストがどのポートにつながっているか分かるようにメッセージ出力するためのコードです。MACアドレスをキーにしたハッシュにポート番号を格納しています。受け取ったパケットが、まだ記録がないMAC から届いた場合か記録があってもポート番号に変更があった時にメッセージ出力するようにしています。

赤いところ:
start メソッド
VLAN ごとに含まれるポート番号の配列を @port_list_of_mac 変数にあらかじめ指定しています。VLAN ID をキーとしたハッシュです。
ポート番号から VLAN ID を求めるため @vlan_id_of_port のハッシュをあらかじめ計算しています。

packet_in メソッド
ポート番号から VLAN ID を求めて、その VLAN のポート番号の配列を求めています。
以前は、すべてのポートに対してパケットを送信していた箇所を、入力ポート番号が属する VLAN の各ポートにパケットを送信するように変更しています。

■テスト

trema を起動します。

$ trema run PortBasedVLAN1.rb -c h4s1.conf
Switch[0x0000000000000001] is up.

Lubuntu の network-monitor サービスを停止していないと、勝手にパケットが飛ぶので仮想ホスト以外のMACが検出されてメッセージが出力されますがこれらは無視してください。

別のターミナルウィンドウを開き、各仮想ホストからパケットを送ります:

$ trema send_packet -s vhost1 -d vhost2
$ trema send_packet -s vhost2 -d vhost3
$ trema send_packet -s vhost3 -d vhost4
$ trema send_packet -s vhost4 -d vhost1

そうすると trema を起動した画面に以下のように各仮想ホストのMACが検出されてどのポートにつながっているか確認できます:

MAC[02:00:00:00:00:01] is found at Port 3.
MAC[02:00:00:00:00:02] is found at Port 1.
MAC[02:00:00:00:00:03] is found at Port 2.
MAC[02:00:00:00:00:04] is found at Port 4.

上記のポートと仮想ホストの接続関係を前提に通信のテストを行います。

まず、テストの前に以下のコマンドで統計情報をクリアしておきます:

$ trema reset_stats

(1) テスト1: VLAN をまたがった通信
ポート3の vhost1 からポート1 の vhost2 へパケットを送り vhost2 側の受信パケットを確認してみます。

$ trema send_packet -s vhost1 -d vhost2
$ trema show_stats -r vhost2

ポート3 は VLAN2, ポート1 は VLAN1 に属し異なる VLAN なのでパケットが届かず vhost2 では何もパケットを受信していないので空行が表示されます。

(2) テスト2: VLAN 内の通信
ポート2 の vhost3 からポート1 の vhost2 へパケットを送り vhost2 側の受信パケットを確認してみます。

$ trema send_packet -s vhost3 -d vhost2
$ trema show_stats -r vhost2
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.1.2,1,192.168.1.3,1,1,50

VLAN1 内の通信なので受信パケットが vhost2 に届いています。

(3) その他のポートの組み合わせも試してみます

$ trema send_packet -s vhost3 -d vhost4
$ trema show_stats -r vhost4

$ trema send_packet -s vhost1 -d vhost4
$ trema show_stats -r vhost4
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.1.4,1,192.168.1.1,1,1,50

こちらも、VLAN内の通信となる場合だけパケットが受信できています。

以上です。

2014年6月29日 (日)

◆ 単純なブリッジの実装その3~より完璧な土管化~【OpenFlow1.0をTremaの土管として使う】

[2014/07/27 追記。イーサネットの最少パケットサイズを確保する修正をした記事を書きました。「◆ 単純なブリッジの実装その4~Open vSwitch対策~【OpenFlow1.0をTremaの土管として使う】」]

[注意: 本記事は、OpenFlow の適切な使い方ではありません。単にパケットの出し入れの道具として利用しています。]

以前書いた記事「◆ 単純なブリッジの実装その2~複数ポート対応~【OpenFlow1.0をTremaの土管として使う】」のコードを、パケットのデータを加工して流すことにも対応できるように修正してみます。

先の記事のコードでは、パケットを送付する際、Trema の send_packet_out に引数 :packet_in を使って受信メッセージをそのまま送信データとして渡しています。仕様を確認してみましょう。
http://rubydoc.info/github/trema/trema/master/Trema/Controller:send_packet_out

packet_in (PacketIn) — default: nil
— The PacketIn object received by packet_in handler. If this option is not nil, :buffer_id,
:data, and :in_port option is set automatically
according to the value of :packet_in.

:packet_in を使うと自動で :buffer_id, :in_port, :data を設定します。

OpenFlow では、コントローラからはパケットのデータそのものを渡すのではなくスイッチ側で管理している識別子 buffer_id を渡すという仕掛けがあります。コントローラでデータを加工して送付したい場合にはこの機能は不要です。
openflow 1.0.0 仕様書の "25.3.6 Send Packet Message" には以下の説明があります:
http://archive.openflow.org/documents/openflow-spec-v1.0.0.pdf

/* uint8_t data[0]; */ /* Packet data. The length is inferred
                          from the length field in the header.
                          (Only meaningful if buffer_id == -1.) */

このカッコ書きのところがポイントです。データに変更を加えたパケットを送付するには buffer_id を指定してはいけないということです。

Trema の send_packet_out の引数 :buffer_id を確認してみると:

:buffer_id (Number) — default: 0xffffffff
— The buffer ID assigned by the datapath.
If 0xffffffff, the frame is not buffered, and
the entire frame must be passed in :data.

:buffer_id はデフォルトのままで引数 :data に指定したデータを送付します。

以上から、:packet_in を使うのではなく、:data, :in_port を指定すれば良いということがわかります。

■対策後のコード
赤字のところが変更箇所です。

class SimpleBridge3 < Controller

  def start
    @port_list = [ 1, 2, 3 ]    # all port numbers
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    actions = [ ]
    @port_list.each do | port |
      if ( message.in_port != port )
        actions.push( SendOutPort.new( port ) )
      end
    end

    send_packet_out( datapath_id,
      :in_port => message.in_port,
      :data => message.data,

      :actions => actions )
  end

end

2014年6月11日 (水)

◆【改訂】OpenFlow フレームワーク Trema 0.4 のインストール手順【0.4.7対応】

[2014-0727 追記: apt-get install で Not Found になる場合について追加しました。]
[2014-0727 追記2: 新規に Lubuntu 13.04 をインストールする場合の注意事項を追加。]

Trema 0.4.7 では、前提となる RubyGems のバージョンがあがっているため、https://github.com/trema/trema に記載のコマンドを実行しただけではインストールに失敗することが分かりました。失敗しないようにするためのインストール手順を整理しておきます。

RubyGems をバージョンアップしないとどうなるかは、前回の記事「◆ Trema 0.4.7インストール失敗とバージョン指定インストール」に記載しています。

■確認環境
・OS: Lubuntu 13.04 Desktop (i386)
    (2014年06月08日にソフトウェアアップデート済)
  未確認ですが Ubuntu 13.04 Desktop (i386)でも同じだと思います。
  ※[2014-0727 追記:新規に Lubuntu13.04 をインストールされる場合は、記事「◆サポート期限切れの Lubuntu 13.04 を新規インストール 」を参照ください。]
・Trema: 0.4.7

■インストール手順

https://github.com/trema/trema の「Getting Started」に従ってインストールしていきます。

1. 「1.Install the prerequisites at the command prompt:」に従い以下のコマンドを実行:

$ sudo apt-get install gcc make git ruby rubygems ruby-dev libpcap-dev libsqlite3-dev libglib2.0-dev

[2014-0727 追記: ここで、「Not Found」が出て失敗する現象が起きる場合は、記事「◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処」を参照して対処ください。
]

2.前提の確認 (ここがミソ)

「Getting Started」には書いていない手順です。前提を満たしているか確認します。
「Supported Platforms」を見ると以下の記載があります(2014年06月11時点):
•Ruby 1.9.3 or higher
•RubyGems 1.8.25 or higher

実際にインストールされているバージョンを確認します。

$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]
$ gem -v
1.8.23

RubyGems のバージョンが 1.8.23 で満たせていません。そこで、RubyGems のバージョンをあげるため以下のコマンドを実行します:

$ sudo gem install rubygems-update -v 1.8.25
$ sudo update_rubygems

update_rubygems コマンドを実行するとバージョンアップ分の変更内容が大量に出力されます。ちょっとびっくりしますが問題ありません。

ここでは rubygem-update のインストールで -v 1.8.25 と指定することで Trema が必要とする最低のバージョンにしています。
バージョン指定なしだと最新版(現時点で 2.3.0)が入るのですが trema のインストール時に妙なメッセージが出るので避けた方が良さそうです。
(ちなみに 1.8 の最新 1.8.29 でも大丈夫でしたが、Trema さえ入れば良いと割り切って 1.8 の最新にする手順にはしていません。)

では、バージョンを再度確認します:

$ gem -v
1.8.25

今度は 1.8.25 なので前提を満たせていることが確認できました。

3. 「Install Trema at the command prompt:」に従い以下のコマンドを実行します:

$ sudo gem install trema

コマンド実行時の画面は以下の通り:

$ sudo gem install trema
Fetching: bundler-1.6.2.gem (100%)
Fetching: gli-2.10.0.gem (100%)
Fetching: Platform-0.4.0.gem (100%)
Fetching: open4-1.3.4.gem (100%)
Fetching: POpen4-0.1.4.gem (100%)
Fetching: rake-10.3.2.gem (100%)
Fetching: paper_house-0.6.2.gem (100%)
Fetching: bindata-2.1.0.gem (100%)
Fetching: pio-0.7.0.gem (100%)
Fetching: json-1.8.1.gem (100%)
Building native extensions.  This could take a while...
Fetching: rdoc-4.1.1.gem (100%)
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
 = 1.8.7 : gem install rdoc-data; rdoc-data --install
 = 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Fetching: trema-0.4.7.gem (100%)
Building native extensions.  This could take a while...
Successfully installed bundler-1.6.2
Successfully installed gli-2.10.0
Successfully installed Platform-0.4.0
Successfully installed open4-1.3.4
Successfully installed POpen4-0.1.4
Successfully installed rake-10.3.2
Successfully installed paper_house-0.6.2
Successfully installed bindata-2.1.0
Successfully installed pio-0.7.0
Successfully installed json-1.8.1
Successfully installed rdoc-4.1.1
Successfully installed trema-0.4.7
12 gems installed
Installing ri documentation for bundler-1.6.2...
Installing ri documentation for gli-2.10.0...
Installing ri documentation for Platform-0.4.0...
Installing ri documentation for open4-1.3.4...
Installing ri documentation for POpen4-0.1.4...
Installing ri documentation for rake-10.3.2...
Installing ri documentation for paper_house-0.6.2...
Installing ri documentation for bindata-2.1.0...
Installing ri documentation for pio-0.7.0...
Installing ri documentation for json-1.8.1...
Installing ri documentation for rdoc-4.1.1...
Installing ri documentation for trema-0.4.7...
Installing RDoc documentation for bundler-1.6.2...
Installing RDoc documentation for gli-2.10.0...
Installing RDoc documentation for Platform-0.4.0...
Installing RDoc documentation for open4-1.3.4...
Installing RDoc documentation for POpen4-0.1.4...
Installing RDoc documentation for rake-10.3.2...
Installing RDoc documentation for paper_house-0.6.2...
Installing RDoc documentation for bindata-2.1.0...
Installing RDoc documentation for pio-0.7.0...
Installing RDoc documentation for json-1.8.1...
Installing RDoc documentation for rdoc-4.1.1...
Installing RDoc documentation for trema-0.4.7...

4.Trema のバージョン確認

では、Trema のバージョン確認をしてみます:

$ trema version
trema version 0.4.7

無事 Trema がインストールできました。


■ RubyGems 2.3.0 を使うとどうなるのか?

上書きをするか求められて N を選択するとインストールが中断されます:

$ sudo gem install trema
Fetching: json-1.8.1.gem (100%)
Building native extensions.  This could take a while...
Successfully installed json-1.8.1
Fetching: rdoc-4.1.1.gem (100%)
rdoc's executable "rdoc" conflicts with /usr/bin/rdoc
Overwrite the executable? [yN] N
ERROR:	Error installing trema:
	"rdoc" from rdoc conflicts with /usr/bin/rdoc

再度、実行して上書きを y で許可すると今度は大量のメッセージが・・・:

$ sudo gem install trema
rdoc's executable "rdoc" conflicts with /usr/bin/rdoc
Overwrite the executable? [yN]	y
rdoc's executable "ri" conflicts with /usr/bin/ri
Overwrite the executable? [yN]	y
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
 = 1.8.7 : gem install rdoc-data; rdoc-data --install
 = 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Successfully installed rdoc-4.1.1
Fetching: rake-10.3.2.gem (100%)
Successfully installed rake-10.3.2
Fetching: bindata-2.1.0.gem (100%)
Successfully installed bindata-2.1.0
Fetching: pio-0.7.0.gem (100%)
Successfully installed pio-0.7.0
Fetching: Platform-0.4.0.gem (100%)
Successfully installed Platform-0.4.0
Fetching: open4-1.3.4.gem (100%)
Successfully installed open4-1.3.4
Fetching: POpen4-0.1.4.gem (100%)
Successfully installed POpen4-0.1.4
Fetching: paper_house-0.6.2.gem (100%)
Successfully installed paper_house-0.6.2
Fetching: gli-2.10.0.gem (100%)
Successfully installed gli-2.10.0
Fetching: bundler-1.6.2.gem (100%)
Successfully installed bundler-1.6.2
Fetching: trema-0.4.7.gem (100%)
Building native extensions.  This could take a while...
Successfully installed trema-0.4.7
Installing ri documentation for rdoc-4.1.1
Installing ri documentation for rake-10.3.2
unable to convert "\xC5" from ASCII-8BIT to UTF-8 for examples/NBT.txt, skipping
Installing ri documentation for bindata-2.1.0
Installing ri documentation for pio-0.7.0
Installing ri documentation for Platform-0.4.0
Installing ri documentation for open4-1.3.4
Installing ri documentation for POpen4-0.1.4
unable to convert "\xCF" from ASCII-8BIT to UTF-8 for examples/fail/hello, skipping
Installing ri documentation for paper_house-0.6.2
Installing ri documentation for gli-2.10.0
Installing ri documentation for bundler-1.6.2
unable to convert "\xD0" from ASCII-8BIT to UTF-8 for objects/tremashark/syslog_relay, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for objects/tremashark/stdin_relay, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for objects/tremashark/tremashark, skipping
unable to convert "\xC0" from ASCII-8BIT to UTF-8 for objects/tremashark/packet_capture, skipping
unable to convert "\xE4" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-vsctl, skipping
unable to convert "\x98" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovsdb-client, skipping
unable to convert "\x94" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-appctl, skipping
unable to convert "\xE0" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-controller, skipping
unable to convert "\xEC" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-openflowd, skipping
unable to convert "\xE4" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-dpctl, skipping
unable to convert "\xAC" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovsdb-tool, skipping
unable to convert "\xB8" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-ofctl, skipping
unable to convert "\xB0" from ASCII-8BIT to UTF-8 for objects/openvswitch/bin/ovs-benchmark, skipping
unable to convert "\x8C" from ASCII-8BIT to UTF-8 for objects/openvswitch/sbin/ovsdb-server, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for objects/openvswitch/sbin/ovs-brcompatd, skipping
unable to convert "\xD8" from ASCII-8BIT to UTF-8 for objects/openvswitch/sbin/ovs-vlan-bug-workaround, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for objects/openvswitch/sbin/ovs-vswitchd, skipping
unable to convert "\xD0" from ASCII-8BIT to UTF-8 for objects/packetin_filter/packetin_filter, skipping
unable to convert "\xF0" from ASCII-8BIT to UTF-8 for objects/examples/openflow_switch/echo_switch, skipping
unable to convert "\xF0" from ASCII-8BIT to UTF-8 for objects/examples/openflow_switch/hello_switch, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/dumper/dumper, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/switch_monitor/switch_monitor, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/packet_in/packet_in, skipping
unable to convert "\xC0" from ASCII-8BIT to UTF-8 for objects/examples/traffic_monitor/traffic_monitor, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/switch_info/switch_info, skipping
unable to convert "\xA7" from ASCII-8BIT to UTF-8 for objects/examples/multi_learning_switch/multi_learning_switch, skipping
unable to convert "\xA8" from ASCII-8BIT to UTF-8 for objects/examples/switch_event_config/delete_forward_entry, skipping
unable to convert "\xA8" from ASCII-8BIT to UTF-8 for objects/examples/switch_event_config/dump_forward_entries, skipping
unable to convert "\xA8" from ASCII-8BIT to UTF-8 for objects/examples/switch_event_config/add_forward_entry, skipping
unable to convert "\xA8" from ASCII-8BIT to UTF-8 for objects/examples/switch_event_config/set_forward_entries, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/cbench_switch/cbench_switch, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/repeater_hub/repeater_hub, skipping
unable to convert "\x90" from ASCII-8BIT to UTF-8 for objects/examples/packetin_filter_config/dump_filter, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for objects/examples/packetin_filter_config/add_filter, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for objects/examples/packetin_filter_config/delete_filter_strict, skipping
unable to convert "\x90" from ASCII-8BIT to UTF-8 for objects/examples/packetin_filter_config/dump_filter_strict, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for objects/examples/packetin_filter_config/delete_filter, skipping
unable to convert "\xB0" from ASCII-8BIT to UTF-8 for objects/examples/learning_switch/learning_switch, skipping
unable to convert "\xB0" from ASCII-8BIT to UTF-8 for objects/examples/list_switches/list_switches, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/openflow_message/features_request, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/openflow_message/hello, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/openflow_message/vendor_action, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/openflow_message/echo, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/examples/openflow_message/set_config, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/management/set_logging_level, skipping
unable to convert "\xD0" from ASCII-8BIT to UTF-8 for objects/management/application, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/management/echo, skipping
unable to convert "\xA6" from ASCII-8BIT to UTF-8 for objects/management/show_stats, skipping
unable to convert "\x9D" from ASCII-8BIT to UTF-8 for objects/oflops/bin/oflops, skipping
unable to convert "\x94" from ASCII-8BIT to UTF-8 for objects/oflops/bin/cbench, skipping
unable to convert "\x95" from ASCII-8BIT to UTF-8 for objects/phost/phost, skipping
unable to convert "\xEC" from ASCII-8BIT to UTF-8 for objects/phost/cli, skipping
unable to convert "\xAA" from ASCII-8BIT to UTF-8 for objects/switch_manager/switch, skipping
unable to convert "\xC0" from ASCII-8BIT to UTF-8 for objects/switch_manager/switch_manager, skipping
unable to convert "\x9D" from ASCII-8BIT to UTF-8 for vendor/oflops-0.03.trema1/oflops, skipping
unable to convert "\x94" from ASCII-8BIT to UTF-8 for vendor/oflops-0.03.trema1/cbench/cbench, skipping
unable to convert "\xE4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-vsctl, skipping
unable to convert "\xE3" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/nlmon, skipping
unable to convert "\x94" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-appctl, skipping
unable to convert "\xE0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-controller, skipping
unable to convert "\xE4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-dpctl, skipping
unable to convert "\xD8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-vlan-bug-workaround, skipping
unable to convert "\xB8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-ofctl, skipping
unable to convert "\xB0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/utilities/ovs-benchmark, skipping
unable to convert "\xE0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-lockfile, skipping
unable to convert "\xD5" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-random, skipping
unable to convert "\xF0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-sha1, skipping
unable to convert "\xFE" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-classifier, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-aes128, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-byte-order, skipping
unable to convert "\x88" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-list, skipping
unable to convert "\xD7" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-uuid, skipping
unable to convert "\xD8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-reconnect, skipping
unable to convert "\x88" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-hmap, skipping
unable to convert "\xDC" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-bundle, skipping
unable to convert "\x86" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-strtok_r, skipping
unable to convert "\xD3" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-file_name, skipping
unable to convert "\xCC" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-ovsdb, skipping
unable to convert "\xDC" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-json, skipping
unable to convert "\xF0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/testsuite, skipping
unable to convert "\xE3" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-packets, skipping
unable to convert "\xC8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-jsonrpc, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-unix-socket, skipping
unable to convert "\xE2" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-timeval, skipping
unable to convert "\xD3" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-util, skipping
unable to convert "\xB7" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-flows, skipping
unable to convert "\xB8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-multipath, skipping
unable to convert "\xF8" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-hash, skipping
unable to convert "\xA0" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-csum, skipping
unable to convert "\x80" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-vconn, skipping
unable to convert "\xEC" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-openflowd, skipping
unable to convert "\x91" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/tests/test-type-props, skipping
unable to convert "\x8C" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/ovsdb/ovsdb-server, skipping
unable to convert "\x98" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/ovsdb/ovsdb-client, skipping
unable to convert "\xAC" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/ovsdb/ovsdb-tool, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/vswitchd/ovs-brcompatd, skipping
unable to convert "\xD4" from ASCII-8BIT to UTF-8 for vendor/openvswitch-1.2.2.trema1/vswitchd/ovs-vswitchd, skipping
unable to convert "\x95" from ASCII-8BIT to UTF-8 for vendor/phost/src/phost, skipping
unable to convert "\xEC" from ASCII-8BIT to UTF-8 for vendor/phost/src/cli, skipping
Installing ri documentation for trema-0.4.7
11 gems installed

ここから RubyGems 1.8.25 にダウングレードしてインストールさせてみます:

$ sudo gem uninstall rubygems-update
$ sudo gem install rubygems-update -v 1.8.25 Fetching: rubygems-update-1.8.25.gem (100%) Successfully installed rubygems-update-1.8.25 Parsing documentation for rubygems-update-1.8.25 Installing ri documentation for rubygems-update-1.8.25 Done installing documentation for rubygems-update after 0 seconds 1 gem installed
$ sudo update_rubygems RubyGems 1.8.25 installed == 1.8.25/ 2013-01-24 * 6 bug fixes:   * Added 11627 to setup bin_file location to protect against errors. Fixes #328 by ConradIrwin   * Specification#ruby_code didn't handle Requirement with multiple   * Fix error on creating a Version object with a frozen string.   * Fix incremental index updates   * Fix missing load_yaml in YAML-related requirement.rb code.   * Manually backport encoding-aware YAML gemspec ------------------------------------------------------------------------------ RubyGems installed the following executables: /usr/bin/gem1.9.1 $ sudo gem uninstall trema Remove executables: trema, trema-config in addition to the gem? [Yn] Y Removing trema Removing trema-config Successfully uninstalled trema-0.4.7 $ sudo gem install trema Fetching: trema-0.4.7.gem (100%) Building native extensions.  This could take a while... Successfully installed trema-0.4.7 1 gem installed Installing ri documentation for trema-0.4.7... Installing RDoc documentation for trema-0.4.7... $ trema version trema version 0.4.7

2014年6月 8日 (日)

◆ Trema 0.4.7インストール失敗とバージョン指定インストール

[2014/6/8 16:30追記:
インストール失敗はすでに https://github.com/trema/trema/issues/366 にて報告されている現象でした。
ここに記載があるように事前に RubyGems を更新する作業をしたところ Trema 0.4.7 のインストールに成功しました。以下の手順になります:
  sudo gem install update-rubygems
  sudo update_rubygems
  sudo gem install trema
2014/6/9 00:15追記:

  上記の方法で成功はしたものの Warning がやたら出たりしてまだ少し変。RubyGems のバージョンが 2.2.2 になっていたので、以下のようにして 1.8.x のままにした方が良さそう。

 
sudo gem install update-rubygems -v 1.8.25
あとでもう少し確認します。

]
[2014/06/11 追記:
インストール方法を整理して 「
◆【改訂】OpenFlow フレームワーク Trema 0.4 のインストール手順【0.4.7対応】」を書きました。
]

パソコンの入れ替えがあって OpenFlow フレームワーク Trema のテスト環境を新規に作ろうとしたら Trema のインストールに失敗してはまったのでここに記録を残しておきます。
最新の 0.4.7 でだめなら一つ前の 0.4.6 を入れられないかと調べてみたら gem コマンドには --version オプションがあってバージョン指定ができるんですね。
0.4.6 にしたら無事インストール成功しました。

■現象発生環境
  OS: Lubuntu 13.04 Desktop (i386, 32bit)
  Trema: 0.4.7 … インストール失敗
            0.4.6 … インストール成功

■現象発生時のインストール画面とエラー箇所

以下の通り:

$ sudo gem install trema
Fetching: bundler-1.6.2.gem (100%)
Fetching: gli-2.10.0.gem (100%)
Fetching: Platform-0.4.0.gem (100%)
Fetching: open4-1.3.4.gem (100%)
Fetching: POpen4-0.1.4.gem (100%)
Fetching: rake-10.3.2.gem (100%)
Fetching: paper_house-0.6.2.gem (100%)
Fetching: bindata-2.1.0.gem (100%)
Fetching: pio-0.7.0.gem (100%)
Fetching: json-1.8.1.gem (100%)
Building native extensions.  This could take a while...
Fetching: rdoc-4.1.1.gem (100%)
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
= 1.8.7 : gem install rdoc-data; rdoc-data --install
= 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Fetching: trema-0.4.7.gem (100%)
Building native extensions.  This could take a while...
ERROR: Error installing trema:
ERROR: Failed to build gem native extension.

"/usr/bin/ruby1.9.1" -rubygems /var/lib/gems/1.9.1/gems/rake-10.3.2/bin/rake RUBYARCHDIR=/var/lib/gems/1.9.1/gems/trema-0.4.7/ruby RUBYLIBDIR=/var/lib/gems/1.9.1/gems/trema-0.4.7/ruby
rake aborted!
Bundler::GemspecError: There was a RuntimeError while loading trema.gemspec:
can't modify frozen String from
  /var/lib/gems/1.9.1/gems/trema-0.4.7/trema.gemspec:7:in `block in <main>'

/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler.rb:393:in `rescue in eval_gemspec'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler.rb:382:in `eval_gemspec'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler.rb:353:in `block in load_gemspec_uncached'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/shared_helpers.rb:52:in `chdir'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/shared_helpers.rb:52:in `chdir'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler.rb:348:in `load_gemspec_uncached'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler.rb:338:in `load_gemspec'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/gem_helper.rb:31:in `initialize'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/gem_helper.rb:13:in `new'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/gem_helper.rb:13:in `install_tasks'
/var/lib/gems/1.9.1/gems/bundler-1.6.2/lib/bundler/gem_tasks.rb:2:in `<top (required)>'
/var/lib/gems/1.9.1/gems/trema-0.4.7/Rakefile:760:in `<top (required)>'
(See full trace by running task with --trace)

Gem files will remain installed in /var/lib/gems/1.9.1/gems/trema-0.4.7 for inspection.
Results logged to /var/lib/gems/1.9.1/gems/trema-0.4.7/./gem_make.out

赤字で示したところがエラー発生個所。trema.gemspec の7行目で問題起きています。ソースコードから7行目を見てみると以下の通り:
  gem.version = Trema::VERSION

この Trema::VERSION はというと、ruby/trema/version.rb で定義されていました。0.4.7 で VERSION の記述のしかたがfreeze 指定に変更されていることが影響していそうです:
Trema 0.4.7 の場合の VERSION の記述:
  VERSION = '0.4.7'.freeze
Trema 0.4.6 の場合の VERSION の記述:
  VERSION = "0.4.6"

■暫定的な回避策
Trema 0.4.6 をインストールします。--version でバージョンを指定します。

  sudo gem install trema --version 0.4.6

以下の通りエラーなくインストールが完了しました:

$ sudo gem install trema --version 0.4.6
Fetching: gli-2.8.1.gem (100%)
Fetching: rake-10.1.1.gem (100%)
Fetching: paper_house-0.5.0.gem (100%)
Fetching: bindata-1.6.0.gem (100%)
Fetching: pio-0.3.0.gem (100%)
Fetching: rdoc-4.0.1.gem (100%)
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
= 1.8.7 : gem install rdoc-data; rdoc-data --install
= 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Fetching: trema-0.4.6.gem (100%)
Building native extensions.  This could take a while...
Successfully installed gli-2.8.1
Successfully installed rake-10.1.1
Successfully installed paper_house-0.5.0
Successfully installed bindata-1.6.0
Successfully installed pio-0.3.0
Successfully installed rdoc-4.0.1
Successfully installed trema-0.4.6
7 gems installed
Installing ri documentation for gli-2.8.1...
Installing ri documentation for rake-10.1.1...
Installing ri documentation for paper_house-0.5.0...
Installing ri documentation for bindata-1.6.0...
Installing ri documentation for pio-0.3.0...
Installing ri documentation for rdoc-4.0.1...
Installing ri documentation for trema-0.4.6...
Installing RDoc documentation for gli-2.8.1...
Installing RDoc documentation for rake-10.1.1...
Installing RDoc documentation for paper_house-0.5.0...
Installing RDoc documentation for bindata-1.6.0...
Installing RDoc documentation for pio-0.3.0...
Installing RDoc documentation for rdoc-4.0.1...
Installing RDoc documentation for trema-0.4.6...

2013年11月 2日 (土)

◆ 単純なブリッジの実装その2~複数ポート対応~【OpenFlow1.0をTremaの土管として使う】

前回作成した簡単なブリッジは2ポートのみにしか対応していませんでしたが、今回は3ポート以上にも対応するように修正しました。

■Trema のソースコード

class SimpleBridge2 < Controller

  def start
    @port_list = [ 1, 2, 3 ]    # all port numbers
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    actions = [ ]
    @port_list.each do | port |
      if ( message.in_port != port )
        actions.push( SendOutPort.new( port ) )
      end
    end

    send_packet_out( datapath_id,
      :packet_in => message,
      :actions => actions )
  end

end

■解説

変更箇所を赤字にしています。

start

対象とするポート番号を持つ配列である @port_list には、上記コードでは例として1,2,3の3つのポート番号を指定しています。ここには3つでも4つでも対象のポート番号を指定できます。

packet_in

変数 actions は新規に追加した変数です。SendOutPort.new で生成した出力先ポート番号指定の配列です。パケットが入って来たポート(message.in_port) 以外の対象ポート番号すべてに出力するようにしています。

2013年10月24日 (木)

◆ 単純なブリッジの実装【OpenFlow1.0をTremaの土管として使う】

[2013/10/25 追記。テスト結果を加執しました]

前回の記事の方針をもとにして、2ポートのブリッジを作成しました。今回は何も機能がなくて、MAC の学習機能もフィルタリング機能もなく、リピーターと変わりません。

■Tremaのコード

class SimpleBridge < Controller

  def start
    @port_list = [ 1, 2 ]	# all port numbers
  end

  def switch_ready( datapath_id )
    info "Switch[0x%016x] is up." % datapath_id

    send_flow_mod_add( datapath_id, :priority => 100 )

    @port_list.each do | port |
      send_flow_mod_add( datapath_id,
        :match => Match.new( :in_port => port ),
        :actions => SendOutPort.new( OFPP_CONTROLLER ) )
    end
  end

  def switch_disconnected( datapath_id )
    info "Switch[0x%016x] is disconnected." % datapath_id
  end

  def packet_in( datapath_id, message )
    return unless message.reason == Trema::PacketIn::OFPR_ACTION

    if ( message.in_port == @port_list[0] )
      target_port = @port_list[1]
    else
      target_port = @port_list[0]
    end

    send_packet_out( datapath_id,
      :packet_in => message,
      :actions => SendOutPort.new( target_port ) )
  end

end

■解説

実現しているのは以下の機能:
(1) 1番ポートから入って来たパケットを2番ポートへ送る。
(2) 2番ポートから入って来たパケットを1番ポートへ送る。
それだけです。

start
対象とする2つの OpenFlow ポートの番号をインスタンス変数の配列 @port_listに格納しています。
ここを書き換えれば 1, 2 番以外のポートを対象にすることができます。

switch_ready
OpenFlowスイッチが接続してきたらフローエントリを登録します。
登録しているエントリは3つです。

・フローエントリ1
パケットを捨てる。

優先度(priority)を 100 と低くしています。これにより、次に示すフローエントリ2,3に合致しないパケットに対して適用されるフローエントリにしています。
つまり、対象とする2つの OpenFlow ポート以外のパケットは捨てるという動作を OpenFlow スイッチにさせています。
      
・フローエントリ2、および 3
対象とする2つの OpenFlow ポートに入ってきたパケットを OpenFlow コントローラに送る。

Trema のデフォルトでは優先度は 65535 でフローエントリを登録するので 100 より優先されます。
参照:http://rubydoc.info/github/trema/trema/master/Trema/Controller:send_flow_mod_add

    :priority (Number) ? default: 0xffff  - The priority level of the flow entry.


packet_in
1行目は、パケットが入ってきた理由が OFPR_ACTION (アクションにより届いたパケット)かどうかを判定しています。
フローエントリ2、3以外の理由でパケットが入ってきた場合は return で抜けて何もしない(=パケットを捨てる)ようしています。
これにより、フローエントリの登録が完了する前にOpenFlowスイッチが受信したパケットが要因で packet_in が呼ばれた場合でも何もしないようにしています。
前回の記事で考察したように、パケットのデータに欠けがないパケットのみを処理対象にするためにアクションにより届いたパケットのみを扱うようにしています。

2行目からは、入って来たポート番号を確認し、もう一方のポートにパケットを送りだしています。


では、実行してみます。

■実行環境
・OS: Lubuntu 13.04 Desktop (i386)
・Trema: 0.4.3
・Ruby: 1.9.3p194

■Trema の仮想ネットワークによる実行

(1) 仮想ネットワーク定義

vswitch("ofs1") {
  datapath_id "0x1"
}
netns("host1") {
  ip "192.168.0.1"
  netmask "255.255.255.0"
}
netns("host2") {
  ip "192.168.0.2"
  netmask "255.255.255.0"
}
link "host1", "ofs1"
link "host2", "ofs1"

(2) 実行前の下準備

Trema の仮想ネットワークに勝手にパケット流して邪魔するのでテストの間はネットワークマネージャを一時停止しておきます。

$ sudo service network-manager stop
network-manager stop/waiting

(3) Trema の起動

ここでは、Trema のコードのファイル名を SimpleBridge.rb とし、仮想ネットワーク定義のファイル名を vnet-2netns.conf としています。

$ trema run SimpleBridge.rb -c vnet-2netns.conf
Switch[0x0000000000000001] is up.

(4) ping の実行

別の端末を用意して、host1 から host2(192.168.0.2) へ ping をパケットサイズ1000で実行します。

$ sudo ip netns exec host1 ping -c3 -s1000 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 1000(1028) bytes of data.
1008 bytes from 192.168.0.2: icmp_req=1 ttl=64 time=81.8 ms
1008 bytes from 192.168.0.2: icmp_req=2 ttl=64 time=29.5 ms
1008 bytes from 192.168.0.2: icmp_req=3 ttl=64 time=28.7 ms

--- 192.168.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 28.799/46.737/81.846/24.828 ms

128バイトを超えるパケットもきちんと応答が返りました。テスト成功です。

(5) Trema の終了

以下のコマンドでTremaを終了させます:

$ trema killall

すると、trema run を実行していた端末では以下が出力されて trema が終了しています。

Switch[0x0000000000000001] is disconnected.

(6) 必要なら...ネットワークマネージャの再起動

以下のようにして再起動します:

$ sudo service network-manager start
network-manager start/running, process 313

上記の313の箇所はプロセスIDなので実行ごとに異なる値です。

«◆ 【OpenFlow1.0スイッチをTremaの土管として使う】検討してみた→いけそう

最近のトラックバック

無料ブログはココログ