设备接口层初始化


这篇笔记分析了设备接口层的初始化代码实现,其中有些数据结构的详细情况会在后续相关的笔记中进一步说明。

开机初始化: net_dev_init()

// 对应系统参数/proc/sys/net/core/dev_weight
int weight_p __read_mostly = 64;            /* old backlog weight */

/*
 * 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;
    
    // 全局变量dev_boot_phase确保只初始化一次
    BUG_ON(!dev_boot_phase);

    // 在procfs中创建维测信息节点
    if (dev_proc_init())
        goto out;

    // 在sysfs中注册一个名为"net"的设备类
    if (netdev_kobject_init())
        goto out;

    // 初始化一个哈希表,该哈希表会用于后续的数据包向上(如IP层)分发过程
    INIT_LIST_HEAD(&ptype_all);
    for (i = 0; i < PTYPE_HASH_SIZE; i++)
        INIT_LIST_HEAD(&ptype_base[i]);

    // 网络命名空间级别的初始化
    if (register_pernet_subsys(&netdev_net_ops))
        goto out;

    // 每个CPU上分配一个接收队列,该队列将用于后续的非NAPI接收过程
    for_each_possible_cpu(i) {
        struct softnet_data *queue;
        
        queue = &per_cpu(softnet_data, i);
        // 初始化非NAPI模式的数据包接收队列
        skb_queue_head_init(&queue->input_pkt_queue);
        queue->completion_queue = NULL;
        // 初始化NAPI模式的轮询队列
        INIT_LIST_HEAD(&queue->poll_list);
        
        // 为了将NAPI和非NAPI两种接收流程归一化,设备接口层使用backlog变量将非NAPI方式
        // 改造成了NAPIF方式,这里指定其poll()回调轮询配额
        queue->backlog.poll = process_backlog;
        queue->backlog.weight = weight_p;
        queue->backlog.gro_list = NULL;
    }

    // 标识boot阶段完成
    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.
     */
    // 确保在每个网络命名空间中,lo是第一个注册,最后一个销毁的设备
    if (register_pernet_device(&loopback_net_ops))
        goto out;

    // 注册一个网络命名空间删除回调,当网络命名空间被销毁时,将该网络命名空间
    // 中的所有未去注册设备全部更改到默认的initnet命名空间中
    if (register_pernet_device(&default_device_ops))
        goto out;

    // 注册网络收发软中断
    open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    open_softirq(NET_RX_SOFTIRQ, net_rx_action);
    
    // 监测CPU热插拔事件
    hotcpu_notifier(dev_cpu_callback, 0);
    // 路由相关初始化
    dst_init();
    // 设备接口层多播相关初始化
    dev_mcast_init();
    rc = 0;
out:
    return rc;
}
subsys_initcall(net_dev_init);

namespace级别初始化: netdev_init()

完成namespace中

/* Initialize per network namespace state */
static int __net_init netdev_init(struct net *net)
{
    // 初始化网络设备对象通用列表
    INIT_LIST_HEAD(&net->dev_base_head);
    
    // 创建以网络设备名字为key的网络设备对象哈希表
    net->dev_name_head = netdev_create_hash();
    if (net->dev_name_head == NULL)
        goto err_name;
    // 创建以网络设备索引为key的网络设备对象哈希表
    net->dev_index_head = netdev_create_hash();
    if (net->dev_index_head == NULL)
        goto err_idx;
    return 0;

err_idx:
    kfree(net->dev_name_head);
err_name:
    return -ENOMEM;
}

网络命名空间net

struct net {
...
    struct list_head 	dev_base_head;
    struct hlist_head 	*dev_name_head;
    struct hlist_head	*dev_index_head;
}

struct net_device
{
...
    struct hlist_node	name_hlist;
    struct list_head	dev_list;
    struct hlist_node	index_hlist;
}

net中设计了三个链表来维护系统中所有注册的网络设备对象:

  1. dev_base_head: 通用的网络设备对象双向链表;
  2. dev_name_head: 以网络设备名字为key的网络设备对象哈希表;
  3. dev_index_head: 以网络设备索引为key的网络设备对象哈希表;

procfs文件节点

设备接口层初始化过程中,通过dev_proc_init()在/proc/net目录下创建了三个文件用来暴露一些信息。
在这里插入图片描述

  • dev文件
    从该文件可以查看基于网络设备的数据包统计信息。
    在这里插入图片描述
  • ptype文件

从该文件可以查看当前内核由哪些函数会处理哪些类型的L2层帧。如下第一行表示packet_rcv_spkt()函数处理eth0上的所有类型帧;第二行表示ip_rcv()函数处理所有接口上类型为ETH_P_IP(0x0800)的帧;第三行表示arp_rcv()函数处理所有接口上类型为ETH_P_ARP(0x0806)的帧;第二行表示ipv6_rcv()函数处理所有接口上类型为ETH_P_IPV6(0x86dd)的帧。
在这里插入图片描述

  • softnet_stat文件
    在这里插入图片描述

sysfs文件节点

在/sys/class目录下创建net设备类,后续注册的每个网络设备在该目录下都会创建一个软链接,指向对应的devices目录。
在这里插入图片描述
每个设备的目录下包含了大量针对该网络设备的控制节点文件。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值