ゲーミングノートパソコンでも仮想環境で完全無線フルトラしたい

## はじめに
外出用にm1 macbookを買いました。素晴らしい電池持ちと性能とトレードオフでlinuxと微妙に違う挙動(特にctrlとcommand)、パッケージマネージャの更新が遅い(これは大概pacmanになれてるせい)、parallels買わないとろくにwindowsが使えない(windowsはVRChatするだけ)などかゆいところに手が届かない感じでもやもやしていました。
デスクトップは別用でGPUを使う、帰省も大型休み毎にすることも踏まえて外出時とデスクトップのGPUが使えないときのVR専用兼開発機としてゲーミングノートパソコンを買ってしまいました。
私はデュアルブート絶対許さない主義なので、今回も[windows in ArchLinuxで無線フルトラする](https://qiita.com/Sumi-Sumi/items/0900d6accd9a7f9d02c2#1-gpu%E3%81%8C%E3%83%9B%E3%82%B9%E3%83%88pc%E3%81%AB%E3%83%90%E3%82%A4%E3%83%B3%E3%83%89%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%8B%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B)のときと同じようにwindowsには仮想環境の中だけで生きてもらおうとしたのですが、デスクトップのときとは違い非常に手間取ったので備忘録として残したいと思います。
VRChat向けにしていますが、通常用途でVMに外から接続したいときでも有効です。(調べても設定まで解説しているのはあまり出てこなかった)

## 本当にする必要ありますか???
ラップトップはデスクトップと比べてベンダー特有の設定が多分に含まれており、設定の変更にはベンダーが提供するwindows専用のアプリが必要な場合が多いです。有志がlinux向けに設定変更用のアプリを開発している機種もありますが、安定した状態で使うにはwindowsとのデュアルブートを勧めます。特に最近の15インチ以上のノートパソコンには、m.2スロットが2スロット以上搭載されているものも存在し(14インチでもある?)、デュアルブート構築時にwindowsがlinuxのパーティションを消し去るという悲劇を回避できます。また、biosの更新にも前述の専用アプリが必要になる場合が多いためwindowsは残しておくのが無難かと思います。
~~まぁそもそもベンダー特有の設定でしか変更できないようなラップトップを買う前によく調べてlinuxをメインで使えるようなパソコンを買おう...~~
更にWiFi特有の問題によりVMのwindowsに外からアクセスするのは非常にめんどくさくなっています。
GPUに外部ディスプレイがつながっていないとろくにGPUを使ってくれないのも非常に辛いです。(余分なパーツが必要)
それでもlinuxになれると他のOS使いにくいんじゃ...

## 今回設定した環境について

| モデル名 | ASUS Zephyrus G14 GA401QM |
| :-: |:-: |
| ホストOS | Archlinux |
| ゲストOS | windows10 |
| CPU | Ryzen9 5900HS (8C16T) |
| RAM | 16GB |
| iGPU | AMD Radeon |
| dGPU | NVIDIA RTX 3060 (6GB) |

## インストールの前に(まだwindowsを消し飛ばさないで!!!)
* windows側で高速スタートアップを無効化してください
    * linux側でwifiカードが見えなくなります
* Armoury CrateからiGPUモードを無効化してください
    * NVIDIA GPUの有効化無効化がlinuxからできなくなります
* Armoury Crateから最新のドライバーをインストールしてください
    * 一応ASUSのゲーミングラップトップはまだ寛容なのかBIOSの更新はBIOSから直接できます ([EasyFlush](https://www.asus.com/jp/support/FAQ/1008859/))
* セキュアブートを無効化する
    * 気になるようであれば後で有効化の手順を踏んでください(持ち運ぶものなのでやったほうがいい)

##  Zephyrus G14にArchlinuxをインストールする
* [ArchWiki]()と[ASUS NoteBook Linux](https://asus-linux.org/wiki/arch-guide/)見てインストールしてください。
    * カーネルはカスタムカーネルである```linux-g14```をインストールしてください
* lvmで構築するとパーティションの分割、削除が楽かつwindowsの動作が速くなります
* nvidia-driverなどもここで入れてください
    * ただし、**mkinitcpio.confのmoduleには何も入れなくていいです**

## 必要なパッケージをインストールする
```shell
# 仮想化関連
pacman -S qemu qemu-arch-extra edk2-avmf libvirt virt-manager

# ネットワーク関連
pacman -S dhcp
paru -S parprouted
```

## 仮想環境を構築する
1. ```asusctl graphics -m integrated```でiGPUモードにする     
    ・```asusctl graphics -g```でintegratedになっているかつ```lspci | grep VGA```でNVIDIA GPUが表示されていなければ大丈夫です
2. [こちらのガイド](https://asus-linux.org/wiki/vfio-guide/)を参考にwindowsをインストールしてください    
    ・ インストール直後、デバイスマネージャーでGPUを見るとerror code43が表示されていますが最新のNVIDIA driverをインストールすればエラーコードは消えます     
    ・NVIDIA driverは[公式サイト](https://www.nvidia.co.jp/Download/index.aspx?lang=jp)から入れてください     
    ・chocolateyで入れるとエラーになります(ハマりポイント)
3. インストールが終了したらシャットダウンする

#### **※注意**
* Zephyrus G14の場合、type-c経由で外部ディスプレイを繋がないとアプリがGPUを使ってくれません。
type-cのディスプレイがない場合、[仮想ディスプレイアダプタ](https://www.amazon.co.jp/Cablecc-CY%E4%BB%AE%E6%83%B3%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%83%BCUSB-C-Type-C-EDID%E3%83%80%E3%83%9F%E3%83%BC%E3%83%97%E3%83%A9%E3%82%B0%E3%83%98%E3%83%83%E3%83%89%E3%83%AC%E3%82%B9%E3%82%B4%E3%83%BC%E3%82%B9%E3%83%88%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF1920x1080p-60Hz/dp/B086MKR9WH)が別途必要になります。
* ガイドにも書かれていないのでしないと思いますが、デスクトップのときと違いmkinitcpio.confにvirioモジュールやnvidiaのモジュールは書かなくていいです。(というか書いたらだめ???)

## 仮想ブリッジを構築する(ここの構築が一番めんどくさかった)
wifi(というよりIEEE 802.11の策定)はレイヤー2転送をサポートしていないため通常のブリッジネットワークを構築できないようです。(詳しいことは[こちら](https://headtonirvana.hatenablog.com/entry/2020/07/11/223922)で説明されています。)
wifi使用下でのブリッジネットワークの構築は[BridgeNetworkConnectionsProxyArp](https://wiki.debian.org/BridgeNetworkConnectionsProxyArp)や[こちらの記事](https://qiita.com/mmt/items/a085af0418874b6cc7d1)で説明されていますが、有線ポートとのブリッジなので直接使えません。
これらを応用しつつ、systemdのサービスとすることで自動構築できるようにしていきます。

###  1. 構築テスト
* 以下はrootで実行する

```shell
# bridgeの追加
ip link add br0 type bridge

# bridgeにipアドレスの追加
# ipアドレスはローカルネットワーク内のアドレスにする
# ホストのipが192.168.1.10であるとき、与えるアドレスは192.168.1.x (xは任意)
ip addr add 192.168.1.15/24 dev br0

# DHCPの中継(デバッグモードで起動)
# アドレスはDHCPサーバーのアドレス
# wlan0はホストのwifiデバイスに置き換える
dhcrelay 192.168.1.1 -i wlan0 -i br0 -d

# 以下は別のシェルで行う
# Proxy ARPの中継(デバッグモードで起動)
parprouted -d wlan0 br0
```

### 2. virt-managerのネットワーク設定
* virt-managerのネットワークをNATからbridge deviceに変更してbr0を指定

### 3. VMの起動とネットワークの確認
* 起動してネットワークにつながるか確認
* dhrelayとparproutedにエラーが出ていないか
    * ipv4のアドレスが付与されていないことでdhcrelayがエラーを吐きやすい
* ifconfigでローカルネットワーク内のアドレスが付与されているか
* 別の端末からifconfigで確認したアドレスにpingを飛ばして返ってくれば成功
* 成功すればVMのシャットダウン
* ```ip link del br0```でブリッジの削除とdhcrelayとparproutedをkillする

### 4. systemd-networkによるブリッジデバイスの作成
* systemd-networkでブリッジデバイスを作成する際に```ConfigureWithoutCarrier=yes```を付与しないとブリッジデバイスにアドレスが付与されない
* 作成後```systemctl restart systemd-networkd```で作成

```br0.netdev
[NetDev]
Name=br0
Kind=bridge
```

```30-br0.network 
[Match]
Name=br0

[Network]
Address=192.168.1.15/24
ConfigureWithoutCarrier=yes
```

### 5. systemdサービスの作成と有効化
* 2で接続できることを確認したらdhcrelayとparproutedのsystemdサービスを作成する
* dhcrelayでshを使用してるのはDHCPサーバのipを自動で取得させるため
* 作成したら```systemctl enable --now parprouted dhcrelay```で有効化
* 3と同じようにVMのネットワーク接続の確認
    * 接続できなかったら```systemctl status dhcrelay parprouted```で確認して対処

```/etc/systemd/system/parprouted.service
[Unit]
Description=Setup parprouted
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/parprouted wlp2s0 br0
RemainAfterExit=true

[Install]
WantedBy=multi-user.target
```

````/etc/systemd/system/dhcrelay.service
[Unit]
Description=Start up dhcrelay wlan0 to br0
Wants=network-online.target
After=network-online.target parprouted.service

[Service]
ExecStart=/bin/sh -c "/usr/bin/dhcrelay $(ip r | head -n 1 | awk '{print $3}') -i wlan0 -i br0"
RemainAfterExit=true

[Install]
WantedBy=multi-user.target
```
　
### 6. Virtual Desktopから接続できるか確認
* VMに[Virtual Desktop](https://www.vrdesktop.net/https://www.vrdesktop.net/)をインストールして接続してください
    * 接続できなれければネットワーク設定が間違っているか設定が反映されていないかです
    * ```ip a```でbr0にアドレスが付与されているか確認してください

## VRCとフルトラのセットアップ
* [この記事](https://qiita.com/Sumi-Sumi/items/0900d6accd9a7f9d02c2#1-gpu%E3%81%8C%E3%83%9B%E3%82%B9%E3%83%88pc%E3%81%AB%E3%83%90%E3%82%A4%E3%83%B3%E3%83%89%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%8B%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B)の**必要なソフトをダウンロードしてセットアップする**以降を参考にセットアップしてください
* 無線フルトラの方法は上の記事とその参考に任せます。

## 終わりに
wifi環境下のVMで外部からwindowsに接続する方法がなかなか見つからなかったので構築までに3日かかりました。
また、systemd-networkdはネットワークに接続されていないデバイスにアドレスを付与するにはオプションを設定しないと付与できないところでもつまりました。(それによってdhcrelayとparproutedが起動せずループしてたことでハイバネーションも使えなかった)
ラップトップでVRすると温度が100℃近くなるので心臓に悪いです。
NVIDIA(というよりwindows??)は仮想アダプタがなくてもlinuxの```prime-run```のようにGPUを使えるようにしてほしいです。~~(そもそも仮想環境でVRするな)~~