4.1接收帧
由硬件驱动在中断处理程序中直接调用netif_rx
netif_rx(skb)★ (dev.c/core)----将接收到的消息挂在每CPU的输入队列中
if(netpoll_rx函数与把数据拿走)
return
__skb_queue_tail(把所有收到的数据保存起来)
netif_rx_schedule
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
重要:在netif_rx的上层函数中利用dev_alloc_skb创建skb结构,并设置skb->dev。在netif_rx中把skb加入每CPU的输入队列。然后在process_backlog 函数中,从每CPU输入队列中取出skb(从队列中循环读取skb,直到读完),调用netif_receive_skb对每一个skb进行处理。
在net_dev_init函数中初始化了软中断: (dev.c/core)
open_softirq(NET_TX_SOFTIRQ, net_tx_action,NULL);
open_softirq(NET_RX_SOFTIRQ, net_rx_action,NULL);
所以NET_RX_SOFTIRQ中断的处理函数是net_rx_action,NET_TX_SOFTIRQ中断的处理函数是net_tx_action。需要让上层接收数据时,只要触发相应的软中断,如__raise_softirq_irqoff(NET_RX_SOFTIRQ)。内核就会在适当时机执行do_softirq来处理pending的软中断。
net_rx_action★ (dev.c/core)
n->poll = process_backlog ((structnet_device *)
netif_receive_skb (skb)
pt_prev->func(skb,skb->dev)= ip_rcv★(在这里完成了交接)
__raise_softirq_irqoff(NET_RX_SOFTIRQ)
4.2发送帧
dev_queue_xmit(sk_buff *skb..)★ (dev.c/core, P182)
------分支细节见书籍P101
dev->hard_start_xmit= el_start_xmit (struct sk_buff*, struct net_device *)★ –
调用outw汇编指令发送数据,够底层了
重要:这里的net_device是从skb->dev得到的,而skb->dev是在函数ip_finish_output中得到的,有skb->dev =skb->dst->dev; 而skb->dst是路由选择后被赋值的
rcu_read_unlock_bh
lookback的发送函数见下面(P183):
net_tx_action(struct softirq_action *)★ (dev.c/core)
__kfree_skb(释放已发送的,此时中断由dev_kfree_skb_irq函数发起)
qdisc_run(struct net_device *)---发送包函数
--- qdisc_restart
----- dev->hard_start_xmit(skb, dev)(在网卡上实际的发送包)
netif_schedule(struct net_device *★ (netdevice.h)
__netif_schedule (调度设备发包,netdevice.h)
raise_softirq_irqoff(NET_TX_SOFTIRQ)
net_tx_action