34.8.桥接

有时将网络(如以太网段)分割成网络段,而无需创建 IP 子网并使用路由器将这些段连接在一起,是有用的。以这种方式连接两个网络的设备称为“桥接器”。

一座桥梁通过学习其网络接口上各设备的 MAC 地址来工作。只有当源 MAC 地址和目的 MAC 地址位于不同网络时,它才在网络间转发流量。在许多方面,桥梁就像一个只有很少端口的以太网交换机。一个具有多个网络接口的 FreeBSD 系统可以被配置为充当桥梁。

桥接在以下情况下可以派上用场:

连接网络

桥的基本操作是连接两个或更多网络段。有许多原因可以使用基于主机的桥接而不是网络设备,例如布线约束或防火墙。桥还可以连接以 hostap 模式运行的无线接口到有线网络,并充当接入点。

过滤/流量整形防火墙

当需要防火墙功能但不需要路由或网络地址转换(NAT)时,可以使用桥接。

例如,一个小公司通过 DSL 或 ISDN 连接到 ISP。有来自 ISP 的十三个公共 IP 地址和网络上的十台计算机。在这种情况下,使用基于路由器的防火墙很困难,因为子网划分问题。可以配置基于桥接的防火墙,而不会有任何 IP 地址问题。

网络监听设备

桥接可以连接两个网络段,以便使用桥接接口上的 bpf(4) 和 tcpdump(1) 检查通过它们的所有以太网帧,或者通过在称为 span 的附加接口上发送所有帧的副本来实现。

第二层 VPN

两个以太网网络可以通过在 IP 链路上桥接网络到 EtherIP 隧道或基于 tap(4)的解决方案,如 OpenVPN 来连接。

第二层冗余

网络可以通过多个链接连接在一起,并使用生成树协议(STP)来阻止冗余路径。

本节说明了如何使用 if_bridge(4) 将 FreeBSD 系统配置为桥接。还提供了 netgraph 桥接驱动程序的说明,详见 ng_bridge(4)。

34.8.1. 启用桥接

在 FreeBSD 中,if_bridge(4) 是一个内核模块,当创建桥接接口时,ifconfig(8) 会自动加载它。也可以通过将 device if_bridge 添加到定制内核配置文件中,将桥接支持编译到定制内核中。

桥接是使用接口克隆创建的。要创建桥接接口:

# ifconfig bridge create
bridge0
# ifconfig bridge0
bridge0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether 96:3d:4b:f1:79:7a
        id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
        maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200
        root id 00:00:00:00:00:00 priority 0 ifcost 0 port 0

当创建桥接接口时,它会自动分配一个随机生成的以太网地址。maxaddr 和 timeout 参数控制桥接将在其转发表中保留多少个 MAC 地址,以及每个条目在最后一次被看到后多少秒后被删除。其他参数控制 STP 的操作方式。

接下来,指定要添加为桥接的成员的网络接口。为了使桥接转发数据包,所有成员接口和桥接都需要处于启动状态:

# ifconfig bridge0 addm fxp0 addm fxp1 up
# ifconfig fxp0 up
# ifconfig fxp1 up

桥接现在可以在 fxp0 和 fxp1 之间转发以太网帧。将以下行添加到/etc/rc.conf 中,以便在启动时创建桥接:

cloned_interfaces="bridge0"
ifconfig_bridge0="addm fxp0 addm fxp1 up"
ifconfig_fxp0="up"
ifconfig_fxp1="up"

如果桥接主机需要 IP 地址,请在桥接接口上设置,而不要在成员接口上设置。地址可以静态设置或通过 DHCP 设置。此示例设置了静态 IP 地址:

# ifconfig bridge0 inet 192.168.0.1/24

还可以将 IPv6 地址分配给桥接接口。要使更改永久生效,请将寻址信息添加到/etc/rc.conf 中。

34.8.2. 启用生成树

以太网网络要正常运行,两台设备之间只能存在一条活动路径。STP 协议检测环路并将冗余链路置于阻塞状态。如果其中一条活动链路失败,STP 会计算出不同的树,并启用其中一条阻塞路径以恢复网络中所有点的连接。

快速生成树协议(RSTP 或 802.1w)与传统的 STP 向后兼容。RSTP 提供更快的收敛速度,并与相邻交换机交换信息,快速转换到转发模式,避免环路的产生。FreeBSD 支持 RSTP 和 STP 作为操作模式,其中 RSTP 是默认模式。

