协议栈数据发送

来源:互联网 发布:mac obs 插件 编辑:程序博客网 时间:2024/06/06 06:30

传输层的数据发送

传输层的数据发送的触发

   1、由用户进程下一次send系统调用

   2、协议栈收到数据反馈后执行数据的发送

tcp_write_xmit()
{
  while ((skb = tcp_send_head(sk))) 
  {
     tcp_event_new_data_sent(sk, skb);//重新获取首部
  }

}


数据发送经过ip层路由和邻居协议后

发送队列关联了Qdiscnet/core/Dev.cint dev_queue_xmit(struct sk_buff *skb){struct net_device *dev = skb->dev;//ip层路由的时候,会计算得到包的出口设备struct netdev_queue *txq;struct Qdisc *q;txq = dev_pick_tx(dev, skb);q = rcu_dereference(txq->qdisc);if (q->enqueue) {rc = __dev_xmit_skb(skb, q, dev, txq);goto out;}}多队列网卡需要选择从哪个队列出去net/core/Dev.cstatic struct netdev_queue *dev_pick_tx(struct net_device *dev,struct sk_buff *skb){const struct net_device_ops *ops = dev->netdev_ops;u16 queue_index = 0;if (ops->ndo_select_queue)queue_index = ops->ndo_select_queue(dev, skb);else if (dev->real_num_tx_queues > 1)queue_index = skb_tx_hash(dev, skb);skb_set_queue_mapping(skb, queue_index);return netdev_get_tx_queue(dev, queue_index);}将包放入到Qdisc中net/core/dev.cstatic inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev,struct netdev_queue *txq){        .....rc = qdisc_enqueue_root(skb, q);qdisc_run(q);       .....return rc;}
static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch){  return sch->enqueue(skb, sch);}static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch){   qdisc_skb_cb(skb)->pkt_len = skb->len;   return qdisc_enqueue(skb, sch) & NET_XMIT_MASK;}
启动发送的软中断net/sched/sch_generic.cvoid __qdisc_run(struct Qdisc *q){unsigned long start_time = jiffies;while (qdisc_restart(q)) {if (need_resched() || jiffies != start_time) {__netif_schedule(q);break;}}clear_bit(__QDISC_STATE_RUNNING, &q->state);}net/core/dev.cstatic inline void __netif_reschedule(struct Qdisc *q){struct softnet_data *sd;unsigned long flags;local_irq_save(flags);sd = &__get_cpu_var(softnet_data);q->next_sched = sd->output_queue;sd->output_queue = q;raise_softirq_irqoff(NET_TX_SOFTIRQ);local_irq_restore(flags);}net/core/dev.cvoid __netif_schedule(struct Qdisc *q){if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state))__netif_reschedule(q);}

数据即使触发了协议栈的发送,也不会立即出网卡,还要经过Qdisc的流量调节,Qdisc的流量调节是通过软中断来控制

这决定了数据的发送又是一个异步的过程了

用户态=>传输层发送队列=>网卡的多队列或者Qdisc队列

3个环节都是异步执行的

第一个环节是要用户态切换到内核态

第二个环节都是在内核态,只不过后续的数据发送在中断的上下文中处理


0 0
原创粉丝点击