公开学习文档

公开学习文档


问题

<h2>问题</h2> <ol> <li> <p>队列的本质是什么?涉及几部分内存? 本质是 ring buffer,涉及 2 部分内存:一个是 ring buffer,一个是 DMA 相关。</p> </li> <li> <p>网卡收到数据后会 DMA 到内存,这个内存,是否就是上面申请的那个?</p> </li> <li> <p>request_irq 如何选择中断绑定的 CPU ?和中断亲和性是什么关系?</p> </li> <li> <p>有机会好好梳理下网卡的中断设置</p> </li> <li> <p>local_bh_disable() 作用? 主要就是增加软中断计数,可以避免执行软中断</p> </li> <li> <p>调用 send() 成功返回,是否意味着数据已经成功发送给对端? 从代码来看,会触发发送,但对方不一定收到,可能在中途被丢包了。</p> </li> <li>本机通信时,如果数据量大于 lo 的 MTU 是否会分包?</li> </ol> <h2>收包过程</h2> <ol> <li> <p>数据包到达网卡,网卡将数据 DMA 到 ring buffer,触发硬件中断 -- 硬件中断和队列的关系?硬件中断具体做了什么?ring buffer 是指针数组吗?</p> <p>ring buffer 并不是简单的指针数组(但效果上似乎是的),实际申请了 2 个环形队列数组,但似乎都没有直接存放数据包数据。 中断如果占用太长的时间,会导致其它中断响应不过来,因此中断处理应该非常简单。 每个队列都会申请一个中断,中断触发时,执行 igb_msix_ring() 函数,它是在 igb_main.c 中定义的,相关函数如下:</p> </li> </ol> <pre><code class="language-c">// 总的来说,就是获取中断关联的 q_vector 中的 napi,将其加入到每 CPU 的 sd-&amp;gt;poll_list 中 static irqreturn_t igb_msix_ring(int irq, void *data) { struct igb_q_vector *q_vector = data; // 每个 q_vector 上面都有一个 napi /* Write the ITR value calculated from the previous interrupt. */ igb_write_itr(q_vector); napi_schedule(&amp;amp;q_vector-&amp;gt;napi); return IRQ_HANDLED; } void __napi_schedule(struct napi_struct *n) { unsigned long flags; local_irq_save(flags); ____napi_schedule(&amp;amp;__get_cpu_var(softnet_data), n); local_irq_restore(flags); } static inline void ____napi_schedule(struct softnet_data *sd, struct napi_struct *napi) { list_add_tail(&amp;amp;napi-&amp;gt;poll_list, &amp;amp;sd-&amp;gt;poll_list); // 将 napi 加入到 sd-&amp;gt;poll_list 中 __raise_softirq_irqoff(NET_RX_SOFTIRQ); } // 对于 q_vector-&amp;gt;napi 初始化如下(此函数会根据队列数进行 for 循环调用) static int igb_alloc_q_vector(struct igb_adapter *adapter, int v_count, int v_idx, int txr_count, int txr_idx, int rxr_count, int rxr_idx) { // ... /* allocate q_vector and rings */ q_vector = kzalloc(size, GFP_KERNEL); if (!q_vector) return -ENOMEM; /* initialize NAPI */ netif_napi_add(adapter-&amp;gt;netdev, &amp;amp;q_vector-&amp;gt;napi, igb_poll, 64); // 在此初始化,这里就是对应的 poll 函数 // ... } // 来看看 poll 函数 /** * igb_poll - NAPI Rx polling callback * @napi: napi polling structure * @budget: count of how many packets we should handle **/ static int igb_poll(struct napi_struct *napi, int budget) { struct igb_q_vector *q_vector = container_of(napi, struct igb_q_vector, napi); // 获取到原始的 q_vector bool clean_complete = true; #ifdef CONFIG_IGB_DCA if (q_vector-&amp;gt;adapter-&amp;gt;flags &amp;amp; IGB_FLAG_DCA_ENABLED) igb_update_dca(q_vector); #endif if (q_vector-&amp;gt;tx.ring) clean_complete = igb_clean_tx_irq(q_vector); // if (q_vector-&amp;gt;rx.ring) clean_complete &amp;amp;= igb_clean_rx_irq(q_vector, budget); /* If all work not completed, return budget and keep polling */ if (!clean_complete) return budget; /* If not enough Rx work done, exit the polling mode */ napi_complete(napi); igb_ring_irq_enable(q_vector); return 0; }</code></pre> <p>&gt; 中断响应分为上半部和下半部。上半部应该是中断处理函数,是需要马上要处理的;下半部是可以慢慢处理的,一般是:软中断,tasklet 等机制。</p> <ol> <li> <p>硬件中断处理函数,登录并触发软中断 -- 具体是如何处理的,每次都会触发软中断吗?poll_list 到底如何理解?硬件中断是如何设置的?/proc/interrupts 中记录的是软中断吗?</p> <p>硬中断处理函数如上,主要就是将 q_vector-&gt;napi 加入到每 CPU 的 sd-&gt;poll_list 中,并触发软中断。从代码的角度,几乎肯定会触发软中断。 硬件中断的具体细节,还有待进一步分析。 /proc/interrupts 记录的是 irq 的触发情况,这并不是软中断(似乎就是硬中断),一般来说,软中断是指 softirq 进程处理的中断。</p> </li> <li> <p>软中断函数执行,执行 poll 函数 -- 软中断具体是什么时候执行?</p> <p>软中断执行的是固定函数 net_rx_action,里面获取当前 CPU 的 softnet_data,从 softnet_data-&gt;poll_list 中依次获取 napi 对象 n,并调用 n-&gt;poll() 进行具体处理。 硬中断处理函数仅触发软中断,只是在当前 CPU 的 NET_RX_SOFTIRQ 的标记位置 1,没有看到主动触发调用。 软中断触发的时机:1、硬中断处理结束退出时,会检查激活 softirqd;2、</p> </li> <li> <p>poll 函数是网卡注册的,控制走协议栈 -- poll 函数具体做了什么?如果控制走协议栈?</p> </li> <li> <p>在哪里控制发给应用层?如果应用层收包不及时会怎么样?</p> </li> <li>所有具体的收包流程都是在软中断来处理的吗?如果数据包过多,会不会影响其它的中断功能?</li> </ol> <h2>其它</h2> <ol> <li>发包过程是如何的?由谁来检查是否有包要发?</li> </ol>

页面列表

ITEM_HTML