UML(User-Mode-Linux)入门

由标题我们已经知道这里要说的UML不是“统一建模语言”,而是“用户模式的Linux”,使用它有什么好处呢?让我们先保留点神秘感,一步一步学习,通过实践来感悟它的魅力。
实验环境:电脑一台(装有Ubuntu13.10系统,Kernel版本为3.11.0-12-generic,64位)
下面将通过UML环境的搭建、GDB调试、网络测试这3个方面来了解下UML:
一.搭建UML实验环境
1.下载Linux Kernel源码
访问https://www.kernel.org/网站,看到现在(2014-3-10)最新的版本为3.13.6,那么就下载它了:
cd ~/uml/
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.13.6.tar.xz
2.编译UM配置的Kernel
解压下载的内核源码:tar xvf linux-3.13.6.tar.xz
配置及编译内核源码:
cd linux-3.13.6
make ARCH=um defconfig
生成UM默认的配置文件,运行后有如下信息:
xinu@slam:~/uml/linux-3.13.6$ make ARCH=um defconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
SHIPPED scripts/kconfig/zconf.tab.c
SHIPPED scripts/kconfig/zconf.lex.c
SHIPPED scripts/kconfig/zconf.hash.c
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
*** Default configuration is based on 'x86_64_defconfig'
#
# configuration written to .config
#
配置文件生成后,就是编译了,执行如下命令:
make ARCH=um
编译完成后会在当前目录下生成linux可执行文件。
3.准备根文件系统
编译完成后,需要一个根文件系统,此时可以从http://fs.devloop.org.uk/下载一个现成的资源,由于看到Ubuntu Saucy对UML的兼容不好(没有命令行界面,即运行后输入无响应),故而下载与Ubuntu同系的Debian Wheezy,下载及解压命令如下:
cd ..
wget http://fs.devloop.org.uk/filesystems/Debian-Wheezy/Debian-Wheezy-AMD64-root_fs.bz2
bunzip2 Debian-Wheezy-AMD64-root_fs.bz2
解压后是名为 Debian-Wheezy-AMD64-root_fs 文件。
4.运行UML
cd linux-3.13.6/
./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
运行起来后,到最后有如下提示:
Serial line 0 assigned device '/dev/pts/4'
Debian GNU/Linux 7 changeme tty0
changeme login:
此时我们输入root,回车后有如下提示:
Last login: Mon Mar 10 09:14:54 UTC 2014 on tty0
Linux changeme 3.13.6 #3 Mon Mar 10 16:46:54 CST 2014 x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@changeme:~#
这就表示UML启动成功了,当然从上面提供的网站下载的文件系统有些未必匹配使用,我这边测试了还能使用的有busybox的,该包跟我们嵌入式平台平时移植的Busybox一致,不过版本会旧些,我们还是继续先使用Debian的。
先到这,我们把UML关机先,输入halt命令,提示如下:
root@changeme:~# halt
Broadcast message from root@changeme (tty0) (Mon Mar 10 09:23:30 2014):
The system is going down for system halt NOW!
INIT: Switching to runlevel: 0
INIT: Sending processes the TERM signal
[info] Using makefile-style concurrent boot in runlevel 0.
[ ok ] Asking all remaining processes to terminate...done.
[ ok ] All processes ended within 1 seconds...done.
[ ok ] Stopping enhanced syslogd: rsyslogd.
[info] Saving the system clock.
hwclock: Cannot access the Hardware Clock via any known method.
hwclock: Use the --debug option to see the details of our search for an access method.
[ ok ] Deconfiguring network interfaces...done.
[ ok ] Unmounting temporary filesystems...done.
[ ok ] Deactivating swap...done.
EXT4-fs (ubda): re-mounted. Opts: (null)
[info] Will now halt.
reboot: System halted
xinu@slam:~/uml/linux-3.13.6$
至此,UML环境搭建并测试成功了。
二.GDB调试UML
1.运行UML并确认其对应的进程
打开一终端,使用./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m命令运行起UML后,再打开另一终端,并运行ps uf | grep linux | grep -v grep | grep -v git命令,会有如下输出:
xinu@slam:~$ ps uf | grep linux | grep -v grep | grep -v git
xinu 7160 4.2 1.7 276996 36476 pts/5 S+ 16:05 0:17 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7167 0.0 1.7 276996 36476 pts/5 S+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7168 0.0 1.7 276996 36476 pts/5 S+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7169 0.0 1.7 276996 36476 pts/5 S+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7170 0.0 0.0 15528 972 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7359 0.0 0.0 15804 1124 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7432 0.0 0.0 15552 840 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 7439 0.0 0.0 15512 848 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 9501 0.0 0.0 16352 692 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 9581 0.0 0.0 15572 988 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 9632 0.0 0.0 15568 1024 pts/5 t+ 16:05 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 9639 0.0 0.0 16212 1340 pts/5 t+ 16:06 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
xinu 9641 0.0 0.0 16676 2020 pts/5 t+ 16:06 0:00 \_ ./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m
从上面的输出内容可知对应主进程的PID为7160。
2.连接调试
使用GDB连接上已运行的UML环境并进行调试尝试。在新打开的另一终端输入如下命令:
sudo gdb -p 7160
此时如果gdb attach上UML后会有如下输出(注意需root权限):
xinu@slam:~$ sudo gdb -p 7160
[sudo] password for xinu:
GNU gdb (GDB) 7.6.1-ubuntu
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 7160
Reading symbols from /home/xinu/Linux内核启示说/build/uml/linux-3.13.6/linux...done.
Reading symbols from /lib/x86_64-linux-gnu/libutil.so.1...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libutil-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libutil.so.1
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.17.so...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib/x86_64-linux-gnu/libnss_compat.so.2...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libnss_compat-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libnss_compat.so.2
Reading symbols from /lib/x86_64-linux-gnu/libnsl.so.1...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libnsl-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libnsl.so.1
Reading symbols from /lib/x86_64-linux-gnu/libnss_nis.so.2...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libnss_nis-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libnss_nis.so.2
Reading symbols from /lib/x86_64-linux-gnu/libnss_files.so.2...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libnss_files-2.17.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libnss_files.so.2
0x00007fd1da9f9840 in __nanosleep_nocancel ()
at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb)
连接上后,我们就开始尝试了,在上面的(gdb)后面运行指令set follow-fork-mode parent,确保等会gdb一直在该进程,即在fork创建新的子进程后继续调试父进程,子进程不受影响。
接下来,在(gdb)后面继续运行指令break sys_clone创建一个断点,此时会输出如下内容:
(gdb) break sys_clone
Breakpoint 1 at 0x6003526d: file kernel/fork.c, line 1679.
接下来在(gdb)后面继续运行info break查看刚创建的断点,有如下内容输出:
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000006003526d in SyS_clone
at kernel/fork.c:1679
接下来在(gdb)后面输入continue,让程序继续运行,处于被调试状态,此时会有如下内容输出:
(gdb) continue
Continuing.
接下来在运行起来的UML里输入命令ls -l,会有如下内容输出:
root@changeme:~# ls -l
此时没有任何输出,一直处于闪烁光标等待内容输出的状态,而gdb端有如下输出:
(gdb) continue
Continuing.
Breakpoint 1, SyS_clone (clone_flags=18874385, newsp=0, parent_tidptr=0,
child_tidptr=1073899664, tls_val=0) at kernel/fork.c:1679
1679 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
(gdb)
即此时在UML里运行的ls -l命令停在了刚在gdb设置的断点处,接下来我们可以在gdb里查看断点处的相关信息,在(gdb)后面输入l后会有如下输出:
(gdb) l
1674 int, stack_size,
1675 int __user *, parent_tidptr,
1676 int __user *, child_tidptr,
1677 int, tls_val)
1678 #else
1679 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
1680 int __user *, parent_tidptr,
1681 int __user *, child_tidptr,
1682 int, tls_val)
1683 #endif
(gdb)
此时可以看到断点所在1679行处前后的相关代码行源码,便于我们定位问题。至此,演示了在用户空间下调试UML里Kernel,体验了个回gdb。
三.UML网络测试
在UML里可以支持多种网络适配模式(详情可访问http://user-mode-linux.sourceforge.net/old/networking.html),而最常用的是TAP和VDE。
TAP接口是一个能让应用程序对网络第2层帧进行注入操作的虚拟网络设备。当kernel发送帧给TAP设备,此时监听到设备的应用程序能够接收到该消息。TAP接口是一个常规的以太网口,能够用来桥接或者用于tcpdump命令操作。(下面操作如无注明则均在UML的Kernel源码目录下进行)
首先,运行sudo apt-get install uml-utilities和sudo apt-get install bridge-utils命令安装相应的工具包。
工具安装好后,接下来模拟两种网络连接方式:一种是UML与主机间的网络连接;一种是两台UML之间的网络连接。
接下来先测试下UML与主机间采用TAP方式的网络连接:
执行如下命令创建一个TAP网络接口:
sudo tunctl -t tapX1
sudo ifconfig tapX1 192.168.0.121
主机端配置好后,接下来运行UML,使用如下命令:
./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m eth0=tuntap,tapX1,,
(在执行该句命令时,我这边会出现在UML里操作eth0没权限的问题,故而在该命令前加sudo,请根据实际情况确认需不需要添加)
运行UML后,在UML里面执行如下命令:
ifconfig eth0 192.168.0.123
此时在UML里执行如下命令:
ping 192.168.0.121
会有如下内容输出:
root@changeme:~# ping 192.168.0.121
PING 192.168.0.121 (192.168.0.121) 56(84) bytes of data.
64 bytes from 192.168.0.121: icmp_req=1 ttl=64 time=0.422 ms
表示UML能PING通主机,再在主机端执行如下命令:
ping 192.168.0.123
会有如下内容输出:
xinu@slam:~/uml/linux-3.13.6$ ping 192.168.0.123
PING 192.168.0.123 (192.168.0.123) 56(84) bytes of data.
64 bytes from 192.168.0.123: icmp_seq=1 ttl=64 time=0.122 ms
表示主机也能PING通UML了,至此,主机与UML之间的TAP网络测试成功。
接下来再测试下两台UML之间采用TAP方式的网络连接:
执行如下命令创建两个TAP网络接口tap-X1和tap-X2,并将这两个虚拟网口添加到桥接br-X1X2中再将相关网口和桥接设备启动:
sudo tunctl -b -u $(whoami) -t tap-X1
sudo ip link set up dev tap-X1
sudo brctl addbr br-X1X2
sudo brctl stp br-X1X2 off
sudo ip link set br-X1X2 up
sudo brctl addif br-X1X2 tap-X1
sudo tunctl -b -u $(whoami) -t tap-X2
sudo ip link set up dev tap-X2
sudo brctl addif br-X1X2 tap-X2
进入到Kernel源码目录:cd ~/uml/linux-3.13.6,再执行如下操作:
终端1:./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m eth0=tuntap,tap-X1
终端2:./linux ubda=../BusyBox-1.13.2-amd64-root_fs mem=256m eth0=tuntap,tap-X2
接下来在进入的UML里运行如下命令进行相应的配置:
终端1:ip link set up dev eth0
ip addr add 192.168.0.1/24 dev eth0
终端2:ip link set up dev eth0
ip addr add 192.168.0.2/24 dev eth0
接下来,从终端1上运行ping 192.168.0.2,有如下输出:
root@changeme:~# ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_req=1 ttl=64 time=0.422 ms
从终端2上运行ping 192.168.0.1,有如下输出:
# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
64 bytes from 192.168.0.1: seq=0 ttl=64 time=0.932 ms
至此,两台UML之间TAP网络连接方式也测试通过。
上面说明了TAP的使用,接下来尝试下VDE。VDE交换设备是由软件模拟的一个网络交换设备。下面是两台UML通过VDE进行网络连接的过程:
首先,运行sudo apt-get install vde2命令安装相应的工具包。工具安装好后,在主机端的命令行运行命令vde_switch,会进入vde$命令行,可在该命令行里进行端口、VLAN等参考的配置,此处仅运行起来,先不进行更复杂的配置。
接下来需要将Kernel里的VDE选项选中,进行配置前先运行sudo apt-get install libvdeplug-dev 将相应的库安装上,不然等会编译Kernel会有如下错误:
arch/um/drivers/vde_user.c:8:24: fatal error: libvdeplug.h: No such file or directory
#include <libvdeplug.h>
^
compilation terminated.
make[1]: *** [arch/um/drivers/vde_user.o] Error 1
make: *** [arch/um/drivers] Error 2
安装好库后,到我们作为UML的Kernel源码目录下配置内核,相应操作如下:
cd ~/uml/linux-3.13.6
make menuconfig ARCH=um
在出来的配置界面中将如下项选中:
UML Network Devices--->[*]VDE transport
退出并保存后再运行如下命令重新编译下Kernel:
make ARCH=um
编译好后,接下来再打开两个终端,分别运行两个UML,分别使用之前下载的Debian和Busybox的根文件系统,下面是相应的命令:
先进入到Kernel源码目录:cd ~/uml/linux-3.13.6,再执行如下操作:
终端1:./linux ubda=../Debian-Wheezy-AMD64-root_fs mem=256m eth0=vde
终端2:./linux ubda=../BusyBox-1.13.2-amd64-root_fs mem=256m eth0=vde
接下来在进入的UML里运行如下命令进行相应的配置:
终端1:ip link set up dev eth0
ip addr add 192.168.0.1/24 dev eth0
终端2:ip link set up dev eth0
ip addr add 192.168.0.2/24 dev eth0
接下来,从终端1上运行ping 192.168.0.2,有如下输出:
root@changeme:~# ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_req=1 ttl=64 time=0.422 ms
从终端2上运行ping 192.168.0.1,有如下输出:
# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
64 bytes from 192.168.0.1: seq=0 ttl=64 time=0.932 ms
至此,VDE模式也配置成功了。
四.总结
通过上面的实践,会发现这样的实验环境有助于课堂讲解和实验环境的搭建,关键是便于自己在宿舍里单机学习。而整个实验过程,了解到了UML的好处,结合对Kernel的了解,主要有如下几点:
1.调试Linux Kernel里的算法和执行流程;
2.便于验证处理非硬件导致的OOPS或系统死锁问题;
3.内存跨界访问、空指针问题;
4.非硬件相关的文件系统优化、损坏等问题跟踪处理;
5.一台主机可运行多个UML,模拟多机网络实验;
6.便捷添加系统调用;
7.内核模块的调试。

评论

此博客中的热门博文

I/O映射之I/O端口

通过Netlink检测网线插拔

使用seq_file