Linux 网络虚拟化 Macvlan(基于物理网络接口虚拟网络接口) 认知

不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树

写在前面


  • 博文内容涉及 Macvlan 的简单认知,以及一个Demo
  • 博文内容根据《 Kubernetes 网络权威指南:基础、原理与实践》 整理
  • 理解不足小伙伴帮忙指正

不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树


物理网卡的分身术:Macvlan

Macvlan(MAC Virtual LAN)是一种在 Linux 操作系统上实现的网络虚拟化技术。它允许您创建基于物理网络接口的虚拟网络接口,并为每个虚拟接口分配独立的 MAC 地址。每个 Macvlan 接口与物理网络接口(主接口)共享相同的物理网络连接,但具有不同的 MAC 地址,因此它们可以像独立的网络接口一样进行独立的网络通信。

通俗的来讲,macvlan 可以基于一个物理网卡设备,生成多个MAC地址和IP 地址不同的逻辑网卡

Macvlan五大工作模式解析

Macvlan出现之前,我们可以通过网卡别名(例如eth0:1)的方式为一块以太网卡添加多个IP地址,却不能为其添加多个MAC地址。原因是以太网卡是以MAC地址为唯一识别的,而网卡别名并没有改变这些网卡的MAC地址。

Macvlan 接口可以看作是物理以太网接口的虚拟子接口。Macvlan允许用户在主机的一个网络接口上配置多个虚拟的网络接口

每个Macvlan接口都有自己的区别于父接口的MAC地址,并且可以像普通网络接口一样分配IP地址。因此,使用Macvlan技术带来的效果是一块物理网卡上可以绑定多个IP地址,每个IP地址都有自己的MAC地址

Macvlan 虚拟出来的虚拟网卡,在逻辑上和物理网卡是对等的,应用程序可以像使用物理网卡的IP地址那样使用Macvlan 设备的 IP地址。

Macvlan 的主要用途是网络虚拟化(包括容器和虚拟机)。另外,有一些比较特殊的场景,例如,keepalived使用虚拟MAC地址。需要注意的是,使用Macvlan的虚拟机或者容器网络与主机在同一个网段,即同一个广播域中。

Macvlan支持5种模式,分别是bridge、VEPA、Private、Passthru和Source模式。

bridge模式

该模式类似 Linux bridge,是 Macvlan 最常用的模式,比较适合共享同一个父接口的Macvlan网卡进行直接通信的场景。

bridge 模式下,拥有相同父接口的两块 Macvlan 虚拟网卡可以直接通信,不需要把流量通过父接口发送到外部网络,广播帧将会被洪泛到连接在“网桥”上的所有其他子接口和物理接口

网桥带双引号是因为实际上并没有网桥实体的产生,而是指在这些网卡之间数据流可以实现直接转发,这有点类似于
Linux网桥。

Macvlan的bridge模式和Linux网桥不是一回事,它不需要学习MAC地址,也不需要生成树协议(STP),因此性能要优于Linux网桥。

用通俗的话理解,类似利用 Linux 网桥 建立了一个新的通道,允许 Macvlan 接口与物理网络中的其他设备进行通信,同时又保证了与物理网络的隔离

bridge模式的缺点是如果父接口故障,所有Macvlan子接口会跟着故障,子接口之间也将无法进行通信

VEPA模式

VEPA(Virtual Ethernet Port Aggregator,虚拟以太网端口聚合)是默认模式。

所有从Macvlan接口发出的流量,不管目的地址是什么,全部发送给父接口,类似于连接到一个特殊的交换机,这个交换机负责处理 Macvlan 接口与物理网络之间的通信,使得 Macvlan 接口可以与其他设备进行通信。

在二层网络下,由于生成树协议的原因,两个Macvlan接口之间的通信会被阻塞,这时就需要接入的外部交换机支持hairpin,把源和目的地址都是本地Macvlan接口地址的流量,发给相应的接口。

在VEPA模式下,从父接口收到的广播包会洪泛给所有的子接口。

目前,大多数交换机都不支持 hairpin 模式,但Linux可以通过一种hairpin模式的网桥,让VEPA模式下的 Macvlan接口能够直接通信,接下来,配置Linux网桥某个端口的hairpin模式:

1
brctl hairpin  br0 eth0 on

以上命令的作用是配置Linux网桥br0,使得从eth0收到包后再从eth0发送出去。

以上brctl haripin子命令原型是:

