linux 协议栈学习 第八节 链路层GRO的处理
来源:互联网 发布:java 各版本新特性 编辑:程序博客网 时间:2024/05/16 18:57
linux 协议栈学习 第八节 链路层GRO的处理
链路层的接收匹配函数__napi_gro_receive(napi, skb):
该函数对报文进行匹配,并不合并报文。
匹配规则必须同时满足以下两个条件):
1、两个报文的接收dev必须相同。
2、两个报文的以太头必须相同。
static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb){ struct sk_buff *p; /*遍历napi 实例上的gro_list上挂的skb, 根据上面说的匹配规则设置链表上报文的same字段*/ for (p = napi->gro_list; p; p = p->next) { NAPI_GRO_CB(p)->same_flow = (p->dev == skb->dev) && !compare_ether_header(skb_mac_header(p), skb_gro_mac_header(skb)); NAPI_GRO_CB(p)->flush = 0; } return dev_gro_receive(napi, skb);}
int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb){ struct sk_buff **pp = NULL; struct packet_type *ptype; __be16 type = skb->protocol; struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; int same_flow; int mac_len; int ret; /*如果接收网络设备设置成不支持GRO功能,就不进行GRO合并处理*/ if (!(skb->dev->features & NETIF_F_GRO)) { goto normal; } /*如果是ip 分片报文,不进行GRO处理, * 因为在ip层会对ip分片报文进行合并 */ if (skb_is_gso(skb) || skb_has_frags(skb)) { goto normal; } /*加RCU读锁对 ptype_base hahs 链表进行保护*/ rcu_read_lock(); /*遍历链表,找到处理该类型报文的ptype, *并且该类型的ptype 实现了处理gro 的函数 */ list_for_each_entry_rcu(ptype, head, list) { if (ptype->type != type || ptype->dev || !ptype->gro_receive) continue; /*如果找到了,初始化报文头指针, *并重置 skb中GRO使用的私有字段, *这些字段会在相应协议实现的GRO处理函数中进行设置 */ skb_set_network_header(skb, skb_gro_offset(skb)); mac_len = skb->network_header - skb->mac_header; skb->mac_len = mac_len; NAPI_GRO_CB(skb)->same_flow = 0; NAPI_GRO_CB(skb)->flush = 0; NAPI_GRO_CB(skb)->free = 0; /*调用该协议类型注册的GRO处理函数对报文进行处理*/ pp = ptype->gro_receive(&napi->gro_list, skb); break; } rcu_read_unlock(); /*如果没找到对该协议类型报文进行处理的GRO,不进行GRO操作*/ if (&ptype->list == head) { goto normal; } same_flow = NAPI_GRO_CB(skb)->same_flow; ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED; /*如果协议的GRO处理函数返回了合并后的报文, *就调用napi_gro_complete把报文送进协议栈进行处理 */ if (pp) { struct sk_buff *nskb = *pp; *pp = nskb->next; nskb->next = NULL; napi_gro_complete(nskb); napi->gro_count--; } /*如果same 被设置了,说明在链表上找到了相匹配的报文了, *已经合并过了,不再需要缓存了 */ if (same_flow) { goto ok; } /*如果没找到相匹配的报文,需要缓存。 *缓存前需要判断队列是否已满或该报文是否应该缓存 */ if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS) { goto normal; } /*缓存没有匹配的报文到gro_list,返回值为GRO_HELD*/ napi->gro_count++; NAPI_GRO_CB(skb)->count = 1; skb_shinfo(skb)->gso_size = skb_gro_len(skb); skb->next = napi->gro_list; napi->gro_list = skb; ret = GRO_HELD;pull: /*经过这个协议栈的GRO receive的处理, *这时NAPI_GRO_CB(skb)->data_offset字段已经设置好了。 *如果GRO需要处理的数据不在skb的线性区, *把需要的数据copy到线性区,方便以后操作 */ if (skb_headlen(skb) < skb_gro_offset(skb)) { int grow = skb_gro_offset(skb) - skb_headlen(skb); BUG_ON(skb->end - skb->tail < grow); memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); skb->tail += grow; skb->data_len -= grow; skb_shinfo(skb)->frags[0].page_offset += grow; skb_shinfo(skb)->frags[0].size -= grow; /*如果把数据移入线性区后第一页就空了, *释放空页并把后续页依次前移 */ if (unlikely(!skb_shinfo(skb)->frags[0].size)) { put_page(skb_shinfo(skb)->frags[0].page); memmove(skb_shinfo(skb)->frags, skb_shinfo(skb)->frags + 1, (--skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t))); } }ok: return ret;normal: ret = GRO_NORMAL; goto pull;}
链路层的GRO完成函数:
合并完成后的报文调用该函数来把报文送入协议栈。
static int napi_gro_complete(struct sk_buff *skb){ struct packet_type *ptype; __be16 type = skb->protocol; struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; int err = -ENOENT; /*如果没有和别的报文合并过, *就可以直接送协议栈进行处理了 */ if (NAPI_GRO_CB(skb)->count == 1) { skb_shinfo(skb)->gso_size = 0; goto out; } /*找到相关协议把报文送给协议的grp_complete函数处理*/ rcu_read_lock(); list_for_each_entry_rcu(ptype, head, list) { if (ptype->type != type || ptype->dev || !ptype->gro_complete ) continue; err = ptype->gro_complete(skb); break; } rcu_read_unlock(); if (err) { WARN_ON(&ptype->list == head); kfree_skb(skb); return NET_RX_SUCCESS; } /*各层协议处理完成后,送给协议栈进行处理*/out: return netif_receive_skb(skb);}
0 0
- linux 协议栈学习 第八节 链路层GRO的处理
- linux协议栈学习 第七节 GRO的实现
- linux kernel 网络协议栈之GRO
- linux kernel 网络协议栈之GRO
- Linux网络子系统中链路层中GRO的处理
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测
- Linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试
- linux kernel 网络协议栈之GRO(Generic receive offload)
- linux kernel 网络协议栈之GRO(Generic receive offload)
- 第八节 linux文件系统
- 第八节linux文件系统
- php学习 第八节
- 【Linux4.1.12源码分析】协议栈gro收包之MAC层处理
- 【c语言】 运输公司对用户计算运输费用
- 工作日志 4.23
- Box2D基本概念的学习记录
- 第八周——重载运算符——阅读程序
- C语言宏定义##连接符和#符的使用
- linux 协议栈学习 第八节 链路层GRO的处理
- Druid数据库连接池的使用和详解
- 为什么我喜欢android
- Appium_Python_Client的使用
- stack_queue_priority_queue 容器适配器
- 认识与入门 Markdown
- 【c语言】有一个函数: x < 1 --- y = x 1 <= x < 10 --- y = 2 * x - 1 x >= 10 --- y = 3 * x - 11 输
- c#委托案例和理解
- 回溯-POJ2676-Sudoku