跟踪Linux

时间:2018-04-05 11:45:35

标签: c linux-kernel perf kprobe jprobe

我对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() - kernel / irq / handle.c
  • handle_irq_event_percpu() - kernel / irq / handle.c
  • handle_irq_event() - kernel / 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. 我也遇到了其他工具,同时也经历了上述方法。像perf,perf-tools,eBPF。但是,我不确定哪种方法最适合我。
  5. 只是为了澄清我的最后一项任务:我正在尝试捕获我的数据包最早到达的时间戳,如:

    t1
    t2
    t3
    t4 
    

    我很感激对此有任何意见。

    谢谢!

0 个答案:

没有答案