当前位置: 首页 > news >正文

Linux ip_rcv_finish路由缓存查找与dst_entry绑定

Linux ip_rcv_finish路由缓存查找与dst_entry绑定

ip_rcv_finish 是IPv4接收路径上NF_INET_PRE_ROUTING钩子之后、路由决策之前的核心函数。它的主要职责是对输入数据报执行路由查找,将结果缓存的 dst_entry 绑定到 skb 上,供后续处理(转发或本地交付)使用。

一、 ip_rcv_finish的调用链

数据报从网卡经过 GRO 处理后进入 netif_receive_skb,逐级到达 ip_rcv,经过 NF_INET_PRE_ROUTING 钩子后调用 ip_rcv_finish:

int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
const struct iphdr *iph = ip_hdr(skb);
int err;
int rt_type;
struct rtable *rt;

/* 步骤1:尝试使用early_demux或input route cache加速查找 */
if (skb_dst(skb) == NULL) {
int dscp = iph->tos & IPTOS_TOS_MASK;

/* 路由查找 */
rt = ip_route_input_noref(skb, iph->daddr, iph->saddr,
dscp, skb->dev);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
goto drop;
}
}

/* 步骤2:根据路由类型分流处理 */
rt = skb_rtable(skb);
rt_type = rt->rt_type;

if (rt_type == RTN_MULTICAST) {
/* 多播路由处理 */
__IP_INC_STATS(net, IPSTATS_MIB_INMCASTPKTS);
} else if (rt_type == RTN_BROADCAST) {
/* 广播路由处理 */
__IP_INC_STATS(net, IPSTATS_MIB_INBCASTPKTS);
} else if (rt_type == RTN_LOCAL) {
/* 本地交付 */
} else if (rt_type == RTN_UNICAST) {
/* 单播转发 */
}

/* 步骤3:调用NF_INET_FORWARD或NF_INET_LOCAL_IN钩子 */
return dst_input(skb);
}

核心操作是调用 ip_route_input_noref 执行路由查找。该函数返回 struct rtable 指针并绑定到 skb->_skb_refdst 字段。

二、 ip_route_input_noref的查找逻辑

ip_route_input_noref 封装了路由查找的三个层级,定义于 net/ipv4/route.c:

int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct rtable *rt;
struct net *net = dev_net(dev);
int err;

/* 层级1:首先尝试路由缓存查找 */
rt = ip_route_input_slow(skb, daddr, saddr, tos, dev);
if (IS_ERR(rt))
return PTR_ERR(rt);

/* 绑定路由表项到skb */
skb_dst_set_noref(skb, &rt->dst);

return 0;
}

旧内核(4.16之前)使用路由缓存(rt_hash_table),查找路径为:缓存 -> FIB。新内核完全基于FIB查找,去掉了中央路由缓存以减少RCU锁竞争。

三、 FIB查找入口:fib_lookup

ip_route_input_slow 最终调用 fib_lookup 执行路由表查询:

static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct fib_result res;
struct rtable *rt;
struct net *net = dev_net(dev);
int err;
int flags = 0;
struct in_device *in_dev = __in_dev_get_rcu(dev);
struct flowi4 fl4 = {
.daddr = daddr,
.saddr = saddr,
.flowi4_tos = tos & IPTOS_RT_MASK,
.flowi4_oif = 0,
.flowi4_iif = dev->ifindex,
};

/* 执行路由查找 */
err = fib_lookup(net, &fl4, &res, 0);
if (err) {
/* 未命中路由,丢弃并发送ICMP Dest Unreach */
res.fi = NULL;
goto no_route;
}

/* 根据查表结果构造struct rtable */
rt = __mkroute_input(skb, &res, &fl4, in_dev, daddr, saddr, tos);
if (IS_ERR(rt))
return PTR_ERR(rt);

/* 设置skb的路由缓存 */
skb_dst_set(skb, &rt->dst);
return 0;
}

fib_lookup 返回 struct fib_result,包含命中的路由表项 fib_info 和路由类型(RTN_LOCAL/RTN_UNICAST等)。__mkroute_input 根据这些信息分配并初始化 rtable。

四、 dst_entry的绑定与释放

skb_dst_set 的实现分为引用计数管理模式。普通模式使用 skb_dst_set,而 ip_route_input_noref 使用 skb_dst_set_noref:

static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
}

static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
skb->_skb_refdst = (unsigned long)dst;
dst_hold(dst);
}

区别在于 skb_dst_set_noref 不增加dst_entry的引用计数,依赖RCU保护保证dst_entry不会在skb处理过程中被释放。这减少了原子操作的缓存一致性开销。路由缓存在RCU读锁保护下有效,如果内核需要将skb传递给其他上下文(如加入队列),必须调用 skb_dst_force 将NOREF转换为引用计数模式。

五、 多播/广播/本地路由的特殊处理

当路由类型为 RTN_LOCAL 时,ip_route_input_slow 调用 ip_local_deliver 处理:

if (res.type == RTN_LOCAL) {
/* 本地交付路由 */
rt = rt_dst_alloc(in_dev->dev, ...);
rt->rt_type = RTN_LOCAL;
rt->dst.input = ip_local_deliver;
skb_dst_set(skb, &rt->dst);
return 0;
}

对于多播,内核有独立的输入路径:

err = ip_route_input_mc(skb, daddr, saddr, tos, dev, &res);
if (!err) {
rt = skb_rtable(skb);
rt->rt_type = RTN_MULTICAST;
rt->dst.input = ip_local_deliver; /* 多播同时本地交付 */
return 0;
}

