VLAN

出自 ArchWiki

虚拟局域网 使您能够细分 LAN。 Linux 可以接受 VLAN 标记的流量,并将每个 VLAN ID 显示为不同的网络接口(例如:VLAN ID 100eth0.100)。

本文介绍了如何使用 iproute2systemd-networkdnetctl 配置 VLAN。

即时配置

在以下示例中,我们假设接口eth0,分配的名称eth0.100,VLAN ID 为 100

创建 VLAN 设备

使用以下命令添加 VLAN 接口

# ip link add link eth0 name eth0.100 type vlan id 100

运行 ip link 以确认已创建。

此接口的行为类似于普通接口。所有路由到它的流量都将通过主接口(在本例中为 eth0),但带有 VLAN 标签。只有配置正确的 VLAN 感知设备才能接受它们,否则流量将被丢弃。

使用像 eth0.100 这样的名称只是一种约定,并非强制执行;您可以选择使用 eth0_100 或类似 IPTV 这样的描述性名称。要查看接口上的 VLAN ID(如果您使用了非常规名称)

# ip -details link show eth0.100

-details (-d) 标志显示接口的完整详细信息

# ip -details addr show
4: eth0.100@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
   link/ether 96:4a:9c:84:36:51 brd ff:ff:ff:ff:ff:ff promiscuity 0 
   vlan protocol 802.1Q id 100 <REORDER_HDR> 
   inet6 fe80::944a:9cff:fe84:3651/64 scope link 
      valid_lft forever preferred_lft forever

添加 IP 地址

现在为刚创建的 VLAN 链接添加 IPv4 地址,并激活该链接

# ip addr add 192.168.100.1/24 brd 192.168.100.255 dev eth0.100
# ip link set dev eth0.100 up

关闭设备

要在移除链接之前干净地关闭设置,您可以执行以下操作

# ip link set dev eth0.100 down

移除设备

移除 VLAN 接口明显不那么复杂

# ip link delete eth0.100

持久配置

systemd-networkd

单接口

使用以下数字前缀的配置文件(请记住文件内容区分大小写,并且可以更改数字前缀)

/etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
DHCP=ipv4
;these are arbitrary names, but must match the *.netdev and *.network files
VLAN=eth0.100
VLAN=eth0.200
/etc/systemd/network/20-eth0.100.netdev
[NetDev]
Name=eth0.100
Kind=vlan

[VLAN]
Id=100
/etc/systemd/network/21-eth0.200.netdev
[NetDev]
Name=eth0.200
Kind=vlan

[VLAN]
Id=200

您将需要为每个 .netdev 关联 .network 文件,以处理寻址和路由。例如,要使用静态 IP 设置 eth0.100 接口,并使用 DHCP 设置 eth0.200 接口(但忽略提供的默认路由),请使用

/etc/systemd/network/30-eth0.100.network
[Match]
Name=eth0.100

[Network]
DHCP=no

[Address]
Address=192.168.0.25/24
/etc/systemd/network/31-eth0.200.network
[Match]
Name=eth0.200

[Network]
DHCP=yes

[DHCP]
UseRoutes=false

然后启用 systemd-networkd.service。 有关详细信息,请参阅 systemd-networkd

单接口多 VLAN,每个 VLAN 具有自己的网关

每个 vlan 都有自己的路由表和一个 RoutingPolicyRule,用于指定此路由应用于哪些源 IP 地址。

/etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
VLAN=eth0.10
VLAN=eth0.11
DNS=192.168.100.101
DNS=192.168.100.102
/etc/systemd/network/20-eth0.10.netdev
[NetDev]
Name=eth0.10
Kind=vlan

[VLAN]
Id=10
/etc/systemd/network/30-eth0.10.network
[Match]
Name=eth0.10

[Network]
Address=192.168.1.14/24
Address=192.168.1.24/24

[Route]
Gateway=192.168.1.1
Table=10

[RoutingPolicyRule]
From=192.168.1.0/24
Table=10
/etc/systemd/network/21-eth0.11.netdev
[NetDev]
Name=eth0.11
Kind=vlan

[VLAN]
Id=11
/etc/systemd/network/31-eth0.11.network
[Match]
Name=eth0.11

[Network]
Address=192.168.100.54/24

[Route]
Gateway=192.168.100.1
Table=11

[RoutingPolicyRule]
From=192.168.100.0/24
Table=11
检查
# ip rule
0:      from all lookup local
0:      from 192.168.1.0/24 lookup 10
0:      from 192.168.100.0/24 lookup 11
32766:  from all lookup main
32767:  from all lookup default

使用 ip route list table。例如

# ip route list table 10
default via 192.168.1.1 dev enp1.10 proto static
# ip route list table 11
default via 192.168.100.1 dev enp1.11 proto static

Bonded 接口

与上面类似,您只是要堆叠更多概念。您需要确保在交换机中设置了 bond,并确保它是带有标记 VLAN 的 trunk,与您在下面创建的内容相对应。约定是创建一个名为 bond0 的 bond 接口,但是存在一个已知问题,即加载 bonding 模块时,会创建一个名为 bond0 的 bond 设备,systemd 然后拒绝配置该设备(因为 systemd 试图尊重地保留它没有创建的任何设备)。

