ubuntu20.04 搭建kernel调试环境第六篇(下)-网络原理

ubuntu中qemu启动多个guest虚拟机,guest如何访问外网?guest之间如何实现网络通信?我常用qemu调试自己编译的kernel,需要在guest和host之间共享一些调试文件,如何达到这个目的?
开发人员经常遇到环境差异(ubuntu宿主机、自己编译的kernel config、rootfs、qemu等等因素)导致"别人成功的经验”不能复制到自己机器上,所以有必要深入了解一下qemu的网络是怎么实现的,遇到问题才能快速解决。

一、qemu与宿主机通讯例子

参考ubuntu20.04 搭建kernel调试环境第六篇(上)--网络配置_geshifei的博客-CSDN博客_qemu 网络配置

二、libvirt

libvirt是一套管理虚拟化平台的工具集(官网https://libvirt.org/),支持qemu等多种虚拟化平台。这是本文的主角,我们用它的网络模块实现网络通讯。

安装命令:
1)apt install bridge-utils
2)apt install uml-utilities
3)apt install libvirt-daemon-system

开机后,libvirt启动deamon进程/usr/sbin/libvirtd在ubuntu在宿主机中创建一个虚拟网桥virbr0,并在网桥中创建一个虚拟网卡virbr0-nic。

root@linux:/home/gsf# brctl show
bridge name	bridge id		     STP enabled	interfaces
virbr0		8000.5254005ec9bb	     yes		virbr0-nic

virbr0用于桥接多个虚拟机,配合libvirt生成的NAT规则,可实现guest访问外网、其他机器。
virbr0-nic上并没有网络流量,引入它只是为了让virbr0有个固定的mac,virbr0的mac是从virbr0-nic复制过来的。这么做是因为内核的一个行为导致的,内核会拷贝网桥下的第一块网卡的mac做为网桥的mac,所以如果virbr0网卡有变化时,则会导致virbr0的mac地址也随着变化,导致一段时间内网络异常,所以增加一个virbr0-nic来固定virbr0的mac。

ubuntu中启动两个虚拟机后的信息:

root@linux:/home/gsf# brctl show
bridge name	bridge id		     STP enabled	interfaces
virbr0		8000.5254005ec9bb	     yes		tap0
							                    tap1
							                    virbr0-nic

三、virbr0及guest机器的mac地址、ip地址

1,网桥mac及ip地址

网桥名称、mac、ip定义在/var/lib/libvirt/dnsmasq/default.conf。文件内容如下。
注意,不要直接修改该文件(重启后会丢失),而应用virsh net-edit default命令来修改。

root@linux:/home/gsf# cat /var/lib/libvirt/dnsmasq/default.conf
##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
##    virsh net-edit default
## or other application using the libvirt API.
##
## dnsmasq conf file created by libvirt
strict-order
user=libvirt-dnsmasq
pid-file=/run/libvirt/network/default.pid
except-interface=lo
bind-dynamic
interface=virbr0
dhcp-range=192.168.122.2,192.168.122.254,255.255.255.0
dhcp-no-override
dhcp-authoritative
dhcp-lease-max=253
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
root@linux:/home/gsf#

2,guest机器mac及ip地址

a)DHCP方式获取ip地址

用buildroot编译rootfs时,可以指定eth0通过DHCP获取ip地址(参考ubuntu20.04 搭建kernel调试环境第六篇(上)--网络配置)。qemu启动后,可以查看/etc/network/interfaces文件:

# cat /etc/network/interfaces 
# interface file auto-generated by buildroot

auto lo
iface lo inet loopback

# 指定DHCP方式
auto eth0
iface eth0 inet dhcp
  pre-up /etc/network/nfs_check
  wait-delay 15
  hostname $(hostname)
#

guset申请ip地址时,宿主机libvird通过dnsmasq给guest分配ip地址。

root@linux:/home/gsf# ps -aux |grep libvirt
root        ……  /usr/sbin/libvirtd
libvirt+    ……  /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper

文件default.conf(见上)字段dhcp-range=192.168.122.2,192.168.122.254,255.255.255.0指定了DHCP地址池范围,所以如果我在ubuntu host机器中启动两个guest虚拟机,dnsmasq将给他们分配类似于192.168.122.76、192.168.122.78这样的地址。

guest与host机器之间是怎么进行DHCP交互的,后文说明。

