Libvirt と Open vSwitch による仮想ネットワークの構築

この記事は、Libvirt と Open vSwitch を使って仮想ネットワークを検証したメモである。

Libvirt は、製品名 Red Hat Enterprise Linux virtualization として、サブスクリプション契約で利用することができる。Open vSwitch は Red Hat OpenStack、Red Hat OpenShift、Red Hat Virtualization の実現要素として組み込まれている有用な技術であり、使用には同様の制約がある。

しかしながら、LibvirtとOpen vSwitchは、OSSライセンスで提供されるプロダクトのため、Ubuntu Linux でも利用できる。そこで、これらを利用して仮想ネットワークを構築して検証した。仮想ネットワークとは、ソフトウェアによって実現するネットワークであり、物理ネットワークの上に構築するソフトウェアで実現したネットワーク環境を指す。


## 仮想サーバーのクラスタを構成する時の課題

次の図は、標準的なLinuxの仮想化環境のLibvirtとKVMを組み合わせた構成である。この図を見て解るとおり、一つのハイパーバイザー(Libvirt/KVMホスト)上に、ハブとなるブリッジ virbr0により仮想マシンの連携ができるため、仮想マシンのクラスタを構成することも可能だ。しかし、複数のハイパーバイザーで、仮想サーバーのクラスタを構成するケースでは、ハイパーバイザークラスタを横断するブリッジ接続が必要になる。

![pic-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/904d7936-336a-8cb6-452d-b5b3ee47a59d.png)

ここで簡単に用語を解説しておく。Linux の KVM(Kernel Virtual Machine)は、Linuxカーネルをハイパーバイザーとして動作せることで、一つのハードウェア上で仮想化されたサーバーを複数起動することを可能にする。そして、Libvirtは、ハイパーバイザーを含む仮想化プラットフォームを管理するためのAPI、デーモン、管理コマンドである。サポート対象は、KVM, Xen, VirtualBox, VMware, Hyper-V, PowerVMなどがある。 

Linux の KVM を利用する Libvirt のインストールは、それぞれの Linuxディストリビューションでパッケージ化されているので、rpm や apt などのパッケージマネージャーから簡単にセットアップできる。Libvirt をインストールすると、図のように、デフォルトのネットワークとして、ブリッジ virtbr0 が設定される。このブリッジには、DHCP と NAT の機能が備わっているため、仮想マシンのスタート時に、自動的にIPアドレスが付与される。また、インターネットにアクセスする際は、物理NICにパケットを渡す直前で、NAT によってホストOS の IPアドレスを使って、インターネットなどの外部ネットワークと通信することができる。


例えば、Kubernetesクラスタのように、複数のハイパーバイザーに仮想サーバーを配置することで、可用性とスケールを実現するケースでは、Libvirt のブリッジだけでは不足である。つまり、仮想サーバーが、何らかの方法でハイパーバイザーを移動しても、IPアドレスを変更する必要が無いブリッジで繋がった仮想ネットワークが必要である。仮想サーバーで構成されるクラスタの数が増えても、物理的なケーブル接続の変更や追加を必要としないソフトウェア定義によるネットワーク、すなわち SDN(Software Defined Network) が必要となる。Open vSwitch は SDN を実現するための一つのソフトウェアであり、次の図に表すように、複数のハイパーバイザー横断で、仮想サーバーのネットワーク環境を提供するソフトウェアである。
![pic-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/0226afce-0982-6cbf-ec23-57c77308274d.png)


## ソフトウェア定義ネットワーク

ソフトウェア上から論理的なネットワーク構成を集中的に制御する技術「SDN」（Software-Defined Networking: ソフトウェア定義ネットワーク）は、オープンソース・ソフトウェア、および、メーカー製品などが複数ある。今回のテーマは Open vSwitch の利用であるが、説明のために周辺を含めて整理する。

* Open vSwitch
* Open Virtual Network
* Openflow

## Open vSwitch

Open vSwitch は、Apache 2.0ライセンスで配布されるマルチレイヤ仮想スイッチであり、以下の特徴がある。

