【Linux4.1.12源码分析】二层报文发送之qdisc实现分析
来源:互联网 发布:产品网络销售的看法 编辑:程序博客网 时间:2024/05/29 10:54
二层发送中,实现qdisc的主要函数是__dev_xmit_skb和net_tx_action,本篇将分析qdisc实现的原理,但是不涉及qdisc内部的算法,仅对框架进行分析。
1、__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. */contended = qdisc_is_running(q);//判断qdisc是否运行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) &&//qisc没有运行,且没有缓存报文,则直接可以发送报文 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. */qdisc_bstats_update(q, skb);if (sch_direct_xmit(skb, q, dev, txq, root_lock, true)) {if (unlikely(contended)) {spin_unlock(&q->busylock);contended = false;}__qdisc_run(q);//sch_direct_xmit返回为正值,说明qdisc中有报文待发送,尝试发送缓冲区报文} elseqdisc_run_end(q);//正常发送完成,qdisc停止运行rc = NET_XMIT_SUCCESS;} else {rc = q->enqueue(skb, q) & NET_XMIT_MASK;//qdisc running或者有缓存报文, 则把报文发动qdisc队列中if (qdisc_run_begin(q)) {//尝试启动qdisc,如果qisc成功启动,则尝试发送报文if (unlikely(contended)) {spin_unlock(&q->busylock);contended = false;}__qdisc_run(q);//发送qdisc缓冲队列中的报文}}spin_unlock(root_lock);if (unlikely(contended))spin_unlock(&q->busylock);return rc;}
2、__qdisc_run函数
void __qdisc_run(struct Qdisc *q){int quota = weight_p;int packets;while (qdisc_restart(q, &packets)) {//循环发送报文/* * Ordered by possible occurrence: Postpone processing if * 1. we've exceeded packet quota * 2. another process needs the CPU; */quota -= packets;if (quota <= 0 || need_resched()) {//如果配额或需要调度,则触发软中断后退出__netif_schedule(q);break;}}qdisc_run_end(q);//qdisc停止}3、qdisc_restart函数
static inline int qdisc_restart(struct Qdisc *q, int *packets){struct netdev_queue *txq;struct net_device *dev;spinlock_t *root_lock;struct sk_buff *skb;bool validate;/* Dequeue packet */skb = dequeue_skb(q, &validate, packets);//从缓存区中得到待发送的报文,因为流量限制原因,就算缓冲区有报文,也可能返回NULLif (unlikely(!skb))return 0;root_lock = qdisc_lock(q);dev = qdisc_dev(q);txq = skb_get_tx_queue(dev, skb);return sch_direct_xmit(skb, q, dev, txq, root_lock, validate);//发送报文}4、dequeue_skb函数
static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, int *packets){struct sk_buff *skb = q->gso_skb;const struct netdev_queue *txq = q->dev_queue;*packets = 1;*validate = true;if (unlikely(skb)) {/* check the reason of requeuing without tx lock first */txq = skb_get_tx_queue(txq->dev, skb);if (!netif_xmit_frozen_or_stopped(txq)) {q->gso_skb = NULL;q->q.qlen--;} elseskb = NULL;/* skb in gso_skb were already validated */*validate = false;} else {if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) {skb = q->dequeue(q);//调用qdisc的dequeue函数获取skbif (skb && qdisc_may_bulk(q))<span style="white-space:pre"></span>//如果还能继续获取skb,则一次性获取多个skbtry_bulk_dequeue_skb(q, skb, txq, packets);}}return skb;}
net_tx_action
net_tx_action为报文发送软中断,在处理报文发送软中断时,尝试该CPU softnet_data上所有qdisc发送报文。
static void net_tx_action(struct softirq_action *h){struct softnet_data *sd = this_cpu_ptr(&softnet_data);if (sd->completion_queue) {struct sk_buff *clist;local_irq_disable();clist = sd->completion_queue;sd->completion_queue = NULL;local_irq_enable();while (clist) {struct sk_buff *skb = clist;clist = clist->next;WARN_ON(atomic_read(&skb->users));if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED))trace_consume_skb(skb);elsetrace_kfree_skb(skb, net_tx_action);__kfree_skb(skb);}}if (sd->output_queue) {struct Qdisc *head;local_irq_disable();head = sd->output_queue;sd->output_queue = NULL;sd->output_queue_tailp = &sd->output_queue;local_irq_enable();while (head) {struct Qdisc *q = head;spinlock_t *root_lock;head = head->next_sched;root_lock = qdisc_lock(q);if (spin_trylock(root_lock)) {smp_mb__before_atomic();clear_bit(__QDISC_STATE_SCHED, &q->state);qdisc_run(q); //尝试启动qdisc发送报文spin_unlock(root_lock);} else {if (!test_bit(__QDISC_STATE_DEACTIVATED, &q->state)) {__netif_reschedule(q);} else {smp_mb__before_atomic();clear_bit(__QDISC_STATE_SCHED, &q->state);}}}}}
1 0
- 【Linux4.1.12源码分析】二层报文发送之qdisc实现分析
- 【Linux4.1.12源码分析】二层报文发送之dev_queue_xmit
- 【Linux4.1.12源码分析】二层报文发送之net_tx_action
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(MAC层)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(IP层)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(UDP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(TCP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(skb_segment)
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】IP层报文发送之ip_output
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】二层报文发送之GSO条件判断
- 【Linux4.1.12源码分析】vxlan报文发送之udp_tunnel_xmit_skb
- 【Linux4.1.12源码分析】vxlan报文发送之iptunnel_xmit
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_local_deliver)
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_forward)
- 【Linux4.1.12源码分析】协议栈报文接收之传输层处理分析(UDP)
- 【Linux4.1.12源码分析】协议栈报文接收之netif_receive_skb函数分析
- 青头小白之重装系统
- 重视前端技术从node.js开始
- Android--自定义荷载进度的两种方法
- irq_desc操作
- 给玩家加载邮件消息
- 【Linux4.1.12源码分析】二层报文发送之qdisc实现分析
- 爱奇艺 2
- Java笔记 - 多线程-实现Runnable接口
- bootstrapSelect 下拉框插件
- Less
- 番茄助手Visual Assist X的简单使用以及消除中文注释警告
- Accuracy Layer
- C(4)数组or数组元素做实参
- 几种常见的排序算法 及代码实现