【Linux4.1.12源码分析】二层报文发送之报文GSO分段(IP层)
来源:互联网 发布:新三板数据 编辑:程序博客网 时间:2024/05/29 13:04
IP层的GSO/GRO定义在ip_packet_offload结构体中。
static struct packet_offload ip_packet_offload __read_mostly = {.type = cpu_to_be16(ETH_P_IP),.callbacks = {.gso_segment = inet_gso_segment, //gso分段函数.gro_receive = inet_gro_receive, //gro收包函数.gro_complete = inet_gro_complete,},};
inet_gso_segment函数
static struct sk_buff *inet_gso_segment(struct sk_buff *skb,netdev_features_t features){struct sk_buff *segs = ERR_PTR(-EINVAL);const struct net_offload *ops;unsigned int offset = 0;bool udpfrag, encap;struct iphdr *iph;int proto;int nhoff;int ihl;int id;if (unlikely(skb_shinfo(skb)->gso_type & ~(SKB_GSO_TCPV4 | SKB_GSO_UDP | SKB_GSO_DODGY | SKB_GSO_TCP_ECN | SKB_GSO_GRE | SKB_GSO_GRE_CSUM | SKB_GSO_IPIP | SKB_GSO_SIT | SKB_GSO_TCPV6 | SKB_GSO_UDP_TUNNEL | SKB_GSO_UDP_TUNNEL_CSUM | SKB_GSO_TUNNEL_REMCSUM | 0)))goto out;skb_reset_network_header(skb);nhoff = skb_network_header(skb) - skb_mac_header(skb);//根据network header和mac header得到IP头相对MAC的偏移if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))//检测skb是否可以移动到L4头?goto out;iph = ip_hdr(skb);ihl = iph->ihl * 4;//得到IP包头的实际长度,基于此可以得到L4的首地址if (ihl < sizeof(*iph))goto out;id = ntohs(iph->id);proto = iph->protocol;//L4层协议类型/* Warning: after this point, iph might be no longer valid */if (unlikely(!pskb_may_pull(skb, ihl)))//检测skb是否可以移动到L4头?goto out;__skb_pull(skb, ihl);//报文data指针移动到传输层encap = SKB_GSO_CB(skb)->encap_level > 0;if (encap)features &= skb->dev->hw_enc_features;//如果encap,那么feature与hw_enc_features取交集SKB_GSO_CB(skb)->encap_level += ihl;//用来标示是否为内层报文skb_reset_transport_header(skb);//设置transport header值segs = ERR_PTR(-EPROTONOSUPPORT);if (skb->encapsulation && skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))udpfrag = proto == IPPROTO_UDP && encap;elseudpfrag = proto == IPPROTO_UDP && !skb->encapsulation;//vxlan封装报文走此分支,此时udpfrag为falseops = rcu_dereference(inet_offloads[proto]);if (likely(ops && ops->callbacks.gso_segment))segs = ops->callbacks.gso_segment(skb, features);//UDP或TCP的分段函数if (IS_ERR_OR_NULL(segs))goto out;skb = segs;do {iph = (struct iphdr *)(skb_mac_header(skb) + nhoff);//根据分段报文的mac header 和 IP偏移if (udpfrag) {//ip分片报文iph->id = htons(id);iph->frag_off = htons(offset >> 3);//设置ip头的frag_off值if (skb->next)iph->frag_off |= htons(IP_MF);//后面还有报文,需要设置more frag标记offset += skb->len - nhoff - ihl;//计算offset值,下一个报文需要使用} else {iph->id = htons(id++);//每个报文为完整的IP报文}iph->tot_len = htons(skb->len - nhoff);ip_send_check(iph);//计算ip头 csum值if (encap)//如果encap值非空,说明当前处于内层报文中,所以需要设置inner heaer值skb_reset_inner_headers(skb);skb->network_header = (u8 *)iph - skb->head;//设置network header} while ((skb = skb->next));out:return segs;}
0 0
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(IP层)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(MAC层)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(UDP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(TCP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(skb_segment)
- 【Linux4.1.12源码分析】二层报文发送之GSO条件判断
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】IP层报文发送之ip_output
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】二层报文发送之dev_queue_xmit
- 【Linux4.1.12源码分析】二层报文发送之net_tx_action
- 【Linux4.1.12源码分析】二层报文发送之qdisc实现分析
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_local_deliver)
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_forward)
- 【Linux4.1.12源码分析】协议栈报文接收之传输层处理分析(UDP)
- 【Linux4.1.12源码分析】vxlan报文发送之udp_tunnel_xmit_skb
- 【Linux4.1.12源码分析】vxlan报文发送之iptunnel_xmit
- socket 发送 二层 报文
- ubuntu12.04下安装opencv库的步骤及出现的问题
- 10.9
- 初识别输入输出
- Kinect-Fusion ICP算法构建带法向量点云金字塔
- SpringBoot 1.4升级中遇到的奇葩问题
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(IP层)
- 変分学引入
- 软考总结--网络
- Typedef与#define的区别
- Android反编译学习总结
- 面向对象的三大特征
- 判断一个数是否能同时被3和5整除 手痒之作
- 树状数组精解与模板及简单例题hdu1166
- 龟兔赛跑问题