> 文档中心 > linux内核网络收包过程(三)

linux内核网络收包过程(三)

目录

网络协议

IP协议层处理


 

网络协议栈

 

netif_receive_skb_list_internal->__netif_receive_skb_list->__netif_receive_skb_list_core

函数会根据包的协议,假如是 udp 包,会将包依次送到 ip_rcv(), udp_rcv() 协议处理函数中进⾏处

static int __netif_receive_skb_core(struct sk_buff pskb, bool pfmemalloc,    struct packet_type ppt_prev){//将数据送入抓包点,tcpdumplist_for_each_entry_rcu(ptype, &ptype_all, list) {if (pt_prev)ret = deliver_skb(skb, pt_prev, orig_dev);pt_prev = ptype;}    //取出协议type = skb->protocol;/* deliver only exact match when indicated */if (likely(!deliver_exact)) {deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,&ptype_base[ntohs(type) &   PTYPE_HASH_MASK]);}...return ret;}//遍历liststatic inline void deliver_ptype_list_skb(struct sk_buff *skb,  struct packet_type pt,  struct net_device *orig_dev,  __be16 type,  struct list_head *ptype_list){struct packet_type *ptype, *pt_prev = *pt;list_for_each_entry_rcu(ptype, ptype_list, list) {if (ptype->type != type)continue;if (pt_prev)deliver_skb(skb, pt_prev, orig_dev);pt_prev = ptype;}*pt = pt_prev;}//funstatic inline int deliver_skb(struct sk_buff *skb,      struct packet_type *pt_prev,      struct net_device *orig_dev){return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);}

函数处理的任务  

  1. type = skb->protocol取出协议信息,
  2. 遍历注册在这个协议上的回调函数列表, ptype_base 是 hash table初始化时注册的
  3. pt_prev->func 协议层注册的处理函数ip_rcv

 

IP协议层处理

  

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,   struct net_device *orig_dev){struct net *net = dev_net(dev);skb = ip_rcv_core(skb, net);return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,net, NULL, skb, dev, NULL,ip_rcv_finish);}static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb){struct net_device *dev = skb->dev;int ret;skb = l3mdev_ip_rcv(skb);ret = ip_rcv_finish_core(net, sk, skb, dev, NULL);if (ret != NET_RX_DROP)ret = dst_input(skb);return ret;}

NF_HOOK 是⼀个钩⼦函数,执行ip_rcv_finish

函数调用关系 ip_rcv_finish_core         ip_route_input_noref                 ip_route_input_rcu                         ip_route_input_mc                                 rt_dst_alloc

   

struct rtable *rt_dst_alloc(struct net_device *dev,    unsigned int flags, u16 type,    bool nopolicy, bool noxfrm, bool will_cache){rt->dst.output = ip_output;if (flags & RTCF_LOCAL)rt->dst.input = ip_local_deliver; ...}

skb_dst(skb)->input 调⽤的 input ⽅法就是路由⼦系统赋的 ip_local_deliver  

int ip_local_deliver(struct sk_buff *skb){struct net *net = dev_net(skb->dev);    ...return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,net, NULL, skb, skb->dev, NULL,ip_local_deliver_finish);}static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb){__skb_pull(skb, skb_network_header_len(skb));ip_protocol_deliver_rcu(net, skb, ip_hdr(skb)->protocol);return 0;}void ip_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int protocol){const struct net_protocol *ipprot;int raw, ret;resubmit:raw = raw_local_deliver(skb, protocol);ipprot = rcu_dereference(inet_protos[protocol]);if (ipprot) {ret = INDIRECT_CALL_2(ipprot->handler, tcp_v4_rcv, udp_rcv,skb); ...__IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);}...}

inet_protos 中保存着 tcp_v4_rcv() 和 udp_rcv() 的函数地址。    

 参考

https://course.0voice.com/v1/course/intro?courseId=2&agentId=0