在 FreeBSD 7.0 上运行 Qemu,并通过 tap 联网

原文: Qemu with tap networking on FreeBSD Current(译者注:原文标题为在 FreeBSD CURRENT 版本上运行 Qemu,这里翻译成 FreeBSD 7.0 的原因是当时的 CURRENT 即目前的 7.0,而目前描述 CURRENT 已是 8.0-CURRENT)
作者: scottro
翻译: Sutra Zhou

根据大家的回复,我做了一些修改。
————————————–
修改记录
2007年1月17日

修改 qemu-ifup 脚本,0.0.0.0 地址是不必要的。
补充了一些资料,关于 bridge0 接口的 IP 地址。
修正一个拼写错误,我把 guest 操作系统的 IP 和 host 的IP 写成一样的了。(对不起朋友们)
改了一些编辑风格。
添加了介绍 qemu 网络的页面的链接。

2007年1月19日

对操作 ifconfig bridge0 addm tap0 进行了更详细的补充

2007年1月21日

添加启动和关闭脚本(来自kludgy)
给 tap 接口获取权限添加更好的解释

2007年1月27日

对卸载模块做了一些补充

2007年1月29日

对卸载模块做了更多补充

2007年2月3日

对 slirp 又开始工作作了补充描述

2007年4月9日

关于本指南所介绍的方法在当前的 CURRENT 版本(译者注:FreeBSD CURRENT 版本)上不工作了注解,然后晚上又添加了如何解决这个问题的办法(并去掉顶部的注意事项,因为那个已经没有用了)

2007年4月10日

添加关于 net.link.tap.up_on_open 的信息

2007年6月1日

添加一个在 freebsd-emulation 上的关于桥接的讨论。

2007年6月2日

修正桥接的配置–删除一个可能坏的设备,在指定了网桥的 IP 地址后–非常感谢 Per Hedeland。也在 qemu-ifup 脚本中添加了 exit 0,再次感谢 Per。最后,让 qemu-ifup 脚本更智能,再次地,感谢 Per。

————————————-

假设你已经阅读了vermaden‘s excellent qemu howto ,并已经安装了客户机操作系统。默认情况下,qemu 将采用我们称为用户模式的网络启动──客户机操作系统将自动指定 IP 地址为 10.0.2.x ,这样 pinging 就不会工作,而大部分其它工作可以进行──你可以浏览互联网,通过 ssh 从客户机连接到宿主机,等等。

Qemu 的网络有多种形式。使用哪种方式由你的需要决定。我一直使用着默认的用户模式直到它在 CURRENT (译者注:CURRENT 指 FreeBSD CURRENT,这里指 FreeBSD 7.0-CURRENT,下同)上不能工作。要浏览各种不同的方式,你可以随时查看非 qemu 官方的维基页面网络配置页

截至2月上旬,最新的 qemu 再次工作在默认的用户模式网络上(更恰当地应称为slirp)。但是,一旦你设置了 tap,它可能变得更便利。客户机可以简单地成为你网络上的另外一个节点。

Tap 网络方式增加了许多新的特性。Pingging 会工作,VPN网络看起来工作得更好(至少在 Windows 客户机上可以使用 Nortel VPN 客户端)。

这个指南只适用于 FreeBSD-7。设置 tap 网络的方法已经改变。如果你是 FreeBSD-6.x,则请看 acidos 网站上的文章

我要给我最诚挚的谢意给 Bakul Shah,他的帮助省去了我大量的 googling (译者注:用 Google 搜索)和错误的开始。所有的错误,当然,我的。Bakul 的设置要远远比我的准确。

这里是非常简单的设置。我们打算通过手动配置 IP 地址和网关在宿主机的同一个子网里拥有一个 qemu 客户机。不管怎样,我需要这样的配置。

好了,假设你已经有一个能够启动起来的 qemu 客户机,首先我们有几件事要做。

我们必需允许一个普通用户使用 tap 网络。我们称这个用户为 John,用户名为 john。我假设各位都能熟练使用 sudo。用户 john 已经在 sudoers 文件中配置好了。大量的准备工作将不得不由 root 用户来做或者需要 root 权限来做。

