IPv4之报文分片


分片是网络层的一个重要任务,IPv4需要对两种IP数据包进行分片:

  1. 本地产生的数据包;
  2. 转发的数据包;

这两种数据包的长度如果超过了出口设备的MTU(或者PMTU),IPv4就会对数据包进行分片处理,使其适配出口设备的MTU。

重要说明

IPv4使用ip_fragment()函数执行分片处理,在设计时,要求该函数能够处理所有的情况。在实现过程中,可能高层协议已经为分片进行了一些准备工作,所以代码也充分考虑了实际可能的情况,对某些场景进行了优化,下面分情况介绍。

对于本机发送的数据包,TCP在封装skb时就会考虑MTU的限制,它会尽可能的保证每个skb不超过MTU,从而可以避免网络层再进行分段,因为分段对TCP性能的影响较大。考虑UDP,它并不会像TCP一样保证skb不超过MTU,但是其在封装skb时(通过ip_append_data()函数),会将属于同一个IP报文的所有分片都组织成skb列表(非第一个分片都放在第一个分片skb的frag_list链表中),这样网络层在执行分片时将会节省很多工作量。

对于转发的数据包,则无法向本地发送一样,提前做很多的工作,网络层必须依靠自己来兼容所有可能的情况。同样的,天有不测风云,对于一些特殊的异常场景,本机发送的数据包也有可能并没有按照预期情况组织,这时网络层也要能够兼容处理。

综上,网络层在实现分片时,设计了快速路径和慢速路径两个流程来分别对应上面的两种情况。

分片时机: ip_finish_output()

如笔记IPv4之数据包发送流程IPv4之数据包接收流程介绍,无论是本机发送的数据包,还是转发的数据包,最后在数据包通过Netfilter的POST_ROUTING点后,都会交由ip_finish_output()函数继续处理。

static int ip_finish_output(struct sk_buff *skb)
{
   
...
	// 如果报文长度超过了MTU并且不是GSO场景,那么需要分片,分片后再输出。否则直接输出
	if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
		return ip_fragment(skb, ip_finish_output2);
	else
		return ip_finish_output2(skb);
}

报文分片: ip_fragment()

如注释所述,入参skb代表了一个完整的IP报文,ip_fragement()将其分割成一个个mtu大小的分片。

/*
 *	This IP datagram is too large to be sent in one piece.  Break it up into
 *	smaller pieces (each of size equal to IP header plus
 *	a block of the data of the original IP data part) that will yet fit in a
 *	single device frame, and queue such a frame for sending.
 */
int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
   
	struct iphdr *iph;
	int raw = 0;
	int ptr;
	struct net_device *dev;
	struct sk_buff *skb2;
	unsigned int mtu, hlen, left, len, ll_rs, pad;
	int offset;
	__be16 not_last_frag;
	struct rtable *rt = skb->rtable;
	int err = 0;

	dev = rt->u.dst.dev;

	/*
	 *	Point into the IP datagram header.
	 */
	iph = ip_hdr(skb);

	// 需要进行分片,但是报文本身又不允许分片,那么发送失败,向源端发送ICMP需要分片报文
	if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
   
		IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
			  htonl(ip_skb_dst_mtu(skb
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IPv4报文格式是一种用于在网络中传输数据的协议头部格式。它由固定长度的20字节(或者更多,取决于选项字段的使用)组成。以下是IPv4报文格式的各个字段: 1. 版本(Version):占4位,表示IPv4协议的版本,通常为4。 2. 首部长度(Header Length):占4位,表示IPv4首部的长度,以32位字为单位。IPv4首部最小长度为20字节。 3. 区分服务(Differentiated Services):占8位,用于定义服务质量和优先级。 4. 总长度(Total Length):占16位,表示整个IPv4数据报的长度,包括首部和数据部分。 5. 标识(Identification):占16位,用于唯一标识一个数据报片段。 6. 标志(Flags):占3位,用于控制数据报的分片和重组。 7. 片偏移(Fragment Offset):占13位,用于指示数据报片段在原始数据报中的位置。 8. 生存时间(Time to Live,TTL):占8位,表示数据报在网络中可经过的最大路由跳数。 9. 协议(Protocol):占8位,表示数据报的封装协议,如TCP或UDP。 10. 首部校验和(Header Checksum):占16位,用于检验IPv4首部的完整性。 11. 源地址(Source Address):占32位,表示发送方的IP地址。 12. 目标地址(Destination Address):占32位,表示接收方的IP地址。 13. 选项字段(Options):占可变长度,用于传输一些额外的控制信息,如时间戳或记录路由。 14. 数据(Data):占变长,包括传输的实际数据。 以上是IPv4报文格式中的主要字段,其中一些字段可以根据具体的使用情况而变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值