可以使用 ifconfig(8)在成员接口上启用 STP。对于以 fxp0 和 fxp1 作为当前接口的桥接,启用 STP 如下:

# ifconfig bridge0 stp fxp0 stp fxp1
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether d6:cf:d5:a0:94:6d
        id 00:01:02:4b:d4:50 priority 32768 hellotime 2 fwddelay 15
        maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200
        root id 00:01:02:4b:d4:50 priority 32768 ifcost 0 port 0
        member: fxp0 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP>
                port 3 priority 128 path cost 200000 proto rstp
                role designated state forwarding
        member: fxp1 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP>
                port 4 priority 128 path cost 200000 proto rstp
                role designated state forwarding

此桥接具有 00:01:02:4b:d4:50 的生成树 ID 和 32768 的优先级。由于 root id 相同,表明这是树的根桥。

网络上的另一台桥接设备也启用了 STP:

bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether 96:3d:4b:f1:79:7a
        id 00:13:d4:9a:06:7a priority 32768 hellotime 2 fwddelay 15
        maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200
        root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4
        member: fxp0 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP>
                port 4 priority 128 path cost 200000 proto rstp
                role root state forwarding
        member: fxp1 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP>
                port 5 priority 128 path cost 200000 proto rstp
                role designated state forwarding

第 root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4 行显示根桥是 00:01:02:4b:d4:50,并且从此桥到根桥的路径成本是 400000。到根桥的路径是通过 port 4,即 fxp0。

34.8.3. 桥接接口参数

一些 ifconfig 参数对桥接接口是唯一的。本节总结了这些参数的一些常见用途。可用参数的完整列表在 ifconfig(8) 中说明。

private 私有接口不会将任何流量转发到任何其他 port 也被指定为私有接口的设备上。流量将被无条件地阻止,因此不会转发任何以太网帧,包括 ARP 数据包。如果需要有选择地阻止流量,应使用防火墙。

span 一个 span port 会传输桥接接口接收到的每一个以太网帧的副本。在桥上配置的 span ports 数量是无限的,但如果将接口指定为 span port,则不能将其用作常规桥接 port。这对于在连接到桥接 ports 之一的另一台主机上被动地窥探桥接网络是最有用的。例如,要将所有帧的副本发送到名为 fxp4 的接口:

# ifconfig bridge0 span fxp4

如果一个桥接成员接口被标记为 sticky,动态学习的地址条目会被视为转发缓存中的静态条目。Sticky 条目永远不会从缓存中过时或被替换,即使地址出现在另一个接口上也是如此。这样可以获得静态地址条目的好处,而无需预先填充转发表。在桥的特定部分学习的客户端不能漫游到另一部分。

使用 sticky 地址的一个示例是将桥与虚拟局域网(VLAN)相结合,以便隔离客户网络而不浪费 IP 地址空间。考虑 CustomerA 在 vlan100 上,CustomerB 在 vlan101 上,桥的地址为 192.168.0.1 :

# ifconfig bridge0 addm vlan100 sticky vlan100 addm vlan101 sticky vlan101
# ifconfig bridge0 inet 192.168.0.1/24

在这个例子中,两个客户端都将 192.168.0.1 看作是它们的默认网关。由于桥的缓存是 sticky 的,一个主机无法伪造另一个客户的 MAC 地址以截取其流量。

VLAN 之间的任何通信都可以使用防火墙阻止,或者可以像本例中看到的那样使用专用接口:

# ifconfig bridge0 private vlan100 private vlan101

客户彼此完全隔离,可以分配整个 /24 地址范围,无需进行子网划分。

可以限制接口后面的唯一源 MAC 地址数量。若达到限制,具有未知源地址的数据包将被丢弃,直到现有主机缓存条目到期或被移除。

以下示例将 vlan100 上的 CustomerA 的最大以太网设备数设置为 10:

# ifconfig bridge0 ifmaxaddr vlan100 10

桥接口还支持监视器模式,在此模式下,经过 bpf(4)处理的数据包将被丢弃,并且不会被进一步处理或转发。这可用于将两个或多个接口的输入复用为单个 bpf(4)流。这对于重构通过两个单独接口传输 RX/TX 信号的网络 taps 发送的流量是有用的。例如,要将四个网络接口的输入读取为一个流:

# ifconfig bridge0 addm fxp0 addm fxp1 addm fxp2 addm fxp3 monitor up
# tcpdump -i bridge0

34.8.4. SNMP 监控

