1. 中断基础

中断是硬件与操作系统之间异步通信的核心机制。当外设(如网卡)需要 CPU 处理数据时,通过中断信号通知 CPU 暂停当前任务,转而执行中断服务程序(ISR)。理解中断的底层原理是优化网络驱动性能的前提。

1.1 中断的基本概念

中断允许 CPU 在等待外设操作时执行其他任务,从而提升系统吞吐量。中断分为同步中断(异常)和异步中断(硬件中断)。在网络驱动场景中,我们主要关注硬件中断。

关键术语:
  • IRQ(Interrupt ReQuest):中断请求线,每个外设或中断源分配一条 IRQ 编号。
  • ISR(Interrupt Service Routine):中断服务程序,内核注册的处理函数。
  • 中断上下文:ISR 运行在中断上下文中,不可睡眠,不能调用可能导致阻塞的函数。
  • 中断延迟:从硬件产生中断信号到 CPU 开始执行 ISR 的时间间隔。

1.2 中断向量表(IVT / IDT)

中断向量表是 CPU 用于查找中断处理程序入口地址的数据结构。在 x86 架构中,实模式下称为 IVT,保护模式和长模式下称为 IDT(Interrupt Descriptor Table)。

模式 名称 表项大小 最大中断数 基址寄存器
实模式 IVT 4 字节(段:偏移) 256 固定 0x0000
保护模式 IDT 8 字节(门描述符) 256 IDTR
长模式(x86-64) IDT 16 字节(门描述符) 256 IDTR

每个 IDT 表项是一个门描述符(Gate Descriptor),包含中断处理程序的地址、特权级、段选择子等信息。CPU 收到中断向量号后,通过 IDTR 找到 IDT 基址,乘以向量号索引到对应门描述符,跳转执行。

实践提示: 在 Linux 内核中,arch/x86/kernel/idt.c 负责初始化 IDT。网络驱动注册的中断处理函数最终会挂载到 IDT 的某个表项上。使用 cat /proc/interrupts 可以查看当前系统中每个中断号对应的 CPU 处理统计。
中断向量表查找流程 中断向量表(IDT)查找流程 网卡中断信号 中断控制器 CPU IDT(中断描述符表) 向量 0x00 向量 0x01 向量 0x2B(网卡) ISR 处理函数 中断向量号 由中断控制器分配

1.3 中断控制器:APIC 与 IOAPIC

现代 x86 系统使用 APIC(Advanced Programmable Interrupt Controller) 架构替代传统的 8259A PIC。APIC 系统由两部分组成:LAPIC(Local APIC) 和 IOAPIC(I/O APIC)。

1.3.1 LAPIC(本地 APIC)

  • 集成在 CPU 内部,每个 CPU 核心拥有独立的 LAPIC。
  • 管理本地中断源(如定时器、性能计数器、IPI)。
  • 接收来自 IOAPIC 的中断消息,并递交给 CPU 核心。
  • 支持中断优先级和中断屏蔽。

1.3.2 IOAPIC(I/O APIC)

  • 位于芯片组(PCH)中,负责收集外设的中断请求。
  • 将外设 IRQ 映射为中断向量,并通过系统总线发送中断消息到目标 LAPIC。
  • 支持 中断重定向:可以将不同外设的中断分发到不同 CPU 核心。
  • 支持 MSI(Message Signaled Interrupts):外设直接写中断消息到内存,绕过 IOAPIC。
特性 传统 8259A PIC APIC + IOAPIC
支持 CPU 数量 单 CPU 多 CPU(SMP)
中断优先级 固定 8 级 256 级可编程
中断分发策略 固定到 BSP 可配置(轮询、固定、最低优先级)
MSI 支持 不支持 原生支持
可编程性 低 高(通过 IOREDTBL)
APIC/IOAPIC 中断架构 APIC / IOAPIC 中断架构 外设 网卡 磁盘 USB IOAPIC I/O 中断控制器 IOREDTBL[0..23] 中断重定向表 系统总线 中断消息 LAPIC (CPU0) 本地中断控制器 LAPIC (CPU1) 本地中断控制器 中断分发流程 外设 → IOAPIC(查重定向表)→ 系统总线(中断消息)→ 目标 LAPIC → CPU 核心 → IDT → ISR

1.4 中断处理流程与性能关键点

一个完整的中断处理流程涉及硬件和软件的紧密协作:

  1. 外设触发中断:网卡收到数据包后,通过 PCIe 总线发送 MSI/MSI-X 中断消息。
  2. IOAPIC 接收并重定向:IOAPIC 根据 IOREDTBL 配置,将中断消息发送到指定 CPU 的 LAPIC。
  3. LAPIC 接收并递交给 CPU:LAPIC 检查中断优先级,如果高于当前 CPU 优先级,则触发 CPU 中断。
  4. CPU 查找 IDT:CPU 保存当前上下文,根据中断向量号在 IDT 中找到对应的门描述符。
  5. 执行 ISR:CPU 跳转到 ISR 入口,执行中断处理逻辑(如网卡驱动中的 handle_irq)。
  6. 中断结束(EOI):ISR 执行完毕后,向 LAPIC 写入 EOI 命令,允许后续中断。
性能陷阱: 在传统中断模式下,每个数据包到达都会触发一次中断。高吞吐量场景下(如 10Gbps 网络),每秒可能产生数十万次中断,导致 CPU 频繁上下文切换,缓存污染严重。这正是 NAPI 轮询机制要解决的核心问题——在中断与轮询之间找到平衡点。

1.5 中断亲和性(IRQ Affinity)

通过设置中断亲和性,可以将特定外设的中断绑定到指定 CPU 核心上处理。这在多核系统中至关重要,可以避免中断在多个核心间迁移导致的缓存失效。

配置方法 命令/路径 说明
查看 IRQ 统计 cat /proc/interrupts 显示每个中断号在各 CPU 上的处理次数
设置亲和性 echo 1 > /proc/irq/{IRQ_NUM}/smp_affinity 写入 CPU 位图(十六进制),1 表示 CPU0
设置亲和性列表 echo 0-3 > /proc/irq/{IRQ_NUM}/smp_affinity_list 直接指定 CPU 列表
查看当前分发策略 cat /proc/irq/{IRQ_NUM}/smp_affinity 返回当前绑定的 CPU 位图
调优建议: 对于网络密集型的应用,建议将网卡中断绑定到与应用程序不同的 CPU 核心上,避免中断处理与应用线程争抢 CPU 资源。例如,将 IRQ 绑定到 CPU0-1,应用运行在 CPU2-3。使用 irqbalance 服务可以自动平衡中断分布,但在极致性能场景下建议手动绑定。

1.6 本章小结