b)静态方式获取ip地址

如果buildroot编译rootfs时没有指定eth0为DHCP,就需要通过静态方式获取ip了。qemu启动后:

# cat /etc/network/interfaces 
# interface file auto-generated by buildroot

auto lo
iface lo inet loopback

因为interfaces文件中只有lo接口,所以ifconfig是看不到eth0的:

# ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B) 

我们需要配置静态ip、dns:

在虚拟机中执行命令
# vi /etc/network/interfaces
# interface file auto-generated by buildroot

auto lo
iface lo inet loopback

# 增加eth0配置
iface eth0 inet static
address 192.168.122.16
netmask 255.255.255.0

# 设置dns
dns-nameservers 192.168.122.1

在/etc/resolv.conf中增加一行:

nameserver 192.168.122.1 # eth0

在我的系统中/etc/resolv.conf -> /tmp/resolv.conf,tmp是tmpfs,所以重启会丢失。

执行ifup eth0,ifconfig就能看到eth0接口了,并且ping其他的guest机器、外网都是正常的。

# ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:59  
          inet addr:192.168.122.16  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe12:3459/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3 errors:0 dropped:0 overruns:0 frame:0
          TX packets:21 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:252 (252.0 B)  TX bytes:1665 (1.6 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:876 (876.0 B)  TX bytes:876 (876.0 B)

# ping www.baidu.com
PING www.baidu.com (180.101.49.13): 56 data bytes
64 bytes from 180.101.49.13: seq=0 ttl=51 time=13.801 ms
64 bytes from 180.101.49.13: seq=1 ttl=51 time=10.078 ms

# ping 192.168.122.76
PING 192.168.122.76 (192.168.122.76): 56 data bytes
64 bytes from 192.168.122.76: seq=0 ttl=64 time=9.660 ms
64 bytes from 192.168.122.76: seq=1 ttl=64 time=2.889 ms

3,MAC地址

guest ip有了,那guest的mac又是怎么来的?答案是,qemu启动时,人为指定的。

qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 --nographic -append "root=/dev/sda console=ttyS0" -hdb ext4.img -net nic,macaddr=32:54:00:11:34:51,model=e1000 -net bridge,id=net0,helper=/usr/lib/qemu/qemu-bridge-helper,br=virbr0

注意macaddr第一个字节不能是基数(基数是组播地址),比如示例中32字段不能改成31。

有了ip、mac,就具备了网络通信的条件,下文描述通讯细节。

四、网络实现

1,模块框架图

以ubuntu宿主机中启动2个qemu虚拟机为例(qemu参数差别在于指定的nic mac不一样),执行ping 114.114.114.114来说明。

启动虚拟机:

虚拟机1:
qemu-system-x86_64 -kernel bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 --nographic -append "root=/dev/sda console=ttyS0" -hdb ext4.img -net nic,macaddr=32:24:01:11:34:55,model=e1000 -net bridge,id=net0,helper=/usr/lib/qemu/qemu-bridge-helper,br=virbr0

虚拟机2:
qemu-system-x86_64 -kernel bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 --nographic -append "root=/dev/sda console=ttyS0" -hdb ext4.img -net nic,macaddr=32:24:01:11:34:56,model=e1000 -net bridge,id=net0,helper=/usr/lib/qemu/qemu-bridge-helper,br=virbr0

参数 -net nic,创建一个虚拟网络接口eth0,qemu本质上就是一个用户态程序,所以eth0并不是真正的网络接口,而是模拟出来的nic。eth0流量需要借助于linux的tun/tap设备驱动来实现(tun/tap设备可以理解成虚拟网卡,功能类似物理网卡)。

2,guest间网络通讯

qemu启动时会在ubuntu宿主机创建tap0设备,并将将tap设备加入到虚拟网桥virbr0,同时还会将eth0与tap0关联起来,用户态eth0的网络访问通过read/write tap设备来做,所以多个guest之间可以经virbr0进行网络通讯。

3,guset与host间网络通讯

libvirt基于iptables在宿主机中做了NAT(net address translation)规则,将souce ip是192.168.122.0/24的数据包(即guest机器发出的数据包,具体ip地址取决于网桥ip),用MASQUERADE这个target将source ip替换成宿主机物理网卡ip地址。这样数据包看起来就像是宿主机发出的数据包一样,宿主机收到响应数据包时,根据连接跟踪表,决定响应的数据包发给哪个guest。具体说来,一个访问外网的数据包处理流程如下:
1)nat表postrouting链(iptables的四表五链,见最后附图),MASQUERADE将数据包的源ip(192.168.122.17)替换成宿主机物理网卡ip(10.233.11.5)

