Metonymical Deflection

ゆるく日々のコト・たまにITインフラ

Windows10 VLAN Interface設定

PowerShellによるWindows10でのVLAN Interface設定方法について記載します。

以前の記事ではWindowsIntelNICを使用したVLAN Interfaceの設定方法を書きました。しかし、Windows10 1809+Intel PROSet 23.5.2の構成で試したところ、VLANやチームなどのタブが表示されず、困り果てたので、PowerShellによる設定方法を記載します。

2021/06/26Update
GUIによるWindows10でのVLAN Interface設定方法について記載しました。
metonymical.hatenablog.com

1.構成

1-1.環境
OS                               : Windows10pro Ver:1809 Build:17763.437 
NIC                              : Intel I350, I219-V(OnboardNIC)
Driver                           : Intel PROSet 23.5.2

2020/02/15追記
OS                               : Windows10pro Ver:1909 Build:18363.657 
NIC                              : Intel I350
Driver                           : Intel PROSet 25.0.0.0

上記の構成でNICのVLAN設定を行おうとしたら、VLANやチーム化のタブが表示されなかった場合の対処方法となります。

2.Intel PROSetのDL

以下のIntelサイトよりPROSetドライバをDLします。
イーサネット製品」を選択の上、絞り込み条件にて「Windows10」 を選択してください。
downloadcenter.intel.com

以下のような画面でDLします。
f:id:metonymical:20190504060825p:plain

3.Intel PROSetのインストール

exe形式のファイル*1なので、そのまま実行してください。
インストール時の注意点として、セットアップ・オプション時に
「Advanced Network Services」にチェックを入れてください。
f:id:metonymical:20190504061214p:plain

3-1.NICのプロパティを開いて構成画面を確認

構成をクリックします。
f:id:metonymical:20190504061620p:plain
現在は、VLANやチーム化のタブが表示されません。
f:id:metonymical:20190504061717p:plain
ちなみに、以前は以下の画面のように表示されており、ここから設定が可能でした。
f:id:metonymical:20190504055949j:plain

ここから、PowerShellを使って、VLAN設定を行っていきます。

4.PowerShellによるVLAN設定

管理者権限にてPowerShellを起動してください。

4-1.コマンド

以下にコマンドのみ記載しておきます。

IntelNIC用のモジュールをインポート
Import-Module -Name "C:\Program Files\Intel\Wired Networking\IntelNetCmdlets"

GetコマンドにてNICの名前(ParentName)を取得
Get-IntelNetAdapter

NICの名前を-ParentName に指定し、追加したいVLANIDを指定
Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 30

追加したいVLANIDを複数指定の場合
Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 30,35,39

追加したいVLANIDを複数かつ連続指定の場合
Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID (300..304)

VLANIDや名前の変更
Set-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 3 -NewVLANID 300 -NewVLANName "VLAN300"

VLAN Interfaceの削除
Remove-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 30
4-2.IntelNetCmdletsモジュールのインポート

PowerShellにIntelNetCmdletsモジュールをインポートします。
出力結果は特に表示されません。

PS C:\Windows\system32> Import-Module -Name "C:\Program Files\Intel\Wired Networking\IntelNetCmdlets"
4-3.IntelNICの情報取得

以下のコマンドで現在のIntelNICの状態を取得します。
次項にてNameに表示されたNICの名前をParentNameとして指定するため、テキストエディタなどにコピーしておいてください。

PS C:\Windows\system32> Get-IntelNetAdapter

Location        Name                                                           ConnectionName            LinkStatus
--------        ----                                                           --------------            ----------
0:31:6:0        Intel(R) Ethernet Connection (7) I219-V                       local                     1.00 Gbps ...
5:0:0:0         Intel(R) I350 Gigabit Network Connection                      physical1                 1.00 Gbps ...
5:0:1:0         Intel(R) I350 Gigabit Network Connection #2                   physical2                 1.00 Gbps ...
4-4.VLAN Interfaceの追加 その1

以下のコマンドにてVLAN Interfaceを追加します。
ここでは例として、物理NICIntel(R) I350 Gigabit Network Connectionに、VLANID300のVLAN Interfaceを追加しています。

PS C:\Windows\system32> Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 300

VLANID VLANName                                       ParentName
------ --------                                       ----------
300    VLAN300                                        Intel(R) I350 Gigabit Network Connection
4-5.VLAN Interfaceの追加 その2

以下のコマンドにてVLAN Interfaceを複数追加します。
ここでは例として、物理NICIntel(R) I350 Gigabit Network Connectionに、VLANID300と304のVLAN Interfaceを追加しています。VLANIDはカンマで区切ってください。

PS C:\Windows\system32> Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 300,304

VLANID VLANName                                       ParentName
------ --------                                       ----------
300    VLAN300                                        Intel(R) I350 Gigabit Network Connection
304    VLAN304                                        Intel(R) I350 Gigabit Network Connection
4-6.VLAN Interfaceの追加 その3

以下のコマンドにてVLAN Interfaceを複数かつ連続追加します。
ここでは例として、物理NICIntel(R) I350 Gigabit Network Connectionに、VLANID300から304のVLAN Interfaceを追加しています。VLANIDは(300..304)として指定してください。

PS C:\Windows\system32> Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID (300..304)

VLANID VLANName                                       ParentName
------ --------                                       ----------
300    VLAN300                                        Intel(R) I350 Gigabit Network Connection
301    VLAN301                                        Intel(R) I350 Gigabit Network Connection
302    VLAN302                                        Intel(R) I350 Gigabit Network Connection
303    VLAN303                                        Intel(R) I350 Gigabit Network Connection
304    VLAN304                                        Intel(R) I350 Gigabit Network Connection

VLAN Interfaceが一つも作成されていない状態で、上記コマンドを打つと、私の環境ではVLAN Interface作成まで(プロンプトが出力結果を返すまで)に5分程度掛かりました。

4-7.VLAN Interfaceの追加 その4

以下のコマンドにて、UnTag(タグなし)のVLAN Interfaceを追加します。
ここでは例として、物理NICIntel(R) I350 Gigabit Network Connectionに、VLANID0のVLAN Interfaceを追加しています。
また、UnTagのVLAN Interfaceを追加する場合、物理NICに1つ以上のVLAN Interfaceを作成した後に追加してください。

PS C:\Windows\system32> Add-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection" -VLANID 0

VLANID VLANName                                       ParentName
------ --------                                       ----------
0      タグなし                                       Intel(R) I350 Gigabit Network Connection
4-8.VLAN Interfaceの名前編集

以下のコマンドにて、タグなしのVLAN Nameを変更します。
ここでは例として、物理NICIntel(R) I350 Gigabit Network ConnectionのVLANID0のVLAN Nameを変更しています。
2Byte文字は極力使用したくないので。。

PS C:\Windows\system32> Set-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection"  -VLANID 0 -NewVLANName "untag"

VLANID VLANName                                       ParentName
------ --------                                       ----------
0      untag                                          Intel(R) I350 Gigabit Network Connection

また、Set-IntelNetVLANコマンドでは、VLANIDを変更することも可能です。
ここでは例として、物理NICIntel(R) I350 Gigabit Network ConnectionのVLANID300のVLANIDを3に変更しています。
但し、以下のコマンドのみですと、VLAN Nameは変更されないため、先のコマンドにてVLAN Nameも変更しておいてください。また、併用も可能です。

PS C:\Windows\system32> Set-IntelNetVLAN -ParentName "Intel(R) I350 Gigabit Network Connection"  -VLANID 300 -NewVLANID 3

VLANID VLANName                                       ParentName
------ --------                                       ----------
3      VLAN300                                        Intel(R) I350 Gigabit Network Connection

ちなみに、上記のVLAN Nameは以下の画面で表示されます。
実際はレジストリ上に記載されるため、極力2Byte文字は使用したくないと考えています。
f:id:metonymical:20190504071841p:plain

5.設定の確認

5-1.VLAN Interfaceの確認

以下のコマンドにて、設定したVLAN Interfaceを確認することが可能です。

PS C:\Windows\system32> Get-IntelNetVLAN

VLANID VLANName                                       ParentName
------ --------                                       ----------
301    VLAN301                                        Intel(R) I350 Gigabit Network Connection
303    VLAN303                                        Intel(R) I350 Gigabit Network Connection
300    VLAN300                                        Intel(R) I350 Gigabit Network Connection
0      untag                                          Intel(R) I350 Gigabit Network Connection
302    VLAN302                                        Intel(R) I350 Gigabit Network Connection
304    VLAN304                                        Intel(R) I350 Gigabit Network Connection

6.補足

6-1.ヘルプの使用

以下のように、helpと入力した後、コマンドに引数なしで実行するとヘルプが表示されます。

PS C:\Windows\system32> help Add-IntelNetVLAN

名前
    Add-IntelNetVLAN

概要
    アダプターまたはインテル(R) ANS チームのいずれかで VLAN を作成します。


構文
    Add-IntelNetVLAN []

    Add-IntelNetVLAN []


説明
    Add-IntelNetVLAN は、アダプターまたはインテル(R) ANS チームのいずれかに新しい VLAN を追加できます。新しい VLAN は、1 つまたは複数の VLAN ID を指定することによって追加されます。デバイ
    スの名前またはデバイスのオブジェクトのいずれかを使用して、親デバイスを指定できます。テーブル表示で新しい VLAN を表示します。

    アダプターまたはチームに最大 64 個の VLAN を追加できます。

    注:Windows* 10 搭載のシステムでインテル(R) アドバンスト・ネットワーク・サービス (インテル(R) ANS) チームまたは VLAN を作成するには、最新の Microsoft* Windows* 10 更新プログ
    ラムをインストールする必要があります。


関連するリンク
    Get-IntelNetAdapter
    Get-IntelNetTeam

注釈
    例を参照するには、次のように入力してください: "get-help Add-IntelNetVLAN -examples".
    詳細を参照するには、次のように入力してください: "get-help Add-IntelNetVLAN -detailed".
    技術情報を参照するには、次のように入力してください: "get-help Add-IntelNetVLAN -full".
    オンライン ヘルプを参照するには、次のように入力してください: "get-help Add-IntelNetVLAN -online"

さらに、詳細やコマンド例を確認したい場合は、注釈に従って、以下のようにコマンドを入力してください。

get-help Add-IntelNetVLAN -examples
get-help Add-IntelNetVLAN -detailed
get-help Add-IntelNetVLAN -full

初回は以下のようにアップデートを要求されるため、yを入力してアップデートしてください。

PS C:\Windows\system32> get-help Add-IntelNetVLAN -examples

Update-Help を実行しますか?
Update-Help コマンドレットは、Windows PowerShell モジュールの最新のヘルプ
ファイルをダウンロードして、コンピューターにインストールします。Update-Help
コマンドレットの詳細については、https://go.microsoft.com/fwlink/?LinkId=210614 を参照してください。
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"): y

2020/02/15 追記
Windows10 1809→1909にVersion Upしたところ、VLAN Interfaceの設定が全て消えました。
このため、Version Up後は再度作り直しが必要となります。
また、作り直した後、コンパネ上の名前*2が「イーサネットxx」と表示されます。
これを元々使っていた名前(例えば、vlan300)に変更しようとすると、以下のエラーが表示され、同じ名前に設定することができません。
f:id:metonymical:20200216002705p:plain
このため、「vlan0300」や「v300」など名前を工夫してください。*3


加えて、IntelNICドライバのVersionは24.3以降の方が良さそうです。
情報ソースは以下のURLとなります。
https://forums.intel.com/s/question/0D50P00004Vdz0P/windows-1909?language=ja

私もVer23.5.2のままだったことに起因したのか、VLAN Interfaceの有効化ができなくなりました。
このため、IntelNICドライバをVer25.0.0.0へアップデートしたところ正常に動作することを確認しました。


以上です。

7.最後に

以下のサイトを参考にさせて頂きました。
https://www.intel.co.jp/content/www/jp/ja/support/articles/000023545/network-and-i-o.html

以前は、Windows Server2016かつPowerShellのみでVLAN Interface作成が可能だった時期があったと思います。その後、Intel PROSetのVer22系にてWindows10でもVLAN InterfaceがGUI(NICの構成のプロパティ)で作成可能になりました。

しかし、Windows10でできるようになったものの、VerUpするたびにVLAN Interfaceが消えたりしていたため、一抹の不安を感じていたのですが、Intelのサイトやフォーラムを読んでいくと、いろいろと試行錯誤していた変遷がわかりました。NICの構成のプロパティでは、色々と制約があったようで、今回ご紹介したPowerShellによる設定となったようです。

今後はIntel ACU(Adapter Configuration Utility)上で設定できるみたいなので、それを待ちたいと思います。

また、今回はチーミングについて触れていませんが、上記のIntelサイトにはチーミングコマンドについても記載があるため、興味がある方はヘルプを参照しながら設定してみてください。

*1:32bit版であればPROWin32.exeなど

*2:Power Shellで設定するVLAN Nameではなく、コンパネ上の表示名の方です。

*3:VerUp前の名前はレジストリ上にゴミとして残っていますが、これを消すのリスクの方が大きいと思いますので。

CentOS7 ovs(Open vSwitch)+DPDKのビルドとネットワーク設定方法

CentOS7によるovs(Open vSwitch)+DPDKのビルドとネットワーク設定方法について記載しました。
前回記事にDPDKを実装しました。
当初はOvSもDPDKもrpmビルドしたものをインストールするところまではOKだったのですが、いざ仮想マシンからトラフィックを流すと上手く流れず・・・だったので、ソースからビルドしました。

1.構成