1
irpin <bridge> <port> {on|off}

或者使用iproute2直接设置网卡的hairpin模式

1
ip link set dev eth0 hairpin on 

也可以通过写sysfs目录下的设备文件设置网桥某个端口的hairpin模式。下面的例子设置了网桥br0的eth1端口的hairpin:

1
echo 1 > /sys/class/net/br0/brif/eth1/hairpin_mode

配置了 hairpin 后,源地址和目的地址都是本地 Macvlan 接口地址的流量,会被 Linux 网桥发回给相应的接口。

如果想在物理交换机层面对虚拟机或容器之间的访问流量进行优化设定,VEPA模式是一种比较好的选择。

Private模式

Private 模式类似于 VEPA 模式,但又增强了VEPA模式的隔离能力,其完全阻止共享同一父接口的Macvlan虚拟网卡之间的通信。即使配置了 hairpin,让从父接口发出的流量返回宿主机,相应的通信流量依然被丢弃。

就好像在一个封闭的空间里,Macvlan 接口只能与同一主机上的其他 Macvlan 接口进行通信,无法与外部网络中的设备进行通信

Private的具体实现方式是丢弃广播/多播数据,这就意味着以太网地址解析ARP将无法工作。除非手工探测 MAC 地址,否则通信将无法在同一宿主机下的多个Macvlan网卡间进行,如果需要Macvlan的隔离功能,那么Private模式会非常有用。

Passthru模式

Passthru模式翻译过来就是直通模式。在这种模式下,每个父接口只能和一个Macvlan网卡捆绑,并且Macvlan网卡继承父接口的MAC地址。就像是将数据包直接传递给物理网络设备,绕过了网络协议栈的处理,使得 Macvlan 接口可以直接与物理网络设备进行通信。

Source模式

在这种模式下,寄生在物理设备上,Macvlan 设备只接收指定的源 Mac 地址的数据包,其他数据包一概丢弃,使得 Macvlan 接口的 MAC 地址与该设备的 MAC 地址相同,并且只能与该设备进行通信

Macvlan 设备基本命令

在宿主机上创建 Macvlan 设备

1
2
ip link add veth2.1 link veth2 type macvlan mode bridge
ip link set veth2.1 up

查看该Macvlan网卡的详细信息:

1
ip -d link show eth0.1

一般情况下,Macvlan设备的MAC地址是Linux系统自动分配的,用户也可以自定义。使用以下命令就可在新建Macvlan网卡的同时指定其MAC地址:

