版本说明
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。