多播路由的 dst.input 设置为 ip_local_deliver,意味着多播数据报既会被本地交付,也可能被转发(如果启用了多播路由)。

六、 dst_input调用与后续路径

ip_rcv_finish 的最后一步调用 dst_input,展开为调用 dst->input:

static inline int dst_input(struct sk_buff *skb)
{
return skb_dst(skb)->input(skb);
}

对于单播转发,dst->input 是 ip_forward;对于本地交付,dst->input 是 ip_local_deliver。这个函数指针在路由查找阶段由 __mkroute_input 或 rt_dst_alloc 设置。

七、 路由查找的性能优化

ip_route_input_noref 使用了多项优化:
- ip_route_input_slow 的结果不会缓存到中央哈希表,但per-cpu的cache hit仍然存在
- 使用 RCU 保护的 FIB Trie 查找而不是旧的路由缓存
- 通过 fib_multipath_hash 实现等价多路径的哈希分发

当路由查找失败时,ip_route_input_slow 发送 ICMP Destination Unreachable(Network Unreachable)并丢弃数据报:

no_route:
/* 发送ICMP Network Unreachable */
rt = rt_dst_alloc(dev, ...);
rt->rt_type = RTN_UNREACHABLE;
rt->dst.error = -EHOSTUNREACH;
rt->dst.output = ip_error;
...

ip_rcv_finish 通过将路由查找结果以 dst_entry 形式绑定到 skb,为后续处理提供了完整的转发/交付决策依据。该绑定贯穿skb的整个生命周期,直到skb被消费(本地交付)或转发(发送)后释放。

http://www.gsyq.cn/news/1516303.html

相关文章:

  • Proteus仿真DAC0832生成三角波:手把手教你用AT89C52单片机搞定(附完整代码与电路图)
  • 2026九江本地企业认可的 5 家电能质量评估服务机构实地测评汇总 - 中检检测集团
  • 2026年自贡市黄金回收白银回收铂金回收彩金回收 地址联系大全+支持现场结算无套路 - 前途无量YY
  • CopilotKit:打造安全高效的 Agent 应用前端框架,小白也能轻松构建大模型交互界面
  • 毕业设计避坑指南:手把手教你搞定110kV变电站电气一次部分设计(附CAD图纸)
  • ChatGLM2-6B的‘瑞士军刀’:拆解GLMBlock里的SwiGLU与RMSNorm
  • 嵌入式开发避坑指南:汽车ECU刷写中Flash Driver的RAM地址分配与安全设计要点
  • 2026最新诚信优选深圳市黄金回收白银回收铂金回收彩金回收去哪卖?五家实地探访靠谱门店汇总及联系方式推荐 - 亦辰小黄鸭
  • DLOS:面向大语言模型输出的治理操作系统
  • 2026广西市民高频选择的 5 家实体水质检测饮用水检测井水检测第三方实地测评整理 - 诚金汇钻回收公司
  • 百度网盘提取码查询终极指南:3步告别繁琐搜索的免费神器
  • 2026最新诚信优选瑞安市黄金回收白银回收铂金回收彩金回收去哪卖?五家实地探访靠谱门店汇总及联系方式推荐 - 亦辰小黄鸭
  • Pandas DataFrame核心原理:索引与向量化操作实战指南
  • 2026 年 6 月 13 日 房贷压力大,跌势里卖金还月供值不值?永康黄金回收靠谱实体店 - 回收测评
  • AMD AI 开发者计划学习笔记:从 ROCm 到 Ryzen AI,理解 AMD 的 AI 开发生态
  • 2026音频转文字大师合集,电脑手机免费工具专业软件使用教程
  • 绕过GetProcAddress检测:手写PE解析器实现安全的LdrLoadDll挂钩(含x64汇编细节)
  • FPGA设计提速:利用Vivado时序路径报告中的‘Logic Levels’和‘Cell Delay’优化关键路径
  • 2026最新诚信优选咸宁市黄金回收白银回收铂金回收彩金回收去哪卖?五家实地探访靠谱门店汇总及联系方式推荐 - 亦辰小黄鸭
  • paperxie 科研提速神器!分档适配普通 / 核心 / SCI,期刊论文 AI 创作全流程拆解
  • 2026甘肃省市民高频选择的 5 家实体水质检测饮用水检测井水检测第三方实地测评整理 - 诚金汇钻回收公司
  • 2026免费PDF合并工具保姆级教程!在线+桌面端一键搞定
  • 保姆级教程:手把手教你用ROS调试EGO_Planner的轨迹服务器(traj_server.cpp)
  • 保姆级拆解:CODESYS 3.5.19 Robotics例程里,PickAndPlace的坐标变换到底是怎么玩的?
  • 告别开发板!用面包板+STC32G12K128搭建你的第一个单片机系统(Keil C251环境保姆级配置)
  • 2026阜阳本地企业认可的 5 家电能质量评估服务机构实地测评汇总 - 中检检测集团
  • Paperxie 论文格式一站式托管,四千校专属模板一键校准学业文稿版式
  • 2026东营本地企业认可的 5 家电能质量评估服务机构实地测评汇总 - 中检检测集团
  • 2026年嵊州市黄金回收白银回收铂金回收彩金回收 地址联系大全+支持现场结算无套路 - 前途无量YY
  • 金税四期下,衡水企业该怎样挑选靠谱财税咨询机构? - 百航