Trema/SimpleRouterの処理で気になってたこと

Trema の examples に入っている Simple Router を元にいくつかいじってみたりしていた のだけど、その処理でちょっと気になったことがあったので調べてみた。

気になったこと

SimpleRouter の handle_unresolved_packet の処理、下の図の黄色い線をたどっていったところについて。

この処理は、スイッチに何かしらのパケットが入ってきたのだけど、宛先の情報が未知の (ARP Table に存在しない) 場合に発生する。つまり、Simple Router に、セグメントをまたいで転送すべき何かしらの未知のフローが入ってきたときに、転送先の情報 (MACアドレス) を問い合わせて解決する処理を行う。

  def handle_unresolved_packet( dpid, message, interface, ipaddr )
    arp_request = create_arp_request_from( interface, ipaddr )
    packet_out dpid, arp_request, SendOutPort.new( interface.port )
  end

気になったのは、ここでは ARP Request の送信しかしていないことなんだよね。未知のフロー(パケット)が入ってきた(Packet In)ので、その入ってきたパケット (message) を持っているのだけど、ARP Request したあとは message をを処理していない。

気になったことの確認

……つまり、未知のフローについて最初の 1 発目のパケットは捨てちゃってるんだよねこれ。というのをまず確認してみる。Simple Router と同梱されている simple_router_netns.conf でテストをしてみる。といっても、起動後に1発だけパケットを売ってみると言うだけなんだけど。

stereocat@oftest02:~/trema-orig/trema$ sudo ip netns exec host1 ping -c1 192.168.2.2
PING 192.168.2.2 (192.168.2.2) 56(84) bytes of data.

--- 192.168.2.2 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

stereocat@oftest02:~/trema-orig/trema$

パケットは落ちる。

そのときの TremaShark のキャプチャ結果とそこから起こしたシーケンスはこうなる。

また、SimpleRouter の各メソッドの頭でメソッド名をログに出力するようにして実行してみるとこうなる。

Sun Feb  3 16:31:43 2013 [info] # packet_in                 -------(1)
Sun Feb  3 16:31:43 2013 [info] # handle_arp_request
Sun Feb  3 16:31:43 2013 [info] # packet_out                -------(2)
Sun Feb  3 16:31:43 2013 [info] # packet_in                 -------(3)
Sun Feb  3 16:31:43 2013 [info] # handle_ipv4
Sun Feb  3 16:31:43 2013 [info] # should_forward?
Sun Feb  3 16:31:43 2013 [info] # forward
Sun Feb  3 16:31:43 2013 [info] # resolve_next_hop
Sun Feb  3 16:31:43 2013 [info] # handle_unresolved_packet  -------(4)
Sun Feb  3 16:31:43 2013 [info] # packet_out
Sun Feb  3 16:31:43 2013 [info] # packet_in                 -------(5)
Sun Feb  3 16:31:43 2013 [info] # handle_arp_reply
Sun Feb  3 16:31:43 2013 [info] New entry: MAC addr = c2:d6:2a:1d:44:9a, port = 1

何が分かるかというと、気になっていたことはやっぱりそうだったと言うことなんだけどね。Unresolved Packet については、送信先MAC を解決するための ARP Request を受けた後は特に何もしていない。

ためしに

何も考えずに、ARP Request した後で message の送信処理やってやるっていうのはダメなんだよな、という確認。

  def handle_unresolved_packet( dpid, message, interface, ipaddr )
    info "# handle_unresolved_packet"

    info "## handle_unresolved_packet: create_arp_request"
    arp_request = create_arp_request_from( interface, ipaddr )
    packet_out dpid, arp_request, SendOutPort.new( interface.port )

    info "## handle_unresolved_packet: send message if resolved hwaddr of #{ message.ipv4_daddr }"
    arp_entry = @arp_table.lookup( message.ipv4_daddr )
    if arp_entry
      info "## handle_unresolved_packet: resolved hwaddr and send message"
    else
      info "## handle_unresolved_packet: cannot resolve hwaddr of #{ message.ipv4_daddr }"
    end
  end
Sun Feb  3 16:46:43 2013 [info] # packet_in                 -------(1)
Sun Feb  3 16:46:43 2013 [info] # handle_arp_request
Sun Feb  3 16:46:43 2013 [info] # packet_out                -------(2)
Sun Feb  3 16:46:43 2013 [info] # packet_in                 -------(3)
Sun Feb  3 16:46:43 2013 [info] # handle_ipv4
Sun Feb  3 16:46:43 2013 [info] # should_forward?
Sun Feb  3 16:46:43 2013 [info] # forward
Sun Feb  3 16:46:43 2013 [info] # resolve_next_hop
Sun Feb  3 16:46:43 2013 [info] # handle_unresolved_packet  -------(4)
Sun Feb  3 16:46:43 2013 [info] ## handle_unresolved_packet: create_arp_request
Sun Feb  3 16:46:43 2013 [info] # packet_out
Sun Feb  3 16:46:43 2013 [info] ## handle_unresolved_packet: send message if resolved hwaddr of 192.168.2.2
Sun Feb  3 16:46:43 2013 [info] ## handle_unresolved_packet: cannot resolve hwaddr of 192.168.2.2
Sun Feb  3 16:46:43 2013 [info] # packet_in                 -------(5)
Sun Feb  3 16:46:43 2013 [info] # handle_arp_reply
Sun Feb  3 16:46:43 2013 [info] New entry: MAC addr = 62:81:68:99:5c:3e, port = 1

こうなる。そりゃそうだ。ひとつの Packet In イベントに対応する一連の処理、上のログについては(1)〜(4)でひとかたまりなんだよね。

未知のフローが発生したとき、最初の 1 回については ARP Reply によって発生した Packet In イベントの中で、MAC アドレスが取得できてから message を送信するという処理ができればいい…… 1回イベントをまたいで持ち越せればいい。ということで、message をどこかに待避しておいて、次の Packet In (handle_arp_reply) の時取り出して使う、とかそういう処理を入れてもいいのかもしれないとかちょっと考えてみたが、そうすると処理もテストもえらく厄介になるんだよね。

  • 複数のノード・複数のフローが、非同期的に発生している状況ではどうなるか?
    • いつも狙った順序で狙ったイベントが発生するのかというと、たぶんそうはならない。
    • テストをどうする? そもそもテストケースとして何があればいいんだろう?
  • ARP が解決できない (ARP Replyに対する応答がない) 場合の処理は?
    • 送信側はコントローラの都合なんて関係なくデータを送ってくる。内部で何かしらのバッファリングとかをする? コントローラのリソースを食いつぶさずに処理する方法は?

他にも問題はあると思うけど。まあ非同期に起きるイベントで同期を取るとか考え始める方がダメだな。

特に何があるわけでもない結論

Simple Router のコード読んでて「あれ? 最初の 1 発は捨てちゃうのか」ってのが気になったんですよ。でも IP 通信なんてどうせ送信のタイミングも受信のタイミングも同期取れないので、これで問題ないんだよな (だから非同期イベントだと言っているのだが…という話なんだけど)。MAC宛先がわからなければデータ送りようがない。MAC解決のためのリクエスト出したところで、それがいつ返ってくるのか(返ってくるかどうか)もわからないので、そこで返信待って(返信のタイミング同期させて)何かやるってのは考えない。

非同期イベントに対する処理の考え方がどうも整理できていない気がしたので再確認してみました、ってことです。……再確認したところで何を今いまさら…な感じになってしまった。大丈夫か俺。