当前目录
mkdir root-armvirt; cd root-armvirt; cpio -idv -F ../openwrt-22.03.0-armvirt-64-rootfs.cpio
cd ..; tmux;
qemu-system-aarch64 -nographic -M virt -m 64 -kernel openwrt-22.03.0-armvirt-64-Image \
-no-reboot -nographic -nic user -nic user -cpu cortex-a53 -smp 4 \
-fsdev local,id=rootdev,path=root-armvirt/,security_model=none \
-device virtio-9p-pci,fsdev=rootdev,mount_tag=/dev/root \
-append 'rootflags=trans=virtio,version=9p2000.L,cache=loose rootfstype=9p'
这个vm的网络,是和实体机共享网卡的方式,host方式。如果需要开放vm的端口,需要在创建时指定端口的映射。
方法二,用别人创建好的 combine 的 img 映像
【varoudis/openwrt_arm64_uefi】
【Arm64 (or armvirt) with UEFI boot?】
下载文件,https://www.dropbox.com/s/gpqdrzv1z9mt0ou/openwrt-arm64-efi-generic-ext4-combined.img.gz?dl=0
文件75MB,解压后1.2GB。内部空间984MB,Used:221MB,Available:747MB。
这个映像有点问题。不知道哪个服务导致的问题。这个映像里头,有好多不知名的东西。
如果只给一个网卡,op只有lan口,但br-lan和eth0 都会通过dhcp获取到一个IP。致使op会有多个缺省路由,导致op无法访问外网。被op自身防火墙挡住了。
如果给俩个网卡,op有lan和wan。如果lan口有dhcp,lan还是会获取一个ip和网关。最终还是无法上网。
必须给op两个网卡,一个有dhcp做wan,一个无dhcp做lan,才行。
系统的virbr0的default网络,就不动它了。新增一个virbr1 叫 lan-op 的网络,不带DHCP,不带NAT。就是隔离网络,不能连外网。
也可以根据需要,保留nat。去掉<forword mod='nat />的注释即可。<!--
文件名: lan-op.xml
<network>
<name>lan-op</name>
<forward mode='nat'/>
<bridge name='virbr1' stp='on' delay='0'/>
<ip address='192.168.22.22' netmask='255.255.255.0'>
</network>
virsh net-define lan-op.xml; virsh net-start lan-op; virsh net-autostart lan-op
执行以下命令,创建vm。virt-install \
--virt-type kvm \
--name op-arm64 \
--memory 512 \
--vcpus 2 \
--cpu host-passthrough \
--os-variant linux \
--network bridge=virbr1,model=virtio \
--network bridge=virbr0,model=virtio \
--graphics vnc \
--import \
--noautoconsole \
--autostart \
--disk path=/var/lib/libvirt/images/openwrt-arm64-efi-generic-ext4-combined.img,bus=virtio,format=raw
列出所有的vm,virsh list --all。
virsh, virt-install 操作,参考【CentOS8_debian11_远程ssh连接_在线安装KVM_虚拟化嵌套_安装客户机openwrt_NAT端口映射】。
如果操作错误,想删除这个vm。强制关机virsh destroy op-arm64,删除vmvirsh undefine op-arm64。
如果不删除这个vm,只禁止自动启动,virsh autostart --disable op-arm64。
第一次启动op,修改lan口IP。
virsh console op-arm64,回车进入shell,修改 /etc/config/network,然后/etc/init.d/network reload 或 restart。
或用 uci命令修改IP,见【制作免配置固件】,【官方文档:The UCI system】。uci set network.lan.ipaddr='192.168.xx.10'
uci commit network
/etc/init.d/network reload
最后 按 ctrl+] 退出 console。之后就可以使用浏览器访问web配置界面。
配置一下op使用的dns,否则不能解析域名。
Network->DHCP and DNS->DNS forwording。如果是内网使用,还要去掉"丢弃RFC1918"项的勾。(有效)。
命令行,改/etc/config/dhcp,在config dnsmasq中,有list server '8.8.8.8' 和 option rebind_protection '0'
这个映像有问题,在 System->Startup 中,需要禁用 https-dns-proxy 才行。否则会出来捣乱。
或者,设置WAN口,使用自定义dns。(可以)。
或者,设置LAN口,使用自定义dns。(本应该可以。但此映像无效,不知哪个服务在捣乱)。
这个映像的源,指向了 snapshots。修改一下。
sed -i s_snapshots_releases/22.03.0_ /etc/opkg/distfeeds.conf
sed -i s_arm64/efi_armvirt/64_ /etc/opkg/distfeeds.conf
修改 /etc/opkg.conf 不检查签名。就可以 opkg update 操作了。
只能装普通包,不能装 kmod 包。
如果使用 armvirt-64 的 sdk 编译了第三方 ipk。
编译的包是基于aarch64_cortex-a53架构的。这个映像是基于aarch64_generic的,会拒绝安装。其实是可以运行的。
opkg print-architecture 打印出本系统支持的架构。
解决办法,临时在 /etc/opkg.conf 中加入一行 arch aarch64_cortex-a53 10,装完第三方包后,再删除这一行。
如果有依赖原版的包。那就把opkg print-architecture输出的内容,加上上面这行,都加进去,装完再删。
golang 交叉编译的程序,在op上运行,time.Now()输出的时间,时区不对。是因为op中缺失/etc/localtime文件。
从Linux系统中copy一个过去就好了。
检查一下,openwrt系统中 ntp服务器的ip,是否能对时成功。有的服务比较依赖时间的准确度。
方法三,自己创建 combine 的 img 映像,自己编译内核
参考【Building OpenWrt from Scratch for ARM64 UEFI ACPI VM】
参考这篇文章的后半部分,创建 img
最终发现,官方的 openwrt-22.03.0-armvirt-64-Image,
缺少这三个支持,CONFIG_EFI_STUB=y, CONFIG_EFI=y, CONFIG_EFI_VARS=y。
gurb 能启动,kernel无法启动。
注意: 制作 img 中,只需执行 grub-mkimage, 无需执行 grub-install。
参考这篇文章,从源码编译
同时参考【官方文档】。
2022-11月,重新编译内核。从源码编译。op-22.03.2# 系统为 debian-11.
# apt install ... 安装编译所需的必要包
git clone https://git.openwrt.org/openwrt/openwrt.git #获取源码
cd openwrt
ln -s ../dl dl #可以创建一个dl目录的链接,与其他的sdk共用一个dl目录,避免重复下载
git tag
git checkout v22.03.2 #切到 v22.03.2
./scripts/feeds update -a #这步会重新生成.config文件。下载/更新feeds
./scripts/feeds install -a
wget https://downloads.openwrt.org/releases/22.03.2/targets/armvirt/64/config.buildinfo
cp config.buildinfo .config #替换为官方配置
cat << __END__ >> target/linux/armvirt/config-5.10
CONFIG_EFI_STUB=y
CONFIG_EFI=y
CONFIG_EFI_VARS=y
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
__END__
make menuconfig # 未作修改,直接退出,退出时保存一个新的.config
# 如果不保存.config,在 make world时也会弹出这个 menuconfig要你保存。
make -j3 kernel_menuconfig # 需要下载linux内核源码。进入后,直接退出,未作修改。保存或者不保存都行。
# kernel配置保存在 target/linux/armvirt/config-5.10
make -j3 defconfig
make -j3 download # 需要下载很多,并发不要开太多
make clean
make -j6 world V=s # 快完成的时候,还会下载几个包
# make world V=s 会问问题,一路回车用默认值。不保存kernel配置,问的多些。保存了kernel配置,问的少点。
# 完成后,Image和rootfs都在 bin/targets/armvirt/64/目录中。
# 完成后,这个源码目录占用14.0GB,其中/dl/目录496MB。
2023-03月,重新编译内核。从源码编译。另一次的做法。op-22.03.3# 系统为 debian-11.
# apt install ... 安装编译所需的必要包
git clone https://git.openwrt.org/openwrt/openwrt.git #获取源码
cd openwrt
ln -s ../dl dl #可以创建一个dl目录的链接,与其他的sdk共用一个dl目录,避免重复下载
git tag
git checkout v22.03.3 #切到 v22.03.3
./scripts/feeds update -a #这步会重新生成.config文件。下载/更新feeds
./scripts/feeds install -a
wget https://downloads.openwrt.org/releases/22.03.3/targets/armvirt/64/config.buildinfo
cp config.buildinfo .config #替换为官方配置
cat << __END__ >> target/linux/armvirt/config-5.10
CONFIG_EFI_STUB=y
CONFIG_EFI=y
CONFIG_EFI_VARS=y
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
__END__
# 以上5条不能放到.config中,这是kernel的配置,不是映像包的配置。
make menuconfig # 未作修改,直接退出,退出时保存一个新的.config
# 如果不保存.config,在 make world时也会弹出这个 menuconfig要你保存。
make -j3 defconfig
make -j3 download # 需要下载很多,并发不要开太多
make -j6 clean world V=s # 快完成的时候,还会下载几个包
# make world V=s 会问问题,一路回车用默认值。
# 此次编译,有包冲突。只好用 menuconfig 调整,去掉了很luci等等包。才成功。
# .config的配置,不影响内核 Image的编译。只影响 root-fs 和 initramfs 中的内容。
# 完成后,Image和rootfs都在 bin/targets/armvirt/64/目录中。
有个想法:因为只是为了重编内核,不去下载 feeds的东西,应该也可以。(这个想法 未测试,下次再说)
编译后的文件,【备份在这里】。
用 gunzip 解压。
备份文件:openwrt-22.03.2-armvirt-64-Image.gz
openwrt-22.03.2-armvirt-64-generic-ext4-combined-efi.img.gz
openwrt-22.03.3-armvirt-64-Image.gz
openwrt-22.03.3-armvirt-64-generic-ext4-combined-efi.img.gz
rootfs去官网下载,openwrt-22.03.x-armvirt-64-rootfs-ext4.img.gz。
制作img启动映像。
ls -l openwrt-22.03.2-armvirt-64-Image # 约12MB
gunzip -k openwrt-22.03.2-armvirt-64-rootfs-ext4.img.gz # 得到约105MB的img文件
dd if=/dev/zero of=disk.img bs=1M count=200 # 创建一个200MB的空映像,第二次我做了140MB.
su root
losetup -f disk.img
losetup -a # 看到,挂在 loop0
# EFI分区只放内核的Image。预计占用12-15MB,总空间大于20MB就足够了。
fdisk /dev/loop0 # 创建两个分区。
g # gpt 分区
n # 创建分区1
回车 # 默认值2048
t # 改分区1类型
1 # 类型 EFI System
n # 创建分区2, 默认类型 Linux filesystem
回车 # 默认值
回车 # 默认值
partx -a /dev/loop0 # 或者 partx -u /dev/loop0
mkfs.vfat /dev/loop0p1 # 格式化为FAT32
dd if=openwrt-22.03.2-armvirt-64-rootfs-ext4.img of=/dev/loop0p2 bs=1M
resize2fs /dev/loop0p2
lsblk -o PATH,UUID,PARTUUID /dev/loop0 # 查看 UUID 和 PARTUUID
# 下面内容中 fs_uuid 替换为自己的loop0p1的UUID。
cat << __END__ > grub-early.cfg
search.fs_uuid E555-D276 root
set prefix=(\$root)'/boot'
configfile \$prefix/grub.cfg
__END__
mkdir part1
mount /dev/loop0p1 part1
mkdir -p part1/EFI/BOOT/
cd part1/EFI/BOOT/
grub-mkimage -c ../../../grub-early.cfg -p /boot -o BOOTAA64.EFI -O arm64-efi boot chain configfile fat linux ls part_gpt reboot serial efi_gop search_fs_uuid
cd ../..
mkdir boot
cd boot/
# 下面内容中的 PARTUUID 是 loop0p2 的(不是UUID)。需自己替换。
cat << __END__ > grub.cfg
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 --rtscts=off
terminal_input console serial; terminal_output console serial
set default="0"
set timeout="5"
menuentry "OpenWrt" {
linux /boot/vmlinuz root=PARTUUID=98e93560-8d7d-7e46-8812-916f21d11821 rootwait console=tty0 console=ttyS0,115200n8 noinitrd
menuentry "OpenWrt (failsafe)" {
linux /boot/vmlinuz failsafe=true root=PARTUUID=98e93560-8d7d-7e46-8812-916f21d11821 rootwait console=tty0 console=ttyS0,115200n8 noinitrd
__END__
cp ../../openwrt-22.03.2-armvirt-64-Image vmlinuz
cd ../..
umount part1
partx -d /dev/loop0
losetup -d /dev/loop0
exit # 退出 su root
img启动映像,能够成功启动,内核也成功启动,进入shell,网口也都能获取IP。
分区1已用12MB/分区2已用12MB。不过,忘了选择luci,用浏览器访问配置页面,什么都没有,没法使用。
使用官方的 openwrt-22.03.2-armvirt-64-rootfs-ext4.img.gz
加上自己编译的 openwrt-22.03.2-armvirt-64-Image.gz,重新做一遍,做 140MB的映像。
成功启动,系统干净,可以使用。WEB配置页面只有基本配置。
做好的映像:【openwrt-22.03.2-armvirt-64-generic-ext4-combined-efi.img.gz 压缩包9MB】
可以正常opkg update, 可以安装使用官方包(架构:aarch64_cortex-a53)。
opkg install kmod-fs-vfat, 就可以 mount /dev/vda1 /boot, 挂载boot分区。
22.03.2 映像总大小140MB,空间占用(已用/可用/总大小): 分区1(12/18/30MB), 分区2(14/92/108MB)。
22.03.3 映像总大小140MB,空间占用(已用/可用/总大小): 分区1(11.2/18.7/29.9MB), 分区2(13.4/91.7/107.3MB)。
如果觉得空间不够大,那就自己扩容吧。参考【openwrt_21.02_img_空间扩容_改分区表大小】。
或者自己制作一个img映像,自己设置空间大小。
虚拟机op接受kvm关机指令
使用这个自己重新编译的内核。
在 op内部,执行 halt可以关掉。
在外部用virsh shutdown xxx关不掉。
在外部用virsh destroy xxx可以强制关掉。
以前在Hyper-v中跑op,op能迅速响应"关机"指令。无需 acpid或 qemu-ga。
装opkg install acpid (2个依赖包,约占100KB),op不理会shutdown命令。
再次编译内核,加入,CONFIG_ACPI_CONFIGFS=y
CONFIG_ACPI_TINY_POWER_BUTTON=y
编译后,替换内核。启动 acpid服务。op还是不理会 virsh 的关机命令。放弃。
装opkg install qemu-ga (op22-armvirt,有7个依赖包,约占3.9MB),重启 op后才生效。
可以接受 virsh shutdown 的命令了。(无需 acpid服务,可卸载acpid)。
virt-install 生成的虚拟机,默认已经生成管理 channel。
virsh edit xxxx可以看到,在<devices>...</devices>中,有这几行。<channel type='unix'>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
如果是用virt-manager图形界面创建的虚机,见【如果有图形桌面_virt-manager】。
需要手动添加一个"信道/channel"设备,名称org.qemu.guest_agent.0。
在op中,没装qemu-ga前,有 /dev/vport2p1 这个字符设备。
安装 qemu-ga并重启 op后,脚本会把这个设备链接到 /dev/virtio-ports/org.qemu.guest_agent.0,
qemu-ga 进程就可以启动成功,接受 virsh的命令。
qemu-ga 的配置文件是 /etc/qemu/qemu-ga.conf,op中没这个文件,需要时,自己创建。配置例子如下:[general]
blacklist = guest-ssh-remove-authorized-keys,guest-ssh-add-authorized-keys,guest-ssh-get-authorized-keys,guest-get-devices,guest-get-osinfo,guest-get-users,guest-get-host-name,guest-exec,guest-exec-status,guest-set-user-password,guest-network-get-interfaces,guest-file-seek,guest-file-write,guest-file-read,guest-file-open
当你关闭/重启实体机时,系统会先关闭所有服务,包括关闭 KVM 的 libvirtd 服务,
libvirtd 会发出 shutdown 指定给所有的虚拟机。
如果虚拟机不予理会。那就要等到超时时间,通常是300秒每个虚机,才强制杀掉虚拟机,才能停掉 libvirtd 服务。
超时定义在/etc/init.d/libvirt-guests 或 /usr/lib/systemd/system/libvirt-guests.service。
所以,你会觉得很奇怪,实体机的表现,关机/重启操作之后,5-10分钟内机器没反应,不知道它在忙什么,也不知道要等多久。
映像文件转换格式
请看:【映像文件转换格式】
可以把 img 的 raw格式转为 hyper-v(vhdx), vmware(vmdk), virtualbox(vdi), xen(img)... 使用的格式。
用ImageBuilder打包自定义img
ImageBuilder 就是个打包器。里头有现成的kernel,通过下载ipk包。然后把 kernel 和 ipk 打包成映像。
如果 ipk下载顺利,打包执行的速度就很快。
现成的内核在build_dir/target-xxxxx_musl/linux-xxxxx/目录中。
下载 ImageBuilder, 解压。
make过程中,会去下载 ipk 包。使用的是 wget,不用 curl。
如果需要,设置 ~/.wgetrc,为wget配置代理。只支持http,不支持socks5。
也可以在前面套 tsocks 或 proxychains4。不过 tsocks 会显示不少错误,但不影响执行。proxychains4 正常。
修改 ImageBuiler目录/repository.conf, 改国内源。
make help 查看帮助。
make image 制作缺省配置的固件。
对于 armvirt,只能生成: 内核Image, rootfs。 没有 combined 启动映像。
对于其他架构,会生成 combined 刷机映像。
先做一个和官方一样的img吧。 # 下载官方的img的包列表,
wget https://downloads.openwrt.org/releases/22.03.2/targets/armvirt/64/openwrt-22.03.2-armvirt-64-default.manifest
# 创建 make 命令的脚本,
echo -n 'make image PACKAGES="' > cmd-mymake.sh
cut -d' ' -f 1 openwrt-22.03.2-armvirt-64-default.manifest | xargs echo -n >> cmd-mymake.sh
echo '"' >> cmd-mymake.sh
#可以编辑一下 cmd-mymake.sh 文件,看看要加什么。不修改,做出来的就和官方的一样。
sh cmd-mymake.sh
# 去 ImageBuiler目录/bin/targets/armvirt/64/, 就能找到生成的结果了。
# 对于armvirt,其实就是做了个 rootfs。还需要自己去制作启动映像。
如果是为硬路由制作刷机包,获取官版原有的包列表。参考【用imagebuilder打包一个自定义bin文件】。
可以加更多的ipk包,去除ipk包。添加额外的文件,删除无用文件。参考【官方文档 imagebuilder】。
如果要修改 /etc/config/ 中的配置,见【openwrt_imagebuilder_修改缺省配置_network_firewall_root密码】。
修改img映像的大小:
对于 armvirt 或 x86 或 x86_64, 修改 .config 文件中,
CONFIG_TARGET_ROOTFS_PARTSIZE=104, root分区104MB。rootfs的img是104MB。
CONFIG_TARGET_KERNEL_PARTSIZE=16, boot分区16MB。
最终"可启动"的img,比两个分区总和再大几MB(为了对齐)。
armvirt 不生成"可启动"的img。
对于其他架构,找找类似target/linux/ramips/image/mt7621.mk和target/linux/ramips/image/Makefile中有没有地方修改。
比如 IMAGE_SIZE := 32448k。
别人做好的 VMware 的虚机
【Arm64 (armvirt64) uefi (efi) OpenWrt target】
【OpenWrt.zip】
linux中查看img的内容
losetup -f xxxxxxx.img #挂载到 loop 设备
losetup -a #查看挂在哪个 loop 设备上了,我这是 loop0
partx -a /dev/loop0 #读取分区信息,加载到系统
fdisk -l /dev/loop0 #查看分区信息
lsblk -f #查看各个块设备的文件系统类型
mount /dev/loop0p1 /mypath #挂载文件系统
umount /mypath #卸载文件系统
partx -d /dev/loop0 #卸载系统中的分区信息
losetup -d /dev/loop0 #卸载 loop 设备
除了能查看,修改里头的内容也没有问题。通常是往文件系统中添加些文件。
只要mount上去了,哪怕什么都没做,img映像文件的内容其实已经被修改了。img文件的sha256值就会变。
只挂载到loop设备,查看分区信息,不修改分区信息,img文件不会被修改。
----end----
转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/16670954.html
来自 osnosn的博客 https://www.cnblogs.com/osnosn/ .