版本:Linux 2.4.18
一、调用
在src/net/core/dev.c的软中断函数static void net_rx_action(struct softirq_action *h)中:
引用:line 1479
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if (skb->dev->br_port != NULL &&
br_handle_frame_hook != NULL) {
handle_bridge(skb, pt_prev);
dev_put(rx_dev);
continue;
}
#endif
如果定义了网桥或网桥模块,则由handle_bridge函数处理skb->dev->br_port :接收该数据包的端口是网桥端口组的一员br_handle_frame_hook :定义了网桥处理函数。
二、初始化
引用:src/net/bridge/br.c:
static int __init br_init(void)
{
printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n";
br_handle_frame_hook = br_handle_frame;
br_ioctl_hook = br_ioctl_deviceless_stub;
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_get_hook = br_fdb_get;
br_fdb_put_hook = br_fdb_put;
#endif
register_netdevice_notifier(&br_device_notifier);
return 0;
}
初始化函数指明了网桥的处理函数是br_handle_frameioctl处理函数是:br_ioctl_deviceless_stub。
三、br_handle_frame(br_input.c)
网桥处理函数
引用:void br_handle_frame(struct sk_buff *skb)
{
struct net_bridge *br;
unsigned char *dest;
struct net_bridge_port *p;
/*获取目的MAC地址*/
dest = skb->mac.ethernet->h_dest;
/*skb->dev->br_port用于指定接收该数据包的端口,
若不是属于网桥的端口,则为NULL*/
p = skb->dev->br_port;
if (p == NULL) /*端口不是网桥组端口中*/
goto err_nolock;
/*本端口所属的网桥组*/
br = p->br;
/*加锁,因为在转发中需要读CAM表,所以必须加读锁,
避免在这个过程中另外的内核控制路径(如多处理机上另外一个CPU上的系统调用)修改CAM表*/
read_lock(&br->lock);
if (skb->dev->br_port == NULL) /*前面判断过的*/
goto err;
/*br->dev是网桥的虚拟网卡,如果它未UP,
或网桥DISABLED,p->state实际上是桥的当前端口的STP计算判断后的状态*/
if (!(br->dev.flags & IFF_UP) ||
p->state == BR_STATE_DISABLED)
goto err;
/*源MAC地址为255.X.X.X,即源MAC是多播或广播,丢弃之*/
if (skb->mac.ethernet->h_source[0] & 1)
goto err;
Emperor 于 2006-11-29 09:58:19发表:
基本框架就是这样了,与那些讲网桥原理的书上讲的基本差不多……
网桥之所以是网桥,主要靠这两个函数:
一个学习,一个查表;另外,支持STP,处理BPDU,需要用到函数br_stp_handle_bpdu.哪位有这三个函数的细节分析,可否送九贱一份,免得下午那么辛苦再去啃代码……
扫了一下 br_fdb_insert,结构还是很清析,如果当前项已存在于hash表项中,则更新它(__fdb_possibly_replace),如果是新项,则插入,实际是一个双向链表的维护过程(__hash_link):
同样,查表也是一个遍历链表,进行地址匹配的过程:
Emperor 于 2006-11-29 09:57:32发表:
众所周之,网桥之所以是网桥,比HUB更智能,是因为它有一个MAC-PORT的表,这样转发数据就不用广播,而查表定端口就可以了
每次收到一个包,网桥都会学习其来源MAC,添加进这个表。Linux中这个表叫CAM表(这个名字是其它资料上看的)。如果桥的状态是LEARNING或FORWARDING(学习或转发),则学习该包的源地址skb->mac.ethernet->h_source,将其添加到CAM表中,如果已经存在于表中了,则更新定时器,br_fdb_insert完成了这一过程
STP协议的BPDU包的目的MAC采用的是多播目标MAC地址:从01-80-c2-00-00-00(Bridge_group_addr:网桥组多播地址)开始.所以这里是如果开启了STP,而当前数据包又是一个BPDU(!memcmp(dest, bridge_ula, 5), unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 },则交由相应函数处理。if (br->stp_enabled &&,这里只比较前5个字节,没有仔细研究过STP是使用了全部多播地址(从0 1 : 0 0 : 5 e : 0 0 : 0 0 : 0 0到0 1 : 0 0 : 5 e : 7 f : ff : ff。),还是只使用了一部份,这里看来似乎只是一部份,没去深究了
四、br_handle_frame_finish