Linux内核网络ip_mkroute_input

来源:互联网 发布:淘宝七天下架什么意思 编辑:程序博客网 时间:2024/05/17 01:49
为输入的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