【NetDevOps】新一代网工需要了解的那点事儿(八)---MacVLAN
8 MacVLAN
前面的章节介绍了几种 Linux 虚拟网络设备:tap/tun、veth-pair、bridge等它们本质上是Linux内核提供的网络虚拟化解决方案,本章节要讲的MacVLAN也是其中的一种,准确说这是一种网卡虚拟化的解决方案。因为MacVLAN这种技术能将 一块物理网卡虚拟成多块虚拟网卡 ,由一个变多个(前提是网卡要打开混杂模式)。针对每一个虚拟网卡都可以分配一个独立的MAC地址和IP地址,这就相当于多个虚拟网卡通过一块物理网卡连接到物理网络中。
8.1 基本原理
macvlan是 Linux内核支持的一项特性,支持的版本有 v3.9-3.19 和 4.0+,推荐比较稳定的版本4.0+。它一般是以内核模块的形式存在,我们可以通过以下方法判断当前系统是否支持:
[root@d1 ~]# modprobe macvlan
[root@d1 ~]# lsmod | grep macvlan
macvlan 19239 0
如果以上命令报错或者没有回显,那么说明您的系统暂时不支持macvlan。对于网工肯定纠结macvlan和vlan有啥区别,其实只是长得有点像实现机制是真心不一样啊。通过macvlan虚拟出来的子接口和原来的物理接口是完全独立的,这些macvlan虚拟接口可以单独配置MAC地址和IP地址,而vlan子接口和主接口需共用相同的MAC地址。vlan主要用来划分广播域,而 macvlan本身就是在同一个广播域中。macvlan通过不同的子接口来做到流量的隔离,一般通过收到报文的目的MAC来判断这个包需要交给哪个虚拟网卡转发,虚拟网卡再将数据包交给上层协议栈来处理。
+------------------------------------------------------------------------+
| |
| +-------------------------+ |
| Eth0 | Network Stack | |
| +------------+ | |
| | +----------------+---+--+-+ |
| | | | | |
|Physical Network | | | | |
| + | | | | |
| | | AA +------------+ | | | |
| | | +--------+ Macvlan A +---+ | | |
| | | | +------------+ | | |
| | | | | | |
| +----+----+ | | | | |
| | | +-------+---+ BB +-------------+ | | |
| | Eth 0 +--------+if dst mac is+-------+ Macvlan B +------+ | |
| | | +-----------+ +-------------+ | |
| +---------+ | | |
| | | |
| | CC +-------------+ | |
| +--------+ Macvlan C +---------+ |
| +-------------+ |
| By:[F0rGeEk] |
+------------------------------------------------------------------------+
8.2 工作模式
macvlan子接口之间的通信模式,macvlan分为以下四种网络模式。其中最常用的是bridge模式。
- 1. privite
在private模式下,同一主接口下的子接口之间彼此隔离不能通信。即使从外部的物理网络引流,也不能互相通信。 - 2. vepa
在vepa模式下,子接口之间的通信流量需要引流到外部支持802.1Qbg/VPEA功能的交换机上(可以是物理的或者虚拟的交换机),经由外部交换机转发再绕回来。这里所说的支持802.1Qbg/VPEA功能的交换机是指支持"端口回流"功能或者叫"支持hairpin模式",也就是说数据包从一个端口收到后还能通过这个端口再转发出去。 - 3. bridge
这bridge式下,主要是模拟Linux bridge的功能,但比bridge要好的一点的是每个接口的MAC地址是已知的,不用学习。所以在这种模式下,子接口之间默认就可以互相通信。 - 4. passthru
这种模式只允许单个子接口连接主接口,且必须设置成混杂模式,一般用于子接口桥接和创建 VLAN 子接口的场景。
8.3 MacVLAN实践
这里我们也分两部分来进行实践,一种实在普通的Linux网络环境下,另一种实在Docker容器环境中实践。在Docker网络环境中还可以分为两种,一种是相同macvlan之间的通信还有一种是不同macvlan之间的通信。其中不同vlan之间的通信类似数通中的单臂路由,因为二层是不通的所以需要借助三层网络通信,这里就需要通过一台路由设备(也可以是开启ip_forward的Linux主机)来进行路由转发。本文就介绍最基础最底层的实践方式,不同macvlan之间的通信相信对于网工的你来说简直easy的不要不要的。
- MacVLAN连接连个不同的NS
+-------------------------------------+
| +-------+ +-------+ |
| | NS1 | | NS2 | |
| +---+---+ +---+---+ |
| | | |
| | XXXXXXX | |
| | XX XX | |
| +---+X MacVLAN X+---+ |
| XX XX |
| XXXXXXX |
| + + |
| | | |
| +-----+--+--+-----+ |
| 12.1.1.1| Mac1 | Mac2 |12.1.1.2 |
| +--------+--------+ |
| | ens33 | |
| +-----------------+ |
| By:[F0rGeEk] |
+-------------------------------------+
这里我们的实验环境是将两个不同的Name Space之间通过macvlan连通,如上图所示为物理接口ens33创建两个macvlan子接口,使用bridge模式,并配置IP地址然后将它们分别加入到两个不同的NS中,最后测试连通性。具体过程如下:
# 创建两个macvlan子接口
[root@d1 ~]# ip link add link ens33 dev mac1 type macvlan mode bridge
[root@d1 ~]# ip link add link ens33 dev mac2 type macvlan mode bridge
# 创建两个NS
[root@d1 ~]# ip netns add ns1
[root@d1 ~]# ip netns add ns2
# 将两个macvlan子接口分别加入ns1和ns2
[root@d1 ~]# ip link set mac1 netns ns1
[root@d1 ~]# ip link set mac2 netns ns2
# 为两个macvlan子接口配置IP地址并激活
[root@d1 ~]# ip netns exec ns1 ip addr add 12.1.1.1/24 dev mac1
[root@d1 ~]# ip netns exec ns1 ip link set mac1 up
[root@d1 ~]# ip netns exec ns2 ip addr add 12.1.1.2/24 dev mac2
[root@d1 ~]# ip netns exec ns2 ip link set mac2 up
# 查看两个ns中的macvlan子接口配置信息
[root@d1 ~]# ip netns exec ns1 ip -d link show mac1
3: mac1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 42:e3:dc:fc:32:54 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
macvlan mode bridge addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
[root@d1 ~]# ip netns exec ns2 ip -d link show mac2
4: mac2@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether fa:9e:76:06:1a:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
macvlan mode bridge addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
[root@d1 ~]# ip netns exec ns1 ip addr show mac1
3: mac1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 42:e3:dc:fc:32:54 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 12.1.1.1/24 scope global mac1
valid_lft forever preferred_lft forever
inet6 fe80::40e3:dcff:fefc:3254/64 scope link
valid_lft forever preferred_lft forever
[root@d1 ~]# ip netns exec ns2 ip addr show mac2
4: mac2@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether fa:9e:76:06:1a:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 12.1.1.2/24 scope global mac2
valid_lft forever preferred_lft forever
inet6 fe80::f89e:76ff:fe06:1add/64 scope link
valid_lft forever preferred_lft forever
# 测试连通性
[root@d1 ~]# ip netns exec ns1 ping 12.1.1.2 -c 3
PING 12.1.1.2 (12.1.1.2) 56(84) bytes of data.
64 bytes from 12.1.1.2: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 12.1.1.2: icmp_seq=2 ttl=64 time=0.037 ms
64 bytes from 12.1.1.2: icmp_seq=3 ttl=64 time=0.037 ms
--- 12.1.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.035/0.036/0.037/0.005 ms
抓包分析 ICMP 报文
[root@d1 ~]# tcpdump -i ens33 -w macvlan.pcap
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
^C18 packets captured
19 packets received by filter
0 packets dropped by kernel
[root@d1 ~]# sz macvlan.pcap A
- 容器网络环境中相同macvlan之间
在docker容器网络环境中,macvlan也是一种非常常见且重要的跨主机网络模型。下面我们就针对容器网络进行相同macvlan在不同主机之间通信的实践。实验环境为两台server:Server A和Server B;分别启用一个自定义网络172.33.1.0/24名称为mac1和mac2;分别创建两个容器并指定IP地址;最后测试两个容器之间的网络连通性。
+------------------------------------------------------------------------+
| |
| +-------------------+ +-------------------+ |
| |Server A | |Server B | |
| | +---------+ | | +---------+ | |
| | | Docker A| | | | Docker B| | |
| | +---------+ | | +---------+ | |
| | 172.33.1.11 | | 172.33.1.12 | |
| | | | | | | |
| | +------+------+ | | +------+------+ | |
| | | Mac 1 | | | | Mac 2 | | |
| | +------+------+ | | +------+------+ | |
| | | | | | | |
| | +----+----+ | | +----+----+ | |
| | | ens33 | | | | ens33 | | |
| +----+---------+----+ +----+---------+----+ |
| 172.16.116.131/24 172.16.116.132/24 |
| | | |
| +--------------------------------------------+ |
| By:[F0rGeEk] |
+------------------------------------------------------------------------+
具体实践过程如下:
# 启动docker服务
[root@d1 ~]# service docker start
Redirecting to /bin/systemctl start docker.service
# 创建docker自定义网络
[root@d1 ~]# docker network create -d macvlan --subnet=172.33.1.0/24 --gateway=172.33.1.1 -o parent=ens33 mac1
[root@d2 ~]# docker network create -d macvlan --subnet=172.33.1.0/24 --gateway=172.33.1.1 -o parent=ens33 mac2
# 检查自定义网络是否创建成功
[root@d1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f8a5e7ba5015 bridge bridge local
a96c8a04be60 host host local
e179ce74baa4 mac1 macvlan local
8f8172bcf173 none null local
[root@d2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
68199147d7fe bridge bridge local
eb0d0e219eb8 host host local
9c2b18b8a08a mac2 macvlan local
b7ac4a61fcce none null local
#创建并启用容器
[root@d1 ~]# docker run -itd --name DockerA --ip=172.33.1.11 --network mac1 busybox
00dda3a8691564dce5e062a2c4ea89cb5c9640373102d587eb2c83e122642a67
[root@d1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00dda3a86915 busybox "sh" 4 seconds ago Up 2 seconds DockerA
[root@d2 ~]# docker run -itd --name DockerB --ip=172.33.1.12 --network mac2 busybox
debe59d38ece790d1ffd3d2dc17240a15812b73025fd89b23d9d394f53fa7dc8
[root@d2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
debe59d38ece busybox "sh" 2 seconds ago Up 2 seconds DockerB
# 验证不同宿主机上的容器网络连通性
[root@d1 ~]# docker exec -it DockerA sh
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:21:01:0B
inet addr:172.33.1.11 Bcast:172.33.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:28 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2544 (2.4 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
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)
/ # ping 172.33.1.12 -c 3
PING 172.33.1.12 (172.33.1.12): 56 data bytes
64 bytes from 172.33.1.12: seq=0 ttl=64 time=0.405 ms
64 bytes from 172.33.1.12: seq=1 ttl=64 time=0.361 ms
64 bytes from 172.33.1.12: seq=2 ttl=64 time=0.310 ms
--- 172.33.1.12 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.310/0.358/0.405 ms
抓包分析 ICMP 报文
[root@d2 ~]# tcpdump -i ens33 -w macvlan.pcap
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
^C25 packets captured
26 packets received by filter
0 packets dropped by kernel
[root@d2 ~]# sz macvlan.pcap