MidoNetのパケット処理をDVRと比較してみる
これまで2回にわたって、OpenStackでMidoNetを利用するための手順をご紹介しました。今回は、MidoNetでのパケット処理について、皆様が一番気になるであろうDVRとの違いという観点でご紹介します。
仮想ルータはどこにある?
MidoNet利用時のパケット処理を解説する前に、Neutron OVS plug-inを利用する場合とDVRの機能を利用した場合の挙動の差について説明します。ポイントは、仮想ルータの位置とNAT変換の箇所です。なおDVRの挙動の詳細については、以前の連載「OpenStack(RHEL-OSP6)で試す分散仮想ルータ」もご参照ください。
Neutron OVS plug-in利用時の挙動
OpenStackのネットワークは、外部用ネットワーク(External Network)とインスタンス間通信のための内部用ネットワーク(Tenant Network)に分かれます。その仲介をするのが仮想ルータです。Neutron OVS plug-inを標準設定で利用するときは、仮想ルータはNetwork サーバ(Neutron Serverサービスが起動しているサーバ)上に存在します(図1)。
別テナント上のインスタンス間通信(East-West通信)が必ず仮想ルータを経由するため、Networkサーバの負荷が高くなる傾向があります(図2の青い矢印)。
またインスタンスと外部ネットワークとの通信(North-South通信)は、必ずNetworkサーバ上の仮想ルータでNAT処理されてパケットが流れます(図2の赤い矢印)。しかし、Networkサーバは、Active-Activeの冗長化構成をとることができないため、システム全体の処理能力はNetworkサーバ単体のハードウェア性能に依存します。
DVR機能利用時の挙動
一方DVRを利用すると、Networkサーバ上の仮想ルータを、Computeサーバ上へも拡張が可能です。これらの仮想ルータは、別々の仮想ルータとして存在し、External Networkのセグメント範囲からそれぞれIP Addressが割り当てられます。(図3)
East-West通信は、そのインスタンスが動作しているComputeサーバ同士で直接通信します(図4の青い矢印)。これは、分散仮想ルータにより処理されます。
これに対してNorth-South通信は、Floating IP割り当ての有無により処理が変わります。インスタンスにFloating IPを割り当てている場合、インスタンスが動作しているComputeサーバ上の分散仮想ルータでNAT処理されてパケットが流れます(図4の緑の矢印)。一方Floating IPを割り当てていない場合は、Networkサーバ上のSNAT用仮想ルータでNAT処理されてパケットが流れます。これは、先に説明したNeutron OVS plug-in使用時と同じ挙動です(図4の赤い矢印)。
MidoNet利用時の挙動
MidoNetでは、MidoNet Provider Routerという独自の仮想ルータ上に、Tenant用仮想ルータが作成されます。MidoNet Provider Routerは複数のGWサーバ上で単一の仮想ルータとして構成されます。Tenant用仮想ルータも複数のGWサーバ上で透過的に構成されます(図5)。
MidoNetのパケット処理の流れ
Neutron OVS plug-in利用時、およびDVR利用時のパケットは、仮想ルータ上で処理されていましたが、MidoNetでは仮想ルータだけでなく、Computeサーバ上のMidoNet Agentもパケット処理を行っています。
この処理については、レッドハットの中井氏による「完全分散エッジ処理で実現するNeutron仮想ネットワーク」で詳細に解説されていますので、それをベースに説明します。以下、注目すべき箇所には、☆の後に解説を入れています。
East-West通信
East-West通信は、Computeサーバ上のMidoNet Agentにより処理されます。
前述の図5において、Tenant210(192.168.210.0/24)に属するComputeサーバ1上のVM210-1(192.168.210.13)から、Tenant220(192.168.220.0/24)に属するComputeサーバ2上のVM220-2(192.168.220.14)への通信フローを例にします。
はじめに、各サーバにおけるMidoNet用ポートの割り当て状況を、以下で確認します。
【ポート番号確認】@Compute1 # mm-dpctl --show-dp midonet (略) Port #0 "midonet" Internal (略) Port #1 "tngre-overlay" Gre (略) Port #2 "tnvxlan-overlay" VXLan (略)☆VXLAN用ポート Port #3 "tnvxlan-vtep" VXLan (略) Port #4 "tap6e7f5dc6-2c" NetDev (略)☆インスタンス用ポート Port #5 "tap6f15c9ed-c5" NetDev (略)☆インスタンス用ポート Port #6 "tap5c704d80-de" NetDev (略)☆インスタンス用ポート
インスタンス用ポートがどのインスタンスに割り当てられているかは、Dashboardからログインし、[プロジェクト]−[ネットワーク]−[ネットワーク]−[(Tenantネットワーク名)]で表示されるポート一覧等から確認してください(図6)。
次に、各サーバでのフローテーブルを確認します。Computeサーバ1でのフローテーブルは、以下のようになります。
【フローテーブル確認】@Compute 1 # mm-dpctl --dump-dp midonet (略) Flow: match keys:☆条件 Priority{0} mask: Priority{0} InPort{4}☆ポート4(VM210-1用)から来るパケット mask: InPort{-1} Ethernet{src=fa:16:3e:8e:35:bb, dst=ac:ca:ba:c3:3a:51} mask: Ethernet{src=ff:ff:ff:ff:ff:ff, dst=ff:ff:ff:ff:ff:ff} EtherType{0x800} mask: EtherType{0xffffffff} KeyIPv4{src=192.168.210.13, dst=192.168.220.14, proto=6, tos=16, ttl=64, frag=0}☆VM210-1からVM220-2へのパケット mask: KeyIPv4{src=255.255.255.255, dst=255.255.255.255, proto=-1, tos=-1, ttl=-1, frag=-1} TCP{src=55194, dst=22} mask: TCP{src=65535, dst=65535} TCPFlags{'PSH|ACK'} mask: TCPFlags{''} actions:☆処理 SetKey{Ethernet{src=ac:ca:ba:7d:43:3d, dst=fa:16:3e:6b:07:bf}} SetKey{KeyIPv4{src=192.168.210.13, dst=192.168.220.14, proto=6, tos=16, ttl=63, frag=0}} SetKey{Tunnel{tun_id=23, ipv4_src=192.168.20.102, ipv4_dst=192.168.20.103, tun_flag=0, ipv4_tos=0, ipv4_ttl=-1}}☆tunnel id 23でカプセル化し、Compute1からCompute2へ送る Output{port=2}☆ポート2(VXLAN用ポート)から送出する stats: FlowStats{packets=3, bytes=246} tcpFlags: PSH|ACK lastUsedTime: 1200121773
上記の強調箇所を読み解くと、Computeサーバ1上のVM210-1(192.168.210.13)からVM220-2(192.168.220.14)宛のパケットが来た場合、tunnel id 23でカプセル化してComputeサーバ1からComputeサーバ2へパケットを送出していることがわかります。
一方、Computeサーバ2でのフローテーブルは、以下のようになります。
【フローテーブル確認】@Compute 2 # mm-dpctl --dump-dp midonet (略) Flow: match keys:☆条件 Priority{0} mask: Priority{0} Tunnel{tun_id=23, ipv4_src=192.168.20.102, ipv4_dst=192.168.20.103, tun_flag=0, ipv4_tos=0, ipv4_ttl=-1}☆tunnel id 23でカプセル化されて、Compute1からCompute2へ届いたパケット mask: Tunnel{tun_id=-1, ipv4_src=255.255.255.255, ipv4_dst=255.255.255.255, tun_flag=0, ipv4_tos=0, ipv4_ttl=0} InPort{2}☆ポート2(VXLAN用ポート)からきたパケット mask: InPort{-1} Ethernet{src=ac:ca:ba:7d:43:3d, dst=fa:16:3e:6b:07:bf} mask: Ethernet{src=00:00:00:00:00:00, dst=00:00:00:00:00:00} EtherType{0x800} mask: EtherType{0x0} KeyIPv4{src=192.168.210.13, dst=192.168.220.14, proto=6, tos=16, ttl=63, frag=0}☆VM210-1からVM220-2へのパケット mask: KeyIPv4{src=0.0.0.0, dst=0.0.0.0, proto=0, tos=0, ttl=0, frag=0} TCP{src=55194, dst=22} mask: TCP{src=0, dst=0} TCPFlags{'PSH|ACK'} mask: TCPFlags{''} actions:☆処理 Output{port=6}☆ポート6(VM220-2)へパケットを送出する stats: FlowStats{packets=3, bytes=246} tcpFlags: PSH|ACK lastUsedTime: 1200119105
上記の強調箇所を読み解くと、VXLAN用ポートを経由し、tunnel id 23でカプセル化されてComputeサーバ1からComputeサーバ2へ届いたパケットで、かつVM210-1(192.168.210.13)からVM220-2(192.168.220.14)宛のパケットは、VM220-2へパケットを送出することがわかります。
以上より、East-West通信では、インスタンスが動作しているサーバ間(この例ではComputeサーバ1とComputeサーバ2)のみで完結することがわかります。
North-South通信
North-South通信は、Computeサーバ上のMidoNet Agentと、GWサーバ上のMidoNet AgentおよびBGP Daemonによって処理されます。前述の図5において、Tenant210(192.168.210.0/24)に属するComputeサーバ1上のVM210-1(192.168.210.13。Floating IPなし)から、Target(10.0.0.1)への通信フローを例にします。
Computeサーバ1でのフローテーブルは以下のようになります。
【フローテーブル確認】@Compute 1 # mm-dpctl --dump-dp midonet (略) Flow: match keys: ☆条件 Priority{0} mask: Priority{0} InPort{4}☆ ポート4(VM210-1用)から来るパケット mask: InPort{-1} Ethernet{src=fa:16:3e:8e:35:bb, dst=ac:ca:ba:c3:3a:51} mask: Ethernet{src=ff:ff:ff:ff:ff:ff, dst=ff:ff:ff:ff:ff:ff} EtherType{0x800} mask: EtherType{0xffffffff} KeyIPv4{src=192.168.210.13, dst=10.0.0.1, proto=6, tos=0, ttl=64, frag=0}☆VM210-1からTargetへのパケット mask: KeyIPv4{src=255.255.255.255, dst=255.255.255.255, proto=-1, tos=-1, ttl=-1, frag=-1} TCP{src=57655, dst=22}☆Src port 57655からDst port22へのパケット mask: TCP{src=65535, dst=65535} TCPFlags{'SYN'} mask: TCPFlags{''} actions: ☆処理 SetKey{Ethernet{src=ac:ca:ba:d4:6d:9a, dst=00:0c:29:c2:72:32}} SetKey{KeyIPv4{src=10.10.0.10, dst=10.0.0.1, proto=6, tos=0, ttl=62, frag=0}}☆Src IP Addressを仮想ルータのExternal Network用インタフェースのIP Addressへ変換 SetKey{TCP{src=4623, dst=22}}☆Src portを4623へ変換 SetKey{Tunnel{tun_id=4, ipv4_src=192.168.20.102, ipv4_dst=192.168.20.107, tun_flag=0, ipv4_tos=0, ipv4_ttl=-1}} Output{port=2}☆tunnel id 4でカプセル化し、Compute1からGW1へ送る stats: FlowStats{packets=14, bytes=2473}☆ポート2(VXLAN用ポート)から送出する tcpFlags: PSH|ACK lastUsedTime: 1221653557
上記の強調箇所を読み解くと、Computeサーバ1上のVM210-1(192.168.210.13:57655)からTarget(10.0.0.1:22)宛のパケットは、仮想ルータのExternal Network用インタフェース(10.10.0.10:4623)をSourceとするようなNAT変換をし、tunnel id 4でカプセル化して、Computeサーバ1からGWサーバ1へ送出されていることがわかります。ここでは省略しましたが、GWサーバ2へ向けてのフローも同様に存在します。
一方、GWサーバ1でのMidoNet用ポートの割り当て状況は、以下の通りです。上流ネットワーク用のポートが存在していることが確認できます。
【ポート番号確認】@Compute1 # mm-dpctl --show-dp midonet (略) Port #0 "midonet" Internal (略) Port #1 "tngre-overlay" Gre (略) Port #2 "tnvxlan-overlay" VXLan (略)☆VXLAN用ポート Port #3 "tnvxlan-vtep" VXLan (略) Port #4 "eth2" NetDev (略)☆上流ネットワーク用ポート Port #5 "mbgp1" NetDev (略)
GWサーバ1でのフローテーブルは、以下のようになります。
【フローテーブル確認】@GW1 # mm-dpctl --dump-dp midonet (略) Flow: match keys: ☆条件 Priority{0} mask: Priority{0} Tunnel{tun_id=4, ipv4_src=192.168.20.102, ipv4_dst=192.168.20.107, tun_flag=0, ipv4_tos=0, ipv4_ttl=-1}☆tunnel id4でカプセル化されて、Compute1からGW1へ届いたパケット mask: Tunnel{tun_id=-1, ipv4_src=255.255.255.255, ipv4_dst=255.255.255.255, tun_flag=0, ipv4_tos=0, ipv4_ttl=0} InPort{2}☆ポート2(VXLAN用ポート)からきたパケット mask: InPort{-1} Ethernet{src=ac:ca:ba:d4:6d:9a, dst=00:0c:29:c2:72:32} mask: Ethernet{src=00:00:00:00:00:00, dst=00:00:00:00:00:00} EtherType{0x800} mask: EtherType{0x0} KeyIPv4{src=10.10.0.10, dst=10.0.0.1, proto=6, tos=0, ttl=62, frag=0}☆仮想ルータのExternal Network用インタフェースからTargetへのパケット mask: KeyIPv4{src=0.0.0.0, dst=0.0.0.0, proto=0, tos=0, ttl=0, frag=0} TCP{src=4623, dst=22}☆Src port4623からDst port22へのパケット mask: TCP{src=0, dst=0} TCPFlags{'SYN'} mask: TCPFlags{''} actions: Output{port=4}☆ポート4(上流ネットワーク用ポート)から送出する stats: FlowStats{packets=14, bytes=2473} tcpFlags: PSH|ACK lastUsedTime: 776754605
上記の強調箇所を読み解くと、VXLAN用ポートを経由し、tunnel id 4でカプセル化されてComputeサーバ1からGWサーバ1へ届いたパケットで、かつ仮想ルータのExternal Network用インタフェース(10.10.0.10:4623)からTarget(10.0.0.1:22)に宛てたもの(すなわちComputeサーバ1でNAT変換されたパケット)は、上流ネットワーク用のポートから送出されることがわかります。
GWサーバ2でも、同様のフローが存在します。また、インスタンスにFloating IPを割り当てたときは、ポート変換がない(送信元ノード上でFloating IPと1:1NAT変換をする)以外は、同様の処理となります。
つまりNorth-South通信では、インスタンスが動作しているサーバ上でNAT変換され、複数のGWサーバへ振り分けられて転送されます。
MidoNet利用時の通信をまとめると、図7のようになります。
おわりに
本連載では、OpenStack上でMidoNetを利用する際の手順や仕組みについて解説してきました。前回の連載も合わせて、Neutron DVRとMidoNetの違いを理解いただき、設計要件にどちらが適しているかの判断の手助けとなれば幸いです。
本記事執筆にあたり、OSCA™技術分科会メンバーの皆様、日本OpenStackユーザ会の皆様、Blogで情報公開いただいた皆様にご協力をいただきました。特にミドクラジャパン鈴木氏、松尾氏、レッドハット中井氏には技術情報提供・引用で多大なるご協力をいただきました。心より感謝いたします。
- Linuxは、Linus Torvalds氏の日本およびその他の国における登録商標または商標です。
- MidoNetは、Midokura SARLの登録商標です。
- OpenStack®の文字表記とOpenStackのロゴは、米国とその他の国におけるOpenStack Foundationの登録商標/サービスマークまたは商標/サービスマークのいずれかであり,OpenStack Foundationの許諾を得て使用しています。日立製作所は,OpenStack FoundationやOpenStackコミュニティの関連企業ではなく、また支援や出資を受けていません。
- OSCA™(Open Standard Cloud Association)は、デル株式会社の登録商標です。
- Red Hat、Red Hat Enterprise Linuxは、米国およびその他の国におけるRed Hat, Inc. の登録商標です。
- その他、記載の商標やロゴは、各社の商標または登録商標です。
【参考文献】
完全分散エッジ処理で実現するNeutron仮想ネットワーク(アクセス:2015/10)
http://www.slideshare.net/enakai/midonet-technology-internalsv10
MidoNet Documentation(アクセス:2015/10)
MidoNet integration - RDO(アクセス:2015/10)
https://www.rdoproject.org/MidoNet_integration
OpenStackNetworking Plug-in 比較 -OVS と MidoNet-(アクセス:2015/10)
http://www.osca-jp.com/solution.html
第20回 OpenStack勉強会 Neutron Deep Dive - DVR(アクセス:2015/10)
http://www.slideshare.net/ToruMakabe/20-openstack-neutron-deep-dive-dvr