接收路由查找

IP层接到一个数据包以后,如果需要进行路由,就调用函数myip_route_input, myip_route_input先在缓存里寻找路由,如果失败则调用myip_route_input_slow, myip_route_input_slow调用myfib_lookup在路由表里寻找路由,如果命中,首先在缓存里添加这个路由,然后返回结果。
    路由缓存的数据结构是一个全局哈希表myrt_hash_table,前面文章讲过,该哈希表在模块初始化时被分配了4096个入口。哈希表的每一项都是 一个rtable结构的链表。每一个rtable数据结构都存放向一个IP主机发送报文的路由信息。下面是结构体struct rtable的定义:
    struct rtable
    {
        union{
            struct dst_entry    dst;
            struct rtable       *rt_next;
        }u;
        struct in_device    *idev;
        unsigned        rt_flags;
        __u16           rt_type;
        __u16           rt_multipath_alg;

        __u32           rt_dst;
        __u32           rt_src;
        int             rt_iif;

        __u32           rt_gateway;
        struct flowi    fl;
        __u32           rt_spec_dst;
        struct inet_peer    *peer;
    };
    接收到的数据包,可能是组播包,也可能是广播包,情况比较复杂,对此myip_route_input_slow都有对应的处理,为了简单起见,我们以一个ARP请求包为例来说明myip_route_input的“一部分”工作流程。
    给我的网络设备接口eth0配置一个secondary地址172.16.48.11(其主地址是172.16.48.2),这样在路由表的local表里就多了一项:
        :          the key ip: 172.16.48.11
        :          the alias:
        :              fa tos: 0
        :              fa type: RTN_LOCAL
        :              fa scope: RT_SCOPE_HOST
        :              fa state: 0
        :              the fa info:
        :                  tree ref: 2
        :                  clnt ref: 1
        :                  fib_dead: 0
        :                  fib flags: 0
        :                  protocol: 2
        :                  pref src: 172.16.48.2.
        :                  priority: 0
        :                  fib_mtu: 0
        :                  fib_window: 0
        :                  fib_power: 0
        :                  fib_nhs: 1
        :                  all the nhs:
        :                      0.16.48.2
    当我们收到来自172.16.48.1的一个对172.16.48.11的ARP请求包时。我们需要对接收到的数据包进行路由查询,这样调用myip_route_input:
        myip_route_input(skb, dst=172.16.48.11, src=172.16.48.1, tos=0, dev)
    因为是第一次,路由缓存中并没有我们要找的路由,所以该函数以同样的参数列表调用myip_route_input_slow接口。 myip_route_input_slow先进行一系例判断,当确定该数据包是单播包时,调用myfib_lookup进行路由查找。 myfib_lookup使用内置的路由规则,先查找local表,查找成功。
    然后,对全局变量myrt_cache_stat的in_slow_tot加1,记录本次进入myip_route_input_slow查找路由。后面还会有很多操作,会相应的更新这个状态结构,不再进行描述。
    路由表查询的结果是由结构struct fib_result表示的,此次查询结果的类型是RTN_LOCAL,表示这个数据包是要本地接收的,而不是转发的。接下来,我们要做的一件事情就是确 认这个数据包的源地址的有效性,方法是把源地址和目的地址反向,再去查找路由表,即查找172.16.48.11->172.16.48.1的路 由。显然,这次我们在main表中查到了type为RTN_UNICAST的路由,即源地址是有效的。
    接下来,分配一个结构struct rtable,并进行初始化,主要是其成员fl,这是一个结构体struct flowi。里面填充数据包的源和目的地址的详细信息,还有输入网络设备接口,tos等详细信息。
    最后我们要做的一件事情就是把这个新创建出来的rtable放到路由缓存中,先确定在myrt_hash_table中的具体哪一项,然后在链表中搜索, 如果发现这个rtable已经存在,则把它提到链表头,同时,销毁创建出来的rtable。关于路由缓存的垃圾回收算法等细节,我们再进行专门分析。
    前面我们看到在调用myip_route_input时,第一个参数是skb,最后,我们需要把创建出来的rtable赋给skb->dst。
    接下来,我们再看一个例子,如果我在172.46.48.1 ping 172.16.48.10。这是一个不存在的ip地址,当172.16.48.1发出ARP请求包时,会发生什么事情?
    显然,在查找路由时,我们可以在main表中查到一个RTN_UNICAST的路由,表示不是本地接收,可能本地只是一个网关,或者需要转发。但这个包显然是不需要转发的,所以,我们得到的返回值是:无可达路由。
