首页 > 系统相关 >Linux收包(L2层)

Linux收包(L2层)

时间:2023-12-06 22:45:05浏览次数:35  
标签:protocol 收包 ksoftirqd softirq init L2 Linux net sd

一、环境说明

内核版本:Linux 3.10

内核源码地址:https://elixir.bootlin.com/linux/v3.10/source (包含各个版本内核源码,且王页可全局搜索函数)

网卡:Intel的igb网卡

网卡驱动源码目录:drivers/net/ethernet/intel/igb/

二、Linux启动

Linux驱动,内核协议栈等等模块在具备接收网卡数据包之前,要做很多的准备工作才行。
比如要提前创建好ksoftirqd内核线程,要注册好各个协议对应的处理函数,网络设备子系统要提前初始化好,网卡要启动好等等。

1.创建软中断ksoftirqd内核进程

每个CPU负责执行一个ksoftirq内核进程,比如ksoftirqd/0运行在CPU 0上,这些内核进程执行不同软中断注册的中断处理函数。
执行硬中断的处理函数的 CPU 核心,也会执行该硬中断后续的软中断处理函数。
ksoftirqd 内核进程通过 spawn_ksoftirqd 函数初始化:

// file: kernel/softirq.c
static struct smp_hotplug_thread softirq_threads = {
    .store            = &ksoftirqd,
    .thread_should_run    = ksoftirqd_should_run,
    .thread_fn        = run_ksoftirqd,
    .thread_comm        = "ksoftirqd/%u",
};

static __init int spawn_ksoftirqd(void)
{
    register_cpu_notifier(&cpu_nfb);

    BUG_ON(smpboot_register_percpu_thread(&softirq_threads));

    return 0;
}
early_initcall(spawn_ksoftirqd);

当ksoftirqd被创建出来以后,它就会进入自己的线程循环函数ksoftirqd_should_run和run_ksoftirqd了。不停地判断有没有软中断需要被处理。

2.网络子系统初始化

网络子系统通过net_dev_init函数进行初始化:

// file: net/core/dev.c
static int __init net_dev_init(void)
{
    ......
    // 为每个CPU都申请一个softnet_data数据结构
    for_each_possible_cpu(i) {
        struct softnet_data *sd = &per_cpu(softnet_data, i);

        memset(sd, 0, sizeof(*sd));
        skb_queue_head_init(&sd->input_pkt_queue);
        skb_queue_head_init(&sd->process_queue);
        sd->completion_queue = NULL;
        INIT_LIST_HEAD(&sd->poll_list);
        sd->output_queue = NULL;
        sd->output_queue_tailp = &sd->output_queue;
#ifdef CONFIG_RPS
        sd->csd.func = rps_trigger_softirq;
        sd->csd.info = sd;
        sd->csd.flags = 0;
        sd->cpu = i;
#endif

        sd->backlog.poll = process_backlog;
        sd->backlog.weight = weight_p;
        sd->backlog.gro_list = NULL;
        sd->backlog.gro_count = 0;
    }

    ......
    // 注册软中断处理函数,用于处理接收和发送的数据包
    open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    open_softirq(NET_RX_SOFTIRQ, net_rx_action);
    ......
}

subsys_initcall(net_dev_init);

内核通过open_softirq函数来注册软中断处理函数:

// file: kernel/softirq.c
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
    softirq_vec[nr].action = action;
}

3.协议栈注册

linux通过inet_init将TCP、UDP和ICMP的接收函数注册到了inet_protos数组中,将IP的接收函数注册到了ptype_base哈希表中。

// file: net/ipv4/af_inet.c
static int __init inet_init(void)
{
    ......
    // 添加基础网络协议到inet_protos数组中
    if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
        pr_crit("%s: Cannot add ICMP protocol\n", __func__);
    if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
        pr_crit("%s: Cannot add UDP protocol\n", __func__);
    if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
        pr_crit("%s: Cannot add TCP protocol\n", __func__);

    ......
    // 将IP的接收函数ip_rcv注册到ptype_base列表里
    dev_add_pack(&ip_packet_type);
    ......
}

fs_initcall(inet_init);

TCP、UDP、ICMP和IP协议的处理函数:

//file: net/ipv4/af_inet.c
static const struct net_protocol tcp_protocol = {
    .early_demux    =    tcp_v4_early_demux,
    .handler    =    tcp_v4_rcv,
    .err_handler    =    tcp_v4_err,
    .no_policy    =    1,
    .netns_ok    =    1,
}
static const struct net_protocol udp_protocol = {
    .handler =    udp_rcv,
    .err_handler =    udp_err,
    .no_policy =    1,
    .netns_ok =    1,
};
static const struct net_protocol icmp_protocol = {
    .handler =    icmp_rcv,
    .err_handler =    icmp_err,
    .no_policy =    1,
    .netns_ok =    1,
};
static struct packet_type ip_packet_type __read_mostly = {
    .type = cpu_to_be16(ETH_P_IP),
    .func = ip_rcv,
};

