有时, 会有需要将一个物理网络分成两个独立的网段, 而不是创建新的 IP 子网, 并将其通过路由器相连。 以这种方式连接两个网络的设备称为 “网桥 (bridge)”。 有两个网络接口的 FreeBSD 系统可以作为网桥来使用。
网桥通过学习每个网络接口上的 MAC 层地址 (以太网地址) 工作。 只当数据包的源地址和目标地址处于不同的网络时, 网桥才进行转发。
在很多方面,网桥就像一个带有很少端口的以太网交换机。
适合使用网桥的, 有许多种不同的情况。
网桥的基本操作是将两个或多个网段连接在一起。 由于各式各样的原因, 人们会希望使用一台真正的计算机, 而不是网络设备来充任网桥的角色, 常见的原因包括线缆的限制、 需要进行防火墙, 或为虚拟机网络接口连接虚拟网络。 网桥也可以将无线网卡以 hostap 模式接入有线网络。
使用防火墙的常见情形是无需进行路由或网络地址转换的情况 (NAT)。
举例来说, 一家通过 DSL 或 ISDN 连接到 ISP 的小公司, 拥有 13 个 ISP 分配的全局 IP 地址和 10 台 PC。 在这种情况下, 由于划分子网的问题, 采用路由来实现防火墙会比较困难。
基于网桥的防火墙可以串接在 DSL/ISDN 路由器的后面, 而无需考虑 IP 编制的问题。
网桥可以用于连接两个不同的网段, 并用于监视往返的以太网帧。 这可以通过在网桥接口上使用 bpf(4)/tcpdump(1), 或通过将全部以太网帧复制到另一个网络接口 (span 口) 来实现。
通过 IP 连接的网桥, 可以利用 EtherIP 隧道或基于 tap(4) 的解决方案, 如 OpenVPN 可以将两个以太网连接到一起。
网络可以通过多条链路连接在一起, 并使用生成树协议 (Spanning Tree Protocol) 来阻止多余的通路。 为使以太网能够正确工作, 两个设备之间应该只有一条激活通路, 而生成树能够检测环路, 并将多余的链路置为阻断状态。 当激活通路断开时, 协议能够计算另外一棵树, 并重新激活阻断的通路, 以恢复到网络各点的连通性。
这一节主要介绍 if_bridge(4) 网桥实现。 除此之外, 还有一个基于 netgraph 的网桥实现, 如欲了解进一步细节, 请参见联机手册 ng_bridge(4)。
网桥驱动是一个内核模块, 并会随使用 ifconfig(8) 创建网桥接口时自动加载。 您也可以将 device if_bridge 加入到内核配置文件中, 以便将其静态联编进内核。
包过滤可以通过使用了 pfil(9) 框架的任意一种防火墙软件包来完成。 这些防火墙可以以模块形式加载, 也可以静态联编进内核。
通过配合 altq(4) 和 dummynet(4), 网桥也可以用于流量控制。
网桥是通过接口复制来创建的。 您可以使用 ifconfig(8) 来创建网桥接口, 如果内核不包括网桥驱动, 则它会自动将其载入。
# 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 地址, 以及表项中主机的过期时间。 其他参数控制生成树的运转方式。
将成员网络接口加入网桥。 为了让网桥能够为所有网桥成员接口转发包, 网桥接口和所有成员接口都需要处于启用状态:
# 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 来完成:
# ifconfig bridge0 inet 192.168.0.1/24
除此之外, 也可以为网桥接口指定 IPv6 地址。
当启用包过滤时, 通过网桥的包可以分别在进入的网络接口、 网桥接口和发出的网络接口上进行过滤。 这些阶段均可禁用。 当包的流向很重要时, 最好在成员接口而非网桥接口上配置防火墙。
网桥上可以进行许多配置以决定非 IP 及 ARP 包能否通过, 以及通过 IPFW 实现二层防火墙。 请参见 if_bridge(4) 联机手册以了解进一步的细节。
网桥驱动实现了快速生成树协议 (RSTP 或 802.1w), 并与较早的生成树协议 (STP) 兼容。 生成树可以用来在网络拓扑中检测并消除环路。 RSTP 提供了比传统 STP 更快的生成树覆盖速度, 这种协议会在相邻的交换机之间交换信息, 以迅速进入转发状态, 并避免产生环路。 FreeBSD 支持以 RTSP 和 STP 模式运行, 而 RTSP 是默认模式。
使用 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
网桥的生成树 ID 为 00:01:02:4b:d4:50 而优先级为 32768。 其中 root id 与生成树相同, 表示这是作为生成树根的网桥。
另一个网桥也启用了生成树:
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 连接的。
网桥支持监视模式, 在 bpf(4) 处理之后会将包丢弃, 而不是继续处理或转发。 这可以用于将两个或多个接口上的输入转化为一个 bpf(4) 流。 在将两个独立的接口上的传输的 RX/TX 信号重整为一个时, 这会非常有用。
如果希望将四个网络接口上的输入转成一个流:
# ifconfig bridge0 addm fxp0 addm fxp1 addm fxp2 addm fxp3 monitor up # tcpdump -i bridge0
网桥收到的每个以太网帧都可以发到镜像口上。 网桥上的镜像口数量没有限制, 如果一个接口已经被配置为镜像口, 则它就不能再作为网桥的成员口来使用。 这种用法主要是为与网桥镜像口相连的监听机配合使用。
如果希望将所有帧发到名为 fxp4 的接口上:
# ifconfig bridge0 span fxp4
专用接口不会转发流量到除专用接口之外的其他端口。 这些流量会无条件地阻断, 因此包括 ARP 在内的以太网帧均不会被转发。 如果需要选择性地阻断流量, 则应使用防火墙。
如果网桥的成员接口标记为自学习, 则动态学习的地址项一旦进入转发快取缓存, 即被认为是静态项。 自学习项不会从快取缓存中过期或替换掉, 即使地址在另一接口上出现也是如此。 这使得不必事先发布转发表, 也能根据学习结果得到静态项的有点, 但在这些网段被网桥看到的客户机, 就不能漫游至另一网段了。
另一种用法是将网桥与 VLAN 功能连用, 这样客户网络会被隔离在一边, 而不会浪费 IP 地址空间。 考虑 CustomerA 在 vlan100 上, 而 CustomerB 则在 vlan101 上。 网桥地址为 192.168.0.1, 同时作为 internet 路由器使用。
# ifconfig bridge0 addm vlan100 sticky vlan100 addm vlan101 sticky vlan101 # ifconfig bridge0 inet 192.168.0.1/24
两台客户机均将 192.168.0.1 作为默认网关, 由于网桥快取缓存是自学习的, 因而它们无法伪造 MAC 地址来截取其他客户机的网络流量。
在 VLAN 之间的通讯可以通过专用接口 (或防火墙) 来阻断:
# ifconfig bridge0 private vlan100 private vlan101
这样这些客户机就完全相互隔离了。 可以使用整个的 /24 地址空间, 而无需划分子网。
接口后的源 MAC 地址数量是可以控制的。 一旦到达了限制未知源地址的包将会被丢弃, 直至现有缓存中的一项过期或被移除。
下面的例子是设置 CustomerA 在 vlan100 上可连接的以太网设备最大值为 10。
# ifconfig bridge0 ifmaxaddr vlan100 10
网桥接口和 STP 参数能够由 FreeBSD 基本系统的 SNMP 守护进程进行管理。导出的网桥 MIB 符和 IETF 标准, 所以任何 SNMP 客户端或管理包都可以被用来接收数据。
在网桥机器上从/etc/snmp.config 文件中去掉以下这行的注释 begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so" 并启动 bsnmpd 守护进程。 其他的配置选项诸如 community names 和 access lists 可能也许也需要修改。 参阅 bsnmpd(1) 和 snmp_bridge(3) 获取更多信息。
以下的例子中使用了 Net-SNMP 软件 (net-mgmt/net-snmp) 来查询一个网桥,当然同样也能够使用port net-mgmt/bsnmptools。 在 SNMP 客户端 Net-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的值为2 意味着 STP 网桥拓扑改变了2次,拓扑的改变表示1个或多个 网络中的连接改变或失效并且有一个新树生成。 dot1dStpTimeSinceTopologyChange.0 的值则能够显示这是何时改变的。
监测多个网桥接口可以使用 private 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
本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.