下半部分的数据包流
Packet flow in bottom half
我正在阅读有关从 NIC 中断处理程序到用户的接收路径中的数据包流 space。
我想知道新分配的 skbuff 在 bottom half 上下文中保留到什么时候。
从 LDD 获取 snull_rx() 代码:
void snull_rx(struct net_device *dev, struct snull_packet *pkt)
{
struct sk_buff *skb;
struct snull_priv *priv = netdev_priv(dev);
/*
* The packet has been retrieved from the transmission
* medium. Build an skb around it, so upper layers can handle it
*/
skb = dev_alloc_skb(pkt->datalen + 2);
if (!skb) {
if (printk_ratelimit( ))
printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n");
priv->stats.rx_dropped++;
goto out;
}
memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
/* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
priv->stats.rx_packets++;
priv->stats.rx_bytes += pkt->datalen;
netif_rx(skb);
out:
return;
}
那么在 netif_rx(skb) 之后 skb 会停留在下半部分吗?
谢谢。
上面的代码在硬件中断上下文中运行
netif_rx 将数据包排队并向内核发出信号以在 SOFTIRQ 上下文 (NET_RX)
上继续
编辑:我写了一篇博客 post 概述了整个 linux 网络堆栈(接收路径),提供了大量详细信息, take a look.
答案很复杂,但是是的,netfilter 代码在 softirq 上下文中运行。
流程的工作方式是这样的:
- 一个数据包到达,启用NAPI。
- 软 irq 上下文中的 NAPI 内核线程 运行(
/proc/softirqs
中的NET_RX_SOFTIRQ
)从内存(NIC DMA 处理数据的地方)收集数据包。
- softirq 最多只能消耗其
budget
个数据包或数据包处理的时间限制。你可以找到这个代码 here.
- 这可以防止 softirq 消耗整个 CPU。
- 最终,函数
__netif_receive_skb_core
被调用。此函数的确切路径取决于驱动程序,但对于 e1000e
,路径是:
- NAPI 软中断调用
e1000e_poll
e1000e_poll
呼叫 e1000_clean_rx_irq
e1000_clean_rx_irq
呼叫 e1000_receive_skb
e1000_receive_skb
呼叫 napi_gro_receive
napi_gro_receive
呼叫 napi_skb_finish
napi_skb_finish
呼叫 netif_receive_skb
netif_receive_skb
呼叫 netif_receive_skb
netif_receive_skb
呼叫 __netif_receive_skb_core
- 根据您是否使用接收数据包控制,此处的代码路径会略有不同。
- 无论哪种情况,最终数据包都会被传送到协议层 here。
- 如果我们将 IP 视为我们选择的协议,数据包将被传递到
ip_rcv
,这也将 check netfilter。
- 数据包继续通过每个协议栈,直到通过调用
sock_queue_rcv_skb
排队到套接字的接收缓冲区。例如,UDP 从名为 __udp_queue_rcv_skb
. 的函数中执行 here
- 函数
sock_queue_rcv_skb
将数据排队到套接字接收缓冲区。您可以找到此代码 here.
一些注意事项:
- 您可以通过更改 sysctl
net.core.netdev_budget
为 NAPI 调整 budget
。预算越高,排队到进程接收队列的数据包就越多,但是 CPU 用于 运行 用户进程的时间会更少。
- 如果您的 NIC 支持多个 RX 队列,您可以在多个 CPU 之间分配传入数据包处理负载。
- 如果您的 NIC 不支持多个 RX 队列,您可以使用 Receive Packet Steering 在多个 CPU 之间分配数据包处理负载。
如果您对这个过程有任何其他问题我可以回答,请告诉我。
我正在阅读有关从 NIC 中断处理程序到用户的接收路径中的数据包流 space。
我想知道新分配的 skbuff 在 bottom half 上下文中保留到什么时候。
从 LDD 获取 snull_rx() 代码:
void snull_rx(struct net_device *dev, struct snull_packet *pkt)
{
struct sk_buff *skb;
struct snull_priv *priv = netdev_priv(dev);
/*
* The packet has been retrieved from the transmission
* medium. Build an skb around it, so upper layers can handle it
*/
skb = dev_alloc_skb(pkt->datalen + 2);
if (!skb) {
if (printk_ratelimit( ))
printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n");
priv->stats.rx_dropped++;
goto out;
}
memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
/* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
priv->stats.rx_packets++;
priv->stats.rx_bytes += pkt->datalen;
netif_rx(skb);
out:
return;
}
那么在 netif_rx(skb) 之后 skb 会停留在下半部分吗?
谢谢。
上面的代码在硬件中断上下文中运行 netif_rx 将数据包排队并向内核发出信号以在 SOFTIRQ 上下文 (NET_RX)
上继续编辑:我写了一篇博客 post 概述了整个 linux 网络堆栈(接收路径),提供了大量详细信息, take a look.
答案很复杂,但是是的,netfilter 代码在 softirq 上下文中运行。
流程的工作方式是这样的:
- 一个数据包到达,启用NAPI。
- 软 irq 上下文中的 NAPI 内核线程 运行(
/proc/softirqs
中的NET_RX_SOFTIRQ
)从内存(NIC DMA 处理数据的地方)收集数据包。 - softirq 最多只能消耗其
budget
个数据包或数据包处理的时间限制。你可以找到这个代码 here. - 这可以防止 softirq 消耗整个 CPU。
- 最终,函数
__netif_receive_skb_core
被调用。此函数的确切路径取决于驱动程序,但对于e1000e
,路径是:- NAPI 软中断调用
e1000e_poll
e1000e_poll
呼叫e1000_clean_rx_irq
e1000_clean_rx_irq
呼叫e1000_receive_skb
e1000_receive_skb
呼叫napi_gro_receive
napi_gro_receive
呼叫napi_skb_finish
napi_skb_finish
呼叫netif_receive_skb
netif_receive_skb
呼叫netif_receive_skb
netif_receive_skb
呼叫__netif_receive_skb_core
- NAPI 软中断调用
- 根据您是否使用接收数据包控制,此处的代码路径会略有不同。
- 无论哪种情况,最终数据包都会被传送到协议层 here。
- 如果我们将 IP 视为我们选择的协议,数据包将被传递到
ip_rcv
,这也将 check netfilter。 - 数据包继续通过每个协议栈,直到通过调用
sock_queue_rcv_skb
排队到套接字的接收缓冲区。例如,UDP 从名为__udp_queue_rcv_skb
. 的函数中执行 here
- 函数
sock_queue_rcv_skb
将数据排队到套接字接收缓冲区。您可以找到此代码 here.
一些注意事项:
- 您可以通过更改 sysctl
net.core.netdev_budget
为 NAPI 调整budget
。预算越高,排队到进程接收队列的数据包就越多,但是 CPU 用于 运行 用户进程的时间会更少。 - 如果您的 NIC 支持多个 RX 队列,您可以在多个 CPU 之间分配传入数据包处理负载。
- 如果您的 NIC 不支持多个 RX 队列,您可以使用 Receive Packet Steering 在多个 CPU 之间分配数据包处理负载。
如果您对这个过程有任何其他问题我可以回答,请告诉我。