root@linux:/home/gsf# iptables -nvL -t nat
Chain PREROUTING (policy ACCEPT 1340 packets, 354K bytes)
 pkts bytes target     prot opt in     out     source               destination                

Chain POSTROUTING (policy ACCEPT 159K packets, 11M bytes)
 pkts bytes target     prot opt in     out     source               destination         
 159K   11M LIBVIRT_PRT  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_PRT (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  273 19121 RETURN     all  --  *      *       192.168.122.0/24     224.0.0.0/24        
    0     0 RETURN     all  --  *      *       192.168.122.0/24     255.255.255.255     
    0     0 MASQUERADE  tcp  --  *      *       192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
    0     0 MASQUERADE  udp  --  *      *       192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
   28  2352 MASQUERADE  all  --  *      *       192.168.122.0/24    !192.168.122.0/24    
root@linux:/home/gsf# 

在guest虚拟机中执行ping 114.114.114.114,分别在tap0口和物理网卡口抓包,可以看到从tap0口出来的数据包,源ip被替换成了物理网卡ip:

tap0口数据包(源ip是192.168.122.17):

物理网卡口数据包(源ip是宿主机物理网卡的ip 10.223.11.5):

响应数据包达到宿主机时,宿主机根据连接跟踪表,将响应包转给对应的请求者,即转给字段src=192.168.122.17指定的接收者:

root@linux:/home/gsf# conntrack -L --any-nat
icmp     1 29 src=192.168.122.17 dst=114.114.114.114 type=8 code=0 id=39169 src=114.114.114.114 dst=10.223.11.5 type=0 code=0 id=39169 mark=0 use=1
conntrack v1.4.5 (conntrack-tools): 1 flow entries have been shown.
root@linux:/home/gsf#

四、guest启动时网络初始化流程

guest机器运行的是linux系统,所以它的网络初始化流程与我们常见的linux系统大同小异。

开机执行/etc/init.d/rcS脚本,这个脚本按数字大小执行S开头的脚本,本例中执行S40network

# cat S40network 
#!/bin/sh
#
# Start the network....
#

# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network

case "$1" in
  start)
	printf "Starting network: "
	/sbin/ifup -a
	[ $? = 0 ] && echo "OK" || echo "FAIL"
	;;
  stop)
	printf "Stopping network: "
	/sbin/ifdown -a
	[ $? = 0 ] && echo "OK" || echo "FAIL"
	;;
  restart|reload)
	"$0" stop
	"$0" start
	;;
  *)
	echo "Usage: $0 {start|stop|restart}"
	exit 1
esac

exit $?

开机时执行/sbin/ifup -a,ifup是buildroot编译busybox生成的可执行程序,用来激活指定的网络接口。ifup命令读取/etc/network/interfaces文件,激活文件配置的网络接口。

附一:iptables的四表五链

 (图片来源自网络)

附二:常见问题

1,为了让guest访问外网,需要guest、host在同一个网段中吗?

答:不需要。

libvirt在宿主机插入了一下iptables规则,通过NAT将来自guest的数据包源ip替换成了物理网卡ip,这个数据包就可以发到外网了。

2,guset可以访问samba服务器吗?

答:可以。

参考ubuntu20.04 搭建kernel调试环境第六篇(上)--网络配置_geshifei的博客-CSDN博客_qemu 网络配置

3,buildroot的默认网络配置脚本(/etc/network/interfaces)是怎么生成的?

答:buildroot-2020.02.8/package/ifupdown-script/fupdown-scripts.mk生成

4,为什么修改了buildroot-2020.02.8/package/ifupdown-script,重新编译buildroot,ifupdown-script改动不生效?

答:删除buildroot-2020.02.8/output/build/ifupdown-scripts目录,再重新编译即可。

buildroot没有根据文件修改时间来判断是否重新编译,只要buildroot-2020.02.8/output/build目录中有对应的package,就不会重新编译。

5,为什么conntrack -L --any-nat看的是空的?

