在以太网端口上接收网络数据和 apache2 做某事之间会发生什么?

Mah*_*koe 1 apache hardware networking linux-device-driver linux-kernel

这是一个模糊的问题,因为我自己的理解也同样模糊。我感兴趣的是网络电缆上的零星电压需要发生什么才能导致计算机上运行的程序执行某些操作。

假设我在我的网络服务器上运行 apache2。有人在自己的联网计算机上触发了正确的事件序列,从而导致网络数据到达服务器。然后呢?

我的猜测是主板上有一些外围组件可以侦听数据,然后在 CPU 中引发中断。不知何故,在中断服务例程中,Linux 必须要求 apache2 代码做一些事情。这样对吗?如果是这样,有人愿意分享一些额外的细节吗?

谢谢

Jon*_*art 5

我将概述自下而上发生的事情,并尽可能引用代码。

第 1 层 (PHY)

  • 以太网卡(NIC)接收并解码线上的信号,并将其推入移位寄存器

    • 有关*BASE-T 以太网的每个变体的线路代码详细信息,请参阅双绞线以太网
  • 当接收到完整的以太网帧时,它被放入硬件中的接收 (RX) 队列中

  • NIC引发中断,利用总线专用机构(无论是PCI IRQ线,或消息信号中断
  • 中断控制器( APIC ) 接收中断并将其定向到 CPU
  • CPU 保存运行上下文并切换到中断上下文
  • CPU 加载中断处理程序向量并开始执行它

IRQ 可以被多个设备共享。内核必须弄清楚哪个设备实际上正在中断。我将提到e100.c驱动程序,因为它是在一个 C 文件中实现的,并且得到了很好的评论。

  • Linux 内核查看共享此 IRQ 的所有设备,调用其驱动程序以确定实际引发此中断的设备。调用的驱动程序函数是驱动程序传递给 的任何内容request_irq。(见for_each_action_of_desc()中__handle_irq_event_percpu())。
  • 共享此 IRQ 的设备的每个驱动程序将查看其设备的状态寄存器以查看它们是否有待处理的中断
  • NIC 驱动程序中断处理程序(例如e100_intr())看到 NIC 确实中断了。它禁用设备中断(例如e100_disable_irq())并安排 NAPI 回调(__napi_schedule())。NIC 驱动程序通过返回IRQ_HANDLED. 中断结束。
  • Linux 内核 NAPI 子系统回调 NIC 驱动程序(例如e100_poll),它从 NIC RX 队列中读取数据包并将其放入struct sk_buff(SKB)中,并将其推送到内核网络堆栈中(例如e100_rx_indicate())。

出于性能原因,整个 TCP/IP 堆栈在 Linux 内核中实现:

第 2 层 (MAC)

  • 内核以太网层查看以太网数据包并验证它是否以本机的 MAC 地址为目的地
  • 以太网以太网层看到 Ethertype == IP,将其交给 IP 层
    • 请注意,协议实际上是由设备驱动程序设置的(​​例如在 中e100_indicate())。

第 3 层 (IP)

  • 内核 IP 层接收数据包 ( ip_rcv())
  • 内核 IP 层将所有 IP 片段排队
  • 当收到所有 IP 碎片时,它会处理 IP 数据包。它查看协议字段,看到它是 TCP,将其交给 TCP 层

第 4 层 (TCP)

  • 内核 TCP 层接收数据包 ( tcp_v4_rcv())。
  • 内核 TCP 层查看 src/dst IP/port 并将其与打开的 TCP 连接(套接字)(tcp_v4_rcv()调用__inet_lookup_skb())匹配。

如果是SYN包(新连接):

  • TCP 会看到有一个监听套接字打开了 80 端口
  • TCP 为这个新连接创建一个新的连接对象
  • 内核唤醒正在休眠、在accept通话中被阻塞的任务——或者select

如果不是SYN包(有数据):

  • 内核将来自该段的 TCP 数据在套接字上排队
  • 内核唤醒一个处于睡眠状态、被recv调用阻塞的任务- 或select( sock_def_readable())

第 5 层(应用程序 - HTTP)

Apache ( httpd) 将被唤醒,具体取决于它被阻塞的系统调用:

  • accept()当新的子连接可用时返回(这是用一个名为 的包装器处理的apr_socket_accept()

  • recv() 当套接字有新数据时返回,该数据已被读入用户空间缓冲区

    • Apache 处理缓冲区,解析 HTTP 协议字符串

其他资源