<think>好的,我需要处理用户关于递归实现路由的查询。首先,用户提到参考了站内的四个引用,其中引用[1]和[3]提到了递归在路由中的应用,引用[4]是关于二叉树后序遍历的递归算法。我需要结合这些信息来生成相关的代码示例和解释。 首先,根据引用[1],递归在路由匹配中的应用主要是处理嵌套的子路由。用户提供的示例代码展示了如何通过递归遍历路由配置,匹配当前路径。代码中的match方法接收routes参数,并递归检查子路由。我需要解释这段代码的逻辑,说明递归如何帮助处理多层路由结构。 接着,引用[3]提到路由递归查询,即通过递归查找下一跳地址,直到找到直连路由。这里需要解释路由表中的递归查询过程,可能给出伪代码示例,说明如何通过递归解析下一跳地址。 然后,用户需要代码示例。根据引用[1]的路由匹配代码,可以将其转化为JavaScript的简化示例,展示递归查找路由的过程。同时,引用[4]的二叉树遍历虽然与路由无关,但递归的思想是相通的,可能需要避免混淆,专注于路由相关的递归实现。 还要注意用户提到的系统级指令,比如正确使用LaTeX格式,生成相关问题。需要确保回答中的数学表达式正确使用$...$,独立公式用$$...$$,但当前问题可能不涉及太多数学公式,可能不需要使用。 最后,生成相关问题需要考虑递归在路由中的应用场景、递归与迭代的对比、错误处理以及路由递归查询的具体例子。确保问题与用户查询相关,帮助用户深入理解。 总结步骤: 1. 分析用户提供的引用,提取递归在路由中的应用点。 2. 根据引用[1]的路由匹配代码,解释递归如何处理嵌套路由。 3. 根据引用[3]的路由递归查询,解释并给出伪代码示例。 4. 提供JavaScript和伪代码示例,展示递归实现。 5. 生成相关问题,引导用户进一步学习。</think>以下是根据您需求整理的递归实现路由相关技术解析和代码示例: ### 一、递归在路由中的典型应用 1. **路由匹配(引用[1])** JavaScript示例实现嵌套路由匹配: ```javascript class Router { constructor(routes) { this.routes = routes; this.matched = []; } match(path, routes) { routes = routes || this.routes; for (const route of routes) { if (route.path === path) { this.matched.push(route); return; } if (route.children) { this.match(path, route.children); // 递归核心 } } } } ``` *实现逻辑:* - 首次传入根路由表 - 逐层比对当前路径 - 发现子路由时递归调用自身 - 匹配成功时记录路由对象 2. **路由递归查询(引用[3])** 网络路由伪代码示例: ```python def find_next_hop(target, current_hop): route = routing_table[current_hop] if route.is_direct: return current_hop else: return find_next_hop(target, route.next_hop) # 递归核心 ``` ### 二、关键技术点解析 1. **递归终止条件** - 路径完全匹配($path_{current} = path_{target}$) - 找到直连路由($route_{next} \in direct\_links$) 2. **递归深度控制** - 设置最大递归深度限制($depth_{max} = 10$) - 路径规范化处理(移除冗余`//`) 3. **性能优化** - 记忆化技术缓存查询结果 - 尾递归优化(在支持的语言中) ### 三、路由递归的数学表达 对于路由表$R$,目标地址$t$,递归函数可表示为: $$ f(t, r_i) = \begin{cases} r_i & \text{if } r_i \text{ is direct route} \\ f(t, r_{i+1}) & \text{otherwise} \end{cases} $$ 其中$r_{i+1}$是下一跳路由信息[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值