桥接口和 STP 参数可以通过包含在 FreeBSD 基本系统中的 bsnmpd(1)进行监视。导出的桥接 MIB 符合 IETF 标准,因此任何 SNMP 客户端或监控软件都可以用于检索数据。

要在桥接上启用监视,请取消注释/etc/snmpd.config 中的此行,方法是去掉开始 # 符号:

begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so"

其他配置设置,如社区名称和访问列表,可能需要在此文件中进行修改。有关更多信息,请参阅 bsnmpd(1)和 snmp_bridge(3)。若保存这些编辑内容,请将此行添加到/etc/rc.conf 中:

bsnmpd_enable="YES"

然后,启动 bsnmpd(1):

# service bsnmpd start

以下示例使用 Net-SNMP 软件 (net-mgmt/net-snmp) 从客户端系统查询桥接。也可以使用 net-mgmt/bsnmptools port。从运行 Net-SNMP 的 SNMP 客户端,添加以下行到 $HOME/.snmp/snmp.conf 以导入桥接 MIB 定义:

mibdirs +/usr/share/snmp/mibs
mibs +BRIDGE-MIB:RSTP-MIB:BEGEMOT-MIB:BEGEMOT-BRIDGE-MIB

使用 IETF BRIDGE-MIB (RFC4188) 监控单个桥接:

% snmpwalk -v 2c -c public bridge1.example.com mib-2.dot1dBridge
BRIDGE-MIB::dot1dBaseBridgeAddress.0 = STRING: 66:fb:9b:6e:5c:44
BRIDGE-MIB::dot1dBaseNumPorts.0 = INTEGER: 1 ports
BRIDGE-MIB::dot1dStpTimeSinceTopologyChange.0 = Timeticks: (189959) 0:31:39.59 centi-seconds
BRIDGE-MIB::dot1dStpTopChanges.0 = Counter32: 2
BRIDGE-MIB::dot1dStpDesignatedRoot.0 = Hex-STRING: 80 00 00 01 02 4B D4 50
...
BRIDGE-MIB::dot1dStpPortState.3 = INTEGER: forwarding(5)
BRIDGE-MIB::dot1dStpPortEnable.3 = INTEGER: enabled(1)
BRIDGE-MIB::dot1dStpPortPathCost.3 = INTEGER: 200000
BRIDGE-MIB::dot1dStpPortDesignatedRoot.3 = Hex-STRING: 80 00 00 01 02 4B D4 50
BRIDGE-MIB::dot1dStpPortDesignatedCost.3 = INTEGER: 0
BRIDGE-MIB::dot1dStpPortDesignatedBridge.3 = Hex-STRING: 80 00 00 01 02 4B D4 50
BRIDGE-MIB::dot1dStpPortDesignatedPort.3 = Hex-STRING: 03 80
BRIDGE-MIB::dot1dStpPortForwardTransitions.3 = Counter32: 1
RSTP-MIB::dot1dStpVersion.0 = INTEGER: rstp(2)

dot1dStpTopChanges.0 的值为二,表示 STP 桥拓扑已更改两次。拓扑更改意味着网络中的一个或多个链路已更改或失败,并计算了新树。dot1dStpTimeSinceTopologyChange.0 的值将显示此事件发生的时间。

要监视多个桥接口,可以使用私有 BEGEMOT-BRIDGE-MIB:

% snmpwalk -v 2c -c public bridge1.example.com
enterprises.fokus.begemot.begemotBridge
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge0" = STRING: bridge0
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge2" = STRING: bridge2
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge0" = STRING: e:ce:3b:5a:9e:13
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge2" = STRING: 12:5e:4d:74:d:fc
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge0" = INTEGER: 1
BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge2" = INTEGER: 1
...
BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge0" = Timeticks: (116927) 0:19:29.27 centi-seconds
BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge2" = Timeticks: (82773) 0:13:47.73 centi-seconds
BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge0" = Counter32: 1
BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge2" = Counter32: 1
BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge0" = Hex-STRING: 80 00 00 40 95 30 5E 31
BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge2" = Hex-STRING: 80 00 00 50 8B B8 C6 A9

通过 mib-2.dot1dBridge 子树更改要监视的桥接口:

% snmpset -v 2c -c private bridge1.example.com
BEGEMOT-BRIDGE-MIB::begemotBridgeDefaultBridgeIf.0 s bridge2

最后更新于

FreeBSD 中文社区