1-1.環境
筐体                             : ProLiant DL360e Gen8
System ROM                       : P73 01/22/2018
NIC                              : Intel X540-AT2
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
ovs                              : 2.10.90
DPDK                             : 18.11

2020/08/09追記
以下のOvS Versionにて動作確認を行ったところ、一部手順が変わっていたため、「2020/08/09追記」として追記します。

ovs                              : 2.13.0
DPDK                             : 19.11.2
1-2.全体の流れ

事前準備
DPDKソースビルド
OvSソースビルド
OvS+DPDKのネットワーク設定
仮想マシンのvirsh edit

2.事前準備

2-1.qemu-kvm-evのインストール

CentOS7のqemu-kvmですと、vHostUserClientに対応していないため、qemu-kvm-evを事前にインストールしておきます。

yum -y install centos-release-qemu-ev
sed -i -e "s/enabled=1/enabled=0/g" /etc/yum.repos.d/CentOS-QEMU-EV.repo
yum --enablerepo=centos-qemu-ev -y install qemu-kvm-ev
systemctl restart libvirtd
/usr/libexec/qemu-kvm -version

qemu-evリポジトリファイルのインストール
qemu-evリポジトリの常時無効化*1
qemu-kvm-evのインストール
libvirtd再起動
qemu-kvmのVersion確認

2-2.qemu-kvmの実行ユーザをrootへ変更

qemu-kvmの実行ユーザをqemu→rootに変更します。

vi /etc/libvirt/qemu.conf

user = "root"  #コメントを外す
group = "root"  #コメントを外す

viで/etc/libvirt/qemu.confを開き、上記ユーザとグループの行をコメントアウト

2-3.必要なパッケージのインストール
yum -y install libpcap-devel numactl-devel

2020/08/09追記

yum -y install libcap-ng-devel python3
2-4.HugePageとIOMMUの有効化
sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ default_hugepagesz=1G hugepagesz=1G hugepages=16\"/g" /etc/default/grub
sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ intel_iommu=on iommu=pt pci=realloc\"/g" /etc/default/grub
grub2-mkconfig -o /etc/grub2.cfg
reboot

hugepageの有効化
iommuの有効化*2
grubに設定反映
再起動

2-5.HugePageの確認とマウント
grep Huge /proc/meminfo

出力例
# grep Huge /proc/meminfo
AnonHugePages:    135168 kB
HugePages_Total:      16
HugePages_Free:       16
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB

vi /etc/fstab

最終行に以下を追記
nodev  /mnt/huge_1GB hugetlbfs pagesize=1GB    0 0

HugePageの割り当て状況確認
HugePageの永続化マウント

2-6.vfio-pciの設定
echo "vfio-pci" > /etc/modules-load.d/vfio-pci.conf
echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modules-load.d/iommu.conf

vfio-pciの永続化設定
vfio-pciのiommu利用の永続化

2-6’.uio_pci_generic設定

vfio-pciが利用できない場合は、uio_pci_genericを使用します。

echo "uio_pci_generic" > /etc/modules-load.d/uio_pci_generic.conf

uio_pci_genericの永続化設定

ここまでの準備が整ったら一旦再起動してください。

reboot

3.DPDKソースビルド

3-1.ビルド環境準備

ビルド環境の準備をします。

cd /usr/src/
wget http://fast.dpdk.org/rel/dpdk-18.11.tar.xz
tar xf dpdk-18.11.tar.xz
export DPDK_DIR=/usr/src/dpdk-18.11
cd $DPDK_DIR

ディレクトリ移動
ソースのダウンロード
ソースのtarファイルを解凍
パスのエクスポート
ディレクトリ移動

2020/08/09追記

cd /usr/src/ && \
wget http://fast.dpdk.org/rel/dpdk-19.11.2.tar.xz && \
tar xf dpdk-19.11.2.tar.xz && \
export DPDK_DIR=/usr/src/dpdk-stable-19.11.2 && \
cd $DPDK_DIR
3-2.ビルド

ソースからビルドします。

export DPDK_TARGET=x86_64-native-linuxapp-gcc
export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET
make install T=$DPDK_TARGET DESTDIR=install

パスのエクスポート
パスのエクスポート
ビルド&インストール

多少時間は掛かりますが、最後の方は以下のような出力がでれば正常にビルドが完了しています。

  INSTALL-APP dpdk-test-eventdev
  INSTALL-MAP dpdk-test-eventdev.map
Build complete [x86_64-native-linuxapp-gcc]
================== Installing install/
Installation in install/ complete

4.OvSソースビルド

4-1.ビルド環境準備

ビルド環境の準備をします。

cd /usr/src
git clone https://github.com/openvswitch/ovs.git

ディレクトリ移動
git cloneにてソースのダウンロード

4-2.ビルド

ソースからビルドします。

cd /usr/src/ovs
./boot.sh
./configure --with-dpdk=$DPDK_BUILD
make && make install

ディレクトリ移動
boot.sh実行
configure実行
ビルド&インストール

2019/12/28 追記
上記のmakeでエラーとなる場合は以下で実施してみてください。

cd /usr/src/ovs
./boot.sh
./configure --with-dpdk=$DPDK_BUILD CFLAGS="-g -O2 -msse4.1" && \
make && make install

上記のうち、$DPDK_BUILDは以下のパスとなります。

/usr/src/dpdk-18.11/x86_64-native-linuxapp-gcc

DPDKビルドの流れで記載しているため、$DPDK_BUILDをそのまま記載していますが、configure実行時にNo such file or directoryが表示されるようであれば、上記の絶対パスを以下のように記載して実行ください。

./configure --with-dpdk=/usr/src/dpdk-18.11/x86_64-native-linuxapp-gcc


多少時間は掛かりますが、最後の方は以下のような出力がでれば正常にビルドが完了しています。