1
ip link add eth0.1 link eth0 address f2:a7:fc:ac:59:c6 type macvlan mode vepa
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
root@cs-1080702884152-default:/home/liruilonger# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.26.3 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::f0e2:40ff:fe60:1190 prefixlen 64 scopeid 0x20<link>
ether f2:e2:40:60:11:90 txqueuelen 1000 (Ethernet)
RX packets 16 bytes 1244 (1.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23 bytes 1830 (1.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth2.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::9093:55ff:fe97:7920 prefixlen 64 scopeid 0x20<link>
ether 92:93:55:97:79:20 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7 bytes 586 (586.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Macvlan设备的跨机通信Demo

  • A节点,IP地址为192.168.26.149;
  • B节点,IP地址为192.168.26.106;

我们在A节点创建 macvlan 设备,与B节点的物理网卡进行通信

A 节点信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──[root@liruilongs.github.io]-[~]
└─$ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:93:51:67 brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 192.168.26.149/24 brd 192.168.26.255 scope global dynamic noprefixroute ens160
valid_lft 1792sec preferred_lft 1792sec
inet6 fe80::20c:29ff:fe93:5167/64 scope link noprefixroute
valid_lft forever preferred_lft forever

在 A 节点上创建Macvlan设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──[root@liruilongs.github.io]-[~]
└─$ip link add ens160.1 link ens160 type macvlan mode bridge
┌──[root@liruilongs.github.io]-[~]
└─$ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:93:51:67 brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 192.168.26.149/24 brd 192.168.26.255 scope global dynamic noprefixroute ens160
valid_lft 1745sec preferred_lft 1745sec
inet6 fe80::20c:29ff:fe93:5167/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: ens160.1@ens160: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether aa:92:11:14:3c:34 brd ff:ff:ff:ff:ff:ff

Macvlan设备启用后会自动分配MAC地址而没有IP(v4)地址。为其分配IP地址。

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
┌──[root@liruilongs.github.io]-[~]
└─$ip addr add 192.168.26.141/24 dev ens160.1
┌──[root@liruilongs.github.io]-[~]
└─$ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:93:51:67 brd ff:ff:ff:ff:ff:ff
altname enp3s0
inet 192.168.26.149/24 brd 192.168.26.255 scope global dynamic noprefixroute ens160
valid_lft 1710sec preferred_lft 1710sec
inet6 fe80::20c:29ff:fe93:5167/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: ens160.1@ens160: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether aa:92:11:14:3c:34 brd ff:ff:ff:ff:ff:ff
inet 192.168.26.141/24 scope global ens160.1
valid_lft forever preferred_lft forever
┌──[root@liruilongs.github.io]-[~]
└─$ip route
default via 192.168.26.2 dev ens160 proto dhcp src 192.168.26.149 metric 100
192.168.26.0/24 dev ens160 proto kernel scope link src 192.168.26.149 metric 100
┌──[root@liruilongs.github.io]-[~]
└─$ip link set ens160.1 up

使用新创建的 macvlan 设备 ping B 节点的IP

1
2
3
4
5
6
7
8
9
10
┌──[root@liruilongs.github.io]-[~]
└─$ping -c 3 -I ens160.1 192.168.26.106
PING 192.168.26.106 (192.168.26.106) from 192.168.26.141 ens160.1: 56(84) bytes of data.
64 bytes from 192.168.26.106: icmp_seq=1 ttl=64 time=0.692 ms
64 bytes from 192.168.26.106: icmp_seq=2 ttl=64 time=0.417 ms
64 bytes from 192.168.26.106: icmp_seq=3 ttl=64 time=0.363 ms

--- 192.168.26.106 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2047ms
rtt min/avg/max/mdev = 0.363/0.490/0.692/0.144 ms

用当前的物理网卡 ping Macvlan 设备IP

1
2
3
4
5
6
7
8
9
10
11
12
┌──[root@liruilongs.github.io]-[~]
└─$ping -c 3 -I ens160 192.168.26.141
PING 192.168.26.141 (192.168.26.141) from 192.168.26.149 ens160: 56(84) bytes of data.
From 192.168.26.149 icmp_seq=1 Destination Host Unreachable
From 192.168.26.149 icmp_seq=2 Destination Host Unreachable
From 192.168.26.149 icmp_seq=3 Destination Host Unreachable

--- 192.168.26.141 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2087ms
pipe 3
┌──[root@liruilongs.github.io]-[~]
└─$

在 B 节点使用 物理网卡对 A 节点的 Macvlan 设备 ping 测试

1
2
3
4
5
6
7
8
9
10
┌──[root@vms106.liruilongs.github.io]-[~]
└─$ping -c 3 192.168.26.141
PING 192.168.26.141 (192.168.26.141) 56(84) bytes of data.
64 bytes from 192.168.26.141: icmp_seq=1 ttl=64 time=0.548 ms
64 bytes from 192.168.26.141: icmp_seq=2 ttl=64 time=0.459 ms
64 bytes from 192.168.26.141: icmp_seq=3 ttl=64 time=0.430 ms

--- 192.168.26.141 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2088ms
rtt min/avg/max/mdev = 0.430/0.479/0.548/0.050 ms

通过上面的测试可以发现, 桥接模式下,Macvlan 可以与同一网段的任一机器通信。

Macvlan是将虚拟机或容器通过二层连接到物理网络的一个不错的方案,但它也有一些局限性,例如:

  • 每个虚拟网卡都要有自己的MAC地址,所以Macvlan需要大量的MAC地址,而Linux主机连接的交换机可能会限制一个物理端口的MAC地址数量上限,而且许多物理网卡的MAC地址数量也有限制,超过这个限制就会影响到系统的性能;
  • IEEE 802.11 标准(即无线网络)不喜欢同一个客户端上有多个MAC地址,这意味着你的Macvlan子接口没法在无线网卡上通信。

当然可以使用 IPvlan 来解决上面的这些问题

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)


《 Kubernetes 网络权威指南:基础、原理与实践》


© 2018-至今 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

Linux 网络虚拟化 Macvlan(基于物理网络接口虚拟网络接口) 认知

https://liruilongs.github.io/2024/03/12/Linux/Linux网络/Linux-网络虚拟化-Macvlan-认知/

发布于

2024-03-12

更新于

2024-11-22

许可协议

评论
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×