版本说明
Linux版本: 3.10.103
网卡驱动: ixgbe
网络协议注册
br_add_if
主要是注册桥处理函数br_handle_frame
给skb->edv->rx_handler
。netdev_create-->netdev_rx_handler_register
主要是注册接收函数netdev_frame_hook
,此处是给openvswitch的datapath用的。
报文接收
- 网卡调用
__netif_receivve_skb_core
后,会调用skb->dev->rx_handler
处理2层协议函数,此处只关注桥的,暂不关注ovs的。
br_handle_frame
- 首先判定mac是否本地,是本地的报文则进入到
NFPROTO_BRIDGE
的NF_HOOK
,即NF_BR_LOCAL_IN
,进入处理链,最终完成后调用br_handle_local_finish
完成操作,等着进入再上一层的协议。 - 如果不是本地,则进入转发流程,如果直接转发状态,则调用
br_should_route_hook
,即ebt_route
;如果是学习状态是NF_HOOK
,即NF_BR_PRE_ROUTING
,进入处理链,最终完成调用br_handle_frame_finish
。 - 然后调用
br_fdb_update
学习源MAC地址,更新MAC地址表,__br_fdb_get
或者目的MAC对应的端口。 - 如果查找到了端口,调用
br_forward
转发到对应的端口。 - 找不到端口,调用
br_flood_forward
进行广播。 br_forward
继续调用NF_HOOK
的NF_BR_FORWARD
,完成后调用br_forward_finish
,继续调用NF_HOOK
的NF_BR_POST_ROUTING
,最终调用br_dev_queue_push_xmit
。br_dev_queue_push_xmit-->dev_queue_xmit
进行L2的发送。
报文发送
dev_queue_xmit
netdev_pick_tx
主要是选择发送设备设置的映射关系,查找当前CPU对应的队列,如果多个则计算hash,确定队列。- 支持入队的话,调用
__dev_xmit_skb
进行下一步的操作。不支持队列的话调用dev_hard_start_xmit
进行数据的发送。
__dev_xmit_skb
- 如果队列的状态是非活跃的,则丢包。
- 如果是支持bypass,则调用
sch_direct_xmit
直接发送数据包,没有发送完成,继续调用__qdisc_run
。 - 其他情况入队并且调用
__qdisc_run
。
__qdisc_run
- while循环调用
qdisc_restart
,进行的操作为skb出队,并且调用sch_direct_xmit
直接发送数据包,没有发送完成,返回值非0,继续参与循环。 - 一直循环到数据包发送完毕,或者权重耗完或者需要重新调度,此时调用
__netif_schedule-->__netif_reschedule
,将当前的队列记录在CPU的softnet_data,触发软中断NET_TX_SOFTIRQ
,调用net_tx_action
。
sch_direct_xmit
- 直接调用
dev_hard_start_xmit-->ops->ndo_start_xmit-->ixgbe_xmit_frame
发送数据包。 - 如果发送成功,则返回值为队列剩下的数据包量。
- 如果被自己CPU锁了则报错,被其他CPU锁了则重新入队,等以后再发送。
- 如果busy的话重新入队,等以后发送。
- 所以其实就是发送完成则返回成功0,否则发送非0。