make[3]: Leaving directory `/usr/src/ovs'
make[2]: Leaving directory `/usr/src/ovs'
make[1]: Leaving directory `/usr/src/ovs'

2020/08/09追記
4-1と4-2を合わせて以下の手順でインストールしてください。

cd /usr/src && \
wget https://www.openvswitch.org/releases/openvswitch-2.13.0.tar.gz && \
tar zxvf openvswitch-2.13.0.tar.gz

cd /usr/src/openvswitch-2.13.0 && \
./boot.sh && \
./configure --with-dpdk=$DPDK_BUILD CFLAGS="-Ofast -msse4.2 -mpopcnt" && \
make && make install

5.OvS+DPDKのネットワーク設定

5-1.全体構成

f:id:metonymical:20190106225241j:plain
前回記事の構成図と比較してください。
グレーアウト&斜体文字になっているのが前回設定した箇所です。
今回は(1)~(6)の黒文字になっている箇所を設定していきます。

5-2.全体の流れ ~概要~
  1. DPDKにバインド:(1)(2)
  2. Bridge作成:(3)
  3. Bond作成:(4)
  4. vHostUserClientポート作成:(5)
  5. 仮想マシンの設定:(6)
5-3.コマンド投入前準備1

コマンド投入前には以下のようにパスを通しておいてください。*3

vi /root/.bash_profile

PATH=$PATH:$HOME/bin:/usr/local/share/openvswitch/scripts:/usr/src/dpdk-18.11/usertools
export PATH

2020/08/09追記

vi /root/.bash_profile

PATH=$PATH:$HOME/bin:/usr/local/share/openvswitch/scripts:/usr/src/dpdk-stable-19.11.2/usertools
export PATH
5-4.コマンド投入前準備2

OvSを起動後、DPDK周りの詳細設定を追加しておきます。

ovs-ctl --system-id=random start
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem=1024,1024
ovs-vsctl --no-wait set Open_vSwitch . other_config:vhost-iommu-support=true
ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x33
ovs-vsctl --no-wait get Open_vSwitch . other_config

OvSサービスの開始
DPDKの初期化
NUMA毎のメモリ設定(単位MB)
PMD-CPUマスクの設定
設定内容の確認

上記のうち、dpdk-init=true以外はチューニングパラメータなので、設定しなくてもとりあえずは動きます。

5-5.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。

1.DPDKにバインド
(1)
dpdk-devbind.py --status
dpdk-devbind.py --bind=vfio-pci ens1f0
(2)
dpdk-devbind.py --bind=vfio-pci ens1f1
dpdk-devbind.py --status

2.Bridge作成
(3)
ovs-ctl --system-id=random stop
ovs-ctl --system-id=random start
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev

3.Bond作成
(4)
ovs-vsctl add-bond ovsbr0 bond0 dpdk0 dpdk1 \
 vlan_mode=trunk trunks=11,300-304 \
 bond_mode=balance-tcp lacp=active other_config:lacp-time=fast \
 -- set Interface dpdk0 type=dpdk options:dpdk-devargs=0000:08:00.0 \
 -- set Interface dpdk1 type=dpdk options:dpdk-devargs=0000:08:00.1

4.vHostUserClientポート作成
(5)
mkdir -p /usr/local/openvswitch/
touch /usr/local/openvswitch/vhuc0

ovs-vsctl add-port ovsbr0 vhuc0 \
 vlan_mode=access tag=300 \
 -- set Interface vhuc0 type=dpdkvhostuserclient \
 options:vhost-server-path=/usr/local/openvswitch/vhuc0

5.仮想マシンの設定
(6)
virsh edit Guest3

  <currentMemory unit='KiB'>1048576</currentMemory>
  <memoryBacking>
    <hugepages>
      <page size='1048576' unit='KiB' nodeset='0'/>
    </hugepages>
  </memoryBacking>
  
  <cpu mode='host-passthrough' check='none'>
    <numa>
      <cell id='0' cpus='0' memory='1048576' unit='KiB' memAccess='shared'/>
    </numa>
  </cpu>

  <interface type='vhostuser'>
    <source type='unix' path='/usr/local/openvswitch/vhuc0' mode='server'/>
    <model type='virtio'/>
  </interface>青=追記,緑=置換

2020/08/09追記
仮想マシンのメモリは8GB、Hugepageは1GBとすることで、どこがどこに対応しているのかわかるように記載しました。
また、最新の公式DocではCPU Pinningを実施していましたので、それに合わせています。
加えて「cpuset」を意図的に0-3から10-13に変えることにより、vCPUとPinningされる実際のCPUコアがどこに対応するかをわかるように記載しました。
さらに付け加えると、OvS-DPDKで使用しているCPUコアと被らないようにする意図もあります。*4

5.仮想マシンの設定
(6)
virsh edit Guest3

  <currentMemory unit='KiB'>8388608 </currentMemory>
  <memoryBacking>
    <hugepages>
      <page size='1048576' unit='KiB' nodeset='0'/>
    </hugepages>
  </memoryBacking>
  <vcpu placement='static'>4</vcpu>
  <cputune>
    <shares>8192</shares>
    <vcpupin vcpu='0' cpuset='10'/>
    <vcpupin vcpu='1' cpuset='11'/>
    <vcpupin vcpu='2' cpuset='12'/>
    <vcpupin vcpu='3' cpuset='13'/>
    <emulatorpin cpuset='10-13'/>
  </cputune>

  <cpu mode='host-model' check='partial'>
    <model fallback='allow'/>
    <numa>
      <cell id='0' cpus='0-3' memory='8388608' unit='KiB' memAccess='shared'/>
    </numa>
  </cpu>

  <interface type='vhostuser'>
    <source type='unix' path='/usr/local/openvswitch/vhuc0' mode='server'/>
    <model type='virtio'/>
  </interface>青=追記,緑=置換

6.DPDKにバインド

Kernel上で動作しているX540をDPDK上で動作されるようにバインドします。
(1)
dpdk-devbind.py --status
dpdk-devbind.py --bind=vfio-pci ens1f0
(2)
dpdk-devbind.py --bind=vfio-pci ens1f1
dpdk-devbind.py --status

[root@c765 ~]# dpdk-devbind.py --status

Network devices using kernel driver
===================================
0000:02:00.0 'I350 Gigabit Network Connection 1521' if=eno1 drv=igb unused=vfio-pci,uio_pci_generic *Active*
0000:02:00.1 'I350 Gigabit Network Connection 1521' if=eno2 drv=igb unused=vfio-pci,uio_pci_generic
0000:02:00.2 'I350 Gigabit Network Connection 1521' if=eno3 drv=igb unused=vfio-pci,uio_pci_generic
0000:02:00.3 'I350 Gigabit Network Connection 1521' if=eno4 drv=igb unused=vfio-pci,uio_pci_generic
0000:08:00.0 'Ethernet Controller 10-Gigabit X540-AT2 1528' if=ens1f0 drv=ixgbe unused=vfio-pci,uio_pci_generic
0000:08:00.1 'Ethernet Controller 10-Gigabit X540-AT2 1528' if=ens1f1 drv=ixgbe unused=vfio-pci,uio_pci_generic

[root@c765 ~]# dpdk-devbind.py --bind=vfio-pci ens1f0
[root@c765 ~]# dpdk-devbind.py --bind=vfio-pci ens1f1
[root@c765 ~]# dpdk-devbind.py --status

Network devices using DPDK-compatible driver
============================================
0000:08:00.0 'Ethernet Controller 10-Gigabit X540-AT2 1528' drv=vfio-pci unused=ixgbe,uio_pci_generic
0000:08:00.1 'Ethernet Controller 10-Gigabit X540-AT2 1528' drv=vfio-pci unused=ixgbe,uio_pci_generic

Network devices using kernel driver
===================================
0000:02:00.0 'I350 Gigabit Network Connection 1521' if=eno1 drv=igb unused=vfio-pci,uio_pci_generic *Active*
0000:02:00.1 'I350 Gigabit Network Connection 1521' if=eno2 drv=igb unused=vfio-pci,uio_pci_generic
0000:02:00.2 'I350 Gigabit Network Connection 1521' if=eno3 drv=igb unused=vfio-pci,uio_pci_generic
0000:02:00.3 'I350 Gigabit Network Connection 1521' if=eno4 drv=igb unused=vfio-pci,uio_pci_generic

バインドされると、X540がNetwork devices using DPDK-compatible driverに表示されます。

今回利用するドライバはvfio-pciですが、uio_pci_genericでも利用可能です。
利用したい場合は、以下のように変更すればOKです。

dpdk-devbind.py --bind=uio_pci_generic ens1f0

また、vfio-pciを利用するにあたり、ProLiant DL360G8を使用している方はRMRR設定が必要になる場合があります。
以下のサイトを参考にしてみてください。
DPDK and RMRR Compatibility Issues on the HP Proliant DL360e G8 | www.jimmdenton.com
https://support.hpe.com/hpsc/doc/public/display?sp4ts.oid=7271259&docId=emr_na-c04781229&docLocale=ja_JP


7.Bridge作成

念のため、ovsの再起動をした後、Bridge作成を行ってください。
(3)
ovs-ctl --system-id=random stop
ovs-ctl --system-id=random start
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev

[root@c765 ~]# ovs-ctl --system-id=random stop
Exiting ovs-vswitchd (20081)                               [  OK  ]
Exiting ovsdb-server (20063)                               [  OK  ]
[root@c765 ~]# ovs-ctl --system-id=random start
Starting ovsdb-server                                      [  OK  ]
Configuring Open vSwitch system IDs                        [  OK  ]
Starting ovs-vswitchd Zone 0: name:, len:0x35840, virt:0x17ffb35c0, socket_id:0, flags:0
physical segments used:
  addr: 0x140000000 iova: 0x140000000 len: 0x40000000 pagesz: 0x40000000
Zone 1: name:, len:0x80180, virt:0x17ff25800, socket_id:0, flags:0
physical segments used:
  addr: 0x140000000 iova: 0x140000000 len: 0x40000000 pagesz: 0x40000000
Zone 2: name:, len:0x980, virt:0x17fca4ac0, socket_id:0, flags:0
physical segments used:
  addr: 0x140000000 iova: 0x140000000 len: 0x40000000 pagesz: 0x40000000
Zone 3: name:, len:0x80180, virt:0x17fc14880, socket_id:0, flags:0
physical segments used:
  addr: 0x140000000 iova: 0x140000000 len: 0x40000000 pagesz: 0x40000000
Zone 4: name:, len:0x980, virt:0x17f993b40, socket_id:0, flags:0
physical segments used:
  addr: 0x140000000 iova: 0x140000000 len: 0x40000000 pagesz: 0x40000000
                                                           [  OK  ]
Enabling remote OVSDB managers                             [  OK  ]
[root@c765 ~]# ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev

正常にBridgeが作成されると上記のような出力となります。
ちなみに、name:, len:0x80180, virt:0x17ff25800, socket_id:0, flags:0といった出力より、X540の各ポート*5に対してメモリの割り当て行っているようです。

8.Bond作成

ovsbr0上にアップリンクポート*6を追加し、Bondを組みます。また、TrunkとLACPの設定も同時に追加します。
(4)
ovs-vsctl add-bond ovsbr0 bond0 dpdk0 dpdk1 \
vlan_mode=trunk trunks=11,300-304 \
bond_mode=balance-tcp lacp=active other_config:lacp-time=fast \
-- set Interface dpdk0 type=dpdk options:dpdk-devargs=0000:08:00.0 \
-- set Interface dpdk1 type=dpdk options:dpdk-devargs=0000:08:00.1
ovs-vsctl show

[root@c765 ~]# ovs-vsctl add-bond ovsbr0 bond0 dpdk0 dpdk1 \
>  vlan_mode=trunk trunks=11,300-304 \
>  bond_mode=balance-tcp lacp=active other_config:lacp-time=fast \
>  -- set Interface dpdk0 type=dpdk options:dpdk-devargs=0000:08:00.0 \
>  -- set Interface dpdk1 type=dpdk options:dpdk-devargs=0000:08:00.1
[root@c765 ~]# ovs-vsctl show
8daaa733-f6ef-4b67-a1a9-581875f33420
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            trunks: [11, 300, 301, 302, 303, 304]
            Interface "dpdk0"
                type: dpdk
                options: {dpdk-devargs="0000:08:00.0"}
            Interface "dpdk1"
                type: dpdk
                options: {dpdk-devargs="0000:08:00.1"}
    ovs_version: "2.10.90"
[root@c765 ~]#

上記のように追加されていればOKです。

FullTrunkにしたい場合は、以下の行を削除してください。

vlan_mode=trunk trunks=11,300-304 \

スイッチ側の仕様でLACPが組めない場合、以下のように修正してください。

 bond_mode=balance-tcp lacp=active other_config:lacp-time=fast \
 ↓
 bond_mode=balance-slb \

9.vHostUserClientポート作成

ovsbr0上にダウンリンクポート*7を追加します。
先にSocketファイルとなるvhuc0を作成し、その後ovsbr0にポートを追加します。
(5)
mkdir -p /usr/local/openvswitch/
touch /usr/local/openvswitch/vhuc0

ovs-vsctl add-port ovsbr0 vhuc0 \
vlan_mode=access tag=300 \
-- set Interface vhuc0 type=dpdkvhostuserclient \
options:vhost-server-path=/usr/local/openvswitch/vhuc0

ovs-vsctl show

[root@c765 ~]# mkdir -p /usr/local/openvswitch/
[root@c765 ~]# touch /usr/local/openvswitch/vhuc0
[root@c765 ~]# ovs-vsctl add-port ovsbr0 vhuc0 \
>  vlan_mode=access tag=300 \
>  -- set Interface vhuc0 type=dpdkvhostuserclient \
>  options:vhost-server-path=/usr/local/openvswitch/vhuc0
[root@c765 ~]# ovs-vsctl show
8daaa733-f6ef-4b67-a1a9-581875f33420
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            trunks: [11, 300, 301, 302, 303, 304]
            Interface "dpdk1"
                type: dpdk
                options: {dpdk-devargs="0000:08:00.1"}
            Interface "dpdk0"
                type: dpdk
                options: {dpdk-devargs="0000:08:00.0"}
        Port "vhuc0"
            tag: 300
            Interface "vhuc0"
                type: dpdkvhostuserclient
                options: {vhost-server-path="/usr/local/openvswitch/vhuc0"}
    ovs_version: "2.10.90"

上記のように追加されていればOKです。
ちなみに、vlan_mode=access tag=300としましたが、tag=300のみでも自動的にaccessポートにしてくれます。
また、trunkポートにしたい場合は、Bond設定で投入した「vlan_mode=trunk trunks=11,300-304」を参考に置換してください。

10.仮想マシンの設定

virshで仮想マシンの設定を編集します。
これにより、以下3点を実施します。
仮想マシン上でHugePageを利用可能にする
仮想マシンに対してCPUのパススルー機能を有効化する
・vHostUserにてNICを追加する
(6)
virsh edit Guest3

<currentMemory unit='KiB'>1048576</currentMemory>
<memoryBacking>
<hugepages>
<page size='1048576' unit='KiB' nodeset='0'/>
</hugepages>
</memoryBacking>


<cpu mode='host-passthrough' check='none'>
<numa>
<cell id='0' cpus='0' memory='1048576' unit='KiB' memAccess='shared'/>
</numa>
</cpu>

<interface type='vhostuser'>
<source type='unix' path='/usr/local/openvswitch/vhuc0' mode='server'/>
<model type='virtio'/>
</interface>


青=追記,緑=置換

[root@c765 ~]# virsh edit Guest3

  <currentMemory unit='KiB'>1048576</currentMemory>
  <memoryBacking>
    <hugepages>
      <page size='1048576' unit='KiB' nodeset='0'/>
    </hugepages>
  </memoryBacking>
  
  <cpu mode='host-passthrough' check='none'>
    <numa>
      <cell id='0' cpus='0' memory='1048576' unit='KiB' memAccess='shared'/>
    </numa>
  </cpu>

  <interface type='vhostuser'>
    <source type='unix' path='/usr/local/openvswitch/vhuc0' mode='server'/>
    <model type='virtio'/>
  </interface>青=追記,緑=置換

xmlファイルのため、virsh editで開くと、最初はどこを編集していいか探したり、迷ったりすると思いますが、通常のviエディタと同様に編集可能なため、「cpu mode」などで検索すればすぐに見つかると思います。
あと、vhostuserですが、mode=serverとなっています。以前はmode=clientだったのですが、現在はmode=serverが推奨されています。*8

2020/08/09追記

[root@c765 ~]# virsh edit Guest3

  <currentMemory unit='KiB'>8388608 </currentMemory>
  <memoryBacking>
    <hugepages>
      <page size='1048576' unit='KiB' nodeset='0'/>
    </hugepages>
  </memoryBacking>
  <vcpu placement='static'>4</vcpu>
  <cputune>
    <shares>8192</shares>
    <vcpupin vcpu='0' cpuset='10'/>
    <vcpupin vcpu='1' cpuset='11'/>
    <vcpupin vcpu='2' cpuset='12'/>
    <vcpupin vcpu='3' cpuset='13'/>
    <emulatorpin cpuset='10-13'/>
  </cputune>

  <cpu mode='host-model' check='partial'>
    <model fallback='allow'/>
    <numa>
      <cell id='0' cpus='0-3' memory='8388608' unit='KiB' memAccess='shared'/>
    </numa>
  </cpu>

  <interface type='vhostuser'>
    <source type='unix' path='/usr/local/openvswitch/vhuc0' mode='server'/>
    <model type='virtio'/>
  </interface>青=追記,緑=置換

11.仮想マシンの起動

仮想マシンを起動して疎通確認を行ってみてください。

virsh start Guest3

起動時にPermission Denyなどのエラーが出力される場合があります。
その場合、「2-2.qemu-kvmの実行ユーザをrootへ変更」を参照し、Qemuの実行ユーザが確実にrootとなっていることを確認してください。
その上で、

systemctl restart libvirtd.service

を実行し、それでもダメなら、ホストOSを再起動してみてください。

以上です。

12.最後に

以下のサイトを参考にさせて頂きました。
Bitbucket
Ubuntu Xenial (16.04) でOpen vSwitch+DPDKな環境を作る(vHost User Clientモード編) - 仮想化通信

今回は、下図の右側(OVS with DPDK)を構築しました。
f:id:metonymical:20181224102833j:plain
また、ovsの設定方法についても踏み込んで解説を入れたので、ある程度好きな構成を組めるところまでは網羅できているのではないかと思います。なお、仮想マシン側のネットワーク設定については、過去記事を参考にして頂ければと思います。

次はLXC/LXDコンテナでvHostUserClientモードで接続できないか、もう少し調べてみたいと考えています。

*1:常時qemu-evリポジトリを参照しに行かれるのがイヤだったので設定を入れましたが、別に構わないという方は不要です。

*2:IOMMUについては、DL360G8特有の設定(RMRRの設定)があるため、途中で補足を入れます。

*3:.bash_profileに追記した場合は、ログアウト&ログインを忘れずに

*4:明示的に被らないようにするためには、pmd-cpu-maskの設定をきちんと実施する必要があります。詳細は過去記事の「7.補足その1:ReactorMaskについて」を参照ください。

*5:0000:08:00.0とか0000:08:00.1はPCIのBus Slot Function番号に該当します

*6:DPDK上で稼働しているX540のens1f0とens1f1

*7:仮想マシンが接続されるポート

*8:詳細は、 Data Plane Development Kit vHost User Client Mode with Open vSwitch*に記載されています。

CentOS7 ovs(Open vSwitch)のネットワーク設定方法

CentOS7によるovs(Open vSwitch)のネットワーク設定(Bridge、Bonding、VLAN)の方法について記載しました。
KVMとLXC/LXDにおいてLinuxBridgeで実現可能だったことを、ovsでも同様に実現可能にした内容となっています。
このため、LinuxBridgeからovsへの移行設計が可能になると考えています。*1

過去記事では、nmcliコマンドによるLinuxBridgeについて記載しましたが、LinuxBridgeからovsへ変更した際、どこが変わったのか?のポイントも記載したいと考えています。

1.構成

1-1.環境
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Intel X520-SR2
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
ovs                              : 2.10.1

今回は物理スイッチとLACPで接続するために上記の筐体を使用しましたが、LACP以外のところはVMWareWorkstation12上でも動作しますので、本記事に記載した内容は特に環境依存的なことはないと考えています。

1-2.全体構成

f:id:metonymical:20181225193849j:plain
構成図上に(1)~(13)までの番号を割り振りました。

スイッチ側の設定は以下となります。

interface Port-channel1
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 11,300-302
 switchport mode trunk
 spanning-tree portfast trunk
!
interface TenGigabitEthernet0/1
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 11,300-302
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode active
!
interface TenGigabitEthernet0/2
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 11,300-302
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode active
!
interface Vlan300
 ip address 192.168.30.254 255.255.255.0
!
interface Vlan301
 ip address 192.168.31.254 255.255.255.0
!
interface Vlan302
 ip address 192.168.32.254 255.255.255.0
1-3.全体の流れ ~概要~
  1. Bridge作成:(1)
  2. Bonding:(2)
  3. VLAN(PortGroupの定義):(3)
  4. access port:(4)
  5. trunk port:(5)
  6. Guest側Tagging例1:(6)(7)(8)
  7. Guest側Tagging例2:(9)(10)(11)
  8. fake bridge(VLAN Interface)の作成:(12)
  9. LXCコンテナとfake bridgeのアタッチ:(13)
1-4.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。

1.Bridge作成
(1)
ovs-vsctl add-br ovsbr0

2.Bonding
(2)
ovs-vsctl add-bond ovsbr0 bond0 ens1f0 ens1f1

1&2の永続化設定
vi /etc/sysconfig/network-scripts/ifcfg-ovsbr0

DEVICE=ovsbr0
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f0

DEVICE=ens1f0
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f1

DEVICE=ens1f1
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

[LACPの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-tcp lacp=active other_config:lacp-time=fast vlan_mode=trunk trunks=11,300-302"
HOTPLUG=no

[固定LAGの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-slb lacp=off vlan_mode=trunk trunks=11,300-302"
HOTPLUG=no

3.VLAN(PortGroupの定義)
(3)
vi /tmp/ovsnw.xml

<network>
<name>ovsnw</name>
<forward mode='bridge'/>
<bridge name='ovsbr0'/>
<virtualport type='openvswitch'/>
<portgroup name='untag' default='yes'>
</portgroup>
<portgroup name='vlan11'>
  <vlan>
   <tag id='11'/>
  </vlan>
</portgroup>
<portgroup name='vlan300'>
  <vlan>
    <tag id='300'/>
  </vlan>
</portgroup>
<portgroup name='vlan301'>
  <vlan>
    <tag id='301'/>
  </vlan>
</portgroup>
<portgroup name='vlan302'>
  <vlan>
    <tag id='302'/>
  </vlan>
</portgroup>
</network>

4.access port
(4)
Virt-Manager画面上でvlan300を選択
 or
virsh edit Guest1

 <interface type='network'>
   <mac address='52:54:00:d4:25:2e'/>
   <source network='ovsnw' portgroup='vlan300'/>
   <model type='virtio'/>
   <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
 </interface>

5.trunk port
(5)
Virt-Manager画面上でuntagを選択
 or
virsh edit Guest2

 <interface type='network'>
   <mac address='52:54:00:d4:35:3e'/>
   <source network='ovsnw' portgroup='untag'/>
   <model type='virtio'/>
   <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
 </interface>


6.Guest側Tagging例1
(6)
nmcli connection add type bridge autoconnect yes con-name br301 ifname br301
nmcli connection modify br301 bridge.stp no
nmcli connection modify br301 ipv4.method manual ipv4.addresses 192.168.31.162/24
nmcli connection modify br301 ipv6.method ignore
nmcli connection up br301
nmcli con show
(7)
nmcli connection add type vlan autoconnect yes con-name eth0.301 ifname eth0.301 dev eth0 id 301
nmcli con show
(8)
nmcli connection modify eth0.301 connection.master br301 connection.slave-type bridge
nmcli connection up eth0.301
nmcli con show


7.Guest側Tagging例2
(9)
nmcli connection add type bridge autoconnect yes con-name br302 ifname br302
nmcli connection modify br302 bridge.stp no
nmcli connection modify br302 ipv4.method manual ipv4.addresses 192.168.32.162/24
nmcli connection modify br302 ipv6.method ignore
nmcli connection up br302
nmcli con show
(10)
nmcli connection add type vlan autoconnect yes con-name eth0.302 ifname eth0.302 dev eth0 id 302
nmcli con show
(11)
nmcli connection modify eth0.302 connection.master br302 connection.slave-type bridge
nmcli connection up eth0.302
nmcli con show

8.fake bridge(VLAN Interface)の作成
(12)
vi /etc/sysconfig/network-scripts/ifcfg-vlan302

DEVICE=vlan302
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSIntPort
BOOTPROTO=static
OVS_BRIDGE=ovsbr0
OVS_OPTIONS="vlan_mode=access tag=302 fake_bridge=true"
OVS_EXTRA="set Interface $DEVICE external-ids:iface-id=$(hostname -s)-$DEVICE-vif"
HOTPLUG=no

9.LXCコンテナとfake bridgeのアタッチ
(13)
lxc network attach vlan302 lxc762 eth1

2.Bridge作成

まずはBridgeを作成します。
(1)Bridgeの作成

出力結果
[root@c761 ~]# ovs-vsctl add-br ovsbr0
[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
    ovs_version: "2.10.1"

3.Bonding

Bondを作成し、物理インターフェースをBondにアタッチします。
(2)Bond作成+物理アタッチ

出力結果
[root@c761 ~]# ovs-vsctl add-bond ovsbr0 bond0 ens1f0 ens1f1
[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            Interface "ens1f1"
            Interface "ens1f0"
    ovs_version: "2.10.1"

過去記事の図と比較してもらえればわかると思いますが、過去記事の(3)~(5)を行った状態となります。

また、LinuxBridgeの場合、BridgeとBondが分離しているのに対して、ovsでは、Bridge "ovsbr0"の中にBondが入っています。
具体的には、Port "ovsbr0"とPort "bond0"がBridge "ovsbr0"の中に定義されており、さらに、Port "bond0"のインターフェースとして、物理のens1f0やens1f1が定義されています。

これは仮想スイッチovsbr0のアップリンクポート(物理サーバの外部へ抜けるトラフィックが通るポート)がBondとして定義されている状態と言えます。

仮にESXiのvSwitchで例えるなら、こんな↓状態です。
f:id:metonymical:20181224110914j:plain

4.永続化設定

コマンドを打っただけだと、ホストOSをRebootすると消えてしまうので永続化設定を行います。

vi /etc/sysconfig/network-scripts/ifcfg-ovsbr0

DEVICE=ovsbr0
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f0

DEVICE=ens1f0
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f1

DEVICE=ens1f1
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

[LACPの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-tcp lacp=active other_config:lacp-time=fast vlan_mode=trunk trunks=11,300-302"
HOTPLUG=no

[固定LAGの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-slb lacp=off vlan_mode=trunk trunks=11,300-302"
HOTPLUG=no

設定後はnetworkサービスをリスタート
systemctl restart network

いくつか、ポイントを記載します。
・対向の物理スイッチに合わせて、LACP or 固定LAGのどちらかの設定を行ってください。なお、ここではLACPとします。

・ovsのDefaultでは、vlan_mode=trunkにてFullTrunk状態となっているため、明示的にTrunkするVLANを絞りたい場合に、trunks=11,300-302が必要となります。*2

・NM_CONTROLLED=noにより、該当するインターフェースがNetworkManagerの管理下から外れるため必須設定と考えてください。

・nmcliコマンドでBondを作成した際も、上記パス*3に似たようなファイルが生成されていますが、ovs特有のオプションを指定できる点が異なります。

・networkサービスのリスタートを行っても正常に動作しない場合、少々ダサいですがホストOSごと再起動してみてください。

5.VLAN(PortGroupの定義)

(3)libvirtに対してovsのネットワーク定義
仮想マシン側でNICを追加する際、ovsを選択できるようにするため、libvirt上でネットワークの定義を行います。

その際、仮想マシンとovsをaccessポートで接続するのか?trunkポートで接続するのか?を設定できるようにするため、PortGroupの定義も併せて行います。

ESXiのvSwitchで例えるなら、下図の左側にある「仮想マシンのポートグループ」の設定を行っていくイメージです。
f:id:metonymical:20181224112812j:plain

(3)
vi /tmp/ovsnw.xml

<network>
<name>ovsnw</name>
<forward mode='bridge'/>
<bridge name='ovsbr0'/>
<virtualport type='openvswitch'/>
<portgroup name='untag' default='yes'>
</portgroup>
<portgroup name='vlan11'>
  <vlan>
   <tag id='11'/>
  </vlan>
</portgroup>
<portgroup name='vlan300'>
  <vlan>
    <tag id='300'/>
  </vlan>
</portgroup>
<portgroup name='vlan301'>
  <vlan>
    <tag id='301'/>
  </vlan>
</portgroup>
<portgroup name='vlan302'>
  <vlan>
    <tag id='302'/>
  </vlan>
</portgroup>
</network>

いくつか、ポイントを記載します。
A.「portgroup name='vlan11'」や「portgroup name='vlan300'」は、仮想マシンをovsにaccess portとして接続させたい場合の設定となります。
B.「portgroup name='untag' default='yes'」は、仮想マシンをovsにtrunk portとして接続させたい場合の設定となります。

A.は、主に仮想サーバなど自身でVLAN IDを付けずにトラフィックを流してくる仮想マシンとして使用できます。
B.は、主に仮想ルータ(CSR1000v・vMX・A10 vThunderなど)や仮想スイッチ(CumulusVXやNexus9000v)など、自身でVLAN IDを付けてトラフィックを流してくる仮想マシンとして使用できます。

ちなみに、B.においては、4.永続化設定で記載したように、DefaultでFullTrunk状態です。このため、許可するVLANを絞ることも可能なようですが、ここでは割愛します。*4

上記ファイルの作成が完了したら、virshコマンドで定義していきます。

virsh net-list
virsh net-define /tmp/ovsnw.xml
virsh net-start ovsnw
virsh net-autostart ovsnw
virsh net-list

現在のネットワーク定義を参照
ovsnw.xmlのネットワークを定義
ovsnwのスタート
ovsnwの自動起動設定
現在のネットワーク定義を参照

以下が各コマンドの出力結果となります。

出力結果
[root@c761 ~]# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

[root@c761 ~]# virsh net-define /tmp/ovsnw.xml
Network ovsnw defined from /tmp/ovsnw.xml

[root@c761 ~]# virsh net-start ovsnw
Network ovsnw started

[root@c761 ~]# virsh net-autostart ovsnw
Network ovsnw marked as autostarted

[root@c761 ~]# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
 ovsnw                active     yes           yes

上記の設定が完了すると、Virt-Manager上の画面からovsやPortGroupが選択できるようになります。

6.access port

(4)仮想マシンをovsにaccess portで接続
Virt-Manager画面上で設定する場合は、以下の通り。
f:id:metonymical:20181224121543j:plain

AddHardwareをクリック
Networkを選択
NetworkSource:Virtual Network’ovsnw’を選択
Portgroup:vlan300を選択

virshコマンドで設定する場合は、以下の通り。

virsh edit Guest1

 <interface type='network'>
   <mac address='52:54:00:d4:25:2e'/>
   <source network='ovsnw' portgroup='vlan300'/>
   <model type='virtio'/>
   <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
 </interface>

7.trunk port

(5)仮想マシンをovsにtrunk portで接続
Virt-Manager画面上で設定する場合は、以下の通り。
f:id:metonymical:20181224121543j:plain

AddHardwareをクリック
Networkを選択
NetworkSource:Virtual Network’ovsnw’を選択
Portgroup:untagを選択

virshコマンドで設定する場合は、以下の通り。

virsh edit Guest2

 <interface type='network'>
   <mac address='52:54:00:d4:25:2e'/>
   <source network='ovsnw' portgroup='untag'/>
   <model type='virtio'/>
   <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
 </interface>

8.Guest側Tagging例1と2

Guest2起動後、Guest2のbash上でnmcliコマンドにより、VLANインターフェースを作成します。
nmcliコマンドの詳細については、過去記事を参照ください。

(6)
nmcli connection add type bridge autoconnect yes con-name br301 ifname br301
nmcli connection modify br301 bridge.stp no
nmcli connection modify br301 ipv4.method manual ipv4.addresses 192.168.31.162/24
nmcli connection modify br301 ipv6.method ignore
nmcli connection up br301
nmcli con show
(7)
nmcli connection add type vlan autoconnect yes con-name eth0.301 ifname eth0.301 dev eth0 id 301
nmcli con show
(8)
nmcli connection modify eth0.301 connection.master br301 connection.slave-type bridge
nmcli connection up eth0.301
nmcli con show

(9)
nmcli connection add type bridge autoconnect yes con-name br302 ifname br302
nmcli connection modify br302 bridge.stp no
nmcli connection modify br302 ipv4.method manual ipv4.addresses 192.168.32.162/24
nmcli connection modify br302 ipv6.method ignore
nmcli connection up br302
nmcli con show
(10)
nmcli connection add type vlan autoconnect yes con-name eth0.302 ifname eth0.302 dev eth0 id 302
nmcli con show
(11)
nmcli connection modify eth0.302 connection.master br302 connection.slave-type bridge
nmcli connection up eth0.302
nmcli con show

7.trunk portの設定により、(5)のeth0とvnet1間はFullTrunkで接続されていると考えてください。

これにより、例えば、SrcIP:192.168.31.162-DstIP:192.168.31.254でPingを打つと、以下のような流れで処理されます。

1. (7)でVLAN ID301がTaggingされる。
2. (5)はFullTrunk状態なので、VLANタグは剥がされずに、そのままスイッチング処理*5される。
3. (2)では11,300-302がAllowedされているので、VLANタグは剥がされずに、そのままスイッチング処理される。
4.物理スイッチ側でVLANタグが剥がされ、以下のVLAN InterfaceがPingに応答する。

interface Vlan301
 ip address 192.168.31.254 255.255.255.0

9.fake bridge(VLAN Interface)の作成

fake bridge(VLAN Interface)の作成と同時に永続化設定も実施します。

vi /etc/sysconfig/network-scripts/ifcfg-vlan302

DEVICE=vlan302
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSIntPort
BOOTPROTO=static
OVS_BRIDGE=ovsbr0
OVS_OPTIONS="vlan_mode=access tag=302 fake_bridge=true"
OVS_EXTRA="set Interface $DEVICE external-ids:iface-id=$(hostname -s)-$DEVICE-vif"
HOTPLUG=no

設定後はnetworkサービスをリスタート
systemctl restart network

fake_bridge=trueを指定しないと、単なるVLAN Interfaceとなってしまうため、次工程(10.LXCコンテナとfake bridgeのアタッチ)に進むと、必ず躓くポイントになります。理由は、LXCに対してVLAN Interface 302をBridgeとして認識させる必要があるためです。

10.LXCコンテナとfake bridgeのアタッチ

fake bridge (VLAN Interface 302)にコンテナlxc762のeth1をアタッチします。

lxc network attach vlan302 lxc762 eth1

アタッチ後、仮想マシンやLXCコンテナを起動すると、ovs上では以下のように構成されていることが確認できます。

[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            trunks: [11, 300, 301, 302, 303, 304]
            Interface "ens1f1"
            Interface "ens1f0"
        Port "vnet0"
            tag: 300
            Interface "vnet0"
        Port "vnet1"
            Interface "vnet1"
        Port "vlan302"
            tag: 302
            Interface "vlan302"
                type: internal
        Port "vethCPI2P0"
            tag: 302
            Interface "vethCPI2P0"
    ovs_version: "2.10.1"

Port "bond0":アップリンクポートの設定(trunk allowed vlan 11,300-304の状態)
Port "vnet0":access vlan 300のポート設定
Port "vnet1":trunkポートの設定(FullTrunk状態)
Port "vlan302":fake bridgeの設定
Port "vethCPI2P0":fake bridgeに接続されたlxc762のポート設定

11.補足1:fake_bridgeについて

fake_bridge=trueを指定しなかった場合、上記コマンドにて「lxc network attach 」まで打った後、Tabキーで補完してみてください。すると、物理インターフェースもしくはBridgeインターフェースしか表示されません。

fake_bridge=trueを指定しなかった場合の出力例
[root@c761 ~]# lxc network attach
eno1       eno3       enp4s16    enp4s16f2  ens1f0     ens2       ovsbr0     
eno2       eno4       enp4s16f1  enp4s16f3  ens1f1     lxdbr0     virbr0

すると、lxcコンテナをovsにアタッチするためには、ovsbr0を選択するしかない状態となってしまいます。
このため、LXCに対して、VLAN Interface 302がBridgeであるということを明示的に認識させる必要があるため、fake_bridge=trueオプションを指定しています。

ちなみに、上記のlxcコマンドでovsbr0を選択した場合、(5)に接続した状態となります。

前述した通り、(5)はFullTrunk状態なので、物理スイッチへトラフィックを流すためには、LXCコンテナ側でVLAN IDを付与する必要があります。

軽量さがメリットであるLXCコンテナで、VLAN IDを付ける設定を実施することは、そもそも使い方が間違っている気がしました。*6

このため、

  • KVM:(4)の通り、PortGroupで所属するVLANを決定する。もしくは、(5)の通り、untagにして仮想マシン側でVLAN IDを付与する。
  • LXC/LXD:(12)(13)に記載の通り、fake bridgeで所属するVLANを決定する。

という使い方が適しているのではないかと考えています。

12.補足2:ovs上での見え方

Guest1と2を起動すると、ovs上では以下のように見えます。

[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "vnet0"
            tag: 300
            Interface "vnet0"
        Port "vnet1"
            Interface "vnet1"
        Port "bond0"
            trunks: [11, 300, 301, 302]
            Interface "ens1f1"
            Interface "ens1f0"
    ovs_version: "2.10.1"

また、今回LCAPを使用しましたが、LCAPの状態を確認する場合は、以下のコマンドで可能です。

ovs-appctl bond/show bond0
ovs-vsctl list port bond0

出力例
[root@c761 ~]# ovs-appctl bond/show bond0
---- bond0 ----
bond_mode: balance-tcp
bond may use recirculation: yes, Recirc-ID : 2
bond-hash-basis: 0
updelay: 0 ms
downdelay: 0 ms
next rebalance: 2115 ms
lacp_status: negotiated
lacp_fallback_ab: false
active slave mac: 90:e2:ba:0b:37:b9(ens1f1)

slave ens1f0: enabled
  may_enable: true

slave ens1f1: enabled
  active slave
  may_enable: true

[root@c761 ~]# ovs-vsctl list port bond0
_uuid               : 85d6d0bb-1b9d-44b0-964c-b83d60451aab
bond_active_slave   : "90:e2:ba:0b:37:b9"
bond_downdelay      : 0
bond_fake_iface     : false
bond_mode           : balance-tcp
bond_updelay        : 0
cvlans              : 
external_ids        : {}
fake_bridge         : false
interfaces          : [a102fd00-be8d-402b-b9f3-1ae3cf3aeb64, cffbeb94-2ab5-453e-832c-ac63c86e5d8a]
lacp                : active
mac                 : 
name                : "bond0"
other_config        : {lacp-time=fast}
protected           : false
qos                 : 
rstp_statistics     : {}
rstp_status         : {}
statistics          : {}
status              : {}
tag                 : 
trunks              : [11, 300, 301, 302]
vlan_mode           : trunk

以上です。

13.最後に

以下のサイトを参考にさせて頂きました。
Open vSwitch
Using VLANs with OVS and libvirt - Scott's Weblog - The weblog of an IT pro focusing on cloud computing, Kubernetes, Linux, containers, and networking
Tag Vlan on Veth to Openvswitch bridge · Issue #3414 · lxc/lxd · GitHub


ovsは、最初は取っ付き難かったのですが、触ってみると意外と楽しかったです。
また、LinuxBridgeと異なる点として、Port(Interface)やBond、VLANの概念がBridgeの中に集約されている(ように見える)ので、よりスイッチっぽいかな?と。
ovsはVxLANのVTEPを作ったり、OpenFlowが使えたりと色々遊べるのですが、まずはLinuxBridgeからの移行で最低限必要な機能は網羅できたかなと思います。

次のステップとして、DPDKを実装したいと考えています。

*1:手前味噌ですが、私はovsに一本化しようと思いました。

*2:ネットワークエンジニアという職業柄、意図しないループが怖いため、TrunkするVLANはなるべく絞りたい派です。

*3:/etc/sysconfig/network-scripts/配下のパス

*4:ovsnw.xml上に、tag id='11,300-302'などと記載すれば、できそうな気がしていますが、libvirt側の話題になるため、また別の機会に確認したいと思います。

*5:宛先MACアドレスMACアドレステーブルを照合し、受信したEtherフレームを然るべきポートへ転送する動作のこと

*6:もちろん、ケースバイケースで充分な議論をする余地はあるかと思います。

CentOS7 ovs(Open vSwitch)のビルドとインストール方法

CentOS7によるovs(Open vSwitch)のビルドとインストール方法について記載しました。
CentOS7でyumを使用すると、openvswitch.x86_64 0:2.0.0-7.el7がインストールされますが、今後DPDK版ovsを作りたいと考えているため、その練習も兼ねて、最新版2.10系のビルドから行います。

1.構成

1-1.環境
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Intel X520-SR2
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
ovs                              : 2.10.1
1-2.全体の流れ

事前準備
rpmビルド
インストール
起動確認

2.事前準備

2-1.ビルド用ユーザ作成

検証環境ですと、rootだけで操作してしまうことが多いのですが、rpmビルドの際、bad owner/groupのエラーで弾かれてしまうため、ビルド用ユーザを作成します。
また、特に記載しませんが、SE Linuxやfirewalldの無効化は行っておいてください。

useradd ovs
usermod -G wheel ovs
passwd ovs
su - ovs

ユーザ作成
wheelグループに追加(sudoさせるため)
パスワード設定
スイッチユーザ

2-2.追加のパッケージインストール

ユーザovsで操作しているものとします。

sudo yum -y install @'Development Tools' rpm-build yum-utils wget libpcap-devel numactl-devel

3.rpmビルド

3-1.ビルド環境準備

ビルド環境の準備をします。

mkdir -p ~/rpmbuild/SOURCES
cd rpmbuild/SOURCES/
wget https://www.openvswitch.org/releases/openvswitch-2.10.1.tar.gz
tar zxvf openvswitch-2.10.1.tar.gz
sed -e 's/@VERSION@/0.0.1/' openvswitch-2.10.1/rhel/openvswitch-fedora.spec.in > ovs.spec

ソース格納ディレクトリの作成
ディレクトリ移動
ソースのダウンロード
ソースのtarファイルを解凍
specファイル生成

3-2.ビルド

ソースからrpmファイルを生成します。

sudo yum-builddep -y ovs.spec
cd openvswitch-2.10.1
./boot.sh
./configure
make rpm-fedora RPMBUILD_OPT="--without check"

依存パッケージのインストール
ovsのソース格納ディレクトリへ移動
boot.sh実行
configure実行
rpmビルド*1

多少時間は掛かりますが、最後の方は以下のような出力がでれば正常にビルドが完了しています。

Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/SRPMS/openvswitch-2.10.1-1.el7.src.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/noarch/openvswitch-selinux-policy-2.10.1-1.el7.noarch.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/noarch/python-openvswitch-2.10.1-1.el7.noarch.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/noarch/openvswitch-test-2.10.1-1.el7.noarch.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-devel-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-ovn-central-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-ovn-host-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-ovn-vtep-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-ovn-common-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-ovn-docker-2.10.1-1.el7.x86_64.rpm
Wrote: /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/RPMS/x86_64/openvswitch-debuginfo-2.10.1-1.el7.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.JbhK5R
+ umask 022
+ cd /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/BUILD
+ cd openvswitch-2.10.1
+ rm -rf /home/ovs/rpmbuild/SOURCES/openvswitch-2.10.1/rpm/rpmbuild/BUILDROOT/openvswitch-2.10.1-1.el7.x86_64
+ exit 0

4.インストール

生成されたrpmをインストールします。*2

sudo yum -y localinstall rpm/rpmbuild/RPMS/x86_64/openvswitch-2.10.1-1.el7.x86_64.rpm

5.起動確認

rpmインストール後はrootに戻ります。

exit
systemctl start openvswitch
systemctl enable openvswitch
systemctl status openvswitch
ovs-vsctl -V

ユーザovsからrootへ変更
ovsサービスの起動
ovsサービスの自動起動設定
ovsサービスの動作確認
ovsのversion確認

以下、出力例

# systemctl start openvswitch
# systemctl enable openvswitch
Created symlink from /etc/systemd/system/multi-user.target.wants/openvswitch.service to /usr/lib/systemd/system/openvswitch.service.

# systemctl status openvswitch
● openvswitch.service - Open vSwitch
   Loaded: loaded (/usr/lib/systemd/system/openvswitch.service; enabled; vendor preset: disabled)
   Active: active (exited) since Mon 2018-12-24 10:21:25 JST; 11s ago
 Main PID: 27852 (code=exited, status=0/SUCCESS)

Dec 24 10:21:25 c76x64ovs3.md.jp systemd[1]: Starting Open vSwitch...
Dec 24 10:21:25 c76x64ovs3.md.jp systemd[1]: Started Open vSwitch.

# ovs-vsctl -V
ovs-vsctl (Open vSwitch) 2.10.1
DB Schema 7.16.1

上記まで完了したら、あとはovs-vsctl add-br ovsbr0などでBridgeを作成していきます。
ovsの設定方法は次回記載します。

以上です。

6.最後に

先にも記載しましたが、ovs-dpdkをやることが目的なこともあり、rpmのビルドから実施しました。

以下のサイトに詳しい説明が記載されていますが、
software.intel.com
今回インストールしたのは、下図の左上(ovsのみ)です。
f:id:metonymical:20181224102833j:plain
左下(dpdk)については、過去記事のpktgenspdk+NVMe-oFで、既に実績があるため、DPDKはサクッと導入できるかな?と考えています。

*1:RPMBUILD_OPT=に--with dpdkを追記すると、DPDKにも対応してくれるようです。もちろん事前にDPDKのビルドは必須ですが。

*2:記載したパスには、debug版やovn版などのrpmも生成されていますので、興味があればインストールしてみてください。

Linux nmcliコマンドによるKVM&LXC/LXD with SR-IOVのInterface設定

LinuxのnmcliコマンドによるBonding、VLAN、Bridge Interfaceの設定方法に加えて、SR-IOVを使用した場合について記載しました。
SR-IOVの使用方法として、KVMとLXC/LXDのそれぞれについてもまとめました。
また、SR-IOVを使用する場合の注意点についても記載しました。
さらに、内部ネットワーク的な疎通可否についても記載しました。

1.構成

1-1.環境
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Intel X520-SR2
OS                               : CentOS7.5(1804)
Kernel                           : 4.19.0-1.el7.elrepo.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
1-2.全体構成

f:id:metonymical:20181104144940j:plain

構成図上に(1)~(21)までの番号を割り振りました。

(1)~(10)については過去記事を参照してください。
metonymical.hatenablog.com

(11)~(21)については主にVLANやIPの設定となります。
各VLANとIPは以下の通りです。
 (11)(13)(16)(19)
 Untag:192.168.30.22x/24
 (12)(14)(18)(21)
 VLAN301:192.168.31.22x/24
 (15)
 Untag:192.168.31.222/24*1

SR-IOVを使用する場合、仮想マシンやコンテナを起動する前にVFを予めアタッチした後*2、起動させます。
アタッチ方法については、nmcliコマンドではできないため、適時解説します。

仮想マシンやコンテナは以下の通りです。
 c750~c753:KVM上の仮想マシン
 lxc754:LXC/LXD上のコンテナ

スイッチ側の設定は以下となります。

interface GigabitEthernet0/1
 switchport trunk encapsulation dot1q
 switchport trunk native vlan 300
 switchport trunk allowed vlan 300,301
 switchport mode trunk
 spanning-tree portfast trunk
!
interface Port-channel1
 switchport trunk encapsulation dot1q
 switchport trunk native vlan 300
 switchport trunk allowed vlan 300,301
 switchport mode trunk
 spanning-tree portfast trunk
!
interface TenGigabitEthernet0/1
 switchport trunk encapsulation dot1q
 switchport trunk native vlan 300
 switchport trunk allowed vlan 300,301
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode on
!
interface TenGigabitEthernet0/2
 switchport trunk encapsulation dot1q
 switchport trunk native vlan 300
 switchport trunk allowed vlan 300,301
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode on
!
interface Vlan300
 ip address 192.168.30.1 255.255.255.0
!
interface Vlan301
 ip address 192.168.31.1 255.255.255.0
1-3.全体の流れ ~概要~
  1. 物理+Bridge:(1)(2)
  2. 物理+Bonding:(3)(4)(5)
  3. Bonding+Bridge:(6)(7)
  4. Bonding+VLAN+Bridge:(8)(9)(10)
  5. c750のEthernet&VLAN+IP:(11)(12)
  6. c751のEthernet&VLAN+IP:(13)(14)
  7. c752のEthernet+IP:(15)
  8. c753のBonding&VLAN+IP:(16)(17)(18)
  9. lxc754のBonding&VLAN+IP:(19)(20)(21)
1-4.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。

1.物理+Bridge
(1)
nmcli connection add type bridge autoconnect yes con-name br1 ifname br1
nmcli connection modify br1 bridge.stp no
nmcli connection modify br1 ipv4.method disabled ipv6.method ignore
nmcli connection up br1
nmcli con show
brctl show
(2)
nmcli connection add type bridge-slave ifname eno3 master br1
nmcli con show
brctl show

(3)
nmcli connection add type bond con-name bond0 ifname bond0 mode balance-xor
nmcli connection mod bond0 ipv4.method disabled ipv6.method ignore
nmcli con show
(4)
nmcli connection add type bond-slave autoconnect yes ifname ens1f0 master bond0
nmcli con show
(5)
nmcli connection add type bond-slave autoconnect yes ifname ens1f1 master bond0
nmcli con show

(6)
nmcli connection add type bridge autoconnect yes con-name br0 ifname br0
nmcli connection modify br0 bridge.stp no
nmcli connection modify br0 ipv4.method disabled ipv6.method ignore
nmcli connection up br0
nmcli con show
brctl show
(7)
nmcli connection modify bond0 connection.master br0 connection.slave-type bridge
nmcli con show
brctl show

(8)
nmcli connection add type bridge autoconnect yes con-name br301 ifname br301
nmcli connection modify br301 bridge.stp no
nmcli connection modify br301 ipv4.method disabled ipv6.method ignore
nmcli connection up br301
nmcli con show
brctl show
(9)
nmcli connection add type vlan autoconnect yes con-name bond0.301 ifname bond0.301 dev bond0 id 301
nmcli con show
brctl show
(10)
nmcli connection modify bond0.301 connection.master br301 connection.slave-type bridge
nmcli connection up bond0.301
nmcli con show
brctl show

c750
(11)
nmcli connection add type ethernet autoconnect yes con-name eth1 ifname eth1
nmcli connection mod eth1 ipv4.method manual ipv4.address 192.168.30.220/24
nmcli connection mod eth1 ipv6.method ignore
nmcli con up eth1
nmcli con show
(12)
nmcli connection add type vlan autoconnect yes con-name eth1.301 ifname eth1.301 dev eth1 id 301
nmcli connection mod eth1.301 ipv4.method manual ipv4.address 192.168.31.220/24
nmcli connection mod eth1.301 ipv6.method ignore
nmcli con up eth1.301
nmcli con show

c751
(13)
nmcli connection add type ethernet autoconnect yes con-name eth1 ifname eth1
nmcli connection mod eth1 ipv4.method manual ipv4.address 192.168.30.221/24
nmcli connection mod eth1 ipv6.method ignore
nmcli con up eth1
nmcli con show
(14)
nmcli connection add type vlan autoconnect yes con-name eth1.301 ifname eth1.301 dev eth1 id 301
nmcli connection mod eth1.301 ipv4.method manual ipv4.address 192.168.31.221/24
nmcli connection mod eth1.301 ipv6.method ignore
nmcli con up eth1.301
nmcli con show

c752
(15)
nmcli connection add type ethernet autoconnect yes con-name eth1 ifname eth1
nmcli connection mod eth1 ipv4.method manual ipv4.address 192.168.31.222/24
nmcli connection mod eth1 ipv6.method ignore
nmcli con up eth1
nmcli con show

c753
Virt-Manager画面上でPCIバイスを選択
 or
virsh edit c753

  <hostdev mode='subsystem' type='pci' managed='yes'>
    <source>
      <address domain='0x0000' bus='0x04' slot='0x10' function='0x0'/>
    </source>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
  </hostdev>
  <hostdev mode='subsystem' type='pci' managed='yes'>
    <source>
      <address domain='0x0000' bus='0x04' slot='0x10' function='0x1'/>
    </source>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
  </hostdev>

(16)
nmcli connection add type bond con-name bond0 ifname bond0 mode balance-xor
nmcli connection mod bond0 ipv4.method manual ipv4.address 192.168.30.223/24
nmcli connection mod bond0 ipv6.method ignore
nmcli con show
(17)
nmcli connection add type bond-slave autoconnect yes ifname ens4 master bond0
nmcli connection add type bond-slave autoconnect yes ifname ens5 master bond0
nmcli con show
(18)
nmcli connection add type vlan autoconnect yes con-name bond0.301 ifname bond0.301 dev bond0 id 301
nmcli connection mod bond0.301 ipv4.method manual ipv4.address 192.168.31.223/24
nmcli connection mod bond0.301 ipv6.method ignore
nmcli con up bond0
nmcli con up bond0.301
nmcli con show
ip add show

lxc754
lxc config device add lxc754 eth1 nic nictype=sriov parent=ens1f0
lxc config device add lxc754 eth2 nic nictype=sriov parent=ens1f1

(19)
nmcli connection add type bond con-name bond0 ifname bond0 mode balance-xor
nmcli connection mod bond0 ipv4.method manual ipv4.address 192.168.30.224/24
nmcli connection mod bond0 ipv6.method ignore
nmcli con show
(20)
nmcli connection add type bond-slave autoconnect yes ifname eth1 master bond0
nmcli connection add type bond-slave autoconnect yes ifname eth2 master bond0
nmcli con show
(21)
nmcli connection add type vlan autoconnect yes con-name bond0.301 ifname bond0.301 dev bond0 id 301
nmcli connection mod bond0.301 ipv4.method manual ipv4.address 192.168.31.224/24
nmcli connection mod bond0.301 ipv6.method ignore
nmcli con up bond0
nmcli con up bond0.301
nmcli con show
ip add show

(1)~(10)の詳細は省略し、以下は(11)から解説します。
また、全ての出力結果を表示させると不要な設定も記載することになるため、一部省略します。

2.c750のEthernet&VLAN+IP

物理とVLANインターフェースを作成しIPをアサインします。
(11)物理インターフェースeth1とIPの設定
(12)VLANインターフェースeth1.301とIPの設定

出力結果
[root@c750 ~]# nmcli con show
NAME      UUID                                  TYPE      DEVICE
eth0      2c180c0c-76b3-4f05-b04e-546812f51811  ethernet  eth0
eth1      5e55d7f8-1db1-48d0-a954-46c996ad5533  ethernet  eth1
eth1.301  e39150fd-d1ab-42e9-8a23-d48733229b38  vlan      eth1.301
virbr0    5ee27a89-6153-4e47-9a68-dbbd1caf1e04  bridge    virbr0
[root@c750 ~]# ip add show
3: eth1:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:4d:da:7b brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.220/24 brd 192.168.30.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe4d:da7b/64 scope link
       valid_lft forever preferred_lft forever
8: eth1.301@eth1:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:4d:da:7b brd ff:ff:ff:ff:ff:ff
    inet 192.168.31.220/24 brd 192.168.31.255 scope global noprefixroute eth1.301
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe4d:da7b/64 scope link tentative
       valid_lft forever preferred_lft forever

3.c751のEthernet&VLAN+IP

物理とVLANインターフェースを作成しIPをアサインします。
(13)物理インターフェースeth1とIPの設定
(14)VLANインターフェースeth1.301とIPの設定

出力結果
c750とほぼ同一のため省略
異なる点は、IPアドレスの第4オクテットが221となります。

4.c752のEthernet+IP

物理インターフェースを作成しIPをアサインします。
(15)物理インターフェースeth1とIPの設定

出力結果
c750とほぼ同一のため省略
異なる点は、IPアドレスの第4オクテットが222となります。

5.c753のBonding&VLAN+IP

仮想マシン起動前にVFをアタッチします。
ホストOSのVirt-Manager上でAdd Hardwareを実施し以下の画面のようにアタッチしてください。
f:id:metonymical:20181104170919j:plain
上記画面の場合、VFのBus:Device(Slot).function番号が0000:04:10:0となっていますが、以下のようにPFとVFのBus:Device(Slot).function番号は対応しています。
ens1f0=04:10:0, 04:10:2
ens1f1=04:10:1, 04:10:3

または、ホストOS上のvirshでアタッチする場合は、以下のように設定してください。
address domain=の行がVFのBus:Device(Slot).function番号に対応しています。

# virsh edit c753

  <hostdev mode='subsystem' type='pci' managed='yes'>
    <source>
      <address domain='0x0000' bus='0x04' slot='0x10' function='0x0'/>
    </source>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
  </hostdev>

  <hostdev mode='subsystem' type='pci' managed='yes'>
    <source>
      <address domain='0x0000' bus='0x04' slot='0x10' function='0x1'/>
    </source>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
  </hostdev>

上記設定が完了した後、仮想マシンを起動して以下の設定を仮想マシン上で行ってください。
BondingインターフェースとVLANインターフェースを作成します。
(16)Bondingインターフェースbond0とIPの設定
(17)ens4とens5をBond0にアサイ
(18)VLANインターフェースbond0.301とIPの設定

出力結果
[root@c753 ~]# nmcli con show
NAME             UUID                                  TYPE      DEVICE
bond-slave-ens4  461a812f-bb8f-4046-84bb-e1e9df598a76  ethernet  ens4
bond-slave-ens5  62bd54a3-bb07-4c0a-8ca4-ed7d3ea236b7  ethernet  ens5
bond0            9962c767-59ff-41bf-b8ed-097061f6016c  bond      bond0
bond0.301        44296f6c-a9b3-4435-be5e-541a0fd5e4b9  vlan      bond0.301
eth0             2c180c0c-76b3-4f05-b04e-546812f51811  ethernet  eth0
virbr0           42ae0bd5-a46a-4e7c-8038-8711ae2aab4d  bridge    virbr0
[root@c753 ~]# ip add show
2: ens4: <\BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
    link/ether 16:27:f0:0c:e1:4b brd ff:ff:ff:ff:ff:ff
3: ens5: <\BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
    link/ether 16:27:f0:0c:e1:4b brd ff:ff:ff:ff:ff:ff
9: bond0:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 16:27:f0:0c:e1:4b brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.223/24 brd 192.168.30.255 scope global noprefixroute bond0
       valid_lft forever preferred_lft forever
10: bond0.301@bond0:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 16:27:f0:0c:e1:4b brd ff:ff:ff:ff:ff:ff
    inet 192.168.31.223/24 brd 192.168.31.255 scope global noprefixroute bond0.301
       valid_lft forever preferred_lft forever
[root@c753 ~]#

6.lxc754のBonding&VLAN+IP

コンテナ起動前にVFを仮想マシンにアタッチします。
ホストOS上で以下のように設定してください。*3

# lxc config device add lxc754 eth1 nic nictype=sriov parent=ens1f0
Device eth1 added to lxc754

# lxc config device add lxc754 eth2 nic nictype=sriov parent=ens1f1
Device eth2 added to lxc754

上記設定が完了した後、コンテナを起動して以下の設定をコンテナ上で行ってください。
また、コンテナ上で事前にyum -y install NetworkManagerを実施しておいてください。
BondingとVLANインターフェースを作成します。
(19)Bondingインターフェースbond0とIPの設定
(20)eth1とeth2をBond0にアサイ
(21)VLANインターフェースbond0.301とIPの設定

出力結果
c753とほぼ同一のため省略
異なる点は、IPアドレスの第4オクテットが224となります。

8.補足1:SR-IOVを使用する場合の注意点

以下3つの注意点があります。
先に結論だけ書きますと、以下の通りとしてください。

  1. VFのMACアドレスについて:固定設定は実施しない
  2. BlackListについて:ixgbevfはBlackListに含めない
  3. VFIO-PCIについて:固定設定は実施しない
8-1.VFのMACアドレスについて

VFのMACアドレスは固定設定とせずに、オール0(ゼロ)のままの状態にしておいてください。
通常、VFのMACアドレスを明示的に固定設定とする場合、/etc/rc.localに以下のように記載しますが、全てコメントアウトしてください。

# vi /etc/rc.local

echo 2 > /sys/class/net/ens1f0/device/sriov_numvfs
echo 2 > /sys/class/net/ens1f1/device/sriov_numvfs
sleep 1
#ip link set ens1f0 vf 0 mac 00:11:22:33:44:55
#ip link set ens1f0 vf 1 mac 00:11:22:33:44:56
#ip link set ens1f1 vf 0 mac 00:11:22:33:44:57
#ip link set ens1f1 vf 1 mac 00:11:22:33:44:58
sleep 1
ip link set ens1f0 vf 0 spoofchk off
ip link set ens1f0 vf 1 spoofchk off
ip link set ens1f1 vf 0 spoofchk off
ip link set ens1f1 vf 1 spoofchk off
exit 0

MACアドレスKVMやLXC/LXD側で動的にアサインさせないと、Bondingが機能しなくなる*4ためです。

8-2.BlackListについて

BlackListを使用した場合、LXC/LXDでVFをコンテナにアタッチしようする際、エラーで弾かれます。
このため、BlackListからixgbevfはコメントアウト、または削除してください。*5

# vi /lib/modprobe.d/dist-blacklist.conf

#
# Listing a module here prevents the hotplug scripts from loading it.
# Usually that'd be so that some other driver will bind it instead,
# no matter which driver happens to get probed first.  Sometimes user
# mode tools can also control driver binding.
#
# Syntax: see modprobe.conf(5).
#

# watchdog drivers
blacklist i8xx_tco

# framebuffer drivers
blacklist aty128fb
blacklist atyfb
blacklist radeonfb
blacklist i810fb
blacklist cirrusfb
blacklist intelfb
blacklist kyrofb
blacklist i2c-matroxfb
blacklist hgafb
blacklist nvidiafb
blacklist rivafb
blacklist savagefb
blacklist sstfb
blacklist neofb
blacklist tridentfb
blacklist tdfxfb
blacklist virgefb
blacklist vga16fb
blacklist viafb

# ISDN - see bugs 154799, 159068
blacklist hisax
blacklist hisax_fcpcipnp

# sound drivers
blacklist snd-pcsp

# I/O dynamic configuration support for s390x (bz #563228)
blacklist chsc_sch

# crypto algorithms
blacklist sha1-mb

# ixgbevf driver
#blacklist ixgbevf
8-3.VFIO-PCIについて

これも理由は8-2.と同様です。
また、KVMの場合、仮想マシン起動時に動的にVFIO-PCIを使用してくれるため、明示的に設定しなくても良いようです。

options行を削除してください。

# vi /etc/modprobe.d/vfio_pci.conf

options vfio_pci ids=8086:10ed

vfio_pci行を削除してください。

# vi /etc/modules-load.d/vfio_pci.conf

vfio_pci

上記8-1~8-2の設定が完了したら、ホストOSを一旦再起動してください。

9.補足2:内部ネットワーク的な疎通可否

全体構成図を見ながら、以下のマトリックスを見てください。
VLAN300:192.168.30.0/24
f:id:metonymical:20181104205525j:plain
VLAN301:192.168.31.0/24
f:id:metonymical:20181104221832j:plain
今回は(11)~(21)にIPアドレスアサインしました。
そこからPing疎通できた箇所にはRTTを記載しました。*6
Ping疎通できなかった箇所はNGと記載しています。

上記の表より、疎通NGだった箇所*7について記載したいと思います。

9-1.VLAN300:192.168.30.0/24の表について

以下2つのフローが疎通NGでした。

  • Src:(13), Dst:(16)
  • Src:(13), Dst:(19)

PF(ens1f0)⇔VF間におけるEtherフレームの受け渡しがうまくいっていないようでした。
ens1f0でPcapした結果、(13)→(16)、(13)→(19)のarpは確認できたものの、戻りのarp replayが見えず。
一方、c753のens4&5でPcapした結果、(13)→(16)へのarp受信後、(16)→(13)へのarp replayを返送していました。
このため、ens1f0での戻りのarp replayが見えない点が怪しいものの解決に至らず。。。

9-2.VLAN301:192.168.31.0/24の表について

以下2つのフローが疎通NGでしたが、疎通不可な理由は9-1に記載した事象と同一です。

  • Src:(15), Dst:(18)
  • Src:(15), Dst:(21)

以下の通信が全滅でした。

  • Src:(14), Dst:ALL

原因は、戻りのEtherフレームにVLAN301のタグが付いていることにより、(3)から(9)へ転送されてしまうためです。
実際、(9)や(15)でPcapしたところ、(14)宛てのVLANタグ付きフレームが受信できました。

9-3.RTTから見えてくるもの

宛先がSWになっているRTTを見てください。概ね1~2ms程度です。
また、自分自身にPingを打った場合のRTTは、おおむね100μs(0.100ms)以下となっています。
それ以外のRTTは概ね900~200μs(0.9~0.2ms)程度です。
Bridgeを使用したインターフェースのRTTと比較して、SR-IOVを使用したインターフェースのRTTは全体的に短時間(500μs程度)となっています。
加えて、SR-IOVを使用した者同士のRTTはさらに短時間(200~300μs程度)となっています。

10.補足3:KVMによるVF自動アサイン設定

「6.lxc754のBonding&VLAN+IP」に記載したアタッチ方法の場合、VFを自動的にアサインしてくれますが、今回紹介したKVMでの方法は手動設定を行いました。
理由は、KVMによるVF自動アサインを行った結果、(16)(17)を作成した際にens5がLinkUpしなかったためです。
但し、仮想マシン上でBondingしない場合は有用な設定方法だと思いますので、補足として記載しておきます。

10-1.定義ファイルの作成

以下のようにxmlの定義ファイルを作成し、virshコマンドで定義ファイルを読み込ませます。

# cat > sriov_ens1f0.xml << EOF
<network>
<name>sriov_ens1f0
<forward mode='hostdev' managed='yes'>
<pf dev='ens1f0'/>
</forward>
</network>
EOF

# virsh net-define sriov_ens1f0.xml
10-2.Virt-Manager上での設定

以下の画面にて、Edit→Connection Detailsを選択
f:id:metonymical:20181104223452j:plain

以下の画面にて、Autostartにチェックを入れApplyをクリック。
左下の再生ボタン*8をクリック。
f:id:metonymical:20181104223546j:plain
以下の画面にて、AddHardwareより、「Virtual Network 'sriov_ens1f0' : Hostdev network」を選択することができるようになります。
f:id:metonymical:20181104224002j:plain

これにより、ens1f0から自動的にVFがアサインされるようになります。
1つのPF上でVFを8個や16個など作成した場合には管理が煩雑となるため、どのVFを使用しているかを意識せずに設定することが可能となります。

以上です。

10.最後に

LinuxBridge*9とSR-IOVを駆使したネットワーク構成としては、概ね網羅できたと思います。

次のステップとしては、Open vSwitchによる分散仮想スイッチ*10の構成になると考えています。
さらに、パフォーマンス面ではDPDKを使用する*11ことに加え、足回りを全てSR-IOVにすることにより、ようやく最下層における基礎/基盤の部分が構成できるようになります。
その上で、あるホストから別のホストへトラフィック*12を転送する際に、MPLSやVxLANでトラフィックを識別し、対向スイッチ上では、MP-BGPやEVPNを使用することにより、Overlayネットワークが構成できるようになります。

SDN/NFVという言葉だけがあちこちに溢れていますが、最下層の仕組みを理解せずに上物だけをやってしまうのは、とても怖い気がしています。

*1:¥(9)にてVLAN301を付与しているためUntagとなります。

*2:厳密には、KVMとLXC/LXDでVFのアタッチ方法が異なります。詳しくは補足に記載します。

*3:補足で解説しますが、LXC/LXDの場合、PF=ens1f0やens1f1を指定するだけで、自動的に空いているVFをアタッチしてくれます。

*4:見かけ上の設定では上手くいったように見えますが、IP疎通性が無くなる場合があります。また、BondingインターフェースのSlaveのうちの一つがLinkUpしてくれないといった状態になります。

*5:つまり、ホストOS上でixgbevfがmodprobeされる状態にしておいてください。

*6:送信元:スイッチに関しては、min/avg/maxRTTの表記となっています。

*7:一部考察も含みます

*8:+ボタンの右隣になる横三角のボタン

*9:仮想スイッチのことです

*10:VMWareでいうところのvDistributionSwitch

*11:所謂、OvS-DPDKのことです

*12:所謂、East-Westトラフィック

LXC/LXDコンテナ上にEPC環境構築

LXC/LXDコンテナ上にEPC環境を構築しました。
利用するEPCはNextEPCとなります。

NextEPCに含まれるサービスは以下の通りです。
mme
hss
sgw
pgw
pcrf
webui

また、以下2つの内容が理解できていることを前提に記載しますので、LXC/LXD環境などは既に構築済みの状態からスタートします。
CentOS7でLXC/LXDのコンテナ環境構築 - Metonymical Deflection
LXC/LXDコンテナのネットワーク設定方法 - Metonymical Deflection

1.環境

1-1.VMWare
筐体                             : 自作PC
CPU                           : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
VMWare              : VMware(R) Workstation 12 Pro 12.5.9 build-7535481  
OS                               : CentOS7.5(1804)
Kernel                           : 3.10.0-862.el7.x86_64
Installed Environment Groups     : Minimal Install

WinおよびVMWare環境は以下の画像で確認してもらった方が良いかもしれません。
Win環境
f:id:metonymical:20180529200243j:plain
VMWare環境
f:id:metonymical:20181021182810j:plain

1-2.全体構成

f:id:metonymical:20181029104855j:plain
今回用意するlxcコンテナはUbuntu18.04となります。
公式サイトを読む限りCentOS7のコンテナでもいけそうなのですが、ビルドが必要っぽいので。
ロードマップには、いずれRPMも公開される旨、記載されていました。

1-3.全体の流れ

lxcコンテナ準備
NextEPCインストール
NextEPCのWebUIにアクセス

2.lxcコンテナ準備準備

2-1.Ubuntu18.04のコンテナ作成

今回はimages:からではなく、ubuntu:からコンテナイメージを引っ張ってきます。

lxc image list ubuntu: | grep 18.04
lxc launch ubuntu:18.04/amd64 lxc8041

出力例
[root@c757 ~]# lxc image list ubuntu: | grep 18.04
| b (9 more)         | 7a4f7e85f1fa | yes    | ubuntu 18.04 LTS amd64 (release) (20181024)     | x86_64  | 174.40MB | Oct 24, 2018 at 12:00am (UTC) |
| b/arm64 (4 more)   | 50fed56edee1 | yes    | ubuntu 18.04 LTS arm64 (release) (20181024)     | aarch64 | 158.29MB | Oct 24, 2018 at 12:00am (UTC) |
| b/armhf (4 more)   | bf45f28d0dca | yes    | ubuntu 18.04 LTS armhf (release) (20181024)     | armv7l  | 157.74MB | Oct 24, 2018 at 12:00am (UTC) |
| b/i386 (4 more)    | 3867042a618e | yes    | ubuntu 18.04 LTS i386 (release) (20181024)      | i686    | 176.20MB | Oct 24, 2018 at 12:00am (UTC) |
| b/ppc64el (4 more) | 852f241c93e1 | yes    | ubuntu 18.04 LTS ppc64el (release) (20181024)   | ppc64le | 182.86MB | Oct 24, 2018 at 12:00am (UTC) |
| b/s390x (4 more)   | a987004cb9f9 | yes    | ubuntu 18.04 LTS s390x (release) (20181024)     | s390x   | 166.14MB | Oct 24, 2018 at 12:00am (UTC) |
~一部省略~
[root@c757 ~]# lxc launch ubuntu:18.04/amd64 lxc8041
Creating lxc8041
Starting lxc8041
[root@c757 ~]# lxc list
+-----------+---------+---------------------+------+------------+-----------+
|   NAME    |  STATE  |        IPV4         | IPV6 |    TYPE    | SNAPSHOTS |
+-----------+---------+---------------------+------+------------+-----------+
| lxc8041   | RUNNING | 10.150.81.57 (eth0) |      | PERSISTENT |           |
+-----------+---------+---------------------+------+------------+-----------+
2-2.コンテナのネットワーク設定

lxc8041のeth1をlxdbr30にアタッチします。

lxc network list
lxc network attach lxdbr30 lxc8041 eth1
lxc network list

出力例
[root@c757 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 2       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 0       |
+---------+----------+---------+-------------+---------+
[root@c757 ~]# lxc network attach lxdbr30 lxc8041 eth1
[root@c757 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 2       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
2-3.ubuntuのネットワーク設定

lxc8041のeth1に固定IPを設定します。
IPアドレスは各自の環境に合わせてください。

[root@c757 ~]# lxc exec lxc8041 vi /etc/netplan/50-cloud-init.yaml

# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    version: 2
    ethernets:
        eth0:
            dhcp4: true
        eth1:
            dhcp4: false
            addresses: [192.168.30.50/24]
            dhcp6: false

設定反映後にIPアドレスが設定されているかを確認し一旦再起動します。

lxc exec lxc8041 netplan apply
lxc list
lxc exec lxc8041 reboot

出力例
[root@c757 ~]# lxc exec lxc8041 netplan apply
[root@c757 ~]# lxc list
+-----------+---------+----------------------+------+------------+-----------+
|   NAME    |  STATE  |         IPV4         | IPV6 |    TYPE    | SNAPSHOTS |
+-----------+---------+----------------------+------+------------+-----------+
| lxc8041   | RUNNING | 192.168.30.50 (eth1) |      | PERSISTENT |           |
|           |         | 10.150.81.57 (eth0)  |      |            |           |
+-----------+---------+----------------------+------+------------+-----------+
[root@c757 ~]# lxc exec lxc8041 reboot

3.NextEPCインストール

3-1.NextEPCのインストール
lxc exec lxc8041 bash
apt-get update
add-apt-repository ppa:acetcom/nextepc
apt-get -y install nextepc

ホストOS上からコンテナのbashへ移動
aptアップデート
リポジトリ登録
NextEPCのインストール

注意事項
リポジトリ登録時に以下のようにEnterキーを押すよう促してくるので、そのままEnterキーを押下してください。

root@lxc8041:~# add-apt-repository ppa:acetcom/nextepc
 NextEPC is a C-language Open Source implementation of the 3GPP Evolved
?Packet Core, i.e. the core network of an LTE network.(http://nextepc.org)
 More info: https://launchpad.net/~acetcom/+archive/ubuntu/nextepc
Press [ENTER] to continue or Ctrl-c to cancel adding it.
3-2.NextEPCのWebUIインストール
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
apt-get -y install nodejs
curl -sL http://nextepc.org/static/webui/install | sudo -E bash -

NodeSource Node.js 8.x のスクリプトインストール
nodejsインストール
NextEPCのWebUIインストール

3-3.サービスの有効化
systemctl enable nextepc-mmed
systemctl enable nextepc-sgwd
systemctl enable nextepc-pgwd
systemctl enable nextepc-hssd
systemctl enable nextepc-pcrfd
systemctl enable nextepc-webui
reboot

各種サービスの有効化
一旦再起動

3-4.サービスの起動確認

再起動後、サービスが起動するまで3分程度待ってください。
再起動直後のステータス

[root@c757 ~]# lxc list
+-----------+---------+----------------------+------+------------+-----------+
|   NAME    |  STATE  |         IPV4         | IPV6 |    TYPE    | SNAPSHOTS |
+-----------+---------+----------------------+------+------------+-----------+
| lxc8041   | RUNNING | 192.168.30.50 (eth1) |      | PERSISTENT |           |
|           |         | 10.150.81.57 (eth0)  |      |            |           |
+-----------+---------+----------------------+------+------------+-----------+

再起動3分後のステータス
pgwtunインターフェースが表示されていればOKです。

[root@c757 ~]# lxc list
+-----------+---------+----------------------+------------------+------------+-----------+
|   NAME    |  STATE  |         IPV4         |       IPV6       |    TYPE    | SNAPSHOTS |
+-----------+---------+----------------------+------------------+------------+-----------+
| lxc8041   | RUNNING | 45.45.0.1 (pgwtun)   | cafe::1 (pgwtun) | PERSISTENT |           |
|           |         | 192.168.30.50 (eth1) |                  |            |           |
|           |         | 10.150.81.57 (eth0)  |                  |            |           |
+-----------+---------+----------------------+------------------+------------+-----------+

4.NextEPCのWebUIにアクセス

4-1.ログイン

ログインします。

http://192.168.30.50:3000
Username:admin
Password:1423

f:id:metonymical:20181029102633j:plain
トップページ
f:id:metonymical:20181029114657j:plain

4-2.Subscriber情報の登録

IMSIの登録
f:id:metonymical:20181029114817j:plain
APNの登録
f:id:metonymical:20181029114850j:plain

以上です。

6.最後に

以下のサイトを参考にさせて頂きました。
Home - LXDドキュメント翻訳プロジェクトNextEPC | Guides | Installation
Raspberry Pi 3上にLTEコア網(Evolved Packet Core:EPC)機能を構築してみた(Raspberry Pi 3+ubuntu16.04 LTS+NextEPC)

メインは公式サイトですが、@m0ch1m0ch1さんの記事が大変良くまとめられています。

ラズパイ上で動くならコンテナ上でも動くかな?と思ってやってみましたが、何とか動くところまでは確認できました。
基地局側の環境を用意するのは、USRPなどが必要となってくるようで、少々敷居が高いのですが、タイミングをみて検証したいなと思っています。
あとはキャリアのSGWと接続テストとかやってみて上手くいきそうであれば、IoT用途に特化したPGWとしては有効活用できそうな気がしています。
また、OAI(Open Air Interface)などにも興味が湧いてきたので、折をみて検証したいなと考えています。
Home · Wiki · oai / openairinterface5G · GitLab

LXC/LXDコンテナのネットワーク設定方法

前々回の続きとなります。
前々回:CentOS7でLXC/LXDのコンテナ環境構築 - Metonymical Deflection

また、前回の内容が理解できていることを前提として記載します。
前回:Linux nmcliコマンドによるBonding VLAN Bridge Interface設定 - Metonymical Deflection

LXC/LXDコンテナは「LightweightなKVM」というイメージで使用しています。
このため、コンテナのトラフィックをBridgeで外部ネットワークに流して使用する場合の設定方法を記載したいと思います。

1.環境

1-1.VMWare
筐体                             : 自作PC
CPU                           : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
VMWare              : VMware(R) Workstation 12 Pro 12.5.9 build-7535481  
OS                               : CentOS7.5(1804)
Kernel                           : 3.10.0-862.el7.x86_64
Installed Environment Groups     : Minimal Install

WinおよびVMWare環境は以下の画像で確認してもらった方が良いかもしれません。
Win環境
f:id:metonymical:20180529200243j:plain
VMWare環境
f:id:metonymical:20181027233404p:plain
前々回の記事に加えてNICを追加していますが、実際に使用するのはトータル3つです。
具体的には以下の通りです。
仮想ネットワークエディタ
f:id:metonymical:20181027233530p:plain
ネットワーク接続
f:id:metonymical:20181027233605p:plain
Intel I219のプロパティ
f:id:metonymical:20181027233641p:plain
WindowsによるVLAN Interface設定方法は過去記事を参照ください。
metonymical.hatenablog.com

なお、ベアメタル環境でも同様に設定可能です。

1-2.全体構成

f:id:metonymical:20181027235006j:plain
上図のうちlxdbr0はLXD init時にDefaultで作成されています。
また、Default Profileの設定よりコンテナ作成時にlxdbr0が使用されるように構成されています。

但し、lxdbr0はNATして外部ネットワークに接続されています。私の用途としては、コンテナ上でyumなどを行いたい場合のInternet接続用マネジメントインターフェースとして使用しています。

しかし、KVMライクにLXC/LXDコンテナを使用したいので、今回行う設定は(1)~(2)となります。

具体的には新規でBridge lxdbr30を作成し、コンテナlxc751を収容します。
(1)はnmcliコマンドでも設定可能ですが、ここではlxc networkコマンドを使用して設定を行っていきます。

なお、前々回の続きという想定なので、lxc751というコンテナは既に作成済みという認識で進めます。

1-2.全体の流れ ~概要~
  1. DHCPによるIP固定設定の場合:(1)(2)
  2. 手動によるIP固定設定の場合:(1)(2)

 ※
 流れというよりも、それぞれ別々の設定となります。

1-3.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。

1.DHCPによるIP固定設定の場合
(1)
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=192.168.30.16/24 \
ipv6.address=none
(2)
lxc network attach lxdbr30 lxc751 eth1
lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
lxc start lxc751
lxc exec lxc751 dhclient eth1
lxc list

lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751
lxc list

2.手動によるIP固定設定の場合
(1)
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=none \
ipv6.address=none
(2)
lxc network attach lxdbr30 lxc751 eth1
lxc start lxc751
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:s/dhcp/none/g
IPADDR=192.168.30.48  #追記
PREFIX=24        #追記
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751
lxc list

2.DHCPによるIP固定設定の場合

物理インターフェースとBridgeインターフェースを1対1でアサインします。
nmcliよりもコマンド数は少ないです
(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ*1
(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ

投入コマンド
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=192.168.30.16/24 \
ipv6.address=none

出力例
[root@c756 ~]# lxc network create lxdbr30 \
> bridge.external_interfaces=ens34 \
> ipv4.address=192.168.30.16/24 \
> ipv6.address=none
Network lxdbr30 created
[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 0       |
+---------+----------+---------+-------------+---------+
[root@c756 ~]# lxc network show lxdbr30
config:
  bridge.external_interfaces: ens34
  ipv4.address: 192.168.30.16/24
  ipv6.address: none
description: ""
name: lxdbr30
type: bridge
used_by: []
managed: true
status: Created
locations:
- none

lxdbr30が作成され、物理インターフェースens34にもアタッチされました。
また、コンテナに対してDHCPIPアドレス割り当てを行うため、lxdbr30自身にもIPアドレスを設定しています。

(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

投入コマンドその1
lxc network attach lxdbr30 lxc751 eth1
lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
lxc start lxc751
lxc exec lxc751 dhclient eth1

出力例
[root@c756 ~]# lxc network attach lxdbr30 lxc751 eth1
[root@c756 ~]# lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
[root@c756 ~]# lxc start lxc751
[root@c756 ~]# lxc exec lxc751 dhclient eth1
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

lxdbr30にコンテナlxc751のeth1をアタッチし、コンテナのIP設定を行っています。
その後コンテナを起動し、lxc751のeth1上でdhclientコマンドを実行しています。
「コンテナのIP設定」と記載しましたが厳密には異なります。
これは、LXDの管理下におかれているlxdbr30に対して、DHCP固定IP 設定を行っています。
なお、上記コマンドの場合、恒久設定ではないためコンテナ上で設定ファイルを作成します。

投入コマンドその2
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751

出力例
[root@c756 ~]# lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
[root@c756 ~]# lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`

