如有错误之处,欢迎指正学习。

handle_bridge()函数,该函数在Linux2.6.34\net\core\Dev.c

linux 内核kvm_内核


这里回调了br_handle_frame_hook()函数,这个是一个钩子函数。Br_handle_frame_hook()函数在Linux2.6.34\net\bridge\Br_input.c中,br_handle_frame_hook=br_handle_frame,所以实际函数为br_handle_frame.

linux 内核kvm_内核_02

linux 内核kvm_linux 内核kvm_03

函数中会提起数据包中的目标地址,如果目标地址是本机的MAC地址则会先调用br_handle_local_finish()函数让网桥学习更新校正CAM表,然后让函数返回skb,这样netif_receive_skb()函数就会继续往下执行,在遍历第二条链表的时候讲数据包上传给L3.

如果目标地址不是本机的,网桥则会选择将其转发出去,这里调用了br_handle_frame_finish()函数进行数据包转发,该函数在Linux2.6.34\net\bridge\Br_input.c


linux 内核kvm_linux 内核kvm_04

linux 内核kvm_数据帧_05

linux 内核kvm_数据帧_06


该函数采用的转发数据包的策略是:如果在网桥维护的CAM表中找得到数据包目标地址MAC所对应的以太网口,网桥会将这数据包从这个以太网口转发出去;如果找不到,则采用洪泛的方式,将数据包转发到每一个以太网口。当然这两种策略都可能会引起一些问题,比如:输出以太网端口不能和输入以太网端口一样等等,这些都有should_deliver()函数(Linux2.6.34\net\bridge\Br_forward.c)来把关。具体如下分析:

函数刚开始就让网桥学习更新和校正CAM表。接下来就是判断目标地址是不是多播地址,则调用br_multicast_forword()来进行转发,这个函数最后还是调用了_br_forword()函数,该函数稍后进行分析。若目标地址不是多播地址,则查阅CAM表,看看数据包的目标地址有没有登记在CAM表上,若有则调用br_forword()函数进行转发数据包,若没有则调用br_flood_forword()函数进行洪泛。



Br_forword()函数在Linux2.6.34\net\bridge\Br_forword.c


linux 内核kvm_linux 内核kvm_07


这里主要是调用了_br_forward()函数,该函数稍后分析。



br_flood_forword()函数在Linux2.6.34\net\bridge\Br_forward.c


linux 内核kvm_linux 内核kvm_08


这个函数同样是调用了_br_forword()函数。



_br_forword()函数在Linux2.6.34\net\bridge\forward.c

linux 内核kvm_网络数据_09

_br_forword()函数也没干什么,就是调用了br_forward_finish()函数。



Br_forward_finish()函数在Linux2.6.34\net\bridge\Br_forward.c

linux 内核kvm_linux_10

Br_forward_finish()函数调用了br_dev_queue_push_xmit()函数。



Br_dev_queue_push_xmit()函数在Linux2.6.34\net\bridge\Br_forward.c

linux 内核kvm_linux_11

该函数刚开始就对数据长度进行检测,如果数据长度大于MTU,就丢弃该数据帧,否则就从数据帧队列中取出数据帧丢给dev_queue_xmit()函数,dev_queue_xmit()函数负责将数据帧转发给网卡驱动程序传出去。这样整个网桥数据转发就结束了。

哦,差点落下了一个,br_handle_frame_finish()函数查找CAM时,会再次判断目标地址是不是属于本机地址,若是本机地址,br_forward()和br_flood_forward()函数就没机会执行了,则会转向执行br_pass_frame_up()函数,把数据帧传的本机的L3。Br_pass_frame_up()函数在Linux2.6.34\net\bridge\Br_input.c


linux 内核kvm_linux 内核kvm_12


Br_pass_frame_up()函数就是回调了netif_receive_skb()函数来实现将数据帧上传到本机的L3。