4.网卡驱动程序初始化以及网卡启动

详细说明见:网卡驱动程序初始化文档

三、迎接数据的到来

 

1.硬中断处理

2.软中断处理

标签:protocol,收包,ksoftirqd,softirq,init,L2,Linux,net,sd
From: https://www.cnblogs.com/573583868wuy/p/17880614.html

相关文章

  • 学习linux文件操作
    学习linux文件操作 这节课开始学习文件和文件夹的创建、复制、移动和删除。touch命令让我能够创建新文件,cp和mv命令使我可以复制和移动文件或目录。对于文件删除,rm命令虽然强大,但也需要小心使用,以免误删重要文件。Linux的文件权限系统也是我学习的重要部分。chmod命令允许我......
  • linux文件操作
    学习linux文件操作 这节课开始学习文件和文件夹的创建、复制、移动和删除。touch命令让我能够创建新文件,cp和mv命令使我可以复制和移动文件或目录。对于文件删除,rm命令虽然强大,但也需要小心使用,以免误删重要文件。Linux的文件权限系统也是我学习的重要部分。chmod命令允许我......
  • Linux I/O重定向与管道详解
    LinuxI/O重定向与管道详解 原理
在Linux中,I/O重定向是通过重定向符号实现的。标准输入重定向使用符号“<”,标准输出重定向使用符号“>”。
例如,将文件file.txt的内容输出到终端,可以使用以下命令:catfile.txt将文件file.txt的内容输出到文件output.txt,可以使用以下命令:ca......
  • linux存储管理
    linux存储管理 Linux存储管理在系统维护中至关重要。其核心是文件系统的管理和存储资源的有效利用。通过命令行或图形化工具,Linux提供了多种方式管理存储。分区、格式化和挂载是基础步骤,可以使用fdisk、mkfs和mount等命令进行。同时,LVM(逻辑卷管理)允许动态调整分区大小。定期清......
  • Linux存储管理心得
    在Linux系统下,系统识别到硬盘后,会为其创建一份初始分区表。硬盘在分区后才可以使用,系统通过分区表来管理硬盘的使用。储存方式:本地储存、外部储存、网路储存。硬盘分区方式:分区类型:MBR、GPT、磁盘容量:<2TB(MBR)、不限(GPT)分区软件:fdisk、gdisk分散区:14个分区、128个主要分区基......
  • Linux如何备份数据库
    前言数据库备份还是很重要的,毕竟总不能当自己不小心把数据删了,就真的只剩下偷偷跑路吧!说笑了,对于这种情况我们要学会备份和恢复,这样面对误删的情况也能沉着冷静处理。数据库备份什么是数据库备份呢?以MySQL举个栗子(当然,备份方式有很多,冷、热备份、逻辑备份、快照备份,我们这次讲的是......
  • linux - 如何正确地关机
    sudosync关机前数据同步写入磁盘,一般情况下,关机命令会调用此命令将内存数据写入硬盘进行数据同步。1.shutdown#现在立刻关机-shutdown-hnow#10分钟后自动关机-shutdown-h+10#取消将要进行的关机-shutdown-c#系统在今天的20:30分关机-shutdown-h20......
  • windows 使用wsl安装linux环境
    网上的教程大多都需要安装虚拟机,找寻起来比较麻烦,特此记录本机用的window11系统第一步:关掉防火墙,以管理员身份打开终端然后输入wsl--install只输入wsl也可,会有对应的帮助信息弹出如果弹出无法解析服务器的名称或地址。如果网络链接没有问题,则需要去检查自己的网络配置,设置DNS......
  • 【转】Linux探秘之用户态与内核态
    一、 Unix/Linux的体系架构                                 如上图所示,从宏观上来看,Linux操作系统的体系架构分为用户态和内核态(或者用户空间和内核)。内核从本质上看是一种软件——控制计算机的硬件资源,并......
  • linux使用tail,grep查看文件,提示配到二进制文件 (标准输入)
    环境centos7.9背景最近在linux下使用cat,tail等查看日志时会报《配到二进制文件(标准输入)》,然后就没有任何输出,通常这些日志是中文英文混打印的如使用vi进日志后能查看中文格式的内容原因那是因为在Linux系统中,使用tail和grep命令来查找中文格式的log时,遇到《Binaryfil......