网络发送调用栈:
__dev_queue_xmit -> __dev_xmit_skb -> __qdisc_run -> qdisc_restart -> sch_direct_xmit -> dev_hard_start_xmit
__dev_queue_xmit -> __dev_xmit_skb -> sch_direct_xmit -> dev_hard_start_xmit
__dev_queue_xmit -> dev_hard_start_xmit
dev_hard_start_xmit -> xmit_one -> netdev_start_xmit ->
ops->ndo_start_xmit(驱动层的发送函数 net_device_ops.ndo_start_xmit)
__dev_xmit_skb函数:
static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
struct net_device *dev,
struct netdev_queue *txq)
{
spinlock_t *root_lock = qdisc_lock(q);
bool contended;
int rc;
qdisc_pkt_len_init(skb);
qdisc_calculate_pkt_len(skb, q);
/*
* Heuristic to force contended enqueues to serialize on a
* separate lock before trying to get qdisc main lock.
* This permits __QDISC___STATE_RUNNING owner to get the lock more
* often and dequeue packets faster.
*/
/*判断qdisc是否处于运行状态 */
contended = qdisc_is_running(q);
if (unlikely(contended))
spin_lock(&q->busylock);
spin_lock(root_lock);
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
kfree_skb(skb);
rc = NET_XMIT_DROP;
} else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&
qdisc_run_begin(q)) {
/*
* This is a work-conserving queue; there are no old skbs
* waiting to be sent out; and the qdisc is not running -
* xmit the skb directly.
*/
/*
实际上这里是直接发送报文,无需使用流量控制,但需要满足三个条件
1. pfifo设置TCQ_F_CAN_BYPASS标志,
2. qdisc_qlen为0,也就是没有多余到数据包待发送,
3. qdisc_run_bein(q)=1,也就是说txq队列上没有运行流量控制
*/
/*更新统计信息 */
qdisc_bstats_update(q, skb);
/*直接调用sch_direct_xmit发送数据,如果返回1,表示需要启用流量控制 */
if (sch_direct_xmit(skb, q, dev, txq, root_lock, true)) {
if (unlikely(contended)) {
spin_unlock(&q->busylock);
contended = false;
}
__qdisc_run(q);/*启动流量控制 */
} else
qdisc_run_end(q);/*标记停止流量控制 */
rc = NET_XMIT_SUCCESS;
} else {
rc = q->enqueue(skb, q) & NET_XMIT_MASK;
if (qdisc_run_begin(q)) {
if (unlikely(contended)) {
spin_unlock(&q->busylock);
contended = false;
}
__qdisc_run(q);
}
}
spin_unlock(root_lock);
if (unlikely(contended))
spin_unlock(&q->busylock);
return rc;
}
///include/net/sch_generic.h
static inline int qdisc_qlen(const struct Qdisc *q)
{
return q->q.qlen;
}
static inline bool qdisc_run_begin(struct Qdisc *qdisc)
{
if (qdisc_is_running(qdisc))
return false;
qdisc->__state |= __QDISC___STATE_RUNNING;
return true;
}
static inline bool qdisc_is_running(const struct Qdisc *qdisc)
{
return (qdisc->__state & __QDISC___STATE_RUNNING) ? true : false;
}
/*
* Transmit one skb, and handle the return status as required. Holding the
* __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this
* function.
*
* Returns to the caller:
* 0 - queue is empty or throttled.
* >0 - queue is not empty.
*/
int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
struct net_device *dev, struct netdev_queue *txq,
spinlock_t *root_lock)
{
int ret = NETDEV_TX_BUSY;
spin_unlock(root_lock);
if (!netif_xmit_frozen_or_stopped(txq))
ret = dev_hard_start_xmit(skb, dev, txq);
spin_lock(root_lock);
if (dev_xmit_complete(ret)) { // 1. 驱动发送成功
ret = qdisc_qlen(q); // 将 qdisc 队列的剩余长度作为返回值
} else if (ret == NETDEV_TX_LOCKED) { // 2. 驱动获取发送锁失败
ret = handle_dev_cpu_collision(skb, txq, q);
} else { // 3. 驱动发送“正忙”,当前无法发送
ret = dev_requeue_skb(skb, q); // 将数据重新入队,等下次发送。
}
if (ret && netif_xmit_frozen_or_stopped(txq))
ret = 0;
return ret;
static inline
struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
unsigned int index)
{
return &dev->_tx[index];
}
static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev,
const struct sk_buff *skb)
{
return netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
}
static inline u16 skb_get_queue_mapping(const struct sk_buff *skb)
{
return skb->queue_mapping;
}
ref:
Linux内核网络数据发送(五)——排队规则_JinrongLiang的博客-CSDN博客_linux 任务排队
Linux 网络子系统之网络协议接口层(二) - 陈富林 - 博客园
【干货】25 张图一万字,拆解 Linux 网络包发送过程(下) - 知乎
linux-network详解4数据包发送 - Action_er - 博客园
Linux网络之设备接口层:发送数据包流程dev_queue_xmit - 明明是悟空 - 博客园