TCP数据发送之TSO/GSO

TSO相关的内容充斥着TCP的整个发送过程,弄明白其机制对理解TCP的发送过程至关重要,这篇笔记就来看看TSO相关内容。

1. 基本概念

我们知道,网络设备一次能够传输的最大数据量就是MTU,即IP传递给网络设备的每一个数据包不能超过MTU个字节,IP层的分段和重组功能就是为了适配网络设备的MTU而存在的。从理论上来讲,TCP可以不关心MTU的限定,只需要按照自己的意愿随意的将数据包丢给IP,是否需要分段可以由IP透明的处理,但是由于分片会带来效率和性能上的损失,所以TCP在实现时总是会基于MTU设定自己的发包大小,尽量避免让数据包在IP层分片,也就是说TCP会保证一个TCP段经过IP封装后传给网络设备时,数据包的大小不会超过网络设备的MTU。

TCP的这种实现会使得其必须对用户空间传入的数据进行分段,这种工作很固定,但是会耗费CPU时间,所以在高速网络中就想优化这种操作。优化的思路就是TCP将大块数据(远超MTU)传给网络设备,由网络设备按照MTU来分段,从而释放CPU资源,这就是TSO(TCP Segmentation Offload)的设计思想。

显然,TSO需要网络设备硬件支持。更近一步,TSO实际上是一种延迟分段技术,延迟分段会减少发送路径上的数据拷贝操作,所以即使网络设备不支持TSO,只要能够延迟分段也是有收益的,而且也不仅仅限于TCP,对于其它L4协议也是可以的,这就衍生出了GSO(Generic Segmentation Offload)。这种技术是指尽可能的延迟分段,最好是在设备驱动程序中进行分段处理,但是这样一来就需要修改所有的网络设备驱动,不太现实,所以再提前一点,在将数据递交给网络设备的入口处由软件进行分段(见dev_queue_xmit()),这正是Linux内核的实现方式。

注:类似的一些概念如LSO、UFO等,可以类比理解,这里不再叙述。

2. TCP延迟分段判定

对于TCP来讲,无论最终延迟分段是由TSO(网络设备)实现,还是由软件来实现(GSO),TCP的处理都是一样的。下面来看看TCP到底是如何判断自己是否可以延迟分段的。

static inline int sk_can_gso(const struct sock *sk)
{
   
	//实际上检查的就是sk->sk_route_caps是否设定了sk->sk_gso_type能力标记
	return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
}

static inline int net_gso_ok(int features, int gso_type)
{
   
	int feature = gso_type << NETIF_F_GSO_SHIFT;
	return (features & feature) == feature;
}

sk_route_caps字段代表的是路由能力;sk_gso_type表示的是L4协议期望底层支持的GSO技术。这两个字段都是在三次握手过程中设定的,客户端和服务器端的初始化分别如下。

2.1 客户端初始化

客户端是在tcp_v4_connect()中完成的,相关代码如下:

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
   
...
	//设置GSO类型为TCPV4,该类型值会体现在每一个skb中,底层在
	//分段时需要根据该类型区分L4协议是哪个,以做不同的处理
	sk->sk_gso_type = SKB_GSO_TCPV4;
	//见下面
	sk_setup_caps(sk, &rt->u.dst);
...
}

2.2 服务器端初始化

服务器端是在收到第三个ACK后进行的初始化,相关代码如下:

struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
				  struct request_sock *req,
				  struct dst_entry *dst)
{
   
...
	//同上
	newsk->sk_gso_type = SKB_GSO_TCPV4;
	sk_setup_caps(newsk, dst);
...
}

2.3 sk_setup_caps()

设备和路由是相关的,L4协议会先查路由,所以设备的能力最终会体现在路由缓存中,sk_setup_caps()就是根据路由缓存中的设备能力初始化sk_route_caps字段。

enum {
   
	SKB_GSO_TCPV4 = 1 << 0,
	SKB_GSO_UDP = 1 << 1,
	/* This indicates the skb is from an untrusted source. */
	SKB_GSO_DODGY = 1 << 2,
	/* This indicates the tcp segment has CWR set. */
	SKB_GSO_TCP_ECN = 1 << 3,
	SKB_GSO_TCPV6 = 1 << 
  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
LRO (Large Receive Offload) 和 GRO (Generic Receive Offload) 是网络协议栈中的两种技术,用于优化数据包的接收处理。 LRO 主要用于 TCP,而 GRO 则适用于所有传输协议 。 LRO 是一种在网卡上进行数据包处理的技术,它将多个接收到的小数据包合并成一个大的数据包,减少了处理的开销。这种技术可以有效地提高网络性能和吞吐量。然而,LRO 只适用于 TCP 协议 。 GRO 是在内核网络协议栈中实现的技术,它通过合并接收到的数据包来减少处理的开销,提高网络性能。与 LRO 不同,GRO 可以应用于所有传输协议,而不仅限于 TCP。GRO 还保留了每个接收到的数据包的熵信息,这对于像路由器这样的应用非常重要。通过匹配条件,如源/目的地址、TOS/协议字段、源/目的端口等,可以进行适当的数据包合并 。 TSO (TCP Segmentation Offload) 和 GSO (Generic Segmentation Offload) 是用于发送数据包的技术。它们的作用是将大的数据包分割成更小的片段,以提高传输效率。TSO 主要用于 TCP,而 GSO 则适用于所有传输协议 。 总结起来,LRO 和 GRO 是用于接收数据包的技术,通过合并数据包减少处理的开销。TSOGSO 是用于发送数据包的技术,通过分割大的数据包提高传输效率。这些技术都在 Linux 内核的网络协议栈中发挥着重要的作用,提高了网络性能和吞吐量 。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO](https://blog.csdn.net/Rong_Toa/article/details/108748689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值