Nested KVM on KVM debian12

■今回は特に仮想マシンのCPUオプションを変えたとき、host-modelとhost-passthrough、customのそれぞれでどうなるのかを確認する

■Nestedにするということはvmx|svmフラグが見える、仮想マシンのホストとして使えるということ
　物理ホストの時点で以下のようなフラグがないなら、Nestedにはできない
　Intel Xeon 4C8Tとamd Ryzen 8C16Tの両方で確認する
　※Xeonは流石に古すぎるのでGPUパススルーやvGPUには使えないので、あくまでCPUのフラグの確認のため

```
# Intel
$ lscpu | grep "Model name"
Model name:                           Intel(R) Xeon(R) CPU E31280 @ 3.50GHz

$ lscpu | grep Virt.*n:
Virtualization:                       VT-x

$ awk '{for(a=1;a<=NF;a++){if($a ~ /vmx|svm/){print $a | "uniq -c"}}}' /proc/cpuinfo 
      8 vmx
```
```
# amd
$ lscpu | grep "Model name"
Model name:                           AMD Ryzen 7 5800U with Radeon Graphics

$ lscpu | grep Virt.*n:
Virtualization:                       AMD-V

$ awk '{for(a=1;a<=NF;a++){if($a ~ /vmx|svm/){print $a | "uniq -c"}}}' /proc/cpuinfo 
     16 svm
```
■仮想マシンのCPU(8vCPU)をhost-passthroughで構成し、vmx|svmフラグが見えていればkvm on kvmができる
　最近の仮想マシンマネージャで作ったのなら、何もしなくてもhost-passthroughになっているはず
 
```
$ virsh console kvm-debian12 
xxx@kvm-debian12:~$ awk '{for(a=1;a<=NF;a++){if($a ~ /vmx|svm/){print $a | "uniq -c"}}}' /proc/cpuinfo 
      8 svm
```

■amd,intelのkvmモジュールが1かYで読み込まれていることを確認
　なんらかのインストール中にCPUフラグを認識した時点で自動設定されているはずなので、手動で設定するケースはトラブルシュートくらい

```
$ awk '{print FILENAME":"$0}' /sys/module/kvm_*/parameters/nested
/sys/module/kvm_intel/parameters/nested:Y

$ lsmod | grep kvm
kvm_intel             380928  0
kvm                  1146880  1 kvm_intel
irqbypass              16384  1 kvm
```
```
$ awk '{print FILENAME":"$0}' /sys/module/kvm_*/parameters/nested
/sys/module/kvm_amd/parameters/nested:1

$ lsmod | grep kvm
kvm_amd               155648  2
kvm                  1146880  1 kvm_amd
irqbypass              16384  11 kvm
ccp                   118784  1 kvm_amd
```
■0かNでkvm_intel,kvm_amdが無ければロードする

```
# Intel
$ cat /etc/modprobe.d/kvm.conf 
options kvm_intel nested=1
$ sudo modprobe -r kvm_intel
$ sudo modprobe kvm_intel
```

```
# amd
$ cat /etc/modprobe.d/kvm.conf 
options kvm_amd nested=1
$ sudo modprobe -r kvm_amd
$ sudo modprobe kvm_amd
```

■モジュールの「-r」はremove、オプションなしはload
```
$ man modprobe | lsec -sep "^\$" -r,

       -r, --remove
           このオプションを指定すると、modprobe は、モジュールを組み込む代わりに、 それを取り外します。そのモジュールが依存しているモジュール
           も使用されていない場合は、 それもまた取り外そうとします。組み込みを行う場合とは違って、 複数のモジュールをコマンドラインで指定する
           ことができます (モジュールを取り外す場合には、モジュールパラメータを指定しても意味がありません)。
```

■vmx|svmフラグをどう見せるか、host-modelとhost-passthrough、customの違い

ざっくりいうと、host-passthroughは全く同じCPUで、
host-modelはCPUの世代ファミリーになる
customはCPUの世代ファミリーになるとともに、ポリシーとしてフラグがたくさん可視化される

