« ◆ ポートベースVLANの作成【OpenFlow1.0をTremaの土管として使う】 | トップページ | ◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処 »

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

以上

« ◆ ポートベースVLANの作成【OpenFlow1.0をTremaの土管として使う】 | トップページ | ◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処 »

Tremaでネットワーク機器プログラミング」カテゴリの記事

コメント

無知ですいません
この環境状態でpingをvhost1からvhost2へ送ると繋がるのでしょうか?
よろしくお願いします。

この記事へのコメントは終了しました。

トラックバック

« ◆ ポートベースVLANの作成【OpenFlow1.0をTremaの土管として使う】 | トップページ | ◆ Lubuntu 13.04 の apt-get install で「Not Found」となる現象への対処 »

最近のトラックバック

無料ブログはココログ