Linux内核网络ip_mkroute_input

为输入的IP包生成一个路由项:
 
ip_mkroute_input

static int ip_mkroute_input(struct sk_buff *skb,        struct fib_result *res,        const struct flowi4 *fl4,        struct in_device *in_dev,        __be32 daddr, __be32 saddr, u32 tos) { #ifdef CONFIG_IP_ROUTE_MULTIPATH  if (res->fi && res->fi->fib_nhs > 1) {   int h;

  if (unlikely(ip_hdr(skb)->protocol == IPPROTO_ICMP))    h = ip_multipath_icmp_hash(skb);   else    h = fib_multipath_hash(saddr, daddr);   fib_select_multipath(res, h);  } #endif

 /* create a routing cache entry */  return __mkroute_input(skb, res, in_dev, daddr, saddr, tos); }

/* called in rcu_read_lock() section */ static int __mkroute_input(struct sk_buff *skb,       const struct fib_result *res,       struct in_device *in_dev,       __be32 daddr, __be32 saddr, u32 tos) {  struct fib_nh_exception *fnhe;  struct rtable *rth;  int err;  struct in_device *out_dev;  bool do_cache;  u32 itag = 0;

 /* get a working reference to the output device */  out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));  if (!out_dev) {   net_crit_ratelimited("Bug in ip_route_input_slow(). Please report.\n");   return -EINVAL;  }

 err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res),       in_dev->dev, in_dev, &itag);  if (err < 0) {   ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,       saddr);

  goto cleanup;  }

 do_cache = res->fi && !itag;  if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&      skb->protocol == htons(ETH_P_IP) &&      (IN_DEV_SHARED_MEDIA(out_dev) ||       inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))   IPCB(skb)->flags |= IPSKB_DOREDIRECT;

 if (skb->protocol != htons(ETH_P_IP)) {   /* Not IP (i.e. ARP). Do not create route, if it is    * invalid for proxy arp. DNAT routes are always valid.    *    * Proxy arp feature have been extended to allow, ARP    * replies back to the same interface, to support    * Private VLAN switch technologies. See arp.c.    */   if (out_dev == in_dev &&       IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) {    err = -EINVAL;    goto cleanup;   }  }

 fnhe = find_exception(&FIB_RES_NH(*res), daddr);  if (do_cache) {   if (fnhe) {    rth = rcu_dereference(fnhe->fnhe_rth_input);    if (rth && rth->dst.expires &&        time_after(jiffies, rth->dst.expires)) {     ip_del_fnhe(&FIB_RES_NH(*res), daddr);     fnhe = NULL;    } else {     goto rt_cache;    }   }

  rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);

rt_cache:   if (rt_cache_valid(rth)) {    skb_dst_set_noref(skb, &rth->dst);    goto out;   }  }

 rth = rt_dst_alloc(out_dev->dev, 0, res->type,       IN_DEV_CONF_GET(in_dev, NOPOLICY),       IN_DEV_CONF_GET(out_dev, NOXFRM), do_cache);  if (!rth) {   err = -ENOBUFS;   goto cleanup;  }

 rth->rt_is_input = 1;  if (res->table)   rth->rt_table_id = res->table->tb_id;  RT_CACHE_STAT_INC(in_slow_tot);

 rth->dst.input = ip_forward;

 rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);  if (lwtunnel_output_redirect(rth->dst.lwtstate)) {   rth->dst.lwtstate->orig_output = rth->dst.output;   rth->dst.output = lwtunnel_output;  }  if (lwtunnel_input_redirect(rth->dst.lwtstate)) {   rth->dst.lwtstate->orig_input = rth->dst.input;   rth->dst.input = lwtunnel_input;  }  skb_dst_set(skb, &rth->dst); out:  err = 0;  cleanup:  return err; }

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值