在 /etc/devfs.conf 添加下面一行

own tap0 john:john

重启 devfs

/etc/rc.d/devfs restart

如果这些模块尚未加载,加载它们。

kldload kqemu aio if_tap if_bridge

使用户能够打开 tap 设备

sysctl net.link.tap.user_open=1

(你将看到屏幕打印一条消息: net.link.tap.user_open is changed from 0 to 1.)
创建一个网桥。

ifconfig bridge0 create

添加物理网络接口到网桥。在我这里,我的网卡是廉价的板载的网卡 vr0 。根据你的网卡自己修改。

ifconfig bridge0 addm vr0 up

在相当长的时间里,该指南在上面这行的up后面给网桥指定了一个 IP 地址。Per Hedeland 指出了这个错误。
如果你还没有启动 qemu,就不会有 tap0 网络接口,如果你之前有一个 qemu 会话然后停止了它,那么你现在可以添加 tap0 网络接口。

ifconfig bridge0 addm tap0

如果这是你机器启动后第一次启动 qemu,或者如果当你最后一次关闭 qemu 时,你已经卸载了 tap 模块,等等,你就会得到一个 tap0 不存在的错误信息。那么,你就不得不等到你启动了 qemu 后再把它加为网桥的成员。(这将在下面详述)
如果你想在机器启动时创建网桥(通过添加一些配置到 /etc/rc.conf ──这将在下面详述)你不必启用你的网卡。而是,简单地使用 addm 而不要在行末添加 up。

关于这个,在 freebsd-emulation 的邮件列表 里,我和 Bakul,Per Hedeland 之间有一个有趣的讨论(查找 2007年6月3日的那一周)。Per 指出我在原来的指南中的错误。

回到我们的话题。

创建一个 /etc/qemu-ifup 脚本。内容如下:

#!/bin/sh
sudo /sbin/ifconfig ${1} up

让这个脚本可以执行

chmod 755 /etc/qemu-ifup

有趣的是,在2007年4月上旬之前,并不需要在 ifconfig 的行末添加 “up” 。我以为 tap 网络不能用了,但是仅仅需要在 ifconfig 这行上添加一个“up”就又能正常了。非常感谢 Tobias Grosser,是他指出了这个解决方法。

你可以修改 sysctl 变量而不是添加在 ifconfig 这行后面添加“up”。这个变量是

net.link.tap.up_on_open

一旦你通过 kldload if_tap 加载了 if_tap 模块。这个变量会默认设置为 0.把它修改成 1

net.link.tap.up_on_open=1

也会工作。你可以只设置其中一个或者另一个。重要的一点是 if_tap 在创建后不再自动启用。非常感谢Bruce M. Simpson,是他告诉了我关于 sysctl 变量这个事情。(在我在 current@FreeBSD.org 和 emulation@FreeBSD.org 上询问为什么 if_tap 不工作时,他和 Tobias 回复了我的问题)
启动 qemu──在这个例子里,我们的 qemu 映像是和 Per vermaden 的文章中一样的 ~/qemu/win2k.img。

决定给客户机什么样的网络地址。在这个例子中,在我的 192.168.1.x 网络中,我们将给客户机一个 192.168.1.40 的地址。这个网络的网关(你也可以通过 netstat -r 来检查)是192.168.1.1。

vermaden 的指南给出了在启动 qemu 时的更多的选项,比如使用 -localtime,调整内存,声音等等。在这里,我们将不会理会这些,我们只是测试网络。

qemu -net nic -net tap -hda ~/qemu/win2k.img

有些时候,我们会得到一个错误信息说 tap9 无法被打开。如果发生了这个,表明忘记去修改 sysctl net.link.tap.user_open 变量为 1 或者 devfs.conf 需要重启。(当然也需要加载 if_tap 模块,才能使在 devfs.conf 中添加的那行生效)

除非你已经在 sudoers 中给 qemu-ifup 脚本添加了 NOPASSWD 选项,那么系统将询问你的密码──记住,qemu-ifup 脚本使用了 sudo。

在客户机系统启动后,tap0 网络接口就会被启动(通过 qemu-ifup 脚本)。这样,现在添加 tap0 到网桥。

