Linux的ip网络收包和转发以及路由查找的逻辑

August 26, 2021 | 1 Minute Read


# 网络包的批量处理流程
gro_normal_one  // 只有gro的代码才会执行到route hint
  netif_receive_skb_list
    __netif_receive_skb_list_ptype
      ip_list_rcv
      ip_sublist_rcv
        ip_list_rcv_finish
        ip_extract_route_hint  // 上一个skb的路由缓存,避免路由查找的优化
          ip_rcv_finish_core
            ip_can_use_hint
            ip_route_use_hint   // 如果前面一个skb目的地址跟现在一样,那就可以直接利用前面skb的路由信息了,不要再查次路由
          ip_sublist_rcv_finish



/* Implements all the saddr-related checks as ip_route_input_slow(),
 * assuming daddr is valid and the destination is not a local broadcast one.
 * Uses the provided hint instead of performing a route lookup.
 */
int ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr,
		      u8 tos, struct net_device *dev,
		      const struct sk_buff *hint)




# 网络包的处理流程
netif_receive_skb_core
  __netif_receive_skb_one_core
    ip_rcv
      ip_rcv_core
        ip_rcv_finish
            ip_rcv_finish_core
               net->ipv4.sysctl_ip_early_demux
               tcp_v4_early_demux  // 本地socket early_demux 转发优化
          ip_route_input_noref // 查找路由
            ip_route_input_slow
          dst_input



// 处理一个ip包的逻辑
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
	   struct net_device *orig_dev
	return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
		       net, NULL, skb, dev, NULL,
		       ip_rcv_finish);



ip_route_input_slow
  if (res->type == RTN_LOCAL) {
    goto local_input;
  }
  ip_mkroute_input
    __mkroute_input /* create a routing cache entry */
      rth->dst.input = ip_forward;    // 设置转发路路由表input
  local_input:  // 本地路由项
    rt_dst_alloc
      rt->dst.input = ip_local_deliver;    // 设置路由表input




# 进入本地的流量
/*
 * 	Deliver IP Packets to the higher protocol layers.
 */
int ip_local_deliver(struct sk_buff *skb)
	return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,
		       net, NULL, skb, skb->dev, NULL,
		       ip_local_deliver_finish);



# 转发的流量
int ip_forward(struct sk_buff *skb) 
  return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
                 net, NULL, skb, skb->dev, rt->dst.dev,
                 ip_forward_finish);

static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
               dst_output(net, sk, skb);



int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
  	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
			    net, sk, skb, indev, dev,
			    ip_finish_output,
			    !(IPCB(skb)->flags & IPSKB_REROUTED));