Trema/PbrLbSwitch(2)

昨日の記事 (Trema/PbrLbSwitch) のデータを見返していて思ったんだけどやっぱりおかしなところがあった。まあ案の定というか。

問題

フロー情報、

root@oftest01:~# sudo ovs-ofctl dump-flows br0 | grep 56085
cookie=0x3, duration=1372.846s, table=0, n_packets=5, n_bytes=1340, priority=65535,tcp,in_port=4,vlan_tci=0x0000,dl_src=54:52:00:00:00:03,dl_dst=00:00:00:02:00:01,nw_src=192.168.11.99,nw_dst=192.168.11.1,nw_tos=0,tp_src=80,tp_dst=56085 actions=mod_dl_src:00:00:00:01:00:01,mod_dl_dst:00:50:56:c0:00:01,output:1
cookie=0x2, duration=1373.854s, table=0, n_packets=6, n_bytes=955, priority=65535,tcp,in_port=1,vlan_tci=0x0000,dl_src=00:50:56:c0:00:01,dl_dst=00:00:00:01:00:99,nw_src=192.168.11.1,nw_dst=192.168.11.99,nw_tos=0,tp_src=56085,tp_dst=80 actions=mod_dl_src:00:00:00:02:00:01,mod_dl_dst:54:52:00:00:00:03,output:4
root@oftest01:~#

載せてありますが、Webサーバからクライアントへの返信について

actions=mod_dl_src:00:00:00:01:00:01,mod_dl_dst:00:50:56:c0:00:01,output:1

になっちゃってるんだよね。VIP:192.168.11.99 に対しては 00:...00:99 が ARP 解決の時には返されるのに、実際リクエスト送って返ってくると、MAC アドレスがつけ変わって返信が届いてしまっている。これはよろしくない。今回は全端末原則として OVS 直収なんだけど、間に L2 スイッチとかが挟まっていたりすると問題が起きる可能性がある(1IP に対して複数 MAC が使われている)。

何故かというと、DSR なので、Client → Server (Request) については MAC/IP の操作処理をいれていたけど、Server → Client (Reply) については、Simple Router の処理をそのまま使っていたから(単純な Routing/Forwarding のみ)です。Simple Router の場合、Routing してパケット返すときには、返し先のセグメントがある interface を検索して、その MAC アドレスを使いますが、今回の場合、network1 (クライアントがいるセグメント) には default gateway の interface (192.168.11.3/00:...:00:01) と vserver の interface (192.168.11.99/00:...:00:99) があって、gateway 側のを選択して使ってしまっているという状況。

修正

LB 処理に対する返信のパケットについても別途 L2 ちゃんと指定して書き換えてやる処理を入れなきゃいけないのでした。

  def pbrlb_reply?(message)
    vsvr = @lb_table.vserver
    if message.ipv4_saddr.to_a == vsvr.ipaddr.to_a &&
        message.tcp? &&
        message.tcp_src_port == vsvr.tcp_port
      return true
    end
  end


  def handle_pbrlb_reply(dpid, message)
    arp_entry = @arp_table.lookup_by_ipaddr(message.ipv4_daddr)
    if arp_entry
      src_interface = @interfaces.find_by_ipaddr(message.ipv4_saddr)
      actions = [
        SetEthSrcAddr.new(src_interface.hwaddr.to_s),
        SetEthDstAddr.new(arp_entry.hwaddr.to_s),
        SendOutPort.new(arp_entry.port)
      ]
      flow_mod dpid, message, actions
      packet_out dpid, message.data, actions
    else
      warn "handle_pbrlb_reply: Not found #{message.ipv4_daddr} entry in arp table, to PBRLB REPLY"
      @arp_table.dump
    end
  end

という感じに。返信については、Client/Server の両方のMACアドレスの情報は当然 arp_table に入ってるよね―と思ったら実は入っていなかったというオチもある。handle_arp_requestARP Request の処理するときに ARP Table の更新するって処理がなかった…。入ってきたパケットについてはちゃんと ARP Table への登録してやらんとイカン。

チェック

こういう動作になる。

root@oftest01:~# sudo ovs-ofctl dump-flows br0 | grep 57834
cookie=0x2, duration=298.31s, table=0, n_packets=4, n_bytes=423, priority=65535,tcp,in_port=4,vlan_tci=0x0000,dl_src=54:52:00:00:00:03,dl_dst=00:00:00:02:00:01,nw_src=192.168.11.99,nw_dst=192.168.11.1,nw_tos=0,tp_src=80,tp_dst=57834 actions=mod_dl_src:00:00:00:01:00:99,mod_dl_dst:00:50:56:c0:00:01,output:1
cookie=0x1, duration=298.319s, table=0, n_packets=5, n_bytes=707, priority=65535,tcp,in_port=1,vlan_tci=0x0000,dl_src=00:50:56:c0:00:01,dl_dst=00:00:00:01:00:99,nw_src=192.168.11.1,nw_dst=192.168.11.99,nw_tos=0,tp_src=57834,tp_dst=80 actions=mod_dl_src:00:00:00:02:00:01,mod_dl_dst:54:52:00:00:00:03,output:4
root@oftest01:~#

MACがちゃんとVIP(192.168.11.99)用のアドレスになってる。

actions=mod_dl_src:00:00:00:01:00:99,mod_dl_dst:00:50:56:c0:00:01,output:1

課題

あと、やってる最中に見えてきたんだけど、ARP 解決と合わせて微妙な動きをしている。Trema/SimpleRouterの処理で気になってたこと で書いたんだけど、リクエストについては、宛先の ARP 解決のために最初の一発は捨てるんだよね。で、今回の場合、TCP Source Port 別に振り分け先を変えると、こういう動作をしちゃったりする。(クライアントの動作によるけど)

最初のリクエストに対して応答がなくていったん終わって、ポートを変えて次のリクエストを出してみたけど、別なサーバに振り分けられるのでやっぱりここでも応答がなくていったん終わって…というので、バックエンドの ARP 解決がある程度終わるまで連鎖的にクライアントを待たせる羽目になってしまうという…。

これは、スイッチが(ARP Table)がほぼ空っぽの状態で、関連する機材の ARP を解決するまでの間起こるので、ある程度流量があるところでの発生確率は低いと思われる。ただ、現状こういうのもあり得ると言うことで、前回の「課題」のところにも書いたけど、バックエンドの機材に対する Health Check とかはやっぱり必要なんだろうなあ。