公开学习文档

公开学习文档


网络子系统

<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;amp;file=file.png" alt="" /></p> <h2>流程</h2> <p>系统启动时,调用 <code>subsys_initcall</code>-&gt; <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;amp;ptype_all); // ptype_all 在 tcpdump 抓包时会用到 for (i = 0; i &amp;lt; PTYPE_HASH_SIZE; i++) INIT_LIST_HEAD(&amp;amp;ptype_base[i]); // ptype_base INIT_LIST_HEAD(&amp;amp;offload_base); if (register_pernet_subsys(&amp;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;amp;per_cpu(softnet_data, i); // softnet_data memset(sd, 0, sizeof(*sd)); skb_queue_head_init(&amp;amp;sd-&amp;gt;input_pkt_queue); skb_queue_head_init(&amp;amp;sd-&amp;gt;process_queue); sd-&amp;gt;completion_queue = NULL; INIT_LIST_HEAD(&amp;amp;sd-&amp;gt;poll_list); // 用来保存驱动的 poll 函数 sd-&amp;gt;output_queue = NULL; sd-&amp;gt;output_queue_tailp = &amp;amp;sd-&amp;gt;output_queue; #ifdef CONFIG_RPS sd-&amp;gt;csd.func = rps_trigger_softirq; sd-&amp;gt;csd.info = sd; sd-&amp;gt;csd.flags = 0; sd-&amp;gt;cpu = i; #endif sd-&amp;gt;backlog.poll = process_backlog; sd-&amp;gt;backlog.weight = weight_p; sd-&amp;gt;backlog.gro_list = NULL; sd-&amp;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;amp;loopback_net_ops)) goto out; if (register_pernet_device(&amp;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>

页面列表

ITEM_HTML