答:guest无网络请求。执行ping后试试。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 搭建 LAMP 环境是在 Ubuntu 20.04 操作系统上安装和配置 Apache、MySQL 和 PHP 的过程。下面是一些大致的步骤: 1. 安装 Apache 服务器 在终端中输入以下命令: ``` sudo apt update sudo apt install apache2 ``` 2. 安装 MySQL 数据库 在终端中输入以下命令: ``` sudo apt install mysql-server sudo mysql_secure_installation ``` 3. 安装 PHP 解释器和扩展 在终端中输入以下命令: ``` sudo apt install php libapache2-mod-php php-mysql ``` 4. 配置 Apache 服务器以使用 PHP 在终端中输入以下命令: ``` sudo nano /etc/apache2/mods-enabled/dir.conf ``` 然后将文件中的 `index.php` 移到文件的开头,保存并退出。 5. 重启 Apache 服务器 在终端中输入以下命令: ``` sudo systemctl restart apache2 ``` 这些步骤可以帮助您在 Ubuntu 20.04 上搭建 LAMP 环境。 ### 回答2: 搭建Ubuntu 20.04的LAMP(Linux,Apache,MySQL,PHP)环境,可以按照以下步骤进行: 1. 安装Ubuntu 20.04操作系统:从官方网站下载Ubuntu 20.04的ISO镜像文件,并将其安装到计算机上。 2. 更新系统:打开终端,运行sudo apt update命令来更新系统软件包。 3. 安装Apache web服务器:在终端中运行sudo apt install apache2命令来安装Apache。 4. 配置防火墙:运行sudo ufw allow 'Apache'命令来允许通过防火墙访问Apache。 5. 安装MySQL数据库服务器:在终端中运行sudo apt install mysql-server命令来安装MySQL。 6. 启动MySQL服务:运行sudo systemctl start mysql命令来启动MySQL服务。 7. 设置MySQL安全:运行sudo mysql_secure_installation命令来设置MySQL的root密码和其他安全相关设置。 8. 安装PHP:在终端中运行sudo apt install php libapache2-mod-php php-mysql命令来安装PHP及其相关模块。 9. 配置Apache以使用PHP:运行sudo nano /etc/apache2/mods-enabled/dir.conf命令来编辑Apache的配置文件,确保index.php在目录索引文件的优先顺序中。 10. 重新启动Apache服务:运行sudo systemctl restart apache2命令来重新启动Apache服务,使更改生效。 至此,你已成功搭建Ubuntu 20.04的LAMP环境。你可以将网页文件放置在Apache的默认网页目录/var/www/html/中,并通过Web浏览器访问localhost来访问你的网页。 请注意,这只是一个基本的LAMP环境搭建过程。根据具体需求,可能还需要额外的配置和安装,如安装其他PHP扩展、调整MySQL的配置等。 ### 回答3: 搭建Ubuntu 20.04上的LAMP环境(即Linux、Apache、MySQL和PHP)是一项常见的任务。下面是一个简单的步骤指南: 第一步是安装Ubuntu Server 20.04操作系统。您可以从Ubuntu官方网站上下载ISO文件,并按照说明进行安装。 安装完成后,确保您的系统已经更新到最新的软件版本。打开终端窗口,运行以下命令来更新系统: ``` sudo apt update sudo apt upgrade ``` 接下来,安装Apache Web服务器。运行以下命令来安装Apache: ``` sudo apt install apache2 ``` 完成安装后,您可以通过打开Web浏览器并输入您的服务器的IP地址来验证Apache是否正常工作。如果您能看到Apache的默认欢迎页面,说明安装成功。 然后,您需要安装MySQL数据库服务器。运行以下命令进行安装: ``` sudo apt install mysql-server ``` 安装过程中,您将被要求设置MySQL的root用户密码。设置密码后,您可以运行以下命令来启动MySQL服务: ``` sudo systemctl start mysql ``` 您还可以运行以下命令来使MySQL在系统启动时自动启动: ``` sudo systemctl enable mysql ``` 最后,您需要安装PHP和相关的扩展。运行以下命令来安装所需的软件包: ``` sudo apt install php libapache2-mod-php php-mysql ``` 安装完成后,您需要重新启动Apache服务以使其生效: ``` sudo systemctl restart apache2 ``` 现在,您已经成功搭建Ubuntu 20.04上的LAMP环境。您可以在/var/www/html目录中创建一个简单的PHP文件,并在Web浏览器中访问来测试PHP是否正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值