eBPF TC egress 方向 tcp checksum 问题

在ebpf tc egress方向修改了tcp的payload信息,我通过bpf_skb_change_tail将tcp payload从尾部减少了diff_len(测试中该值为88)。
常规思路:我都修改了tcp的包了,肯定要需要重新计算checksum ,所以我按照常规方法计算了checksum ,发现返回包传到客户端时,用wireshark抓包,发现多次请求的checksum 都是一样的,这就非常违反常理,按理说checksum 在客户端每次不同的请求下(客户端使用的随机端口号)都是应该不同的。同时我在ebpf/tc程序中打印了我计算的checksum前后的值
在这里插入图片描述
每次请求
我在ebpf中打印的old checksum都是855e,在客户端wireshark抓包的checksum都是5e2d
我在ebpf中计算的checksum恰好为wireshark期望的正确checksum,图中为3fbf和bf3f(字节序不同,值相同),这个值是随着不同请求而变化的,checksum变化符合我们的预期

于是灵机一动,是不是tcp的checksum是在tc hook之后才计算的,我在ebpf/tc里计算完之后恰好和tc hook点之后内核计算的重复了,两者“抵消”,导致客户端抓包每次都是一样的checksum。
ebpf程序中每次打印的old checksum都恒定也印证了这一问题,如果我在ebpf程序中不修改checksum,只减少payload,发现每次请求客户端抓包的checksum都是不同,且实际值和期望的正确值差了58。
于是又联想了old checksum 855e转换字节序后为5e85。这个值和wireshark每次抓到的恒定值5e2d也差58,这58到底是什么含义呢,突然想到0x58的十进制不就是88,不就是我减少的payload的长度吗。

linux5.3版本

于是得出结论:ebpf/tc egress 中checksum不需要重新计算,但是要加减长度(我这只有减的情况,加的不知道),如下代码即可解决问题

tcp->check = tcp->check - bpf_htons(old_tcp_payload_len - new_tcp_payload_len);

结论有点草率,仅供参考,可能和内核版本啥的也有关。

在网络和数据处理的上下文中,Egress datapath 指的是数据离开特定网络设备、系统或区域时所经过的路径。它与 Ingress datapath(数据进入的路径)相对。 在网络交换机或路由器等设备中,Egress datapath 涉及到对即将发送出去的数据帧或数据包进行一系列处理,例如根据转发规则进行调度、排队、修改帧头(如更新 VLAN 标签、MAC 地址等)、速率限制等操作,以确保数据能够正确、高效地从设备的出口端口发送到外部网络。 以软件定义网络(SDN)为例,控制器可以对 Egress datapath 进行精细的控制,根据不同的策略和流量需求,决定如何处理和转发即将离开网络节点的数据。 在一些网络设备的配置和管理中,会明确区分 Ingress 和 Egress 的处理逻辑和规则,以实现对网络流量的双向管控。 ### 代码示例 以下是一个简单的伪代码示例,展示了在网络设备中可能对 Egress 数据进行的一些基本处理: ```python # 模拟 Egress 数据处理函数 def egress_processing(packet, output_port): # 进行速率限制检查 if rate_limit_exceeded(output_port): # 如果超过速率限制,进行丢包处理 drop_packet(packet) return # 修改帧头信息,例如更新 VLAN 标签 packet.vlan_tag = update_vlan_tag(packet.vlan_tag) # 进行排队调度 queue_packet(packet, output_port) # 发送数据包 send_packet(packet, output_port) # 模拟速率限制检查函数 def rate_limit_exceeded(port): # 这里简单返回 False,实际中需要根据端口的速率限制配置进行检查 return False # 模拟更新 VLAN 标签函数 def update_vlan_tag(tag): # 这里简单返回原标签,实际中可以根据策略更新标签 return tag # 模拟排队数据包函数 def queue_packet(packet, port): # 这里简单打印排队信息,实际中需要实现具体的排队算法 print(f"Packet queued for output port {port}") # 模拟发送数据包函数 def send_packet(packet, port): print(f"Packet sent from output port {port}") # 示例调用 packet = {'vlan_tag': 10} output_port = 2 egress_processing(packet, output_port) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值