本文主要是介绍路由下一跳中的变数exception,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
内核通过查询转发信息表(fib_lookup),得到下一跳(fib_nh),从而得到了关于此条路由的相关信息,其中重要的包括下一跳设备nh_dev,下一跳网关nh_gw等。然而,关于此条路由可能存在两个变数exception,其一是这条路由相关的路径MTU(PMTU)发生改变;其二是收到了关于此条路由的ICMP重定向报文。由于此两种改变并不是永久的,内核将他们保存在下一跳fib_nh的exception中。
路径MTU改变
内核接收到目的地址不可达(ICMP_DEST_UNREACH)类型的ICMP消息,判断其code为ICMP_FRAG_NEEDED,需要更新pmtu。此时,内核会创建一个下一跳exception(fnhe)保存新的mtu值:
static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
{if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {struct fib_nh *nh = &FIB_RES_NH(res);update_or_create_fnhe(nh, fl4->daddr, 0, mtu,jiffies + ip_rt_mtu_expires);}
}
路由重定向
内核接收到重定向(ICMP_REDIRECT)类型的ICMP消息,调用update_or_create_fnhe函数创建或者更新路由下一跳exception,设置新的网关地址new_gw。
static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4, bool kill_route)
{//ICMP头中给出了重定向的新网关IP地址。__be32 new_gw = icmp_hdr(skb)->un.gateway;//发送此ICMP消息的设备为旧网关,saddr为其IP地址__be32 old_gw = ip_hdr(skb)->saddr;struct neighbour *n;n = __ipv4_neigh_lookup(rt->dst.dev, new_gw);if (!n)n = neigh_create(&arp_tbl, &new_gw, rt->dst.dev);if (!IS_ERR(n)) {if (fib_lookup(net, fl4, &res, 0) == 0) {struct fib_nh *nh = &FIB_RES_NH(res);update_or_create_fnhe(nh, fl4->daddr, new_gw,0, jiffies + ip_rt_gc_timeout);}}
}
路由exception查询
查询操作会跳过下一跳(fib_nh->nh_gw下一跳中的nh_gw的值可能已不是最新),首先查询是否存在exception,如果存在,rtable使用exception保存的相关值,包括fnhe_pmtu、fnhe_gw等。
static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
{rt->rt_pmtu = fnhe->fnhe_pmtu;rt->dst.expires = fnhe->fnhe_expires;if (fnhe->fnhe_gw) {rt->rt_flags |= RTCF_REDIRECTED;rt->rt_gateway = fnhe->fnhe_gw;rt->rt_uses_gateway = 1;}
}
内核版本
linux-4.14.4
这篇关于路由下一跳中的变数exception的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!