【博客444】Linux Macvlan

Linux Macvlan

背景

在 Macvlan 出现之前,我们只能为一块以太网卡添加多个 IP 地址,却不能添加多个 MAC 地址,因为 MAC 地址正是通过其全球唯一性来标识一块以太网卡的,即便你使用了创建 ethx:y 这样的方式,你会发现所有这些“网卡”的 MAC 地址和 ethx 都是一样的,本质上,它们还是一块网卡,这将限制你做很多二层的操作。有了 Macvlan 技术,你可以这么做了。

目的

Macvlan 允许你在主机的一个网络接口上配置多个虚拟的网络接口,这些网络 interface 有自己独立的 MAC 地址,也可以配置上 IP 地址进行通信。Macvlan 下的虚拟机或者容器网络和主机在同一个网段中,共享同一个广播域。Macvlan 和 Bridge 比较相似,但因为它省去了 Bridge 的存在,所以配置和调试起来比较简单,而且效率也相对高。除此之外,Macvlan 自身也完美支持 VLAN。

同一 VLAN 间数据传输是通过二层互访,即 MAC 地址实现的,不需要使用路由。不同 VLAN 的用户单播默认不能直接通信,如果想要通信,还需要三层设备做路由,Macvlan 也是如此。

用 Macvlan 技术虚拟出来的虚拟网卡,在逻辑上和物理网卡是对等的。物理网卡也就相当于一个交换机,记录着对应的虚拟网卡和 MAC 地址,当物理网卡收到数据包后,会根据目的 MAC 地址判断这个包属于哪一个虚拟网卡。这也就意味着,只要是从 Macvlan 子接口发来的数据包(或者是发往 Macvlan 子接口的数据包),物理网卡只接收数据包,不处理数据包,所以这就引出了一个问题:本机 Macvlan 网卡上面的 IP 无法和物理网卡上面的 IP 通信。

macvlan原理

Macvlan 虚拟网卡设备是寄生在物理网卡设备上的。发包时调用自己的发包函数,查找到寄生的物理设备,然后通过物理设备发包。收包时,通过注册寄生的物理设备的 rx_handler 回调函数,处理数据包。

在这里插入图片描述

Macvlan vs Bridge

Bridge

Bridge 实际上就是一种交换机

在这里插入图片描述

Bridge 有以下特点:

Bridge 是二层设备,仅用来处理二层的通讯。
Bridge 使用 MAC 地址表来决定怎么转发帧(Frame)。
Bridge 会从 host 之间的通讯数据包中学习 MAC 地址。
可以是硬件设备,也可以是纯软件实现(例如:Linux Bridge)。

以下是一个在 Linux 主机上,多个 VM 使用 bridge 相互通讯的状况:

在这里插入图片描述

Macvlan

Macvlan 有以下特点:

可让使用者在同一张实体网卡上设定多个 MAC 地址。

带有上述设定的 MAC 地址的网卡称为子接口(sub interface);
而实体网卡则称为父接口(parent interface)。


parent interface 可以是一个物理接口(eth0),可以是一个 802.1q 的子接口(eth0.10),
也可以是 bonding 接口。

可在 parent/sub interface 上设定的不只是 MAC 地址,IP 地址同样也可以被设定。
sub interface 无法直接与 parent interface 通讯
 (带有 sub interface 的 VM 或容器无法与 host 直接通讯)。

承上,若 VM 或容器需要与 host 通讯,那就必须额外建立一个 sub interface 给 host 用。
sub interface 通常以 mac0@eth0 的形式来命名以方便区別。

用张图来解释一下设定 Macvlan 后的样子:
在这里插入图片描述

Macvlan 的工作模式