ifconfig bridge0 addm tap0

至于 arun 提到的,可以将 bridge0 addm tap0 添加到 qemu-ifup 脚本中。(${1} 在他的例子中是 tap0 网络接口。)如果你倾向于频繁地停止和启动 qemu,并且不想每次都卸载 if_tap 模块,这就会引起一个问题,你将由于 tap0 网络接口已经是网桥的成员而得到一个错误。虽然,这个错误信息可以被忽略,但是(感谢 Per 指出这点)你不得不像我下面提出的那样添加 exit 0。否则,你将得到一个错误提示说 tap 已经存在,或者已经是一个成员,并且脚本执行失败。

我将在启动脚本这节涵盖这一步。如果你总是能在完成 qemu 会话后记得卸载 if_tap 模块,或者你对那些错误提示并不恼火的话,那些修改 qemu-ifup 脚本为:

#!/bin/sh
sudo /sbin/ifconfig ${1} up
sudo /sbin/ifconfig bridge0 addm ${1}
exit 0

你也可以把脚本变得更智能,(再次感谢 Per Hedeland)检查 tap0 是否已经是一个成员,并且这将消除错误信息。

#!/bin/sh

sudo /sbin/ifconfig $1 up
case "`/sbin/ifconfig bridge0`" in
*" $1 "*) ;; # already in the bridge
*) sudo /sbin/ifconfig bridge0 addm $1 ;;
esac
exit 0

这可以避免 ifconfig bridge0 addm tap0 作为一个单独的命令执行。(注意,如果你是使用 net.link.tap.up_on_open 的方式来保证 tap0 启用的话,你不需要添加 “up”这个词在 ifconfig ${0} 的行末。)

调整客户机操作系统的网络。但愿,你知道如何去做。正像上面所述的 IP 地址为 192.168.1.40。子网掩码,DNS 服务器和网关都和宿主机的设置一样。

再检查一下,宿主机的设置如下
IP地址 192.168.1.50
子网掩码 255.255.255.0
默认网关 192.168.1.1
DNS 服务器 192.168.1.80

然后,我们给客户机操作系统的设置如下:
IP 地址 192.168.1.40
子网掩码 255.255.255.0
默认网关 192.168.1.1
DNS 服务器 192.168.1.80

换句话说,它就和局域网上其它的物理主机一样。

如果你需要保存这些设置的话,我们可以修改一些配置文件。

对于 sysctl 变量添加下面一行到 /etc/sysctl.conf

net.link.tap.user_open=1

网桥可以在 /etc/rc.conf 中设置。再次地,我这里使用的是 vr0 网卡,添加下面这些到 /etc/rc.conf

cloned_interfaces="bridge0"
ifconfig_bridge0="addm vr0"

注意,我们在这里只需要添加物理网络接口,而不是 tap0。

添加上面这些到 /etc/rc.conf 也会在启动时加载 if_bridge 模块。要在启动时加载 kqemu 和 aio 添加这些

kqemu_enable="YES"

到 /etc/rc.conf。

要在启动时加载 if_tap 模块,添加

if_tap_load="YES"

到 /boot/loader.conf

我不是经常运行 qemu,所以对于我,使用一个简单的脚本比较方便。我这里有点复杂,例如,在加载模块前需要检查是否已经加载了。

我使用了两个脚本,qemuprep.sh 和 qemudown.sh

qemuprep.sh 内容如下

#!/bin/sh

#load modules if not loaded.
sudo kldload if_tap if_bridge kqemu aio

#create the bridge and configure it.

sudo ifconfig bridge0 create

sudo ifconfig bridge0 addm vr0 up

#fix sysctl
sudo sysctl net.link.tap.user_open=1

#restart devfs to work with tap
sudo /etc/rc.d/devfs restart
exit 0

注意,如果模块已经加载,虽然你会得到一些错误信息,但是不会中断任何东西。
例如,一旦加载了 aio 模块,即使 qemu 已经停止了,再尝试去卸载它也会得到一个错误信息:

kldunload: can’t unload file: Operation not supported

