IP层实现3-接收数据

来看接收数据。如果支持GRO,此函数在napi_gro_complete函数中和deliver_skb函数中调用。

[ net/ipv4/ip_input.c ]

/*
 * 	Main IP Receive routine.
 *
 * The main IPv4 receive method is the ip_rcv() method, which is the handler for all IPv4 packets (including multicasts and broadcasts). 
 * In fact, this method consists mostly of sanity checks. The real work is done in the ip_rcv_finish() method it invokes.
 *
 *
 * pt : 包的类型
	PACKET_HOST		: To us		
	PACKET_BROADCAST	: To all	
	PACKET_MULTICAST	: To group		
	PACKET_OTHERHOST	: To someone else 	
	PACKET_OUTGOING		: Outgoing of any type 
	PACKET_LOOPBACK		: MC/BRD frame looped back 
	PACKET_USER		: To user space	
	PACKET_KERNEL		: To kernel space	
	// Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space 
	PACKET_FASTROUTE	: Fastrouted frame	
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
	const struct iphdr *iph;
	u32 len;

	/* When the interface is in promisc. mode, drop all the crap
	 * that it receives, do not try to analyse it.
	 */
	if (skb->pkt_type == PACKET_OTHERHOST)
		goto drop;

	// add SNMP IPSTATS_MIB_IN
	IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len);

	/* 如果skb是共享的,clone一个新的,此时skb指向新clone出来的
	 */
	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
		IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
		goto out;
	}

	/* 检测skb中的主buffer长度大于iphdr(20字节)的长度
	 */
	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
		goto inhdr_error;

	iph = ip_hdr(skb);	// IP头部

	/*
	 *	RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum.
	 *
	 *	Is the datagram acceptable?
	 *
	 *	1.	Length at least the size of an ip header
	 *	2.	Version of 4
	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *	4.	Doesn't have a bogus length
	 */

	/* The length of the IPv4 header (ihl) is measured in multiples of 4 bytes. 
	 * The IPv4 header must be at least 20 bytes in size, which means that the ihl size must be at least 5. 
	 * The version should be 4 (for IPv4). If one of these conditions is not met, the packet is dropped and the statistics (IPSTATS_MIB_INHDRERRORS) are updated.
	 */
	if (iph->ihl < 5 || iph->version != 4)
		goto inhdr_error;

	BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1);
	BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0);
	BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE);
	IP_ADD_STATS_BH(dev_net(dev),
			IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
			max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));

	/* 检测skb中的主buffer长度大于ip头部长度(ihl*4,The length of the IPv4 header (ihl) is measured in multiples of 4 bytes )
	 */
	if (!pskb_may_pull(skb, iph->ihl*4))
		goto inhdr_error;

	iph = ip_hdr(skb);	// IP头部

	/* According RFC 1122, a host must verify the IPv4 header checksum on every received datagram and silently discard every datagram that has a bad checksum. 
	 * This is done by calling the ip_fast_csum() method, which should return 0 on success. The IPv4 header checksum is calculated only over the IPv4 header bytes:
	 */
	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
		goto csum_error;

	len = ntohs(iph->tot_len);	// IP数据包的长度
	if (skb->len < len) {
		IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
		goto drop;
	} else if (len < (iph->ihl*4))
		goto inhdr_error;

	/* Our transport medium may have padded the buffer out. Now we know it
	 * is IP we can trim to the true length of the frame.
	 * Note this now means skb->len holds ntohs(iph->tot_len).
	 */
	if (pskb_trim_rcsum(skb, len)) {
		IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
		goto drop;
	}

	skb->transport_header = skb->network_header + iph->ihl*4;	// 设置传输层头部的位置

	/* Remove any debris in the socket control block 
	 * 将skb->cb初使化为inet_skb_parm 
	 */
	memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));

	/* Must drop socket now because of tproxy. 
	 * 调用skb->destructor,和对应的socket断开
	 */
	skb_orphan(skb);

	/* The NF_INET_PRE_ROUTING netfilter hook invoked by calling the NF_HOOK macro. 
	 * The netfilter subsystem allows you to register callbacks in five points along the journey of a packet in the network stack. 
	 * The reason for adding the netfilter hooks is to enable loading the netfilter kernel modules at runtime. 
	 * The NF_HOOK macro invokes the callbacks of a specified point, if such callbacks were registered.  
	 * The netfilter hooks can discard the packet and in such a case it will not continue on its ordinary path. 
	 *
	 * The packet can either be delivered to the local machine or be forwarded to another host. 
	 * It is the lookup in the routing table that determines which of these two options will take place.
	 *
	 * When the registered netfilter hook method returns NF_DROP, it means that the packet should be dropped, and the packet traversal does not continue. 
	 * When the registered netfilter hook returns NF_ST
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值