1、VEPA(Virtual Ethernet Port Aggregator

VEPA为默认的工作模式,该模式下,所有macvlan发出的流量都会经过父接口,不管目的地是否与该macvlan共用一个父接口。

在这里插入图片描述

工作原理:

在 VEPA 模式下,所有从 Macvlan 接口发出的流量,不管目的地全部都发送给父接口,
即使流量的目的地是共享同一个父接口的其它 Macvlan 接口。

在二层网络场景下,由于生成树协议的原因,两个 Macvlan 接口之间的通讯会被阻塞,
这时需要上层路由器上为其添加路由(需要外部交换机配置 Hairpin 支持,
即需要兼容 802.1Qbg 的交换机支持,
其可以把源和目的地址都是本地 Macvlan 接口地址的流量发回给相应的接口)。

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

现在大多数交换机都不支持 Hairpin 模式,但 Linux 主机中可以通过一种 Harpin 模式的 Bridge 来让 VEPA 模式下的不同 Macvlan 接口通信。

怎么配置呢?非常简单,通过一条命令就可以解决:

$ brctl hairpin br0 eth1 on

或者使用 iproute2 来设置:

$ bridge link set dev eth0 hairpin on

在 Linux 主机上配置了 Harpin 模式之后,源和目的地址都是本地 Macvlan 接口地址的流量,都会被 br0(假设你创建的 Bridge 是 br0)发回给相应的接口。

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

VEPA 和 Passthru 模式下,两个 Macvlan 接口之间的通信会经过主接口两次:第一次是发出的时候,第二次是返回的时候。这样会影响物理接口的宽带,也限制了不同 Macvlan 接口之间通信的速度。如果多个 Macvlan 接口之间通信比较频繁,对于性能的影响会比较明显。

2、Bridge

在这里插入图片描述

工作原理:

此种模式类似 Linux 的 Bridge,拥有相同父接口的两块 Macvlan 虚拟网卡是可以直接通讯的,
不需要把流量通过父网卡发送到外部网络,广播帧将会被泛洪到连接在"网桥"上的所有其他
子接口和物理接口。这比较适用于让共享同一个父接口的 Macvlan 网卡进行直接通讯的场景。

这里所谓的 Bridge 指的是在这些网卡之间,数据流可以实现直接转发,不需要外部的协助,
这有点类似于 Linux host 内建了一个 Bridge,即用 brctl 命令所做的那一切。

但和 Linux bridge 绝不是一回事,它不需要学习 MAC 地址,也不需要 STP,
因此效能比起使用 Linux bridge 好上很多。

Bridge 模式有个缺点:如果父接口 down 掉,所有的 Macvlan 子接口也会全部 down 掉,同时子接口之间也将无法进行通讯。

3、Private

在这里插入图片描述

工作原理:

此种模式相当于 VEPA 模式的增强模式,其完全阻止共享同一父接口的 Macvlan 虚拟网卡
之间的通讯,即使配置了 Hairpin 让从父接口发出的流量返回到宿主机,
相应的通讯流量依然被丢弃。

具体实现方式是丢弃广播/多播数据,这就意味着以太网地址解析 arp 将不可运行,
除非手工探测 MAC 地址,否则通信将无法在同一宿主机下的多个 Macvlan 网卡间展开。
之所以隔离广播流量,是因为以太网是基于广播的,隔离了广播,以太网将失去了依托。

4、Passthru

在这里插入图片描述

工作原理:

此种模式会直接把父接口和相应的MacVLAN接口捆绑在一起,这种模式每个父接口只能和一个
 Macvlan 虚拟网卡接口进行捆绑,并且 Macvlan 虚拟网卡接口继承父接口的 MAC 地址。
此种模式的优点是虚拟机和容器可以更改 MAC 地址和其它一些接口参。

Macvlan 和 Bridge 的使用场景

使用 Macvlan :

仅仅需要为虚拟机或容器提供访问外部物理网络的连接。
Macvlan 占用较少的 CPU,同时提供较高的吞吐量。
当使用 Macvlan 时,宿主机无法和 VM 或容器直接进行通讯。

使用 Bridge :

当在同一台宿主机上需要连接多个虚拟机或容器时。
对于拥有多个网桥的混合环境。
需要应用高级流量控制,FDB的维护。

Macvlan 的局限

Macvlan 是将 VM 或容器通过二层连接到物理网络的近乎理想的方案,但它也有一些局限性:

1、Linux 主机连接的交换机可能会限制同一个物理端口上的 MAC 地址数量。
虽然你可以让网络管理员更改这些策略,但有时这种方法是无法实行的

2、许多 NIC 也会对该物理网卡上的 MAC地址数量有限制。超过这个限制就会影响到系统的性能。

example

下面的实验创建了两个macvlan接口,分别放到两个netns中;然后验证这两个macvlan口之间客户互通

先使用bridge mode创建两个macvlan接口,其parent接口都是 eth0。

$ sudo ip link add link eth0 name macv1 type macvlan mode bridge
$ sudo ip link add link eth0 name macv2 type macvlan mode bridge

查看创建的结果,注意每个接口都有自己的 mac 地址

$ sudo ip link
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:f4:3e:1d brd ff:ff:ff:ff:ff:ff
3763: macv1@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:76:5f:92:85:8d brd ff:ff:ff:ff:ff:ff
3764: macv2@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:90:ba:08:bd:81 brd ff:ff:ff:ff:ff:ff

创建namespace

$ sudo ip netns add net1
$ sudo ip netns add net2

将macvlan接口插入到namespace

$ sudo ip link set macv1 netns net1
$ sudo ip link set macv2 netns net2

设置网卡IP,设置网卡UP状态

$ sudo ip netns exec net1 ip addr add 52.1.1.151/24 dev macv1
$ sudo ip netns exec net2 ip addr add 52.1.1.152/24 dev macv2

$ sudo ip netns exec net1 ip link set macv1 up
$ sudo ip netns exec net2 ip link set macv2 up

查看网卡状态

$ sudo ip netns exec net1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3763: macv1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:76:5f:92:85:8d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 52.1.1.151/24 scope global macv1
       valid_lft forever preferred_lft forever
$ sudo ip netns exec net2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3764: macv2@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 66:90:ba:08:bd:81 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 52.1.1.152/24 scope global macv2
       valid_lft forever preferred_lft forever

net1和net2无法ping通宿主机,ping自己也不通.2个容器互相ping没有问题

macv1 ping不通宿主机接口 eth0 的地址:
$ sudo ip net exec net1 ping 10.0.1.3
PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
^C
--- 10.0.1.3 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3008ms

可以ping通macv2的地址:
$ sudo ip net exec net1 ping 52.1.1.152
PING 52.1.1.152 (52.1.1.152) 56(84) bytes of data.
64 bytes from 52.1.1.152: icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from 52.1.1.152: icmp_seq=2 ttl=64 time=0.041 ms
64 bytes from 52.1.1.152: icmp_seq=3 ttl=64 time=0.047 ms
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值