在 XDP 网关项目中,为了提高网络包吞吐性能,需要充分利用 CPU 核;这就需要调整网卡 queue 数量,并将 queue 对应的 IRQ 绑定到指定的 CPU 核上。

因此,在绑核之后,需要对 IRQ 绑核进行跟踪,以便观测绑核是否被更改了。

IRQ 绑核的内核函数

IRQ 绑核的方式如下:

  1. echo 1 > /proc/irq/${IRQ_ID}/smp_affinity
  2. echo 1 > /proc/irq/${IRQ_ID}/smp_affinity_list

所以,直接看这 2 个操作对应的内核源代码 kernel/irq/proc.c 吧。

找到如下 2 个函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// https://github.com/torvalds/linux/blob/master/kernel/irq/proc.c

static ssize_t write_irq_affinity(int type, struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
{
    unsigned int irq = (int)(long)pde_data(file_inode(file));
    // ...
}

static ssize_t irq_affinity_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
{
    return write_irq_affinity(0, file, buffer, count, pos);
}

static ssize_t irq_affinity_list_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
{
    return write_irq_affinity(1, file, buffer, count, pos);
}

使用 bpftrace 确认一下:

1
2
3
4
5
6
7
# bpftrace -l 'k:*irq_affinity*'
kprobe:irq_affinity_list_proc_write
kprobe:irq_affinity_proc_write

# bpftrace -e 'k:irq_affinity_list_proc_write, k:irq_affinity_proc_write { printf("irq_affinity: %s\n", comm); }'
Attaching 2 probes...
irq_affinity: zsh

跟踪 IRQ 绑核函数

因为不是要跟踪所有的 IRQ,而是只跟踪网卡 queue 对应的 IRQ;所以在 kprobe 这 2 个函数的时候,需要参考 (int)(long)pde_data(file_inode(file)) 拿到 IRQ ID,并进行过滤。

而后,使用 bpf_get_current_pid_tgid() 拿到当前进程的 PID。

接着,产生一条 perf 事件,将 IRQ ID 和 PID 传递给用户态程序。

用户态程序接收到事件后,需要根据 PID 去查询进程信息,包括父进程信息,一遍确认是哪个进程在更改绑核配置。

总结

跟踪 IRQ 绑核的函数,kprobe irq_affinity_list_proc_writeirq_affinity_proc_write 即可,并将 IRQ ID 和 PID 传递给用户态程序。