Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

パケットからMatchを生成するメソッド #245

Open
rumb opened this issue Oct 16, 2015 · 6 comments
Open

パケットからMatchを生成するメソッド #245

rumb opened this issue Oct 16, 2015 · 6 comments

Comments

@rumb
Copy link

rumb commented Oct 16, 2015

Arp::Request.match(source_mac: "11:11:11:11:11:11")
UdpHeader.match(ip_destination: "192.168.0.1")

こんな感じで、"カジュアル"にMatchのオブジェクト(インスタンス)を作れるありがたいです!!

@yasuhito
Copy link
Member

@rumb ありがとうございます。議論のために、いくつか例をもらえますか?

  • その ARP や UDP など 2, 3 個の例で、最終的にどういう match ができるのか
  • trema のサンプルどれでもいいので、#match を使って書き直すとどうなるか

よろしくおねがいします。

@yasuhito yasuhito changed the title 各パケットフォーマットに対応するクラスにおける、Matchオブジェクトを生成するメソッドの実装について パケットからMatchを生成するメソッド Oct 17, 2015
@rumb
Copy link
Author

rumb commented Oct 19, 2015

@yasuhito
分かりづらくて申し訳ないのですが、以下のような感じでしょうか?

class Arp
 class Request
 ...
  def match (user_options)
   options = {
    in_port: user_options[ :in_port ] || <指定しない>,
    ether_source_address: user_options[ :ether_source_address ] || source_mac || <指定しない>,
    ether_destination_address: user_options[ :ether_destination_address ] || destination_mac || <指定しない>,
    vlan_vid: user_options[ :vlan_vid ] || vlan_vid || <指定しない>,
   ...
   ether_type: <Arp Request のether type>
    }
   Match.new( options )
  end
  ...
 end
end

書き方が分からない部分は<>内の日本語で表記しております。
これで、次の2パターンの使い方が考えられると思います。

Arp::Request.match ( :destination_mac "11:11:11:11:11:11" )
message.match ( :destionation_mac <指定しない> )

上のような場合は、Arp Requestたる最小限のoptionのみ(ethertype)を指定します。
下のように受信したmessageからoptionを作成するときには、逆にexact_matchの条件を緩くして使うという印象です。これに関しては単純にexactmatchに引数をとれるようにすればいいだけかと思います。

サンプルの書き換えた例は少し考えますので、しばしお待ちください。

p.s.
個人的にはether_typeがないことによって思った通りにフローが追加されないことを防止したいというのが一番の理由なのですが、別の方法として、Matchのether_typeはデフォルトで全てのtypeを指定するというのはどうでしょうか?
他のフィールドは指定しないとワイルドカード的な処理がされるので、ether_typeも同じような処理をされるだろうと思って自分がはまったので、どうしてもこの点が気になってしまいます。
ジャストアイディアなので流してもらって構いません。

@rumb
Copy link
Author

rumb commented Oct 22, 2015

@yasuhito
サンプルの書き換えの例ですが、必要性のある例が思いつきませんでした。申し訳ありません。

Arp::Request.match ( :destination_mac "11:11:11:11:11:11" )

このような書き方は、1こ2このフローを入れるプログラムをつくる場合に、私のような初学者は分かりやすく簡単でよいと思います(逆にそれ以上のメリットが考えられませんでした)。しかし、

message.match ( :destionation_mac <指定しない> )

こっちの書き方の場合の使い道が思いつかなかったです。

(以下、蛇足です。)
どちらかというと、現状のexact_matchを拡張して、どのレイヤーまでの情報でマッチさせるかというような使い方ができるといいと思います。
learning_switchやsimple_routerの例では、下記のようにExactMatchでフローを入れていて、同じ宛先でもポート番号が違うだけでpacket_inが発生します。

def flow_mod(message, port_no)
  send_flow_mod_add(
    message.datapath_id,
    match: ExactMatch.new(message),
    actions: SendOutPort.new(port_no)
  )