[ホストCPUをパススルーせずにNested KVM を動かす (openSUSE Leap 15.1)](https://haruka-note.hateblo.jp/entry/20190807_nestedkvm "ホストCPUをパススルーせずにNested KVM を動かす (openSUSE Leap 15.1)")

customはデフォルトらしいので、物理CPUが何であるかを気にしなくていい
CLIから作るとおそらくこれ。はじめからcustomを選んでポリシーが色々付くかどうかはわからない。

[20.11. CPU モデルとトポロジー　](https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-libvirt-dom-xml-cpu-model-top#sect-libvirt-dom-xml-cpu-model-top "20.11. CPU モデルとトポロジー")

■まずはhost-passthrough
　物理CPUがそのまま見えている

```
$ virsh dumpxml kvm-hpdebian | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='host-passthrough' check='none' migratable='on'/>

$ virsh console kvm-hpdebian
xxx@kvm-hpdebian:~$ grep name /proc/cpuinfo | uniq -c
      4 model name	: Intel(R) Xeon(R) CPU E31280 @ 3.50GHz

$ lsmod | grep kvm
kvm_intel             380928  0
kvm                  1146880  1 kvm_intel
irqbypass              16384  1 kvm

```

```
$ virsh dumpxml kvm-debian12 | grep "cpu mode"
  <cpu mode='host-passthrough' check='none' migratable='on'/>

$ virsh console kvm-debian12
xxx@kvm-debian12:~$ grep name /proc/cpuinfo | uniq -c
      8 model name	: AMD Ryzen 7 5800U with Radeon Graphics
      
xxx@kvm-debian12:~$ lsmod | grep kvm
kvm_amd               155648  0
ccp                   118784  1 kvm_amd
kvm                  1146880  1 kvm_amd
irqbypass              16384  1 kvm

```

■仮想マシンを起動したままは変えられないし変えられても反映しないので、仮想マシンを停止して「virsh edit」で「host-model」に変えると、「migratable」オプションが使えなくなるという警告が出るので削除する

>エラー: サポートされない設定: migratable 属性は、'host-passthrough' / 'maximum' CPU モードでのみ許可されます

　一行で閉じているところを複数行にして、意図的に「feature policy」行をつけないとvmx|svmフラグが見えなくなるので注意する
 　パススルーの「AMD Ryzen7 5800U」と違い、「AMDの第3世代EPYCプロセッサ」に抽象化される

```
$ virsh dumpxml kvm-debian12 | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='host-model' check='none'>
    <feature policy='require' name='svm'/>
  </cpu>
$ virsh start kvm-debian12
$ virsh console kvm-debian12
xxx@kvm-debian12:~$  grep name /proc/cpuinfo | uniq -c
      8 model name	: AMD EPYC-Milan Processor

xxx@kvm-debian12:~$  awk '{for(a=1;a<=NF;a++){if($a ~ /vmx|svm/){print $a | "uniq -c"}}}' /proc/cpuinfo 
      8 svm
```
■Intel cpuならvmx。ほかは自動で色々つけてくれるので、仮想マシンを再起動して確認

```
$ virsh dumpxml kvm-hpdebian | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='host-model' check='none'>
    <feature policy='require' name='vmx'/>
  </cpu>
$ virsh start kvm-hpdebian
$ virsh dumpxml kvm-hpdebian | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>SandyBridge-IBRS</model>
    <vendor>Intel</vendor>
    <feature policy='require' name='vme'/>
    <feature policy='require' name='vmx'/>
    <feature policy='require' name='pdcm'/>
    <feature policy='require' name='pcid'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='arat'/>
    <feature policy='require' name='tsc_adjust'/>
    <feature policy='require' name='umip'/>
    <feature policy='require' name='md-clear'/>
    <feature policy='require' name='stibp'/>
    <feature policy='require' name='arch-capabilities'/>
    <feature policy='require' name='ssbd'/>
    <feature policy='require' name='xsaveopt'/>
    <feature policy='require' name='ibpb'/>
    <feature policy='require' name='ibrs'/>
    <feature policy='require' name='amd-stibp'/>
    <feature policy='require' name='amd-ssbd'/>
    <feature policy='require' name='skip-l1dfl-vmentry'/>
    <feature policy='require' name='pschange-mc-no'/>
  </cpu>

$ virsh console kvm-hpdebian
xxx@kvm-hpdebian:~$ grep name /proc/cpuinfo | uniq -c
      4 model name	: Intel Xeon E312xx (Sandy Bridge, IBRS update)
xxx@kvm-hpdebian:~$ awk '{for(a=1;a<=NF;a++){if($a ~ /vmx|svm/){print $a | "uniq -c"}}}' /proc/cpuinfo 
      8 vmx

```
■仮想マシンが起動中のまま、virsh editで「<cpu mode='custom' check='none' />」に変えると、
　amdでも自動で色々つけてくれるので、仮想マシンを再起動して確認

```
$ virsh dumpxml kvm-debian12 | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>EPYC-Milan</model>
    <vendor>AMD</vendor>
    <feature policy='require' name='x2apic'/>
    <feature policy='require' name='tsc-deadline'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='tsc_adjust'/>
    <feature policy='require' name='vaes'/>
    <feature policy='require' name='vpclmulqdq'/>
    <feature policy='require' name='spec-ctrl'/>
    <feature policy='require' name='stibp'/>
    <feature policy='require' name='arch-capabilities'/>
    <feature policy='require' name='ssbd'/>
    <feature policy='require' name='cmp_legacy'/>
    <feature policy='require' name='virt-ssbd'/>
    <feature policy='require' name='lbrv'/>
    <feature policy='require' name='tsc-scale'/>
    <feature policy='require' name='vmcb-clean'/>
    <feature policy='require' name='pause-filter'/>
    <feature policy='require' name='pfthreshold'/>
    <feature policy='require' name='v-vmsave-vmload'/>
    <feature policy='require' name='vgif'/>
    <feature policy='require' name='rdctl-no'/>
    <feature policy='require' name='skip-l1dfl-vmentry'/>
    <feature policy='require' name='mds-no'/>
    <feature policy='require' name='pschange-mc-no'/>
    <feature policy='disable' name='pcid'/>
    <feature policy='require' name='svm'/>
    <feature policy='require' name='topoext'/>
  </cpu>
$ virsh console kvm-debian12
xxx@kvm-debian12:~$ lsmod |grep kvm
kvm_amd               155648  2
kvm                  1146880  1 kvm_amd
irqbypass              16384  11 kvm
ccp                   118784  1 kvm_amd

xxx@kvm-debian12:~$ grep name /proc/cpuinfo | uniq -c
      8 model name	: AMD EPYC-Milan Processor

```
■Intelでは少し設定がかわるようで、「model」指定が必要
　「vendor」行は自動で付くだろうけど、入力する側の意識として追加

>エラー: XML エラー: CPU モデルなしで CPU 機能リストが指定されました

```
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>SandyBridge-IBRS</model>
    <vendor>Intel</vendor>
    <feature policy='require' name='vmx'/>
  </cpu>
```

ほかのフラグが自動で付くのはどうよう
```
$ virsh dumpxml kvm-hpdebian | lsec -sep '^  <[a-z]' "cpu mode"
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>SandyBridge-IBRS</model>
    <vendor>Intel</vendor>
    <feature policy='require' name='vme'/>
    <feature policy='require' name='vmx'/>
    <feature policy='require' name='pdcm'/>
    <feature policy='require' name='pcid'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='arat'/>
    <feature policy='require' name='tsc_adjust'/>
    <feature policy='require' name='umip'/>
    <feature policy='require' name='md-clear'/>
    <feature policy='require' name='stibp'/>
    <feature policy='require' name='arch-capabilities'/>
    <feature policy='require' name='ssbd'/>
    <feature policy='require' name='xsaveopt'/>
    <feature policy='require' name='ibpb'/>
    <feature policy='require' name='ibrs'/>
    <feature policy='require' name='amd-stibp'/>
    <feature policy='require' name='amd-ssbd'/>
    <feature policy='require' name='skip-l1dfl-vmentry'/>
    <feature policy='require' name='pschange-mc-no'/>
  </cpu>
```
  
■KVMでも、「KVM on KVM」でも、やり方はどちらも同じ

[2023-11-03 debian bookwormにKVMを入れてみる](https://labunix.hateblo.jp/entry/20231103/1698937929 "2023-11-03 debian bookwormにKVMを入れてみる")

■いつの間にか「virsh console」するための「update-grub」がなくなっているので、「grub-mkconfig」を使う

```
$ virsh dumpxml kvm-hpdebian | grep console
    <console type='pty' tty='/dev/pts/2'>
    </console>

$ ssh kvm-hpdebian
xxx@kvm-hpdebian~$ su
root@kvm-hpdebian~# grep CMDLINE_LINUX= /etc/default/grub
GRUB_CMDLINE_LINUX="console=pty3 console=ttyS0,115200n8"

root@kvm-hpdebian~# /sbin/grub-mkconfig -o /boot/grub/grub.cfg
root@kvm-hpdebian~# /sbin/shutdown -r now && exit

$ virsh autostart kvm-hpdebian 
ドメイン 'kvm-hpdebian' は自動起動としてマークされています

$ virsh console kvm-hpdebian
```

■余談

host-modelを選んだときに
私は「qemu-system-<architecture>」世代ですが、「virt-install」世代ではストレージプールを先に作る方式のようですね。cockpitというWeb管理で仮想マシンを作ったときに知りました。

■まとめ

Nested KVMでHyper Visor on KVMの記事を見ていると、「host」にして(そんな設定は見たことないけど、内容は「host-model」の設定なので古い設定名かも？)とか、「host-passthrough」じゃないとダメみたいなニュアンスの記述を見かけるけど、「feature policy」を自分で書けないならダメという、いわゆる「#include <stdio.h>」がおまじないみたいに、意味があるところの説明を省いているだけなのだと理解した。