网络子系统
<h2>概述</h2>
<p>主要工作:
1、初始化 ptype_all、ptype_base
2、初始化每 CPU 的 softnet_data
3、为 NET_RX_SOFTIRQ、NET_TX_SOFTIRQ 注册软中断 net_rx_action、net_tx_action</p>
<p>借图:</p>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=99850e2000b2b8f0ee17c5353f676a73&amp;file=file.png" alt="" /></p>
<h2>流程</h2>
<p>系统启动时,调用 <code>subsys_initcall</code>-> <code>net_dev_init()</code> 来初始化,如下:</p>
<pre><code class="language-c">// file: net/core/dev.c
static struct pernet_operations __net_initdata default_device_ops = {
.exit = default_device_exit,
.exit_batch = default_device_exit_batch,
};
/*
* Initialize the DEV module. At boot time this walks the device list and
* unhooks any devices that fail to initialise (normally hardware not
* present) and leaves us with a valid list of present and active devices.
*
*/
/*
* This is called single threaded during boot, so no need
* to take the rtnl semaphore.
*/
static int __init net_dev_init(void)
{
int i, rc = -ENOMEM;
BUG_ON(!dev_boot_phase);
if (dev_proc_init())
goto out;
if (netdev_kobject_init())
goto out;
INIT_LIST_HEAD(&amp;ptype_all); // ptype_all 在 tcpdump 抓包时会用到
for (i = 0; i &lt; PTYPE_HASH_SIZE; i++)
INIT_LIST_HEAD(&amp;ptype_base[i]); // ptype_base
INIT_LIST_HEAD(&amp;offload_base);
if (register_pernet_subsys(&amp;netdev_net_ops)) // 注册网络协议子系统,添加到网络命令空间对应的全局链表pernet_list中
goto out;
/*
* Initialise the packet receive queues.
*/
// 初始化每个 CPU 的 softnet_data
for_each_possible_cpu(i) {
struct softnet_data *sd = &amp;per_cpu(softnet_data, i); // softnet_data
memset(sd, 0, sizeof(*sd));
skb_queue_head_init(&amp;sd-&gt;input_pkt_queue);
skb_queue_head_init(&amp;sd-&gt;process_queue);
sd-&gt;completion_queue = NULL;
INIT_LIST_HEAD(&amp;sd-&gt;poll_list); // 用来保存驱动的 poll 函数
sd-&gt;output_queue = NULL;
sd-&gt;output_queue_tailp = &amp;sd-&gt;output_queue;
#ifdef CONFIG_RPS
sd-&gt;csd.func = rps_trigger_softirq;
sd-&gt;csd.info = sd;
sd-&gt;csd.flags = 0;
sd-&gt;cpu = i;
#endif
sd-&gt;backlog.poll = process_backlog;
sd-&gt;backlog.weight = weight_p;
sd-&gt;backlog.gro_list = NULL;
sd-&gt;backlog.gro_count = 0;
}
dev_boot_phase = 0;
/* The loopback device is special if any other network devices
* is present in a network namespace the loopback device must
* be present. Since we now dynamically allocate and free the
* loopback device ensure this invariant is maintained by
* keeping the loopback device as the first device on the
* list of network devices. Ensuring the loopback devices
* is the first device that appears and the last network device
* that disappears.
*/
if (register_pernet_device(&amp;loopback_net_ops))
goto out;
if (register_pernet_device(&amp;default_device_ops))
goto out;
open_softirq(NET_TX_SOFTIRQ, net_tx_action); // 注册网络软中断
open_softirq(NET_RX_SOFTIRQ, net_rx_action); // 注册网络软中断
hotcpu_notifier(dev_cpu_callback, 0);
dst_init();
rc = 0;
out:
return rc;
}
subsys_initcall(net_dev_init);
</code></pre>
<p>而注册软中断则很简单:</p>
<pre><code class="language-c">// file: kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
</code></pre>