【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
  从以上抓包分析中可以看出docker网络环境中,通过macvlan的方式连通两个不同宿主机上同一个网段的容器时,数据包没有进行二次封装转发的都是原始数据包,这说明使用这种方式更为节能高效。
posted @ 2020-04-01 11:04  为极客而生  阅读(673)  评论(0编辑  收藏  举报