#コンテナのviが起動されるため、sed(:s/eth0/eth1/g)して保存(:wq)します。

[root@c756 ~]# lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`
[root@c756 ~]# lxc restart lxc751
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

「lxc exec lxc751」によりコンテナ上でコマンドを実行できます。
ifcfg-eth0 をコピーして、DEVICE=eth1に書き換え、コンテナを再起動しています。
しばらくして、lxc listによりeth1のアドレスが取得できていればOKです。

3.手動によるIP固定設定の場合

やっていることは前項と同様です。
では、何が異なるか?と言いますと、lxdbr30にIPアドレスを設定したくない場合を想定しています。
具体的には、以下のような構成の場合です。
f:id:metonymical:20181028010926j:plain
コンテナlxc751からLBまで、LBからコンテナlxc752までをそれぞれ同一VLANとしたい場合、Bridgeインターフェース上でIPアドレスを設定してしまうと、ホストOS上のRoutingテーブルにlxdbr30とlxdbr31がconnectedで載ってきてしまうため、LBまで到達せずに内部で折り返してしまいます。
一方でnet.ipv4.ip_forwardを無効にしてしまうと、今度はlxdbr0で稼働しているNAT+Routingが動作しなくなるため、lxdbr30にIPアドレスを設定せずに構成する方法を記載します。

