linux vrf icmp reply /vrf icmp 响应错误消息

static inline void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
{
	__icmp_send(skb_in, type, code, info, IPCB(skb_in));
}

  

static inline void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
{
	__icmp_send(skb_in, type, code, info, IPCB(skb_in));
}

  

内核协议栈中:

  ip_rcv_core
    IPCB(skb)->iif = skb->skb_iif;
  
  vrf_ip_rcv
    skb->dev = vrf_dev;
    skb->skb_iif = vrf_dev->ifindex;
    IPCB(skb)->flags |= IPSKB_L3SLAVE;
  • 保存现场: 当数据包刚被网卡接收时,ip_rcv_core 会立即把当前的入接口索引(skb->skb_iif)备份到控制块(IPCB(skb)->iif)中。

  • VRF 干扰: 随后,如果配置了 VRF,VRF 驱动(drivers/net/vrf.c)会接管数据包,并修改 skb->skb_iif 为 VRF 虚拟设备的索引。

  • 恢复现场: 当需要发送 ICMP 错误消息时(比如在 icmp.c 中),skb->skb_iif 已经被改写了,不再是物理接口。这时,代码就会去读之前备份在 parm->iif 中的原始值,从而向正确的接口报告错误。

  当内核生成 ICMP 错误消息时,它去读 skb->skb_iif,读到的是 VRF 设备。结果就是,ICMP 消息的源 IP 变成了 VRF 设备的 IP(或者 VRF 下其他端口的 IP),而不是真正接收数据包的物理接口 IP。

  运行 traceroute 时,显示的路径节点 IP 是错的

 

bugfix:

  • 核心逻辑: 不要直接读取已经被 VRF 修改过的 skb->skb_iif

  • 新方法: 改为读取**控制块(Control Block)**中的 iif 字段。

image

 traceroute 的核心就是依赖设备返回:

ICMP Time Exceeded

而返回 ICMP 时内核必须要构造 ICMP 包 → 就会执行这段代码。

 

 

posted @ 2025-12-10 19:41  codestacklinuxer  阅读(3)  评论(0)    收藏  举报