疑惑:查个表为什么这么复杂,这个分值什么鬼???
数据包进入队列 udp_queue_rcv_skb()找到数据包目的端口对应的传输控制块后,会调用该函数接收该数据包 。
/* returns: *-1: error *0: success *>0: "udp encap" protocol resubmission * * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb){ struct udp_sock *up = udp_sk(sk); int rc; int is_udplite = IS_UDPLITE(sk);//IPSec相关 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))goto drop; nf_reset(skb); //IPSeck相关处理 if (up->encap_type) {/** This is an encapsulation socket so pass the skb to* the socket's udp_encap_rcv() hook. Otherwise, just* fall through and pass this up the UDP socket.* up->encap_rcv() returns the following value:* =0 if skb was successfully passed to the encap*handler or was discarded by it.* >0 if skb should be passed on to UDP.* <0 if skb should be resubmitted as proto -N*//* if we're overly short, let UDP handle it */if (skb->len > sizeof(struct udphdr) &&up->encap_rcv != NULL) {int ret;ret = (*up->encap_rcv)(sk, skb);if (ret <= 0) {UDP_INC_STATS_BH(sock_net(sk),UDP_MIB_INDATAGRAMS,is_udplite);return -ret;}}/* FALLTHROUGH -- it's a UDP Packet */ }//UDPlite相关处理 if ((is_udplite & UDPLITE_RECV_CC)&&UDP_SKB_CB(skb)->partial_cov) {/** MIB statistics other than incrementing the error count are* disabled for the following two types of errors: these depend* on the Application settings, not on the functioning of the* protocol stack as such.** RFC 3828 here recommends (sec 3.3): "There should also be a* way ... to ... at least let the receiving application block* delivery of packets with coverage values less than a value* provided by the application."*/if (up->pcrlen == 0) {/* full coverage was set*/LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage ""%d while full coverage %d requestedn",UDP_SKB_CB(skb)->cscov, skb->len);goto drop;}/* The next case involves violating the min. coverage requested* by the receiver. This is subtle: if receiver wants x and x is* greater than the buffersize/MTU then receiver will complain* that it wants x while sender emits packets of smaller size y.* Therefore the above ...()->partial_cov statement is essential.*/if (UDP_SKB_CB(skb)->cscov<up->pcrlen) {LIMIT_NETDEBUG(KERN_WARNING"UDPLITE: coverage %d too small, need min %dn",UDP_SKB_CB(skb)->cscov, up->pcrlen);goto drop;} }//如果设置了套接口过滤器时,那么需要提前进行校验和的处理,保证传给过滤器的数据包一定是校验通过的 if (sk->sk_filter) {if (udp_lib_checksum_complete(skb))goto drop; }rc = 0;//锁定socket bh_lock_sock(sk); //如果当前没有用户空间程序正在从接收队列接收数据,那么直接将SKB放入到接收队列中即可 if (!sock_owned_by_user(sk))rc = __udp_queue_rcv_skb(sk, skb); else//如果接收队列已经被锁定,那么暂时将数据放入到后备队列中,后备队列中的数据在//release_sock()中被转移到接收队列中sk_add_backlog(sk, skb); bh_unlock_sock(sk);return rc; drop: UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return -1;}
数据包进接收队列 sk_receive_queuestatic int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb){ int is_udplite = IS_UDPLITE(sk); int rc;//调用sock_queue_rcv_skb()接收 if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {/* Note that an ENOMEM error is charged twice */if (rc == -ENOMEM) {//如果由于内存问题导致数据包接收失败,进行统计UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,is_udplite);atomic_inc(&sk->sk_drops);}goto drop; }return 0; drop: UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return -1;} int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb){ int err = 0; int skb_len;//如果接收该数据包后,占用内存过大,则接收失败 if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=(unsigned)sk->sk_rcvbuf) {err = -ENOMEM;goto out; } //对于设置了套接字过滤器的调用其过滤器回调,过滤失败直接返回失败 err = sk_filter(sk, skb); if (err)goto out; //进行内存相关的统计,如果内存不足或者超过了接收缓存上限,则接收失败 if (!sk_rmem_schedule(sk, skb->truesize)) {err = -ENOBUFS;goto out; }skb->dev = NULL; //输入数据包由该套接字认领 skb_set_owner_r(skb, sk);/* Cache the SKB length before we tack it onto the receive* queue.Once it is added it no longer belongs to us and* may be freed by other threads of control pulling packets* from the queue.*/ skb_len = skb->len; //将该SKB加入到接收队列中 skb_queue_tail(&sk->sk_receive_queue, skb); //调用回调通知可能由于数据不足而block的进程 if (!sock_flag(sk, SOCK_DEAD))sk->sk_data_ready(sk, skb_len);out: return err;}
推荐阅读
- 常用开源协议对比
- Linux系统目录结构介绍
- Linux的sz和rz命令
- linux系统上查看载体为实体机还是虚拟机
- Linux上,最常用的十条命令
- Linux内核快速处理路径尽量多用kmem_cache而慎用kmalloc
- Linux和Windows的区别是什么?
- 一身漏洞狂奔24年!WiFi协议被曝重大漏洞,随时成为监控你的工具
- linux权限管理
- 编写Linux下的UDP Client/Server程序