【计算机网络】使用VirtualBox和namespace搭建桥接环境

  • 在工作中遇到需要使用Virtualbox基于Bridge搭建桥接环境,由此做个记录

  • 主要是Virtualbox实现bridge桥接还需要一些黑手段,跟Vmware的LAN Segment还有些许不同

  • 另外,基于namespace在一台虚拟机上搭建桥接环境的方法也是一种不错的方案

本文大纲

1.桥接拓补介绍

image.png

如上图,使用Virtualbox创建三台Linux主机,然后主机A和主机C分别连接于主机B

主机B上创建bridge设备绑定无ip的双网卡,然后确保主机A和主机C能够网络互通

主机A和主机C的网卡分配1.1.1.0/24同一网段下的ip

2.VirtualBox上分配网卡

VirtualBox有一种虚拟网络叫做Internal Network,能提供内部的私有网络

1.首先,在VirtualBox中新建三台基于CentOS8的Linux主机,分配的网卡如下:

主机A

  • 名称:centos-1
  • 网卡:enp0s3(桥接模式==>管理网卡,方便本地ssh连接)和enp0s8(内部网络模式==>界面名称为intnet-1

主机B

  • 名称:centos-2
  • 网卡:enp0s3(桥接模式==>管理网卡,方便本地ssh连接)、enp0s8(内部网络模式==>界面名称为intnet-1)、enp0s9(内部网络模式==>界面名称为intnet-2

主机C

  • 名称:centos-3
  • 网卡:enp0s3(桥接模式==>管理网卡,方便本地ssh连接)和enp0s8(内部网络模式==>界面名称为intnet-2

注意:主机A和C到主机B的内部网络网卡,对应的界面名称在Virtualbox的选定要匹配起来,流量才能到达对应的网卡。

2.登录Linux主机并分配网卡ip如下,管理网卡在此就省略不写,只要保证能够在本地ssh连接即可

主机A

ifconfig enp0s8 1.1.1.10/24

主机C

ifconfig enp0s8 1.1.1.20/24

主机B

1
2
3
4
ip link add dev br0 type bridge
ip link set dev enp0s8 master br0
ip link set dev enp0s9 master br0
ifconfig br0 up

3.验证网络连通

1
2
主机A:ping 1.1.1.20  ==> 不通
主机B:ping 1.1.1.10 ==> 不通

此时在主机A和主机C分别进行互ping,发现并没有ping通,那这是什么问题呢?

3.原理探究

经过上面的问题,搜索相关的资料发现Virtualbox的独特性,参考链接传送门

对Virtualbox注册型交换机解释,

总的来说,和VMWare的LAN Segment内部有一个虚拟学习型交换机(早期是广播式Hub) 不同, VirtualBox的Internal Network内部的交换机不是学习型的,而是注册型的!

所谓的注册型交换机就是,只有注册过的Mac地址,该交换机才会帮你转发!这类交换机只有两种转发策略

  • 对于广播帧,所有的端口都发一份。
  • 对于单播帧,仅向注册该目标Mac地址的端口发送。

那么交换机(内部网络网卡)是如何注册Mac地址的呢?或者说,从哪里可以看到一个虚拟机的网卡注册了哪个Mac呢?

如何查看mac地址

上面的实验不通的原因:H1 ping H2时,经由Linux Bridge,ARP请求可以广播到H2,此时H2收到的ARP广播中,源MAC自然是H1的MAC地址,当H2回复ARP Reply时,目标MAC为H1的MAC地址,而H1的MAC地址没有注册在intnet2的虚拟交换机中,所以intnet2的交换机不会转发这个帧。最终导致请求响应无法到达H1,因此而不通。

4.如何注册virtualbox的网卡

注册步骤:

1.将centos-1上的intnet-1对应的MAC地址注册在centos-2上的intnet-2

2.将centos-3上的intnet-1对应的MAC地址注册在centos-2上的intnet-1

3.centos-2主机启动后,通过ifconfig命令将intnet-1和intnet-2对应enp0s9,enp0s10网卡MAC改成其他,防止冲突即可。

image.png

例如我的mac地址替换情况如下:

centos-1

  • intnet-1 :080027431935

centos-2

  • intnet-1 :080027CADC26(原mac) –> 0800279DD011
  • intnet-2 :0800270083A6(原mac) –> 080027431935

centos-3

  • intnet-2 :0800279DD011

centos-2替换后的地址如下图:

centos-2的网络配置

新版的virtualbox中mac地址拦可以直接在文本框,复制粘贴进行修改,旧版的有些不支持,呈现灰色状态,这个时候如果想修改可以使用VBoxManage命令指定特定网卡的MAC地址

1
2
VBoxManage modifyvm "centos-2" --macaddress4 080027431935
VBoxManage modifyvm "centos-2" --macaddress3 0800279DD011

最后再说明第三步的作用,之所以需要这一步,是防止地址冲突导致Bridge的转发表中毒

  • mac地址080027431935可以从centos-1的intnet-1学习到
  • mac地址080027431935被配置在自己的enp0s9上

这会导致bridge的转发出现无法工作的错误,所以必须把centos-2的enp0s8,enp0s9这两个网卡的mac地址改成别的,而这个修改动作VirtualBox的Internal Network交换机并不知道(只有新的网卡激活或者重新注册新的MAC会改变转发表,即点击那个小按钮或者执行VBoxManage命令改变MAC地址),所以并不影响bridge的转发表。

启动centos-2后的命令操作如下:

1
2
3
4
5
6
7
8
9
10
11
## 修改网卡的mac地址
ifconfig enp0s8 hw ether 08:00:27:9D:D0:12
ifconfig enp0s9 hw ether 08:00:27:43:19:36

## 新增bridge设备,并加入网卡
ip link add dev br0 type bridge
ip link set dev enp0s8 master br0
ip link set dev enp0s9 master br0

## 启动网桥
ifconfig br0 up

5.验证桥接网络

此时再在centos-1和centos-3上进行互ping就无问题了,网络通了

确保网络已通

在centos-2中利用tcpdump成功抓取br0网口的网络包

网桥抓包情况

6.了解namespace

6.1 什么是namespace?

学习过docker底层实现的可能了解过docker是基于namespace和cgroup实现的,其中namespace 是 Linux 内核用来隔离内核资源的方式。

通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,他们之间保持着不可见的状态,也就是感觉不到对方的存在,但是实际却存在同一个Linux系统上

总结一下就是,Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响

注意:对于每个 network namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。

6.2 namespace的基本操作

基于来自于 iproute2 安装包的 ip 命令可以实现对namespace的操作

  • 创建一个新的namespace,并命名为foo

ip netns add foo

  • 查看Linux系统下存在的namespace列表

ip netns ls

  • 在namespace中执行Linux命令
1
2
3
4
5
ip netns exec foo `Linux 命令`

ip netns exec foo ip addr

ip netns exec foo ls -l

上面的方面都是在namespace外通过命令指定来执行,每一句都带有ip netns exec foo,有没有方法在namespace里面直接执行命令呢?答案是肯定的,通过末尾增加bash命令即可进入

1
2
3
4
5
6
7
8
9
10
11
## 通过指定bash命令进入namespace
ip netns exec foo bash

## 直接执行Linux命令
ip addr

## 退出namespace
exit

## 通过修改 bash 的前缀信息可以区分当前处在哪一个namespace
ip netns exec foo /bin/bash --rcfile <(echo "PS1=\"namespace foo> \"")
  • 删除namespace

ip netns del foo

6.3 namespace的通信

默认情况下,namespace是不能和主机网络,也不能和其他namespace通信的

每个 namespace 在创建的时候会自动创建一个lo的网卡,它的作用和Linux系统中默认看到的lo一样,都是为了实现loopback通信。如果希望 lo 能工作,不要忘记启用它:
ip netns exec net1 ip link set lo up

每个namespace都实现了网络的隔离,如果要使他们彼此之间通信起来就需要用Linux veth peer,可以把veth peer当做是全双工的管道,从一个方向发送的网络数据,可以使两个namespace实现网络数据的通信,veth peer也就是Linux下的虚拟网卡,namespace基于虚拟网卡实现了彼此之间的通信

可以使用ip link add type veth来创建一对veth peer出来,需要记住的是veth peer 无法单独存在,删除其中一个,另一个也会自动消失。另外,创建veth peer的时候也指定它们的名字,比如ip link add dev vethfoo type veth peer name vethbar创建出来的两个名字就是 vethfoovethbar

创建了虚拟网卡后,接下来就是分别将虚拟网卡分配给对应的namespace实现网卡之间的通信,通过使用ip link set 虚拟网卡名称 netns 命名空间名称来实现,比如:ip link set vethfoo netns foo

分配好网卡后再配置网卡ip地址和生成路由表就可以实现namespace之间的通信了,接下来看一个案例,如何实现两个namespace之间的通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
## 创建两个namespace
ip netns add foo
ip netns add bar

## 创建虚拟网卡对
ip link add dev vethfoo type veth peer name vethbar

## 为namespace分配网卡
ip link set vethfoo netns foo
ip link set vethbar netns bar

## 为namespace中的虚拟网卡分配ip地址并启动网卡
ip netns exec foo ip link set vethfoo up
ip netns exec foo ip addr add 1.1.1.10/24 dev vethfoo
ip netns exec bar ip link set vethbar up
ip netns exec bar ip addr add 1.1.1.20/24 dev vethbar

## 启动lo网卡
ip netns exec foo ip link set lo up
ip netns exec bar ip link set lo up

## 最后通过ping验证网络是否连通
ip netns exec foo ping 1.1.1.20

7.使用bridge连接不同的namespace

通过上面掌握到的namespace知识,结合桥接的网络拓补,发现通过来实现bridge来实现多个namespace之间的通信也是无问题的,有了上面的知识铺垫,下面就直接写出具体的命令实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
## 创建三个namespace
ip netns add ns1
ip netns add ns2
ip netns add ns3

## 启动各个namespace的lo网卡
ip netns exec ns1 ip link set lo up
ip netns exec ns2 ip link set lo up
ip netns exec ns3 ip link set lo up

## 创建两对虚拟网卡对
ip link add dev vetha type veth peer name vethb1
ip link add dev vethc type veth peer name vethb2

## 分配虚拟网卡给对应的namespace
ip link set vetha netns ns1
ip link set vethb1 netns ns2
ip link set vethb2 netns ns2
ip link set vethc netns ns3

## 配置ns1和ns3的网卡ip并启动网卡
ip netns exec ns1 ip link set dev vetha up
ip netns exec ns3 ip link set dev vethc up
ip netns exec ns1 ip addr add 1.1.1.10/24 dev vetha
ip netns exec ns3 ip addr add 1.1.1.20/24 dev vethc

## 配置ns2中的bridge和绑定网卡,最后启动网卡
ip netns exec ns2 ip link add dev br0 type bridge
ip netns exec ns2 ip link set dev vethb1 master br0
ip netns exec ns2 ip link set dev vethb2 master br0
ip netns exec ns2 ip link set dev vethb1 up
ip netns exec ns2 ip link set dev vethb2 up
ip netns exec ns2 ip link set dev br0 up

上面的命令集合基于namespace成功搭建了桥接的网络拓补,接下来就是在ns1和ns3进行互ping查看网络是否已经连通

8.验证namespace桥接网络效果

配置后查看各个namespace里面的网卡情况

  • ns1和ns3的网卡情况

ns1和ns3的网卡情况

  • ns2的网卡情况

ns2的网卡情况

ns1和ns3互ping均成功

ns1和ns3互ping均成功


【计算机网络】使用VirtualBox和namespace搭建桥接环境
https://littlejoyo.github.io/2021/05/23/network/virtualbox-bridge/
作者
Joyo
发布于
2021年5月23日
许可协议