网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

时间:2023-03-08 21:10:37

本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫。

01 macvlan 简介

前面的文章讲过了几种 Linux 虚拟网络设备:tap/tun、veth-pair、bridge,它们本质上是 Linux 系统 提供的网络虚拟化解决方案,今天要讲的 macvlan 也是其中的一种,准确说这是一种网卡虚拟化的解决方案。因为 macvlan 这种技术能将 一块物理网卡虚拟成多块虚拟网卡 ,相当于物理网卡施展了 多重影分身之术 ,由一个变多个。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

02 macvlan 的工作原理

macvlan 是 Linux kernel 支持的新特性,支持的版本有 v3.9-3.19 和 4.0+,比较稳定的版本推荐 4.0+。它一般是以内核模块的形式存在,我们可以通过以下方法判断当前系统是否支持:

# modprobe macvlan
# lsmod | grep macvlan
macvlan 24576 0

如果第一个命令报错,或者第二个命令没有返回,说明当前系统不支持 macvlan,需要升级内核。

macvlan 这种技术听起来有点像 VLAN,但它们的实现机制是完全不一样的。macvlan 子接口和原来的主接口是完全独立的,可以单独配置 MAC 地址和 IP 地址,而 VLAN 子接口和主接口共用相同的 MAC 地址。VLAN 用来划分广播域,而 macvlan 共享同一个广播域。

通过不同的子接口,macvlan 也能做到流量的隔离。macvlan 会根据收到包的目的 MAC 地址判断这个包需要交给哪个虚拟网卡,虚拟网卡再把包交给上层的协议栈处理。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

03 四种模式

根据 macvlan 子接口之间的通信模式,macvlan 有四种网络模式:

  • private 模式
  • vepa(virtual ethernet port aggregator) 模式
  • bridge 模式
  • passthru 模式

默认使用的是 vepa 模式。

3.1 private

这种模式下,同一主接口下的子接口之间彼此隔离,不能通信。即使从外部的物理交换机导流,也会被无情地丢掉。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

3.2 vepa

这种模式下,子接口之间的通信流量需要导到外部支持 802.1Qbg/VPEA 功能的交换机上(可以是物理的或者虚拟的),经由外部交换机转发,再绕回来。

注:802.1Qbg/VPEA 功能简单说就是交换机要支持 发夹(hairpin) 功能,也就是数据包从一个接口上收上来之后还能再扔回去。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

3.3 bridge

这种模式下,模拟的是 Linux bridge 的功能,但比 bridge 要好的一点是每个接口的 MAC 地址是已知的,不用学习。所以,这种模式下,子接口之间就是直接可以通信的。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

3.4 passthru

这种模式,只允许单个子接口连接主接口,且必须设置成混杂模式,一般用于子接口桥接和创建 VLAN 子接口的场景。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

3.5 mactap

和 macvlan 相似的技术还有一种是 mactap。和 macvlan 不同的是,mactap 收到包之后不是交给协议栈,而是交给一个 tapX 文件,然后通过这个文件,完成和用户态的直接通信。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

04 实践

在 Linux 系统下,创建 macvlan 的命令形式如下:

ip link add link DEVICE name NAME type { macvlan | macvtap } mode { private | vepa | bridge |
passthru [ nopromisc ] }

通常,单独使用 macvlan 毫无意义,一般都是结合 VM 和容器来构建网络。下面我们就简单使用 namespace 来看看 Linux 是怎么使用 macvlan 的。

实验拓扑如下:

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解

在我的系统中,以接口 enp0s8 为例创建两个 macvlan 子接口(使用 bridge 模式),配置 IP 并将其挂到两个 namespace 中,测试连通性。

# 创建两个 macvlan 子接口
ip link add link enp0s8 dev mac1 type macvlan mode bridge
ip link add link enp0s8 dev mac2 type macvlan mode bridge # 创建两个 namespace
ip netns add ns1
ip netns add ns2 # 将两个子接口分别挂到两个 namespace 中
ip link set mac1 netns ns1
ip link set mac2 netns ns2 # 配置 IP 并启用
ip netns exec ns1 ip a a 192.168.56.122/24 dev mac1
ip netns exec ns1 ip l s mac1 up ip netns exec ns1 ip a a 192.168.56.123/24 dev mac2
ip netns exec ns2 ip l s mac2 up

注:enp0s8 的 IP 是 192.168.56.110/24,配置的子接口 IP 也必须是同一网段的。

完了两个子接口 ping 一下:

root@ubuntu:~# ip netns exec ns1 ip a show mac1
9: mac1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1
link/ether 2e:6e:d9:08:c5:05 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.56.122/24 scope global mac1
valid_lft forever preferred_lft forever
inet6 fe80::2c6e:d9ff:fe08:c505/64 scope link
valid_lft forever preferred_lft forever
root@ubuntu:~# ip netns exec ns1 ping 192.168.56.123
PING 192.168.56.123 (192.168.56.123) 56(84) bytes of data.
64 bytes from 192.168.56.123: icmp_seq=1 ttl=64 time=0.052 ms
64 bytes from 192.168.56.123: icmp_seq=2 ttl=64 time=0.028 ms
^C
--- 192.168.56.123 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.028/0.040/0.052/0.012 ms

可以看到,能够 ping 通,如果把上面的 mode 换成其他模式就行不通了,这个就留给大家去实验了(默认是 vepa 模式)。

另外,在 docker 中,macvlan 是一种较为重要的跨主机网络模型,这块的内容就留作下篇文章再做讲解了。

05 总结

macvlan 是一种网卡虚拟化技术,能够将一张网卡虚拟出多张网卡。

macvlan 的四种通信模式,常用模式是 bridge。

思考一下:

  1. macvlan bridge 和 bridge 的异同点
  2. 还有一种类似的技术,多张虚拟网卡共享相同 MAC 地址,但有独立的 IP 地址,这是什么技术?

这两个问题大家可以留言互动一下。


我的公众号 「Linux云计算网络」(id: cloud_dev) ,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。

网卡也能虚拟化?网卡虚拟化技术 macvlan 详解