因此,如果我在重启机器前运行 qemu 多次,当我执行 qemuprep.sh 脚本时,将会得到一个错误提示说 aio 模块已经加载了。它并无大碍。如果你觉得它碍眼,你可以执行:

kldstat | grep -q aio
if [ "$?" -gt 0 ]; then
sudo kldload if_tap if_bridge kqemu aio

#if it’s already loaded, then just load the others

else

sudo kldload if_tap if_bridge kqemu

来替代 sudo kldload if_tap if_bridge kqemu aio 那一行。

我把宿主机的网络接口添加为成员。(如果你一直没有想通,通过 addm 选项来添加成员到网络接口。可以看 man(8) ifconfig。)

由于我的关闭脚本卸载了 if_tap 模块,devfs.conf 将不得不被重新读取。因此,我在脚本的最后重启 devfs 。你可以在其最后添加下面一行,

qemu -net nic -net tap -hda ~/qemu/"${1}" -localtime

但是由于我大部分时候需要使用 CD 启动,我没有添加这行。如果你只用一个 qemu 的 .img 文件,并且总是使用这个映像来启动,你可以使用你的映像文件来替换其中的 “${1}” 。(我也可以做其它的修改,比如准备一个列表,然后使用时选择一个,或者选择从CD启动)。

当我结束使用 qemu 是,我想一处模块和网桥。当我关闭 qemu 客户机会话是,我运行 qemudown.sh

#bring down the bridge
sudo ifconfig bridge0 destroy

#unload the unused modules.

sudo kldunload kqemu
sleep 1
sudo kldunload if_tap
sleep 1
sudo kldunload if_bridge

exit 0

注意,我没有卸载 aio,因为它不会被卸载。我也发现卸载 if_tap 模块会使 devfs.conf 里增加的那行无效,所以没有必要删除 devfs.conf 里的那一行。

我在卸载 tap 和 bridge 模块前 sleep 1 的原因是可能只是在我的系统里有点怪异。我发现仅仅 kldunload kqemu if_tap if_bridge,tap 和 bridge 模块不会被卸载。不管它是正常的事情还是怪异的事情,我不知道。反正只要 sleep 1 再卸载模块看起来工作正常。
我可以在卸载 if_tap 时添加一些检查,比如 if_tap 是否已经被正确地定义等等,试了一下,但是看起来有点问题。使用 kdlstat 来检查是否已经卸载,或者 if_tap 还没有卸载的话,就再次卸载它。不过,那也是在一些罕见的情况下。

记住,如果 tap 没有被卸载,那么下次启动 qemu,你的 qemu-ifup 脚本将会给出一个错误。所以,如果你启动 qemu 得到一个错误说由于 tap 已经被加载了而无法被添加为网桥 bridge0 的成员的话,你可以注释掉 /etc/qemu-ifup 中的 addm tap0 那一行或者 kldunload 直到你看到 if_tap 被正确卸载。不过,这不是必需,只要你在 qemu-ifup 脚本的最后一行有 exit 0 这一行,这个错误信息不会引起问题。

The above two scripts are rather kludgy. At some point, if I ever get around to it, I hope to make them a bit more sophisticated. See dev1’s script in this thread. Lame as these scripts are, they do the job for me. As arun mentions in his post below, they also save a reasonable amount of typing.(译者注,这段没啥用,不翻了,有点累~)

以上是一个非常简单的 tap 网络配置。 Bakul 的配置,例如,让全部的 qemu 客户机在它们自己的子网里,宿主机给它们提供 dhcp 服务,转发和 nat。他的 qemu-ifup 脚本执行添加 tap0 到网桥的任务。他也运行着多个客户机。

有各种其他方法来做到这一点。你可以根据本指南做出符合自己的脚本。

Advertisements

#freebsd, #qemu

在 FreeBSD(作为宿主机) 上运行 Qemu

