trema / pio

Packet parser and generator in Ruby
27 stars 11 forks source link

" error: undefined method `key?' for nil:NilClass " のエラーの原因について #239

Closed rumb closed 9 years ago

rumb commented 9 years ago

サンプルプログラムの”trema/repeater_hub”を、trema.confを用いたエミュレートではなく、 KVM上で同じトポロジーを作成して実行したところ、下記のエラーが出ました。

[ 実行環境 ] ホストOS : Ubuntu12.04 ゲストOS : Centos7

エラー内容
error: undefined method `key?' for nil:NilClass
/usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/match.rb:137:in `block in initialize': undefined method `key?' for nil:NilClass (NoMethodError)
        from /usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/match.rb:136:in `each'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/match.rb:136:in `each_with_object'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/match.rb:136:in `initialize'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/exact_match.rb:47:in `new'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/exact_match.rb:47:in `initialize'
        from /root/repeater_hub/lib/repeater_hub.rb:12:in `new'
        from /root/repeater_hub/lib/repeater_hub.rb:12:in `packet_in'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:319:in `block in send_handler'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:319:in `synchronize'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:319:in `send_handler'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:324:in `maybe_send_handler'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:296:in `handle_openflow_message'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:264:in `block in start_switch_main'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:264:in `loop'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:264:in `start_switch_main'
        from /usr/local/rvm/gems/ruby-2.2.1/bundler/gems/trema-63d81024e1a2/lib/trema/controller.rb:256:in `block in start_switch_thread'

そこで、"/usr/local/rvm/gems/ruby-2.2.1/gems/pio-0.23.1/lib/pio/open_flow10/exact_match.rb"のコンストラクタのcase文に下記のコードを加えたところ正常に動きました。

加えたコード
      when Pio::Arp::Reply
        options = {
          in_port: packet_in.in_port,
          ether_source_address: packet_in.source_mac,
          ether_destination_address: packet_in.destination_mac,
          vlan_vid: data.vlan_vid,
          vlan_priority: data.vlan_pcp,
          ether_type: data.ether_type,
          ip_tos: 0,
          ip_protocol: data.operation,
          ip_source_address: data.sender_protocol_address,
          ip_destination_address: data.target_protocol_address,
          transport_source_port: 0,
          transport_destination_port: 0
        }

(*) ARP requestのcaseをコピーしてreplyに変更しただけです。

このことから、ARP replyに対する処理ができていなかったものと思われますが、どうしてでしょうか? また、ほかに解決方法はあるでしょうか?

回答よろしくお願いいたします。

shun159 commented 9 years ago

@rumb こんにちは、はじめまして。

これについては、単にParserが未実装なのかもしれません。 例えば、Routerの様にARP Replyを処理するアプリケーションを書く場合にも、 ExactMatchを使うと、この問題に当たるかもしれません。(もちろんARP以外にも他のEthTypeも同様におこりえます。

なので、今はExactMatchの使用を避けて実装をすることをおすすめします。 もし、repeater-hubのようなアプリケーションをお書きでしたら、それはExactMatchである必要はありません。 乱文失礼しました。

※ routerではなく、repeaterでした。。。早とちりすみません。

@yasuhito なにか追記がありましたらお願い致します。

yasuhito commented 9 years ago

近藤さんありがとうございます! とりあえずいま @rumb さんに、exact_match.rb のパッチの PR をおねがいしておきました。

shun159 commented 9 years ago

@yasuhito ちなみに、exact_match.rbの実装で気がついたことですが、 このような実装だといかがでしょうか??

変に口出ししてしまってスミマセン。。。

require 'pio'

exact_match = lambda do |packet_in|
  data = packet_in.data
  case data.ether_type
  when 0x0800
    options = {
      in_port: packet_in.in_port,
      ether_source_address: packet_in.source_mac,
      ether_destination_address: packet_in.destination_mac,
      vlan_vid: data.vlan_vid,
      vlan_priority: data.vlan_pcp,
      ether_type: data.ether_type,
      ip_tos: data.ip_type_of_service,
      ip_protocol: data.ip_protocol,
      ip_source_address: data.ip_source_address,
      ip_destination_address: data.ip_destination_address,
      transport_source_port: data.transport_source_port,
      transport_destination_port: data.transport_destination_port
    }
  when 0x0806
    options = {
      in_port: packet_in.in_port,
      ether_source_address: packet_in.source_mac,
      ether_destination_address: packet_in.destination_mac,
      vlan_vid: data.vlan_vid,
      vlan_priority: data.vlan_pcp,
      ether_type: data.ether_type,
      ip_tos: 0,
      ip_protocol: data.operation,
      ip_source_address: data.sender_protocol_address,
      ip_destination_address: data.target_protocol_address,
      transport_source_port: 0,
      transport_destination_port: 0
    }
  end
  @match = Pio::Match.new(options)
end

packet_in = PacketIn.new(raw_data: arp)
exact_match.(packet_in)
# => #<Pio::OpenFlow10::Match:0x00000004341008
# @format=
#  {:wildcards=>{},
#     :in_port=>0,
#      :ether_source_address=>#<Pio::Mac:35305680 "00:16:b6:b5:3e:c6">,
#      :ether_destination_address=>#<Pio::Mac:35301800 "ff:ff:ff:ff:ff:ff">,
#      :vlan_vid=>65535,
#      :vlan_priority=>0,
#      :ether_type=>2054,
#      :ip_tos=>0,
#      :ip_protocol=>1,
#      :ip_source_address=>#<Pio::IPv4Address:0x00000004362b18 @value=#<IPAddr: IPv4:192.168.213.1/255.255.255.255>>,
#      :ip_destination_address=>#<Pio::IPv4Address:0x00000004360890 @value=#<IPAddr: IPv4:192.168.213.128/255.255.255.255>>,
#      :transport_source_port=>0,
#   :transport_destination_port=>0}>
shun159 commented 9 years ago

あと、該当しない場合、エラーにするか、もしくはログに吐きつつMatch.new({})とするか…。

yasuhito commented 9 years ago

@shun159 いいですね! ぼくもちょうどそんなことを考えていました。該当しない場合には例外を投げるようにしましょう。ところで、ether_type は 0x0800 と 0x0806 以外にも考えなきゃいけないものって、たくさんあるでしょうか?

rumb commented 9 years ago

@shun159 さん @yasuhito さん

回答ありがとうございます。

最初の内容でPR出しました。

shun159 commented 9 years ago

@yasuhito 多分基本は0x0800と0x0806だけあれば良い気がしますが、0x8100 はあってもいい気がします。

shun159 commented 9 years ago

多重タギングされた時どうするか問題はありそうですけれど…。

yasuhito commented 9 years ago

@shun159 @rumb #244 で ARP の ExactMatch.new を修正しました。いかがでしょうか?

shun159 commented 9 years ago

@yasuhito 見た感じ大丈夫だと思います。

yasuhito commented 9 years ago

@shun159 チェックありがとうございます。 @rumb この変更で KVM + リピータハブは動くでしょうか?

rumb commented 9 years ago

@yasuhito 明日チェックいたしますので、しばしお待ちください

rumb commented 9 years ago

@yasuhito KVM + リピータハブで問題なく動きました。

yasuhito commented 9 years ago

@rumb よかったです! 確認ありがとうございました。