2

我对 Linux 内核的经验非常少。我最近才开始玩弄它。

为了我的研究目的,我一直在尝试追踪数据包到达的最早时间。我可以在设备驱动程序级别通过修改设备驱动程序并在设备驱动程序的中断处理函数中记录时间戳来做到这一点。很抱歉这篇文章可能会有点长。

例如,我修改了这个函数(https://elixir.bootlin.com/linux/v4.7/source/drivers/net/ethernet/intel/i40e/i40e_main.c#L3232)来跟踪调用的时间戳这个功能的。

进一步深入并遵循此调用的堆栈跟踪,我们将找到如下堆栈跟踪:

  • i40e_msix_clean_rings() - i40e 驱动程序的 i40e_main.c 在上面提供的链接中
  • __handle_irq_event_percpu() -内核/irq/handle.c
  • handle_irq_event_percpu() -内核/irq/handle.c
  • handle_irq_event() -内核/irq/handle.c
  • handle_edge_irq() - kernel/irq/chip.c
  • handle_irq() -arch/x86/kernel/irq_64.c
  • do_IRQ() -arch/x86/kernel / irq.c
  • common_interrupt() -不太确定,但实现应该类似于 arch/x86/kernel/head_32.s 中的 early_idt_handler_common()

我试图在函数 do_IRQ() 函数(上面的堆栈跟踪中的粗体字)中跟踪我的数据包到达的时间戳。作为参考,do_IRQ 函数如下所示:

__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
    struct pt_regs *old_regs = set_irq_regs(regs);
    struct irq_desc * desc;
    /* high bit used in ret_from_ code  */
    unsigned vector = ~regs->orig_ax;
    **int int_number;**

    entering_irq();

    /* entering_irq() tells RCU that we're not quiescent.  Check it. */
    RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU");

    desc = __this_cpu_read(vector_irq[vector]);
    **int_number = desc->irq_data.irq;**

    **printk(KERN_INFO "IRQ Number=%d; Vector=%d \n", int_number, vector);**

    if (!handle_irq(desc, regs)) {
        ack_APIC_irq();

        if (desc != VECTOR_RETRIGGERED) {
            pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n",
                         __func__, smp_processor_id(),
                         vector);
        } else {
            __this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
        }
    }

    exiting_irq();

    set_irq_regs(old_regs);
    return 1;
}

为了让我的意图更清楚一点,我已经表明我在这个函数中的更改包含在“**”中。

例如,在我的测试机器上,我的 NIC 绑定到 IRQ 编号19。int_number变量代表该编号。因此,这让我可以跟踪特定 IRQ 编号的 IRQ。

这听起来可能与单队列 NIC 适配器无关,但它适用于多队列适配器,因为我可以将我的数据包定向到带有流控制器的固定队列,并且每个队列都绑定到特定的 IRQ 号。因此,这将帮助我轻松追踪我的数据包。

我的方法:

  1. 在此函数中添加手动实现;我认为这不是正确的方法。
  2. 使用 kprobes。但它是否让我根据变量或参数内部的内容过滤我的踪迹?
  3. 使用 jprobe。我想,通过这种方法,我们将能够玩弄这些论点。我能够处理这个事件。我只是按照jprobe的例子。(https://stuff.mit.edu/afs/sipb/contrib/linux/samples/kprobes/jprobe_example.c)等等。
  4. 在通过上述方法时,我也遇到了其他工具。比如性能、性能工具、eBPF。但是,我不确定哪种方法最适合我。

只是为了澄清我的最终任务:我正在尝试捕获我的数据包最早到达的时间戳,例如:

t1
t2
t3
t4 

我将不胜感激任何形式的投入。

谢谢 !

4

0 回答 0