提示: 要防止 bonding 模块创建初始 bond0 接口,请将 bonding 模块的 max_bonds 选项设置为 0(默认值为 1
/etc/modprobe.d/bonding.conf
options bonding max_bonds=0
有关详细信息,请参阅内核模块#设置模块选项Linux 以太网 Bonding 驱动程序 HOWTO(内核文档)

为了本文的目的,我们将使用 bondname,您可以自行选择。

首先,我们创建 bond 设备

/etc/systemd/network/bondname.netdev
[NetDev]
Name=bondname
Kind=bond

[Bond]
Mode=802.3ad
LACPTransmitRate=fast

现在创建一个 .network 指令,该指令引用 VLAN 和接口载体。在本例中,我们将使用双端口光纤模块的约定

/etc/systemd/network/bondname.network
[Match]
Name=bondname

[Network]
VLAN=vlan10
VLAN=vlan20
VLAN=vlan30
BindCarrier=enp3s0f0 enp3s0f1

我们在这里使用 vlan<number> 命名约定,您可以使用其他名称,但请注意这是一个命名引用,因此您必须拥有一组具有相同名称的对应文件。

我们现在将设置物理网络接口

/etc/systemd/network/enp3s0f0.network
[Match]
Name=enp3s0f0

[Network]
Bond=bondname
/etc/systemd/network/enp3s0f1.network
[Match]
Name=enp3s0f1

[Network]
Bond=bondname

此时您可以重新启动,并且可能应该重新启动,因为 bonded 接口是在启动时创建的。重新启动 systemd-networkd 通常会使用来自这些文件的更改,但设备创建似乎发生在启动时。

我们现在将设置 VLAN。您应该意识到,拥有多个 VLAN 可能会导致您的机器具有多个默认路由的情况,因此您需要在网络指令中指定 Destination 指令,以确保只有一个 VLAN 用于默认路由。在本例中,我们将使用 ID 为 10 的 VLAN 作为我们的默认路由。

/etc/systemd/network/vlan10.netdev
[NetDev]
Name=vlan10
Kind=vlan

[VLAN]
Id=10

现在创建关联的网络指令以设置地址

/etc/systemd/network/vlan10.network
[Match]
Name=vlan10

[Network]
VLAN=vlan10

[Address]
Address=10.10.10.2/24

[Route]
Destination=0.0.0.0/0
Gateway=10.10.10.1

我们将为 ID 为 20 的 VLAN 创建类似的成对文件

/etc/systemd/network/vlan20.netdev
[NetDev]
Name=vlan20
Kind=vlan

[VLAN]
Id=20
/etc/systemd/network/vlan20.network
[Match]
Name=vlan20

[Network]
VLAN=vlan20

[Address]
Address=10.10.20.2/24

[Route]
Destination=10.10.20.0/24
Gateway=10.10.20.1

再次为 ID 为 30 的 VLAN 创建类似的成对文件

/etc/systemd/network/vlan30.netdev
[NetDev]
Name=vlan30
Kind=vlan

[VLAN]
Id=30
/etc/systemd/network/vlan30.network
[Match]
Name=vlan30

[Network]
VLAN=vlan30

[Address]
Address=10.10.30.2/24

[Route]
Destination=10.10.30.0/24
Gateway=10.10.30.1

请注意,vlan10 上的 Destination 设置为 0.0.0.0/0,这将匹配所有出站流量,成为默认路由。

netctl

您可以为此目的使用 netctl,请参阅 /etc/netctl/examples/vlan-{dhcp,static} 中不言自明的示例配置文件。

设置桥接 IP

有时您可能想要配置 docker 运行所在的桥接 IP,例如,当默认 IP 与网络中的其他 IP 地址冲突时。 Docker 有一个直接的方式通过 /etc/docker/daemon.json 设置 bip(桥接 IP)。当此文件尚不存在时,您可以创建它。

/etc/docker/docker.json
{
    "bip": "<desired ip range>/24"
}

故障排除

udev 重命名虚拟设备

一个令人恼火的问题是,udev 可能会在添加虚拟设备时尝试重命名它们,从而忽略为它们配置的 name(在本例中为 eth0.100

# ip link add link eth0 name eth0.100 type vlan id 100
# ip link show 

这可能会生成以下输出

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff
3: rename1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff

udev 忽略了配置的虚拟接口名称 eth0.100,并将其命名为 rename1

解决方案是编辑 /etc/udev/rules.d/network_persistent.rules 并在物理接口配置行的末尾附加 DRIVERS=="?*"

例如,对于接口 aa:bb:cc:dd:ee:ff (eth0)

/etc/udev/rules.d/network_persistent.rules
SUBSYSTEM=="net", ATTR{address}=="aa:bb:cc:dd:ee:ff", NAME="eth0", DRIVERS=="?*"

重新启动应该意味着 VLAN 可以使用分配给它们的名称正确配置。