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() - kernel/irq/handle.c
- handle_irq_event() -カーネル/irq/handle.c
- handle_edge_irq() -カーネル/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 番号にバインドされるため、マルチキュー アダプターには適用できます。したがって、これはパケットを簡単に追跡するのに役立ちます。
私のアプローチ:
- この関数内に手動実装を追加します。これは正しいアプローチではないと思います。
- kprobe を使用します。しかし、変数または引数の内容に基づいてトレースをフィルタリングできますか?
- ジェイプローブを使用。私は、このアプローチで、議論で遊ぶことができると思います。でもなんとかイベントをこなすことができました。私は単純に jprobe の例に従いました。( https://stuff.mit.edu/afs/sipb/contrib/linux/samples/kprobes/jprobe_example.c ) その他いくつか。
- 上記のアプローチを行っているときに、他のツールにも出くわしました。perf、perf-tools、eBPF など。しかし、どちらが私にとって最良のアプローチであるかはわかりません。
私の最終的なタスクを明確にするために、次のようなパケットの最も早い到着のタイムスタンプをキャプチャしようとしています:
t1
t2
t3
t4
これに関するあらゆる種類の情報をいただければ幸いです。
ありがとうございました !