l 缓存:网桥首先会对收到的数据帧进行缓存并处理;
学习:当帧经过网桥,网桥首先在网桥表中查找帧的源MAC地址,如果该地址不在网桥表中,则将有该MAC地址及其所对应的网桥端口信息加入(逆向学习法);
l 过滤:判断入帧的目标节点是否位于发送这个帧的网段中(同一端口中) ,如果是,网桥就不把帧转发到网桥的其他端口;
l 转发:如果帧的目标节点位于另一个网络,网桥就将帧发往正确的网段 (向另一端口转发) ;
每个桥维护了一个基于MAC地址的过滤数据库,网桥根据这个数据库,把收到的帧往相应的局域网(端口)进行转发。
在过滤数据库中,列出了每个可能的目的地(目的MAC地址),以及它属于哪一条输出线路(一个端口号,即表示转发给哪个LAN),每个表项还有一个超时设置。
可以及时学习改变了的地址;
转发:如果在表中找到目标地址,则直接转发给该目的MAC地址对应的端口;
转发:如果在表中找不到目标地址,则按扩散的办法将该数据发送给与该网桥连接的除发送该数据的网段外的所有网段。
以混杂方式工作(接收连接到该网桥的局域网上传送的所有帧)。
l 假设桥在端口x上接收到一个MAC帧,有如下规则
1. 查询网桥表中包的源MAC;如果没有,将该MAC地址及其所对应的网桥端口信息加入;如果有,继续下一步;
2. 查询过滤数据库,确定该目的MAC地址是否在除[端口x]外的其它端口中;如果目的MAC地址在端口x内,不进行转发;
3. 在转发时,如果目的MAC地址在过滤数据库中的某个端口y中,确定端口y是否处在阻塞或转发状态(生成树协议)。【在以后的生成树算法中我们可以看到,一个端口可能有时候是阻塞的,以防止它接收或发送帧】如果端口y是非阻塞的,把该帧通过端口y转发到它所连接的LAN中。
4. 在转发时,如果目的MAC地址没有找到,把该帧往除了它所到来的端口外的所有端口发送,即进行转发(扩散)。
学习:站点A给B发送数据,网桥通过察看帧的源地址了解到A在端口1,过滤数据库中加入<A,1>。
转发:网桥并不知道B在何处,因此把帧向所有其它端口(即端口2和3)进行扩散。(网桥连接的所有端口,除端口1)
转发:B收到A发过来的帧之后,可能会进行回应,即B发送数据给A,这个时候网桥察看源地址了解到B在端口2上,加入表项<B,2>,同时帧的目的地址A在过滤数据库中存在,并且在端口1上,因此B发回给A的帧向端口1转发
过滤:现在站点C向A发送数据,由于A、C和网桥连接到同一个集线器上,网桥也会收到该帧,察看源地址C,记录C在端口1,加入表项<C,1>,同时目的地址A在过滤数据库中并且所在的端口正是收到该帧的端口,因此不进行转发。
老化:过滤数据库表项的TTL每秒都增加,超过某个值则从数据库中清除,一般缺省的TTL设置为300秒。老化主要是考虑到网桥的内存有限、节点移动的情况。
Bridge(桥)是 Linux 上用来做 TCP/IP 二层协议交换的设备,与现实世界中的交换机功能相似。Bridge 设备实例可以和 Linux 上其他网络设备实例连接,既 attach 一个从设备,类似于在现实世界中的交换机和一个用户终端之间连接一根网线。当有数据到达时,Bridge 会根据报文中的 MAC 信息进行广播、转发、丢弃处理。
如图所示,Bridge 的功能主要在内核里实现。当一个从设备被 attach 到 Bridge 上时,相当于现实世界里交换机的端口被插入了一根连有终端的网线。这时在内核程序里,netdev_rx_handler_register()被调用,一个用于接受数据的回调函数被注册。以后每当这个从设备收到数据时都会调用这个函数可以把数据转发到 Bridge 上。当 Bridge 接收到此数据时,br_handle_frame()被调用,进行一个和现实世界中的交换机类似的处理过程:判断包的类别(广播/单点),查找内部 MAC 端口映射表,定位目标端口号,将数据转发到目标端口或丢弃,自动更新内部 MAC 端口映射表以自我学习。
Bridge 和现实世界中的二层交换机有一个区别,图中左侧画出了这种情况:数据被直接发到 Bridge 上,而不是从一个端口接受。这种情况可以看做 Bridge 自己有一个 MAC 可以主动发送报文,或者说 Bridge 自带了一个隐藏端口和寄主 Linux 系统自动连接,Linux 上的程序可以直接从这个端口向 Bridge 上的其他端口发数据。所以当一个 Bridge 拥有一个网络设备时,如 bridge0 加入了 eth0 时,实际上 bridge0 拥有两个有效 MAC 地址,一个是 bridge0 的,一个是 eth0 的,他们之间可以通讯。由此带来一个有意思的事情是,Bridge 可以设置 IP 地址。通常来说 IP 地址是三层协议的内容,不应该出现在二层设备 Bridge 上。但是 Linux 里 Bridge 是通用网络设备抽象的一种,只要是网络设备就能够设定 IP 地址。当一个 bridge0 拥有 IP 后,Linux 便可以通过路由表或者 IP 表规则在三层定位 bridge0,此时相当于 Linux 拥有了另外一个隐藏的虚拟网卡和 Bridge 的隐藏端口相连,这个网卡就是名为 bridge0 的通用网络设备,IP 可以看成是这个网卡的。当有符合此 IP 的数据到达 bridge0 时,内核协议栈认为收到了一包目标为本机的数据,此时应用程序可以通过 Socket 接收到它。一个更好的对比例子是现实世界中的带路由的交换机设备,它也拥有一个隐藏的 MAC 地址,供设备中的三层协议处理程序和管理程序使用。设备里的三层协议处理程序,对应名为 bridge0 的通用网络设备的三层协议处理程序,即寄主 Linux 系统内核协议栈程序。设备里的管理程序,对应 bridge0 寄主 Linux 系统里的应用程序。
Bridge 的实现当前有一个限制:当一个设备被 attach 到 Bridge 上时,那个设备的 IP 会变的无效,Linux 不再使用那个 IP 在三层接受数据。举例如下:如果 eth0 本来的 IP 是 192.168.1.2,此时如果收到一个目标地址是 192.168.1.2 的数据,Linux 的应用程序能通过 Socket 操作接受到它。而当 eth0 被 attach 到一个 bridge0 时,尽管 eth0 的 IP 还在,但应用程序是无法接受到上述数据的。此时应该把 IP 192.168.1.2 赋予 bridge0。
另外需要注意的是数据流的方向。对于一个被 attach 到 Bridge 上的设备来说,只有它收到数据时,此包数据才会被转发到 Bridge 上,进而完成查表广播等后续操作。当请求是发送类型时,数据是不会被转发到 Bridge 上的,它会寻找下一个发送出口。用户在配置网络时经常忽略这一点从而造成网络故障。
如下图:主机A发送的报文被送到交换机S1的eth0口,由于eth0与eth1、eth2桥接在一起,故而报文被复制到eth1和eth2,并且发送出去,然后被主机B和交换机S2接收到。而S2又会将报文转发给主机C、D。
交换机在报文转发的过程中并不会篡改报文数据,只是做原样复制。然而桥接却并不是在物理层实现的,而是在数据链路层。交换机能够理解数据链路层的报文,所以实际上桥接却又不是单纯的报文转发。
交换机会关心填写在报文的数据链路层头部中的Mac地址信息(包括源地址和目的地址),以便了解每个Mac地址所代表的主机都在什么位置(与本交换机的哪个网口相连)。在报文转发时,交换机就只需要向特定的网口转发即可,从而避免不必要的网络交互。这个就是交换机的“地址学习”。但是如果交换机遇到一个自己未学习到的地址,就不会知道这个报文应该从哪个网口转发,则只好将报文转发给所有网口(接收报文的那个网口除外)。
比如主机C向主机A发送一个报文,报文来到了交换机S1的eth2网口上。假设S1刚刚启动,还没有学习到任何地址,则它会将报文转发给eth0和eth1。同时,S1会根据报文的源Mac地址,记录下“主机C是通过eth2网口接入的”。于是当主机A向C发送报文时,S1只需要将报文转发到eth2网口即可。而当主机D向C发送报文时,假设交换机S2将报文转发到了S1的eth2网口(实际上S2也多半会因为地址学习而不这么做),则S1会直接将报文丢弃而不做转发(因为主机C就是从eth2接入的)。
然而,网络拓扑不可能是永不改变的。假设我们将主机B和主机C换个位置,当主机C发出报文时(不管发给谁),交换机S1的eth1口收到报文,于是交换机S1会更新其学习到的地址,将原来的“主机C是通过eth2网口接入的”改为“主机C是通过eth1网口接入的”。
但是如果主机C一直不发送报文呢?S1将一直认为“主机C是通过eth2网口接入的”,于是将其他主机发送给C的报文都从eth2转发出去,结果报文就发丢了。所以交换机的地址学习需要有超时策略。对于交换机S1来说,如果距离最后一次收到主机C的报文已经过去一定时间了(默认为5分钟),则S1需要忘记“主机C是通过eth2网口接入的”这件事情。这样一来,发往主机C的报文又会被转发到所有网口上去,而其中从eth1转发出去的报文将被主机C收到。
原文地址:http://blog.51cto.com/hostman/2106155