kvm_qemu_运行_openwrt_armvirt_img_自己创建combine映像
转载注明来源: 本文链接 来自osnosn的博客,写于 2022-09-08.
参考
- 【Building OpenWrt from Scratch for ARM64 UEFI ACPI VM】
- 【构建 UEFI 启动的 OpenWrt 磁盘映像】
- 【Arm64 (or armvirt) with UEFI boot?】
- 【Boot with local directory as rootfs】
- 【openwrt/openwrt/target/linux/armvirt/README】
- 【使用armvirt架构的虚拟镜像来测试LEDE】
- 【indetectables-net/embedded/openwrt-arm-on-qemu.md】
kvm 安装
- 仅字符界面,无 GUI。
apt install libvirt-daemon-system virtinst qemu-system-arm
。
方法一
- 【使用armvirt架构的虚拟镜像来测试LEDE】
- 【openwrt/openwrt/target/linux/armvirt/README】
- 下载
https://mirrors.aliyun.com/openwrt/releases/22.03.0/targets/armvirt/64/
openwrt-22.03.0-armvirt-64-Image
,openwrt-22.03.0-armvirt-64-Image-initramfs
,openwrt-22.03.0-armvirt-64-rootfs.cpio.gz
, 有 gz 结尾的文件,用 gunzip 解压。 - 进入 tmux 中,(因为op启动后,所有显示就直接输出了,占用了这个终端。如果套上tmux,就比较方便了。)
测试qemu-system-aarch64 -M virt -m 1024m -kernel openwrt-22.03.0-armvirt-64-Image-initramfs -no-reboot -nographic -nic user -nic user -cpu cortex-a53 -smp 4
OK, 之后退出/杀掉。(这个是跑在内存中,所有更改,重启后都会丢失) - 当前目录
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 映像
- 没测试的。
【mslovecc/openwrt-armvirt-v22.03】
【zhkong/openwrt_arm64_uefi】
【cy726/Build-OpenWrt-arm64】 - 以下的测试。
【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'> </ip> </network>
virsh net-define lan-op.xml; virsh net-start lan-op; virsh net-autostart lan-op
- 也可以根据需要,保留nat。去掉
- 执行以下命令,创建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
。
- 如果操作错误,想删除这个vm。强制关机
- 第一次启动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。(本应该可以。但此映像无效,不知哪个服务在捣乱)。
- Network->DHCP and DNS->DNS forwording。如果是内网使用,还要去掉"丢弃RFC1918"项的勾。(有效)。
- 这个映像的源,指向了 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
有个想法:因为只是为了重编内核,不去下载 feeds的东西,应该也可以。(这个想法 未测试,下次再说)# 系统为 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/目录中。
- 编译后的文件,【备份在这里】。
- 用 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 1 回车 # 默认值2048 +30M t # 改分区1类型 1 # 类型 EFI System n # 创建分区2, 默认类型 Linux filesystem 2 回车 # 默认值 回车 # 默认值 w 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命令。
再次编译内核,加入,
编译后,替换内核。启动 acpid服务。op还是不理会 virsh 的关机命令。放弃。CONFIG_ACPI_CONFIGFS=y CONFIG_ACPI_TINY_POWER_BUTTON=y
- 装
opkg install qemu-ga
(op22-armvirt,有7个依赖包,约占3.9MB),重启 op后才生效。
可以接受 virsh shutdown 的命令了。(无需 acpid服务,可卸载acpid)。- virt-install 生成的虚拟机,默认已经生成管理 channel。
virsh edit xxxx
可以看到,在<devices>...</devices>
中,有这几行。
如果是用virt-manager图形界面创建的虚机,见【如果有图形桌面_virt-manager】。<channel type='unix'> <target type='virtio' name='org.qemu.guest_agent.0'/> <address type='virtio-serial' controller='0' bus='0' port='1'/> </channel>
需要手动添加一个"信道/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
- virt-install 生成的虚拟机,默认已经生成管理 channel。
- 当你关闭/重启实体机时,系统会先关闭所有服务,包括关闭 KVM 的 libvirtd 服务,
libvirtd 会发出 shutdown 指定给所有的虚拟机。
如果虚拟机不予理会。那就要等到超时时间,通常是300秒每个虚机,才强制杀掉虚拟机,才能停掉 libvirtd 服务。
超时定义在/etc/init.d/libvirt-guests
或/usr/lib/systemd/system/libvirt-guests.service
。
或/etc/default/libvirt-guests
(debian),/etc/sysconfig/libvirt-guests
(centos)。
所以,你会觉得很奇怪,实体机的表现,关机/重启操作之后,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
。
- 对于 armvirt 或 x86 或 x86_64, 修改
别人做好的 VMware 的虚机
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/ .