end

これを、役割に応じて下記のように任意のレイヤー以下の情報でMatchできると同じいいのではないでしょうか?

LaylerMatch.new(message, 2)

@yasuhito
Copy link
Member

ありがとうございます。たとえば Arp::Request.match(destination_mac: '11:11:11:11:11:11') の例だけでよいので、どんなマッチができるか具体的にタプルを列挙してもらえますか? あとは、どのサンプルでもいいので、.match を使って書き直したサンプルを貼ってみてください。

ぼくの理解している限りでは、ポイントは

  • ether_type をマッチに指定し忘れるとハマるから何とかしたい
  • ether_type の指定を Arp とかの人間が読める文字列でやりたい

の 2 つだと思っています。

で、懸念しているのは .match でマッチを作ったときに、いったいどんなタプルのマッチができるのかわかっていないので (.exact_match も考えていますか?) 例を挙げてもらって直感的に分かりやすければ採用したいと思います。

あと LayerMatch.new でレイヤの番号を指定するのは、自分がレイヤいくつと番号で言われてもそれが何かパッと分からない人間なのであまり乗り気ではありません (笑)。

@rumb
Copy link
Author

rumb commented Oct 26, 2015

@yasuhito
返答が遅れてしまい申し訳ありません。
上記件了解いたしました。

以下が具体的にタプルを列挙した形になります。

Arp::Request.match( destination_mac: '11:11:11:11:11:11') 
=> {
  ether_destination_address: MAC.new("11:11:11:11:11:11"),
  ether_type:  EthernetHeader::EtherType::ARP
}

Udp.match( ip_destination: "192.168.0.0/24")
=> {
  ether_type: EthernetHeader::EtherType::IPV4,
  ip_protocol: ProtocolNumber::UDP,
  ip_destination_address: Ipv4Address.new("192.168.0.1/24"),
}
packet_in.data
=> { 
 ether_type: 2048,
 ether_source_address: "11:11:11:11:11:11"
 ether_destination_address: "22:22:22:22:22:22"
 ip_protocol: 17,
 ip_source_address: "192.168.1.100",
 ip_destination_address "10.0.0.100"
# 一部省略、またアドレス等も実際にはstringではないです。
}

packet_in.match( ip_destination_address:  packet_in.data.target_protocol_address.mask(24) )
=> {
 ether_type: 2048,
 ip_destination_address: "192.168.1.0"
}

packet_in.match(  ether_source_address: packet_in.source_mac )
=> {
 ether_type: 2048,
 ether_source_address: "11:11:11:11:11:11"
}

以下、サンプルの一部を書き換えた例です。
ExactMatchよりも、スイッチらしくL2で動いている感じがします。

learning_switch / lib / learning_switch.rb

  def flow_mod(message, port_no)
    send_flow_mod_add(
      message.datapath_id,
      match: message.match( ether_destination_address: packet_in.destination_mac  ),
      actions: SendOutPort.new(port_no)
    )
  end

至らぬところがあるとは思いますが、よろしくお願いいたします。

@yasuhito
Copy link
Member

だいぶイメージがつかめてきました。良さげですが、この例 (packet_in.match(...)) だと、packet_inether_destination_address: packet_in.destination_mac にマッチする (!?) と読めます。なにかもっといい API はないでしょうか?

たとえば、もしここでやっていることを日本語で説明するとすれば、

  1. packet_in と同じ種類のパケットにマッチするマッチを作って、
  2. 条件 ether_destination_address: packet_in.destination_mac を追加で指定

という 2 段階の処理になります。だから、API としては 1 と 2 のメソッドチェインになるのが自然だと思います。

def flow_mod(packet_in, port_no)
  send_flow_mod_add(
    packet_in.datapath_id,
    match: packet_in.match(ether_destination_address: packet_in.destination_mac),
    actions: SendOutPort.new(port_no)
  )
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants