3.6 Bridging
Hub:也叫repeater hub,是一个Layer-1 device,也就是说它只会将数据包广播到所有port上。
Mac bridge:也叫bridge和Layer-2 switch,因为它可以分析ethernet header,所以有self-learning(自学习)功能,可以有效的避免广播,节省带宽。当发生组播时,打开GMRP 功能,可以有效的减少组播的带宽。
3.6.1 self-learning
在linux中self-learning是如何实现的。
一个很重要的数据结构就是forwarding table,bridge就是根据它来转发frame的,而向forwarding table中添加tuple(记录)的过程就是self-learning的过程。Forwarding talbe定义在br_private.h中的net_bridge struct中,所有的mac和port的对应关系都放在这个结构中,而该结构使用hash来实现的。
检索forwarding table的代码在net/bridge/br_fdb.c中,就是用目的mac address来算hash并迅速定位到forwarding table中正确的tuple。Hash函数叫做br_mac_hash(),下面的代码段指摘自net/bridge/br_fdb.c,用于检索该forwarding table。
struct net_bridge_fdb_entry *_br_fdb_get(struct net_bridge *br, const unsigned char *addr)
{
struct hlist_node *h;
struct net_bridge_fdb_entry *fdb;
hlist_for_each_entry_rcu(fdb,h,&br->hash[br_mac_hash(addr)],hlist) {
if (!compare_ether_addr(fdb->addr.addr,addr)) {
if (unlikely(has_expired(br, fdb)))
break;
return fdb;
}
}
return NULL;
}
hlist_for_each_entry_rcu()在检索由&br->hash[br_mac_hash(addr)]所指向的一个链表,目的是要找到正确的net_bridge_fdb_entry,而net_bridge_fdb_entry包含了要转发的port的信息。rcu(read-copy-update)是一种同步机制提供了线程间的互斥。
当bridge收到一个frame时,会向forwarding table中插入一个net_bridge_fdb_entry,下面的代码段指摘自net/bridge/br_fdb.c,用于插入。
static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr)
{
struct hlist_head *head = &br->hash[br_mac_hash(addr)];
struct net_bridge_fdb_entry *fdb;
if (!is_valid_ether_addr(addr))
return -EINVAL;
fdb = fdb_find(head, addr);
if (fdb) { //找到了就删掉该fdb
if (fdb->is_local)
return 0;
fdb_delete(fdb);
}
if (!fdb_create(head, source, addr, 1)) //生成新的fdb
return -ENOMEM;
return 0;
}
3.6.2 Spanning Tree Protocol
当一个bridged network变得越来越大和复杂时,可能会形成loop,一旦形成loop就会让frame在loop中不停的传输(如果有一个station发送了一个广播包,则形成广播风暴),并使forwarding table变得不稳定。我将根据下图讲述STP的原理。
1、一开始,给个switch和port都会被分配一个ID,该ID包括一个priority value和switch address(对于port ID来说,就是port number),在该例子中,我使用1到6作为ID。
2、每个link上都有一个cost,该cost跟link speed成反比。我假设所有的link的cost都是1。
3、拥有最小id的switch叫做root,root是被动态选举出来的。
4、发送来自于root的frame的port叫做designated port(DP),而该switch叫做designated bridge;接收来自root的frame的port叫做root port(RP)如上图所示。
5、Bridge protocol data unit,简称BPDU,该BPDU frame的目的地址是01-80-C2-00-00-00(一个固定的保留的多播地址),该BPDU frame包含的内容有:root id、transmitting switch id、transmitting port id、从root到当前switch的cost。该BPDU frame从root开始向下发送。
6、每个switch都根据BPDU来配置自己,配置规则如下:
A) 如果一个switch发现它能够提供一个更低的cost,那么它就成为一个designated bridge,并发送BPDU
B) 当存在多条link而这些link的cost都相等时,id最小的那个switch会被选为designated bridge(or port)。
C) 如果当前的一个switch发现自己的id要小于root id,则它会变成新的root并发送MPDU。
D) 一个switch不能够转发BPDU,它只能create一个新的BPDU,并发给其他的switch。
7、通过以上步骤就找出了所有的DP和RP,既不是DP又不是RP的port就被阻塞,通过阻塞port就破解了loop。
3.6.3 STP的实现
下图是STP的调用流程:
br_config_bpdu是最重要的结构,定义在net/bridge/br_private_stp.h中,这个结构中的很多成员都对应于BPDU frame的字段。
br_stp_rcv()定义在/net/bridge/br_stp_bpdu.c中,该函数分析bpdu并建立一个br_config_bpdu结构。该bpdu结构和port信息被传递给br_received_config_bpdu(),它定义在br_stp.c中,该函数首先调用br_record_config_information()注册bpdu信息,然后调用br_configuration_update()来更新bridge的配置,然后再调用br_port_state_selection()来更新port状态。
br_configuration_update()调用br_root_selection() and br_designated_port_selection()来选择一个new root和决定一个designated port。
Remark:在br_root_selection()中有root是如何被选举出来的代码。
3.6.4 VLAN
One-armed router:它一个port链接在switch的trunk port上,用来做两个vlan的路由。
Vlan id一共12bits,共4096个vlans。
Frame的source mac后面增加了4bytes的tag,这4个byte,前2个byte表示协议类型(0x8100),后两个byte是vlan的控制域,而控制域由3个field构成:priority、CFI、vlan id。
[此为原创,转载请标明出处,谢谢!]