* ハイパーバイザーソフトウェア Xen、KVM、Proxmox VE、およびVirtualBoxで利用可能
* VMware vNetwork Distributed Switch、Cisco Nexus 1000V シリーズ仮想スイッチと同様に、複数の物理サーバーへのデプロイが可能
* Open vSwitch は、ハイパーバイザー内で実行されるソフト スイッチとしても、スイッチング シリコンの制御スタックとしても動作
* 仮想管理システム　OpenStack、openQRM、OpenNebula、oVirtに組み込まれる
* Linux ディストリビューション Ubuntu、Debian、Fedora、openSUSE、そして、BSD系UnixのFreeBSDとNetBSD、などで利用可能
* 標準の管理インターフェイスとプロトコル (NetFlow、sFlow、IPFIX、RSPAN、CLI、LACP、802.1ag など) をサポート
* プログラムによる拡張によって大規模なネットワーク自動化を可能にする
* オープンソースとして公開されている高速パケット処理用のライブラリとネットワークドライバ DPDK (Data Plane Development Kit)に移植された。
* Red Hat Enterprise Linux 6.4/7.0 以降のすべてのリリース、Red Hat OpenStack Platform、Red Hat Virtualization 4、Red Hat OpenShift のイネーブラーとして Open vSwitch カーネル モジュールが含まれている。

#### 参考資料
* Open vSwitch プロジェクトHP、https://www.openvswitch.org/
* Red Hat OVSサポート、https://access.redhat.com/articles/270223


## Open Virtual Network

OVN(Open Virtual Network)は、OVS(Open vSwitch)のための一連のデーモンで、仮想ネットワークの構成をOpenFlowに変換する。Apache 2 ライセンスのオープンソースソフトウェアである。

* OVNは、OVSより上位の抽象化レイヤーを提供する
* 論理ルーターや論理スイッチとして働く
* OVNはクラウド管理ソフトウェア(CMS:cloud management software)によって使われることを意図する
* OVN は完全にユーザー空間で実行されるので、カーネルモジュールは必要ない
* OVN が提供する機能は以下である
   * 分散仮想ルーター
   * 分散論理スイッチ
   * アクセス制御リスト
   * DHCP
   * DNS サーバー
* Red Hat OpenStack Platform に含まれる

#### 参考資料
* OVNプロジェクトHP、https://www.ovn.org/en/
* RED HAT OPENSTACK PLATFORM 13, OVN を使用した OpenStack のネットワーク, https://access.redhat.com/documentation/ja-jp/red_hat_openstack_platform/13/html/networking_with_open_virtual_network/index


## Openflow

従来型のネットワーク機器では、一つのシャーシの中で、制御装置(Control Plane)とパケット転送装置(Data plane)が収められていた。一方のOpenflowでは、ネットワークを構成する機器を一つの制御装置で集中管理し、複雑な転送制御を行なったり柔軟にネットワーク構成を変更できる。
![pic-2-openflow.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/0c8e5441-5e59-266f-bfe3-5c41515a6433.png)


Openflowの構成要素は以下の３つである。
  * OpenFlowコントローラー
  * OpenFlowプロトコル
  * OpenFlowスイッチ


OpenFlowスイッチは、パケットのルックアップと転送を担当する。 スイッチはコントローラと通信し、コントローラは スイッチを管理する。コントローラーとスイッチは、OpenFlow スイッチ プロトコルにより連携する。