(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ

投入コマンド
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=none \
ipv6.address=none

出力例
[root@c756 ~]# lxc network create lxdbr30 \
> bridge.external_interfaces=ens34 \
> ipv4.address=none \
> ipv6.address=none
Network lxdbr30 created
[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 0       |
+---------+----------+---------+-------------+---------+
[root@c756 ~]# lxc network show lxdbr30
config:
  bridge.external_interfaces: ens34
  ipv4.address: none
  ipv6.address: none
description: ""
name: lxdbr30
type: bridge
used_by: []
managed: true
status: Created
locations:
- none

lxdbr30が作成され、物理インターフェースens34にもアタッチされました。
但し、lxdbr30自身にはIPアドレスが設定されていません。

(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

投入コマンドその1
lxc network attach lxdbr30 lxc751 eth1
lxc start lxc751

出力例
[root@c756 ~]# lxc network attach lxdbr30 lxc751 eth1
[root@c756 ~]# lxc start lxc751
[root@c756 ~]# lxc list
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |        IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                     |                                              | PERSISTENT |           |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 10.106.42.75 (eth0) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+

lxdbr30にコンテナlxc751のeth1をアタッチしましたが、コンテナのIPは設定されていません。

投入コマンドその2
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:s/dhcp/none/g
IPADDR=192.168.30.48  #追記
PREFIX=24        #追記
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751

出力例
[root@c756 ~]# lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
[root@c756 ~]# lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`

#コンテナのviが起動されるため、sedで置換してIPとPrefixを追記して保存します。

[root@c756 ~]# lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
IPADDR=192.168.30.48
PREFIX=24
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`
[root@c756 ~]# lxc restart lxc751
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

ifcfg-eth0 をコピーして、DEVICE=eth1に書き換え、コンテナを再起動しています。
しばらくして、lxc listによりeth1のアドレスが表示されていればOKです。

4.補足1:nmcliコマンドでBridgeを作成した場合

nmcliコマンドでBridgeインターフェースを作成しても、lxc上で利用可能です。
しかし、nmcliコマンドで作成した場合、lxdの管理下から外れるため、以下のようにMANAGED=NOとなります。

[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | NO      |             | 0       |
+---------+----------+---------+-------------+---------+

nmcliでBridgeを作成した場合、LXDクラスタを組んだときなどに困りそうな予感はしていますが、もう少し検証してみようと思います。

なお、LXC/LXDのネットワーク周りの設定は以下の公式サイトに詳細が記載されています。
https://lxd-ja.readthedocs.io/ja/latest/networks/

5.補足2:PortForwarding設定

コンテナ内のサービスを外部に公開したい場合、今回解説したBridgeの他に、Defaultで作成されるlxdbr0上でPortForwardingを行う方法があります。

lxc config device add lxc751 httpd proxy listen=tcp:0.0.0.0:80 connect=tcp:localhost:80

lxc751:コンテナ名
httpd:任意の名前
listen=tcp:0.0.0.0:80:ホスト側の待受けポート*2
connect=tcp:localhost:80:コンテナ側(lxc751)の待受けポート

以上です。

6.最後に

以下のサイトを参考にさせて頂きました。
Home - LXDドキュメント翻訳プロジェクト
第535回 LXD 3.0のネットワーク設定:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社

LXC/LXDはコンテナ起動後、ちょいちょいいじりたい時に便利だなと思っています。
なので「LightweightなKVM」とか「KVMライク」といった使い方が、私にはマッチしています。

ちなみに、SR-IOVやCloud-initにも対応しているため、そちらの検証もやってみたいなと思います。

*1:lxcコマンドでは、アサインではなく、アタッチという言葉を使っているため統一します。

*2:IPはホストOSの物理インターフェースのIPアドレスにアクセスしてください。