Linux 内核原生支持 Macvlan
Macvlan 是 Linux 内核提供的一种网络虚拟化技术,它允许在同一个物理网卡上创建多个虚拟网络接口,每个虚拟接口可以有自己的 MAC 地址。这样做的好处是:
- 每个虚拟接口可以像独立网卡一样直接在二层网络通信。
- 可以用来隔离流量、创建容器网络(Docker、LXC 等常用)。
- 性能接近原生网卡,因为大部分流量直接在内核层转发,不经过额外的用户态处理。
- Macvlan 支持从 Linux 内核 2.6.24 开始引入。
- 现代 Linux 发行版(如 CentOS 7/8、Ubuntu 20.04/22.04、Debian 12 等)内核都原生集成了 macvlan 驱动。
- 模块名为
macvlan
,通常是内置的或可以通过modprobe macvlan
加载。
lsmod | grep macvlan
# 或者
modprobe macvlan
#加载macvlan模块
Macvlan 的四个模式
private 模式
描述:同一物理网卡上的 Macvlan 接口彼此隔离,不能直接互相通信,但可以和外部网络通信。
特点:
- 接口之间完全隔离。
- 适合容器之间需要独立 IP,但不互通的场景。
macvlan0 macvlan1 macvlan2
| | |
└─────────> 外部网络
vepa 模式 (Virtual Ethernet Port Aggregator)
描述:同一物理网卡上的接口通信必须通过外部交换机转发。
特点:
- 内部接口不能直接互通。
- 适合企业交换机环境,通过交换机统一转发流量
macvlan0 macvlan1
| |
└───> 交换机 <───┘
bridge 模式
描述:同一物理网卡上的 Macvlan 接口可以互相通信,也能访问外部网络。
特点:
- 内部接口互通。
- 最常用模式,容器互通和外部访问都方便。
macvlan0 <--> macvlan1 <--> macvlan2
\ /
---> 外部网络 <---
passthru 模式
描述:每个 Macvlan 接口独占物理网卡,只有一个接口可以使用物理网卡。
特点:
- 高性能,类似 SR-IOV。
- 一个物理网卡只能绑定一个 passthru 接口。
[eth0] ---> macvlan0 (独占)
小结
模式 | 内部接口互通 | 外部网络访问 | 典型应用 |
---|---|---|---|
private | ❌ | ✅ | 容器隔离 |
vepa | ❌ | ✅ | 企业交换机 |
bridge | ✅ | ✅ | 容器互通 |
passthru | ❌ | ✅ | 高性能直通 |
创建MacVLAN
注意:nmcli
创建的 macvlan 接口会被 NetworkManager 接管(永久生效)
和用 ip link
临时创建的接口是两套机制(临时生效)
临时配置(使用 ip
命令)
假设物理网卡是 eth0
,我们先创建一个 macvlan 接口,再给它分配 IP:
# 创建 macvlan 接口
ip link add link eth0 name macvlan0 type macvlan mode bridge
# 启动接口
ip link set macvlan0 up
# 分配 IP 地址
ip addr add 192.168.1.198/24 dev macvlan0
# 设置默认网关(如需要)
ip route add default via 192.168.1.1 dev macvlan0
这样 macvlan0
就有了 IP,可以 ping
网关或外网了。
⚠️ 注意:如果你给物理网卡 eth0
和 macvlan0
配置了同一网段的 IP,它们之间可能无法直接互通(这是 macvlan 的特性)。
永久配置(开机自动生效)
用 nmcli
创建 macvlan 接口
比如在物理网卡 eth0
上创建一个 macvlan 接口 macvlan0
:
nmcli connection add type macvlan \
ifname macvlan0 \
dev eth0 \
mode bridge \
ip4 192.168.1.100/24 \
gw4 192.168.1.1
nmcli connection up macvlan0
#启用接口
参数说明:
ifname macvlan0
→ 新接口名dev eth0
→ 绑定的物理网卡mode bridge
→ macvlan 模式(可选:private
、vepa
、bridge
、passthru
)ip4
→ IPv4 地址和掩码gw4
→ 网关
这样 macvlan0
就带 IP 上线了。
因为 nmcli
配置会写入 NetworkManager 的配置目录(通常 /etc/NetworkManager/system-connections/
),所以重启后接口依然存在,不需要额外操作。
RHEL通过配置文件创建
创建文件 /etc/sysconfig/network-scripts/ifcfg-macvlan0
DEVICE=macvlan0
DEVICETYPE=Macvlan
PHYSDEV=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.1.100
PREFIX=24
GATEWAY=192.168.1.1
MACVLAN_MODE=bridge
然后重启网络:systemctl restart network
小结
ip link add
→ 临时接口(重启后消失)。nmcli
→ 永久接口(由 NetworkManager 管理)。
脚本:创建MacVLAN的交互式操作
#!/bin/bash
# CentOS7 Macvlan 管理脚本
# 自动加载 macvlan 模块
echo ">>> 检查 macvlan 模块..."
if ! lsmod | grep -q macvlan; then
echo "未加载 macvlan 模块,正在加载..."
modprobe macvlan
if [ $? -eq 0 ]; then
echo "macvlan 模块已成功加载"
else
echo "加载 macvlan 模块失败,请检查内核是否支持"
exit 1
fi
else
echo "macvlan 模块已加载"
fi
# 注意事项
cat <<EOF
================ 注意事项 ================
1. Macvlan 接口与宿主机默认不能互通
2. 请确保目标物理网卡已连接网络
3. DNS 默认为 223.5.5.5
4. 子网掩码默认 255.255.255.0
==========================================
EOF
# 选择物理网卡
function select_parent_if() {
echo ">>> 检测可用物理网卡..."
IFACES=($(ls /sys/class/net | grep -Ev '^(lo|docker.*|veth.*|macvlan.*|virbr.*)$'))
if [ ${#IFACES[@]} -eq 0 ]; then
echo "未找到可用物理网卡"
exit 1
fi
echo "可用物理网卡列表:"
for i in "${!IFACES[@]}"; do
echo "$((i+1))) ${IFACES[$i]}"
done
while true; do
read -p "请选择物理网卡编号 [1-${#IFACES[@]}]: " choice
if [[ "$choice" =~ ^[0-9]+$ ]] && [ $choice -ge 1 ] && [ $choice -le ${#IFACES[@]} ]; then
PARENT_IF=${IFACES[$((choice-1))]}
echo "已选择物理网卡: $PARENT_IF"
break
else
echo "无效输入,请重新选择"
fi
done
}
# 获取用户输入函数
function get_network_config() {
select_parent_if
read -p "请输入新建 macvlan 接口名称 (例如 macvlan0): " VLAN_IF
echo "请选择 macvlan 模式 (回车默认 bridge):"
echo "1) bridge"
echo "2) private"
echo "3) vepa"
echo "4) passthru"
read -p "请输入选项 [1-4]: " MODE_CHOICE
case $MODE_CHOICE in
2) VLAN_MODE="private" ;;
3) VLAN_MODE="vepa" ;;
4) VLAN_MODE="passthru" ;;
*) VLAN_MODE="bridge" ;;
esac
read -p "请输入 IP 地址 (例如 192.168.1.100): " IP_ADDR
read -p "请输入子网掩码 (默认 24 请使用CIDR格式): " NETMASK
NETMASK=${NETMASK:-255.255.255.0}
read -p "请输入网关 (可留空): " GATEWAY
read -p "请输入 DNS (默认 223.5.5.5): " DNS
DNS=${DNS:-223.5.5.5}
}
# 使用 ip 命令创建 macvlan
function create_with_ip() {
get_network_config
echo ">>> 正在创建 macvlan 接口 $VLAN_IF (模式: $VLAN_MODE)..."
ip link add $VLAN_IF link $PARENT_IF type macvlan mode $VLAN_MODE
ip addr add $IP_ADDR/$NETMASK dev $VLAN_IF
ip link set $VLAN_IF up
[ -n "$GATEWAY" ] && ip route add default via $GATEWAY dev $VLAN_IF
echo "nameserver $DNS" > /etc/resolv.conf
echo ">>> 创建完成!"
show_summary
}
# 使用 nmcli 命令创建 macvlan
function create_with_nmcli() {
get_network_config
echo ">>> 正在使用 nmcli 创建 macvlan 接口 $VLAN_IF (模式: $VLAN_MODE)..."
nmcli connection add type macvlan ifname $VLAN_IF dev $PARENT_IF mode $VLAN_MODE ip4 $IP_ADDR/$NETMASK gw4 $GATEWAY
nmcli connection modify $VLAN_IF ipv4.dns "$DNS"
nmcli connection up $VLAN_IF
echo ">>> 创建完成!"
show_summary
}
# 删除所有 macvlan 接口
function delete_all_macvlan() {
echo ">>> 正在删除所有 macvlan 接口..."
for IF in $(ip -o link show | awk -F': ' '{print $2}' | grep macvlan); do
ip link delete $IF
echo "已删除接口: $IF"
done
echo ">>> 所有 macvlan 接口已删除"
}
# 总结信息
function show_summary() {
echo
echo "================ 配置信息总结 ================"
echo "物理网卡: $PARENT_IF"
echo "macvlan接口: $VLAN_IF"
echo "模式: $VLAN_MODE"
echo "IP 地址: $IP_ADDR"
echo "子网掩码: $NETMASK"
echo "网关: ${GATEWAY:-无}"
echo "DNS: $DNS"
echo "============================================"
}
# 菜单
while true; do
echo
echo "========= Macvlan 管理菜单 ========="
echo "1) 使用 ip 创建 macvlan"
echo "2) 使用 nmcli 创建 macvlan"
echo "3) 删除所有 macvlan 接口"
echo "4) 退出"
echo "==================================="
read -p "请选择操作 [1-4]: " choice
case $choice in
1) create_with_ip ;;
2) create_with_nmcli ;;
3) delete_all_macvlan ;;
4) echo "退出程序"; exit 0 ;;
*) echo "无效选项,请重新输入" ;;
esac
done