作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.com
- static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
-
{
-
unsigned seq;
-
int hh_len;
/*
这里使用顺序锁的机制,来读取hh的数据
关于顺序锁的介绍,请参考其他资料。
这里的循环,保证了在读取hh的时候,没有其他线程或者进程修改了hh
*/
-
do {
-
int hh_alen;
-
-
seq = read_seqbegin(&hh->hh_lock);
- /* 得到hh的长度和数据,复制到skb_buff中 */
-
hh_len = hh->hh_len;
-
hh_alen = HH_DATA_ALIGN(hh_len);
-
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
-
} while (read_seqretry(&hh->hh_lock, seq));
/* 调整skb_buff的data和len */
-
skb_push(skb, hh_len);
- /* 调用hh的回调函数,发送skb_buff */
-
return hh->hh_output(skb);
- }
通过搜索hh的hh_output,可以发现,在不同的情况下,hh_output指向的函数是不一样的。
比如,在函数neigh_destroy中,hh->hh_output = neigh_blackhole;而neigh_blackhole,顾名思义是neighbour的一个黑洞,该函数直接释放skb_buff。
根据我的查找,在正确的流程下,hh的hh_output应该指向为dev_queue_xmit。
dev_queue_xmit有一大段的注释——不错,我喜欢:D
- /**
-
* dev_queue_xmit - transmit a buffer
-
* @skb: buffer to transmit
-
*
-
* Queue a buffer for transmission to a network device. The caller must
-
* have set the device and priority and built the buffer before calling
-
* this function. The function can be called from an interrupt.
-
*
-
* A negative errno code is returned on a failure. A success does not
-
* guarantee the frame will be transmitted as it may be dropped due
-
* to congestion or traffic shaping.
-
*
-
* -----------------------------------------------------------------------------------
-
* I notice this method can also return errors from the queue disciplines,
-
* including NET_XMIT_DROP, which is a positive value. So, errors can also
-
* be positive.
-
*
-
* Regardless of the return value, the skb is consumed, so it is currently
-
* difficult to retry a send to this method. (You can bump the ref count
-
* before sending to hold a reference for retry if you are careful.)
-
*
-
* When calling this method, interrupts MUST be enabled. This is because
-
* the BH enable code must have IRQs enabled so that it will not deadlock.
-
* --BLG
- */
从注释中,可以看出这个函数是用于发送skb_buff的——将buffer加入到driver的queue中,剩下的就是driver的事情了。呵呵,胜利就在眼前。这已经是UDP发送数据在TCP/IP函数栈的最后一个函数了,后面关于driver的工作,就不是我学习的范围了。
那么让我们简单的看看dev_queue_xmit吧。
- int dev_queue_xmit(struct sk_buff *skb)
-
{
-
struct net_device *dev = skb->dev;
-
struct netdev_queue *txq;
-
struct Qdisc *q;
-
int rc = -ENOMEM;
-
-
/* Disable soft irqs for various locks below. Also
-
* stops preemption for RCU.
-
*/
-
rcu_read_lock_bh();
/* 得到发送device的发送队列 */
-
txq = dev_pick_tx(dev, skb);
-
q = rcu_dereference_bh(txq->qdisc);
-
-
#ifdef CONFIG_NET_CLS_ACT
-
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
-
#endif
-
if (q->enqueue) {
- /* 该设备有enqueue的处理函数 */
-
rc = __dev_xmit_skb(skb, q, dev, txq);
-
goto out;
-
}
/* 该设备没有队列, 大部分情况都是软件设备(虚拟设备?)*/
-
/* The device has no queue. Common case for software devices:
-
loopback, all the sorts of tunnels...
-
-
Really, it is unlikely that netif_tx_lock protection is necessary
-
here. (f.e. loopback and IP tunnels are clean ignoring statistics
-
counters.)
-
However, it is possible, that they rely on protection
-
made by us here.
-
-
Check this and shot the lock. It is not prone from deadlocks.
-
Either shot noqueue qdisc, it is even simpler 8)
-
*/
-
if (dev->flags & IFF_UP) {
-
int cpu = smp_processor_id(); /* ok because BHs are off */
-
-
if (txq->xmit_lock_owner != cpu) {
- /*
- 别的CPU正在使用该设备,需要尝试获得锁,来获取device的使用权。
- */
-
- HARD_TX_LOCK(dev, txq, cpu);
-
if (!netif_tx_queue_stopped(txq)) {
- /* 发送数据 */
-
rc = dev_hard_start_xmit(skb, dev, txq);
-
if (dev_xmit_complete(rc)) {
-
HARD_TX_UNLOCK(dev, txq);
-
goto out;
-
}
-
}
-
HARD_TX_UNLOCK(dev, txq);
-
if (net_ratelimit())
-
printk(KERN_CRIT "Virtual device %s asks to "
-
"queue packet!\n", dev->name);
-
} else {
- /* 出错了。。。。*/
-
/* Recursion is detected! It is possible,
-
* unfortunately */
-
if (net_ratelimit())
-
printk(KERN_CRIT "Dead loop on virtual device "
-
"%s, fix it urgently!\n", dev->name);
-
}
-
}
-
-
rc = -ENETDOWN;
-
rcu_read_unlock_bh();
-
-
kfree_skb(skb);
-
return rc;
-
out:
-
rcu_read_unlock_bh();
-
return rc;
- }
好了,到了目前为止。UDP的发送过程就基本上完成了。哦,遗漏了一个IP分片函数ip_fragment。
刚刚简单浏览了一遍这个函数,发现比较容易阅读,但是今天已经有点晚了。就留在明天学习了。