OpenFlow と Software Defined Networking に関する情報は、Open Networking Foundation の Web サイト (https://www.opennetworking.org/) で入手できる。

2011 年、Google、Facebook、Microsoft、他の企業が共同で、SDN の促進と採用に専念する組織 Open Networking Foundation (ONF) を設立した。ONFは、SDNアーキテクチャの制御層と転送層の間の標準的なサウスバウンド通信インターフェイスとして OpenFlow を定義し、OpenFlow を標準化を推進している。


#### 参考資料
* ONFプロジェクトHP、https://opennetworking.org/
* List of OpenFlow Software Projects http://yuba.stanford.edu/~casado/of-sw.html
* What Is OpenFlow?, https://info.support.huawei.com/info-finder/encyclopedia/en/OpenFlow.html


## Open vSwitch のアーキテクチャと機能

OVSの機能を、以下に箇条書きにする。これはソフトウェアで実現するL2スイッチだ。

* Standard 802.1Q VLAN modelによるトランクとアクセスポート　
* Link Aggregation Control Protocol (LACP)を利用する、または使用しない NIC ボンディング
* NetFlow, sFlow(R), 視覚化のためのミラーリング
* QoS (Quality of Service) 構成、ポリシー制御
* Geneve, GRE, VXLAN, STT, and LISP トンネリング
* 802.1ag 接続障害管理
* OpenFlow 1.0 以上の拡張機能
* CとPythonから操作可能なトランザクション可能な構成データベース
* Linuxカーネルモジュールによる高パフォーマンス・フォワーディング


次の図は、Open vSwitchの主要な構成要素である。

![pic-3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/7b2841d2-3abb-88ce-852c-1a615866dd86.png)
出典: https://www.researchgate.net/figure/Main-components-of-the-Open-vSwitch-OVS-architecture-placed-in-the-physical-kernel-or_fig7_311338103

以下に、主要部分の説明を箇条書きにする。

* 「OVSDB」は、RFC7047で定義されるOpen vSwitchデータベースのプロトコル
* 「OpenFlow」は、コントローラーとスイッチが連携するためのプロトコル
* 「ovs-vswitchd」は、Linuxカーネルモジュールを伴うフローベーススイッチを実装するデーモン
* 「ovsdb-server」は、「ovs-vswitchd」の構成を保存管理する軽量データベースサーバー
* 「ovs-dpctl」は、スイッチカーネルモジュールの構成ツール
* 「ovs-vsctl」は、「ovs-vswitchd」の構成について、更新と問合せするためのコマンド
* 「ovs-appctl」は、実行中のOpen vSwitchへ命令を送信するコマンド



#### 参考資料
* GitHub openvswitch/ovs, https://github.com/openvswitch/ovs
* What is Open vSwitch, https://docs.openvswitch.org/en/latest/intro/what-is-ovs/



## 検証構成

Open vSwitch でハイパーバイザーを横断する VLAN を作成する。構成のポイントでは、Open vSwitchによりブリッジ ovsbr0 を作成して、VLANタグの利用を設定する。さらに、L2スイッチと繋ぐ物理ポート(enp5s0f0)に対応づける。
これにより、HV-1 と HV-2 で、L2スイッチと接続するポート(enp5s0f0)に VLANタグ 付きのパケットを送出する。L2スイッチのポート３とポート４は、VLANタグ 付きパケットを受けるものとして設定する。ポート１にVLAN 1002、ポート2にVLAN 1001をタグを外して出力する。

![pic-6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/3d476f91-e9b9-2772-10e2-b2b61a006b4b.png)


## ハイパーバイザー #1 へ Libvirt のインストール

この記事は、2023年現在、Linux server OS の中で、最も人気のあるディストリビューションの Ubuntu 20.04 LTS Desktop を利用する。X-Window の Desktopは、仮想サーバーのセットアップを楽に実行できるので、必ず利用したい。
ディストリビューターからサポートは得られないが、インターネット上に沢山の情報があるため、個人のスキルアップには適しているためだ。

企業内でシステムの稼働を確実にするためにベンダーサポートが必須であれば、有償となるがRHELをお勧めしたい。Open vSwitch と Libvirt のコマンドは、UbuntuとRHELで変わりは無い。

Ubuntu 20.04 に 以下のコマンドで、Libvirt/KVMとQEMUをインストールする。

~~~
$ sudo apt install qemu qemu-kvm libvirt-daemon libvirt-clients virt-manager virt-top
~~~

インストールが完了すると、virbr0 が作成され、DHCPとNAT機能が稼働する。新たな仮想サーバーをインストールする際に、この環境はたいへん便利であり、Open vSwitchで置き換えることができないため、この設定は残しておき、併用する。

~~~
$ virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

$ virsh net-dumpxml default
<network>
  <name>default</name>
  <uuid>18ff88ef-50e8-4b42-acfc-811f1fc01b3b</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:57:76:3b'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>
~~~

これにより、仮想サーバーを起動すると、ブリッジI/F virbr0 と接続された vnet0 が作られる。

~~~
$ ip link show vnet0
9: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master virbr0 state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether fe:54:00:e8:dd:e9 brd ff:ff:ff:ff:ff:ff
~~~

余談であるが、仮想ブリッジなどと仮想サーバーを繋げるインタフェースには、vnet, macvtap, tuntapなどがある。その違いについて簡単に整理しておく。

「tuntap」は IP レベルで動作し、一般的な用途は VPN 接続を確立することです。これは、VPN ソフトウェアがネットワークに送信される前にデータを暗号化する機会を与えることができる。

「mactap」は、レイヤー２で実行されているため、任意のレイヤー３プロトコルを転送でき、ポイントツーポイント接続に限定されない。TAPデバイスはブリッジの一部にすることができ、数のゲスト マシンに仮想ネットワーク アダプタを提供するために仮想化システムで一般的に使用される。

「vnet」は、tuntapよりもユーザー モード ソフトウェアがインターフェイスをより柔軟に構成できるようにするため最適化されたデータ プレーンを備えている。


#### 参考資料
* What's the difference between tun/tap vs bridge+vnet vs macvtap? (For virtualization KVM), https://askubuntu.com/questions/383082/whats-the-difference-between-tun-tap-vs-bridgevnet-vs-macvtap-for-virtualiza



## Open vSwitchのインストール

次にOpen vSwitchをインストールする。このコマンドだけで、Open vSwitchが利用可能になるので驚きだ。

~~~
$ sudo apt install openvswitch-switch openvswitch-common
~~~

バージョン 2.13.8 は、2022年6月にリリースされた。半年ほど経過しているが、そのまま利用する。

~~~
# ovs-vsctl show
1f641b32-4d5f-48e8-a25a-c1ac26fd8d3a
    ovs_version: "2.13.8"
~~~

仮想ブリッジ ovsbr0 を追加する。

~~~
# ovs-vsctl add-br ovsbr0
# ovs-vsctl show
1f641b32-4d5f-48e8-a25a-c1ac26fd8d3a
    Bridge ovsbr0
        Port ovsbr0
            Interface ovsbr0
                type: internal
    ovs_version: "2.13.8"
~~~

物理NICのenp5s0f0をトランクポートに設定する。これによりタグのついたフレームを扱う。VLAN IDは1001と1002を利用する。1001は仮想サーバー間のコミュニケーションのためのもので、1002 はインターネットからアクセス可能なDMZのネットワークである。

~~~
# ovs-vsctl add-br ovsbr0
# ovs-vsctl add-port ovsbr0 enp5s0f0
# ovs-vsctl set port enp5s0f0 trunk=1001,1002
~~~

設定内容確認として以下の表示は、、物理NIC enp5s0f0 に VLAN ID 1001,1002 の２つの経路を共有させるトランクポートに設定されたことが、読み取れる。

~~~
# ovs-vsctl show
1f641b32-4d5f-48e8-a25a-c1ac26fd8d3a
    Bridge ovsbr0
        Port enp5s0f0
            trunks: [1001, 1002]
            Interface enp5s0f0
        Port ovsbr0
            Interface ovsbr0
                type: internal
    ovs_version: "2.13.8"
~~~

これで Open vSwitchの設定は完了となる。


## Libvirt の仮想ネットワークの設定

Libvertのネットワークに、Open vSwitch へ接続を追加する。これにより Libvirtのコマンドで、Open vSwitchの接続を指定できるようになる。ポートグループにVLAN IDと関連づけることで、仮想マシン（ドメイン）定義する際に、仮想NICにVLANを対応付けることを可能にする。

~~~file: ovs-network.xml
<network>
  <name>ovs-network</name>
  <forward mode='bridge'/>
  <bridge name='ovsbr0'/>
  <virtualport type='openvswitch'/>
  <portgroup name='vlan-0001' default='yes'>
  </portgroup>
  <portgroup name='vlan-1001'>
    <vlan>
      <tag id='1001'/>
    </vlan>
  </portgroup>
  <portgroup name='vlan-1002'>
    <vlan>
      <tag id='1002'/>
    </vlan>
  </portgroup>
  <portgroup name='vlan-all'>
    <vlan trunk='yes'>
      <tag id='1001'/>
      <tag id='1002'/>
    </vlan>
  </portgroup>
</network>
~~~

次のコマンドで、上記XMLファイルによりOpen vSwitchの仮想ネットワークを定義する。そして、自動スタートになるように、コマンドを実行する。

~~~
# virsh net-define ovs-network.xml
# virsh net-start ovs-network
# virsh net-autostart ovs-network
# virsh net-list
 Name          State    Autostart   Persistent
------------------------------------------------
 default       active   yes         yes
 ovs-network   active   yes         yes
~~~

これで、Libvirtの仮想ネットワークの設定が完了する。


## ハイパーバイザー #2 の設定

ハイパーバイザー#1 (HV-1)と同様に、Libvirt, Open vSwitchの導入と設定を実施する。


## L2スイッチの設定

HV-1とHV-2の上に設定したVLANを繋ぐための設定をL2-SWに入れる。L2スイッチは、タグVLAN(IEEE802.1Q VLAN tagging)とポートVLANの機能を備えるスマートスイッチやマネージドスイッチと呼ばれる製品であれば動作すると考えられる。筆者は低価格な Buffalo BS-GS2024 を使用した。


次の図は、同スイッチの管理画面の一部で、VLAN設定を概観できるVLANステータスを表示するページである。

![pic-5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/6dda347f-ff8f-0f3d-4a3f-fc2ff918fb0c.png)

ここで、ポート２にハイパーバイザー１(HV-1)のタグVLANポートenp5s0f0 を接続する。そして、同様にポート５にハイパーバイザー２(HV-2)を接続する。これにより、HV1上のVLAN 1001と、HV2上のVLAN 1001が、L2スイッチをブリッジとして接続され、それぞれに接続された仮想サーバーは、異なるハイパーバイザー上にあっても疎通できる。ブリッジ接続のためネットワークアドレスは同じにできる。

一方、ポート８、ポート９では、イーサーネットパケットのフレームから、VLANタグを外す(Static Untagged)。これにより通常のイーサーネットフレームによって、パソコンなどを接続して通信できる。

この設定では、ポート８にUTPケーブルを接続すれば、VLAN 1002に接続された仮想サーバーのNICとだけ通信できる。もちろん、IPアドレスやサブネットマスクの設定は別途必要だ。

以上で、仮想サーバーを起動するためのネットワーク設定が完了した。

#### 参考資料
* Buffalo, BS-GS2024, https://www.buffalo.jp/product/detail/bs-gs2024.html


## 仮想サーバーの設定と起動

これから HV-1 と HV-2 で、Open vSwitch のブリッジ ovsbr0 の VLANに接続するために、仮想マシンの定義に手を加える必要がある。

GUI画面の「Virtual Machine Manager」 または CLIの「virt-install」を利用して、仮想マシンに Ubuntu 20.04 Server の Linux OSをインストールする。ここではGUIを主に扱う。

仮想マシンのセットアップの段階で、「Virtual Machine Manager」のメニューから「New Virtual Machine」を選択して　5/5 の画面に「Network selection」の項目がある。この選択肢の中に、以下２つがある。

* Virtual network 'default': NAT
* Virtual network 'ovs-network': Bridge network (OpenVSwitch)

「'default': NAT」は、インストール時に自動設定されるもので、選択することで、仮想サーバーのホストになっているサーバーのIPアドレスを使って、インターネットにアクセスすることができる。インストールする際にはインターネットからダウンロードするパッケージがあるため、こちらの選択肢が適切だ。

「'ovs-network': Bridge network (OpenVSwitch)」は、今回設定したもので、L2スイッチを介して、別のハイパーバイザー上の仮想ネットワークへ接続されている。これを選択すると、Portgroupの選択肢の中で、VLANを選択できる。

インストール完了後に、「Virtual Machine Manager」から該当の仮想マシンを選び「 Virtual Machine Detail」で構成情報を表示して、NICの接続先を「'ovs-network': Bridge network (OpenVSwitch)」へ切り替えること、そして、NICを追加することもできる。

ここでは詳しく扱わないが、次のコマンドを利用して、仮想マシンの定義をXMLファイルを直接編集することもできる。

~~~
$ virsh edit vm-1
~~~

この様にして、仮想マシンを Open vSwitch上のVLANへ繋ぐことができる。DHCPが設定されていないので、手操作で、NICにIPアドレスを設定しなければならない。


## 疎通テスト

疎通テストの構成が次の図となる。この図では、テスト用のPCを２番ポートに接続して、IPアドレスを192.168.1.200と172.16.0.18と設定を切り替えながらpingコマンドを実行することで確認ができる。

この構成での疎通テストのケースと予想結果を挙げておく。VLAN 1001とVLAN 1002 は論理的に隔離されているため、ポート２番に接続されているPCのIPアドレス 192.168.1.200からは、何処にも疎通できない。そして、172.16.0.18に変更することで、VLAN 1001に接続されたNICとだけ疎通することができる。

![pic-7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/ab890f42-6b97-b0aa-acf8-152d2cafcfa0.png)

しかし、VLANの隔離性をテストするのであれば、同じネットワークアドレスのIP間でテストするのが解り易いと、書いていて思った。もし、読者が追検証される時は参考にして頂きたい。


## まとめ

Linuxの仮想化環境 Libvirt / KVM と Open vSwitch と組み合わせ、VLANを設定可能なスマートスイッチに接続することで、VLANを活かした柔軟なネットワーク環境が作れることが確認できた。

Open vSwitch は、OpenFlow スイッチとして OpenFlow プロトコルにより、OpenFlow コントローラーと連携できる。さらに Open Virtual Network による仮想ルーターなどと組み合わせることが可能だ。これによりクラウドの様な大規模な仮想プライベートネットワーク(Virtual Private Network)環境を構築する基礎技術となるのだ。