原文:Running Qemu on FreeBSD, as host
作者:Nakata Maho (http://people.freebsd.org/~maho/ )
翻译:Sutra Zhou (http://zhoushuqun.com/ )

Qemu 是一个由 Fabrice Bellard 开发的非常快速的通用的开源处理器(CPU)模拟器。它可以运行 Windows 2000,XP和GNU/Linux(RedHat,Debian)等。这里我们为 FreeBSD 6.0 描述了各种知识。

如何安装

虽然 Qemu 相当快,但我们需要 KQemu 加速器,否则它慢得多。另外,IDE 总线 DMA 支持也是非常重要的。
编译 QEMU :

# cd /usr/ports/emulator/qemu
# make -DWITH_KQEMU -DWITH_HACKS
# kldloaded aio

kldload aio 是必须的!因为 KQemu 是作为内核模块安装的,请添加下面一行到 /boot/loader.conf 这样内核模块将在开机启动时被加载。

kqemu_load="YES"

注意:继续使用已有的 Windows 2000/XP 磁盘映像是不可能的,因为其已改由活动的 IDE 总线 DMA 支持。

网络

默认情况下,网络由模拟器内部配置;从外部是不可见的。这非常不方便!也有不同的配置方法:你必须是 root 并且你的 qemu 虚拟机在外部可见。假设你知道你的网络接口的名称。我这里是 fxp0。你可以通过下面的方法来检查:

% dmesg | grep Ethernet

首先,以 root 执行,

# kldload bridge.ko
# sysctl net.link.ether.bridge_cfg=fxp0,tap0
net.link.ether.bridge_cfg: -> fxp0,tap0
# sysctl net.link.ether.bridge.enable=1
net.link.ether.bridge.enable: 0 -> 1

创建脚本 /etc/qemu-ifup,内容如下:

#!/bin/sh
ifconfig ${1} 0.0.0.0

并且让脚本可执行:

# chmod 755 /etc/qemu-ifup

为了让每次开机的时候都能执行这些,把下面的内容写到 /etc/sysctl.conf:

net.link.ether.bridge_cfg=fxp0,tap0
net.link.ether.bridge.enable=1

并在 /boot/loader.conf 添加:

bridge_load="YES"

通过下面的方法启动 qemu:

# qemu -net nic -net tap

参考了 freebsd vde helpp

Qemu 作为 VNC 服务器

QEMU 中显示非常慢,因此将 qemu 作为 vnc 服务器运行非常有用。

% qemu -hda /work/qemu/win2000ja/win2000.img -localtime -m 384 -vnc :1 -usbdevice tablet

运行 vncviewer 像这样(你可以通过 ports/net/tightvnc 安装):

% vncviewer :1

你应该等待 Windows 启动好了再连接。

全屏模式(慢)

Qemu 使用 SDL 来输出到屏幕。现代的视频卡支持 VESA 2.0,因此你可以通过 VESA 2.0 来使用 SDL。当你使用 SDL 时你需要额外的设置。首先,重新配置内核:

include GENERIC

ident MAHO

device atapicam
options VESA

保存为 /usr/src/sys/i386/conf/MAHO 或其它类似的名字。然后,

# cd /sys/i386/compile/MAHO
# made cleandepend ; make depend ; make ; make install

你需要做如下额外设置:

# setenv SDL_VIDEODRIVER vgl

然后你可以通过控制台来运行全屏模式。当然,你仍然必须是 root 用户。据我测试,

# kldload vesa

不工作(在我这里)。不幸的,这非常慢,比 X11 模式慢……

总结(我的设置和命令行)

作为总结,我的设置是针对 qemu 0.8.0 的。

qemu -localtime -hda /work/qemu/win2000ja/win2000.img -m 256 -net nic -net tap

/boot/loader.conf

kqemu_load="YES"
bridge_load="YES"
snd_driver_load="YES"
snd_pcm_load="YES"

/etc/sysctl.conf

net.link.ether.bridge_cfg=fxp0,tap0
net.link.ether.bridge.enable=1

/etc/qemu-ifup (chmod 755 /etc/qemu-ifup)

#!/bin/sh
ifconfig ${1} 0.0.0.0

用下面的配置文件重新配置内核

include GENERIC

ident MAHO

device atapicam
options VESA

和额外的环境变量:

# setenv SDL_VIDEODRIVER vgl

我不想成为 root 用户

  • 网桥
  • 全屏模式

链接

Contributors

  • Vlad GURDIGA

#freebsd, #qemu