- 以太网交换机的自学习功能 我们用一个简单例子来说明以太网交换机是怎样进行自学习的。 假定在图3-25 中的以太网交换机有4个接口,各连接一 台计算机,其 MAC 地址分别 是 A,B,C 和 D。 在一开始,以太网交换机里面的交换表是空的(图3-25(a))。
以太网交换机 A[ 3 C 交换表 MAC 地址接口 A 1 B 3
(a)交换表一开始是空的 (b)交换了两帧后的交换表
图3-25 以太网交换机中的交换表
A 先 向B 发送一 帧,从接口1 进入到交换机。交换机收到帧后,先查找交换表,没有 查到应从哪个接口转发这个帧(在 MAC 地址这一列中,找不到目的地址为 B 的项目)。接 着,交换机把这个帧的源地址 A 和 接 口 1 写入交换表中,并向除接口1 以外的所有接口广 播这个帧(这个帧就是从接口1进来的,当然不应当把它再从接口1转发出去)。
C 和 D 将丢弃这个帧,因为目的地址不对。只 B 才收下这个目的地址正确的帧。这也 称为过滤。
从新写入交换表的项目(A,1) 可以看出,以后不管从哪一个接口收到帧,只要其目的地 址是 A, 就应当把收到的帧从接口1转发出去。这样做的依据是:既然 A 发出的帧是从接 口1进入到交换机的,那么从交换机的接口1转发出的帧也应当可以到达A.
假定接下来 B 通 过 接 口 3 向A 发送一帧。交换机查找交换表,发现交换表中的 MAC 地址有 A。 表明要发送给 A 的帧(即目的地址为A 的帧)应从接口1转发。于是就把这个 帧传送到接口1转发给A。 显然,现在已经没有必要再广播收到的帧。交换表这时新增加的 项目(B,3), 表明今后如有发送给B 的帧,就应当从接口3转发出去。
经过一段时间后,只要主机 C 和 D 也向其他主机发送帧,以太网交换机中的交换表就 会把转发到C 或 D 应当经过的接口号(2或4)写入到交换表中。这样,交换表中的项目就 齐全了。要转发给任何一台主机的帧,都能够很快地在交换表中找到相应的转发接口。
考虑到有时可能要在交换机的接口更换主机,或者主机要更换其网络适配器,这就需 要更改交换表中的项目。为此,在交换表中每个项目都设有一定的有效时间。过期的项目就 自动被删除。用这样的方法保证交换表中的数据都符合当前网络的实际状况。
以太网交换机的这种自学习方法使得以太网交换机能够即插即用,不必人工进行配 ·100 ·置,因此非常方便。
但有时为了增加网络的可靠性,在使用以太网交换机组网时,往往会增加一些冗余的 链路。在这种情况下,自学习的过程就可能导致以太网帧在网络的某个环路中无限制地兜圈 子。我们用图3-26的简单例子来说明这个问题。 以太网 交换机#1 B 3 4
图3-26 在两个交换机之间兜圈子的帧
在图3-26中,假定一开始主机 A 通过接口交换机#1 向主机 B 发送一帧。交换机#1收 到这个帧后就向所有其他接口进行广播发送。现观察其中一个帧的走向:离开交换机#1 的 接口3 → 交换机#2 的接口1 → 接口2 → 交换机#1 的接口4 → 接口3 → 交换机#2 的接口1 →…… 。这样就无限制地循环兜圈子下去,白白消耗了网络资源。
为了解决这种兜圈子问题, IEEE 的802.1D 标准制定了一个生成树协议 STP(Spanning Tree Protocol)。 其要点就是不改变网络的实际拓扑,但在逻辑上则切断某些链路,使得从一 台主机到所有其他主机的路径是无环路的树状结构,从而消除了兜圈子现象。
请你举一个简单的代码示例。
以下是一个简单的示例代码,演示如何使用Python实现以太网交换机的自学习功能:
class EthernetSwitch:
def __init__(self):
self.switch_table = {} # 交换表,字典类型
def process_frame(self, source_mac, destination_mac, ingress_port):
if destination_mac in self.switch_table:
egress_port = self.switch_table[destination_mac]
else:
self.switch_table[source_mac] = ingress_port
egress_port = "broadcast"
return egress_port
# 初始化以太网交换机
switch = EthernetSwitch()
# 模拟帧的传输过程
frames = [
{"source_mac": "A", "destination_mac": "B", "ingress_port": 1},
{"source_mac": "B", "destination_mac": "A", "ingress_port": 3},
{"source_mac": "C", "destination_mac": "A", "ingress_port": 2},
{"source_mac": "D", "destination_mac": "B", "ingress_port": 4},
]
for frame in frames:
source_mac = frame["source_mac"]
destination_mac = frame["destination_mac"]
ingress_port = frame["ingress_port"]
egress_port = switch.process_frame(source_mac, destination_mac, ingress_port)
print(f"Frame from {source_mac} to {destination_mac}:")
print(f"Ingress port: {ingress_port}")
print(f"Egress port: {egress_port}")
print("------------")
这个示例代码定义了一个EthernetSwitch类,其中包含一个交换表switch_table来存储MAC地址和接口之间的映射关系。process_frame方法用于处理接收到的帧,根据交换表判断应该从哪个接口转发帧。
在主程序中,我们创建了一个EthernetSwitch的实例switch,并模拟了几个帧的传输过程。每个帧都包含源MAC地址( source_mac)、目的MAC地址(destination_mac) 和进入交换机的接口(ingress_port)。通过调用switch的process_frame方法,输出每个帧的入口端口和出口端口,模拟交换机的转发过程。
这个代码示例只是简单演示自学习功能的实现原理,并没有考虑生成树协议(STP) 等更复杂的功能。在实际的以太网交换机实现中,可能还会包括其他功能,如广播处理、冗余链路的管理等。
Frame from A to B:
Ingress port: 1
Egress port: broadcast
------------
Frame from B to A:
Ingress port: 3
Egress port: 1
------------
Frame from C to A:
Ingress port: 2
Egress port: 1
------------
Frame from D to B:
Ingress port: 4
Egress port: broadcast
------------
根据给定的帧传输过程,我们可以看到以下情况:
- 第一帧从A发送到B,进入端口1,交换机中的交换表为空,因此将该帧从广播端口进行转发,Egress port为broadcast。
- 第二帧从B发送到A,进入端口3。根据交换表,交换机识别到目标MAC地址A对应的出口端口是1,因此将帧从端口1进行转发,Egress port为1。
- 第三帧从C发送到A,进入端口2。根据交换表,交换机识别到目标MAC地址A对应的出口端口是1,因此将帧从端口1进行转发,Egress port为1。
- 第四帧从D发送到B,进入端口4,交换机中的交换表为空,因此将该帧从广播端口进行转发,Egress port为broadcast。
这些结果是基于交换机的自学习机制生成的。交换机首次收到帧时,无法立即知道每个MAC地址所在的接口,因此将帧进行广播。随着帧的不断传输,交换机逐渐学习到MAC地址和接口的映射关系,并将这些信息存储在交换表中。这样,在之后的帧传输中,交换机就可以根据交换表快速决定帧的转发方向,避免了不必要的广播和冲突。