linux内核 路由fib表之输出查找
来源:互联网 发布:中国体育彩票关注软件 编辑:程序博客网 时间:2024/06/05 11:14
2.2.3.2 输出路由查找
ip_route_output_key
功能:
调用ip_route_output_flow
ip_route_output_flow
功能:
1)路由发包查找
2)ipsec处理流程
功能:
查找路由缓存
未找到缓存,慢速发送
功能:
查路由表
不论是否查到,都进行策略路由查找
ip_route_output_key
功能:
调用ip_route_output_flow
ip_route_output_flow
功能:
1)路由发包查找
2)ipsec处理流程
int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,struct sock *sk, int flags)//参数说明:net为网络设备;// rp当查询成功,返回查询到的路由缓存项;// flp用于查询缓存项的条件;// sk,flags用于ipsec路由查找{ int err; //路由查找 if ((err = __ip_route_output_key(net, rp, flp)) != 0) return err; //ipsec路由查找 if (flp->proto) { if (!flp->fl4_src) flp->fl4_src = (*rp)->rt_src; if (!flp->fl4_dst) flp->fl4_dst = (*rp)->rt_dst; err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, flags ? XFRM_LOOKUP_WAIT : 0);//ipsec处理 if (err == -EREMOTE) err = ipv4_dst_blackhole(net, rp, flp); return err; } return 0;}__ip_route_output_key
功能:
查找路由缓存
未找到缓存,慢速发送
int __ip_route_output_key(struct net *net, struct rtable **rp,const struct flowi *flp){ unsigned hash; struct rtable *rth; if (!rt_caching(net)) //查路由缓存 goto slow_output; hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));//计算hash rcu_read_lock_bh(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; rth = rcu_dereference(rth->u.dst.rt_next)) { if (rth->fl.fl4_dst == flp->fl4_dst && rth->fl.fl4_src == flp->fl4_src && rth->fl.iif == 0 && rth->fl.oif == flp->oif && rth->fl.mark == flp->mark && !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && net_eq(dev_net(rth->u.dst.dev), net) && !rt_is_expired(rth)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(out_hit); rcu_read_unlock_bh(); *rp = rth; //将路由缓存表项取出 return 0; } RT_CACHE_STAT_INC(out_hlist_search); } rcu_read_unlock_bh();slow_output: return ip_route_output_slow(net, rp, flp);//慢速发送}2.2.3.2.1 ip_route_output_slow慢速查找输出
功能:
查路由表
不论是否查到,都进行策略路由查找
程序流程图:
static int ip_route_output_slow(struct net *net, struct rtable **rp, const struct flowi *oldflp){ u32 tos = RT_FL_TOS(oldflp); struct flowi fl = { .nl_u = { .ip4_u =//构造路由查找对象 { .daddr = oldflp->fl4_dst, .saddr = oldflp->fl4_src, .tos = tos & IPTOS_RT_MASK, .scope = ((tos & RTO_ONLINK) ? //根据tos和RTO_ONLINK,得出路由的scope RT_SCOPE_LINK : RT_SCOPE_UNIVERSE), } }, .mark = oldflp->mark, .iif = net->loopback_dev->ifindex, .oif = oldflp->oif }; struct fib_result res; unsigned flags = 0; struct net_device *dev_out = NULL; int free_res = 0; int err; struct fib_result pr_res; int ret = 0; int proute_err = 0; res.prset = 0; res.fi = NULL;#ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL;#endif if (oldflp->fl4_src) { //对源地址类型进行合法性检查 err = -EINVAL; if (ipv4_is_multicast(oldflp->fl4_src) ||//组播 ipv4_is_lbcast(oldflp->fl4_src) ||//受限广播255.255.255.255 ipv4_is_zeronet(oldflp->fl4_src))//0.x.x.x地址 goto out; if (oldflp->oif == 0//发包接口为lo && (ipv4_is_multicast(oldflp->fl4_dst) ||//目的地址为组播 oldflp->fl4_dst == htonl(0xFFFFFFFF))) {//广播 /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(net, oldflp->fl4_src); ////将源地址作为目的地址,强制在local表中查找 //返回与给定的源地址相等的第一个设备 if (dev_out == NULL) goto out; fl.oif = dev_out->ifindex;//将源ip对应的dev 赋值给出接口 goto make_route;//**1** } if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) { /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(net, oldflp->fl4_src); if (dev_out == NULL) goto out; dev_put(dev_out);//递减引用计数 dev_out = NULL; } } if (oldflp->oif) { //若出接口不为空 dev_out = dev_get_by_index(net, oldflp->oif);//根据输出设备索引查找设备接口是否存在 err = -ENODEV; if (dev_out == NULL)//检测出接口是否存在 goto out; /* RACE: Check return value of inet_select_addr instead. */ if (__in_dev_get_rtnl(dev_out) == NULL) {//返回出接口对应的入设备in_device dev_put(dev_out); goto out; /* Wrong error code */ } if (ipv4_is_local_multicast(oldflp->fl4_dst) ||//目的地址是本地多播或者受限广播 oldflp->fl4_dst == htonl(0xFFFFFFFF)) { if (!fl.fl4_src) fl.fl4_src = inet_select_addr(dev_out, 0,//选择输出设备地址作为源地址 RT_SCOPE_LINK); goto make_route;//**2** } if (!fl.fl4_src) {//没有指定源地址,则选输出设备作为源地址 if (ipv4_is_multicast(oldflp->fl4_dst)) fl.fl4_src = inet_select_addr(dev_out, 0, fl.fl4_scope); else if (!oldflp->fl4_dst) fl.fl4_src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); } } if (!fl.fl4_dst) {//若目的地址为0 fl.fl4_dst = fl.fl4_src; if (!fl.fl4_dst)//目的和源地址都为0,则修改为127.0.0.1 fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); dev_out = net->loopback_dev;//输出设备设置为lo dev_hold(dev_out); fl.oif = net->loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route;//**3** } DEBUG_V4Route("%s-->\n",__FUNCTION__); if (fib_lookup(net, &fl, &res)) {//0表示成功,1表示失败#ifdef CONFIG_FW_POLICY //策略路由 if(FW_PR_CONFIG) ret = lookup_pr_policy_by_flow(NULL,&res, &fl, &proute_err); if(1 == ret){ free_res = 1; goto proute_ok; }#endif res.fi = NULL; if (oldflp->oif) {//当指定了输出接口 if (fl.fl4_src == 0)//无源地址,取输出设备地址作为源地址 fl.fl4_src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); res.type = RTN_UNICAST; goto make_route;//**4** } if (dev_out) dev_put(dev_out); err = -ENETUNREACH; goto out; } free_res = 1; if (res.type == RTN_LOCAL) {//路由查找结果为本地,则进行本地流程处理 if (!fl.fl4_src) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); dev_out = net->loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) fib_info_put(res.fi); res.fi = NULL; flags |= RTCF_LOCAL; goto make_route;//**5** }#ifdef CONFIG_FW_POLICY else if(FIB_RES_NH(res).nh_scope == RT_SCOPE_HOST){ ; }else{ if(FW_PR_CONFIG) ret = lookup_pr_policy_by_flow(&pr_res, &res, &fl, &proute_err); if(1 == ret){ fib_res_put(&res); memcpy(&res, &pr_res, sizeof(struct fib_result)); } }#endifproute_ok:#ifdef CONFIG_IP_ROUTE_MULTIPATH if (res.fi->fib_nhs > 1 && fl.oif == 0) fib_select_multipath(&fl, &res); else#endif//如果路由的子网掩码为0.0.0.0,同时路由为单播,且没有设置输出接口,则选择默认网关 if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif) fib_select_default(net, &fl, &res); if (!fl.fl4_src) fl.fl4_src = FIB_RES_PREFSRC(res); if (dev_out) dev_put(dev_out); dev_out = FIB_RES_DEV(res); dev_hold(dev_out); fl.oif = dev_out->ifindex;//将输出设备信息替换为查找到的路由条目的输出接口make_route: err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);//构造输出缓存项 if(res.prset) { FIB_RES_GW(res) = res.oldnexthop; FIB_RES_NH(res).nh_scope = res.oldtype; res.prset = 0; } if (free_res) fib_res_put(&res); if (dev_out) dev_put(dev_out);out: return err;}
0 0
- linux内核 路由fib表之输出查找
- linux内核 路由fib表之输入查找
- linux内核 路由fib表之数据结构
- linux内核 路由fib表之初始化
- linux内核 路由fib表之创建
- linux内核 路由fib表之删除
- linux内核 策略路由之查找
- linux路由内核实现分析(二)---FIB相关数据结构
- linux路由内核实现分析(二)---FIB相关数据结构(1)
- linux路由内核实现分析(二)---FIB相关数据结构(2)
- linux路由内核实现分析(二)---FIB相关数据结构(3)
- linux路由内核实现分析(二)---FIB相关数据结构(4)
- 路由表(FIB)详解
- 路由表(FIB)的初始化
- linux内核 路由缓存表之数据结构
- linux内核 路由缓存表之创建
- Linux 路由 学习笔记 之十一 输入、输出路由查找相关的接口函数
- linux路由表,策略路由,路由查找
- JSPatch部署安全策略
- scala进阶20-隐式转换至Ordered与Ordering
- 2-SAT阶段性学习小记
- iOS调用外部地图导航
- JVM垃圾收集器----垃圾标记、回收算法
- linux内核 路由fib表之输出查找
- JSON与XML的区别比较
- UVALive 4730 -树状数组+带权并查集
- java jni 的使用
- 剑指offer--编程题参考代码(2)
- HHU暑期第五弹——图论入门(图的搜索+连通性+最短路径+生成树+二分图匹配+最大流)
- 自定义View仿魅族手机加速(手机管家)效果
- 物料订单创建、下达、报工、收货与投料(代码)
- LightOJ - 1045 Digits of Factorial