图1

直接上图,再分别简单介绍各部分:

PC:笔记本电脑。

gw1:使用一台微型服务器模拟企业用户网关,同时添加静态路由使具备简单路由功能。

gw2:模拟ISP,同时添加静态路由使具备简单路由功能。

TPB:使用linux bridge桥接eth2、eth3。这里有个特殊功能,修改linux内核网络协议栈源码,使内核在不使用GRE模块情况下,具有对IP数据报的加封装和解封装GRE包头功能,同时具备GRE数据包的分片功能。

POP:模拟网络服务(如VPN服务等)提供点,这里省略了很多的网络功能,然后为了能够访问外网,对应于TPB具有加封装和解封装GRE包头功能,也是修改的linux内核网络协议栈源码。

GW3:pfsense(软防火墙和路由器),连接公司网关通往外网。

  • iptables 对数据包打标记

iptables -t mangle -A FORWARD -d x.x.x.x/x -j MARK --set-mark 47

这样代码中可以识别出数据包在内核缓存中是否被标记:

if(skb->mark == 47)... ...

然后对这些被识别出的数据包添加GRE包头, 这里的GRE包头是数据包包头的最外层IP层和GRE层的总称。

  • 加封装和解封装GRE包头(GRE over IPv4)

这里以内核版本版本2.6.32-431.el6.x86_64为例。

下面是ip_gre模块中从加封装GRE包头到发送的代码流程:

netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_forward  --> ip_forward_finish  --> dst_output  -->  ip_output  --> ip_finish_output  -->  ip_finish_output2  --> arp_constructor -->  dev_queue_xmit  -->  dev_hard_start_xmit  -->  ipgre_xmit  -->  __gre_xmit  -->  gre_build_header  -->  ip_tunnel_xmit  -->  ip_local_out  -->  dst_output  -->  dev_queue_xmit

流程比较复杂,这里附上最简版的添加GRE包头的代码,下面代码是经过测试的,但不是在内核源码任何地方都可以用,使用前必须保证skb->data初始位置在MAC层位置上:

int TPB_xmit(struct sk_buff *skb)
{struct gre_base_hdr *greh;struct iphdr *iph, *inner_iph;int needed_headroom = 38;int tunnel_hlen = 4;unsigned char eth_addr[ETH_ALEN];unsigned char hh_data[14]; struct ethhdr *eth1, *eth2;const u8 *p1;u8 eth_daddr[ETH_ALEN];skb->encapsulation = 1;skb_reset_network_header(skb);   if (skb_cow_head(skb, needed_headroom))  //扩展包头,以容得下新添加的IP层和GRE层return 0;skb_pull(skb, 14);                       //将skb->data向数据方向后移14个字节(即mac层长度)的位置,IP头的位置eth1 = eth_hdr(skb);memcpy(eth_addr, eth1->h_source, ETH_ALEN);memcpy(eth_daddr, eth1->h_dest, ETH_ALEN);inner_iph = (struct iphdr*)skb->data;skb_push(skb, tunnel_hlen);          //将skb->data向数据方向反向移动4个字节(GRE包头长度)greh = (struct gre_base_hdr *)skb->data;greh->flags = 0;greh->protocol = skb->protocol;skb_push(skb, sizeof(struct iphdr)); //将skb->data向数据方向反向移动sizeof(struct iphdr)个字节(即IP层长度)的位置,设置为最外层IP头的位置skb_reset_network_header(skb);iph = ip_hdr(skb);iph->version    =       4;iph->ihl        =       sizeof(struct iphdr) >> 2;iph->frag_off   =       0;iph->protocol   =       IPPROTO_GRE;iph->tot_len = inner_iph->tot_len + htons(24);iph->tos        =       0;iph->daddr      =       ip_array_TPB[1];iph->saddr      =       ip_array_TPB[0];iph->ttl        =       64;iph->id = inner_iph->id;iph->check = 0;iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);eth2 = (struct ethhdr*) (((u8 *) hh_data) );eth2->h_proto = skb->protocol;memcpy(eth2->h_source, eth_addr, ETH_ALEN);memcpy(eth2->h_dest, eth_daddr, ETH_ALEN);p1= (const u8*)hh_data;skb_push(skb, 14);   //将skb->data向数据方向反向移动14个字节(即MAC层长度),设置为MAC头的位置skb_reset_mac_header(skb);memcpy(skb->data, hh_data, 14);return 0;
}

接下来的解封装GRE包头介绍,以下ip_gre模块中解封装GRE包头的代码流程:

netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_local_deliver  -->  ip_local_deliver_finish  -->  gre_rcv  -->  gre_cisco_rcv  -->  ipgre_rcv  -->  ip_tunnel_lookup  -->  ip_tunnel_rcv  -->  gro_cells_receive  -->  napi_schedule  -->  __napi_schedule  -->  ____napi_schedule  -->  netif_receive_skb  -->  deliver_skb  -->  ip_rcv  -->  ip_rcv_finish  -->  dst_input  -->  ip_forward  --> ip_forward_finish  -->  dst_output  -->  dev_queue_xmit

同样,流程比较复杂,这里附上最简版解封装GRE包头代码:

struct sk_buff* TPB_trim_gre_header(struct sk_buff *skb)
{unsigned char hh_data[14];unsigned char* skb_data_ptr; skb->data = skb_mac_header(skb);skb_data_ptr = skb->data;memcpy(hh_data, skb_data_ptr, 14);skb_pull(skb, 24);skb_reset_mac_header(skb);memcpy(skb->data, hh_data, 14);skb_pull(skb, 14);skb_reset_network_header(skb);skb_push(skb, 14);return skb;
}
  • GRE包头分片

目前硬件还不支持GRE分片,只能在代码层对GRE包头进行分片。看下整个协议栈的GSO处理逻辑:

图2

详情参考博客: https://www.cnblogs.com/lvyilong316/p/6818710.html

这里在图中tcp_tso_segment处做更改,如下:

dev_hard_start_xmit --> dev_gso_segment  -->  skb_gso_segment  --> skb_mac_gso_segment  -->  inet_gso_segment

-->  gre_gso_segment -->  skb_mac_gso_segment  -->  inet_gso_segment  --> tcp_tso_segment

static const struct net_offload gre_offload = {.gso_send_check =       gre_gso_send_check,.gso_segment    =       gre_gso_segment,
};inet_add_offload(&gre_offload, IPPROTO_GRE);static int gre_gso_send_check(struct sk_buff *skb)
{if (!skb->encapsulation)return -EINVAL;return 0;
}static struct sk_buff *gre_gso_segment(struct sk_buff *skb,int features)
{... ...
}

注意:

在图1中,TPB节点和POP节点都具有加封装和解封装GRE包头功能,在POP节点接收来自TPB节点的加封装的数据包,并且进行GRE分片,如果没有关闭网卡eth3的generic-receive-offload 特性,这里分片的数据包会合并,由于数据包长超过MTU值,会被丢弃, 这里可以暂时将该特性关闭,执行命令 ethtool -K eth3 gro off。

gre包分片及gro、gso等offload特性的应用相关推荐

  1. linux kernel 网络协议栈之GRO(Generic receive offload)

    linux kernel 网络协议栈之GRO(Generic receive offload) 2010年11月26日 Simon Liu 发表评论 阅读评论 原创文章,转载请注明: 转载自pagef ...

  2. linux 网卡gso,linux内核网络协议栈学习笔记:关于GRO/GSO/LRO/TSO等patch的分析和测试...

    TSO,全称是TCP Segmentation Offload,我们知道通常以太网的MTU是1500,除去TCP/IP的包头,TCP的MSS (Max Segment Size)大小是1460,通常情 ...

  3. UDP 与 GRO, GSO

    不知道是不是因为 GSO, GRO 是 Linux 新增特性的原因, 在 google 上找了半天都没有找到一篇详细的介绍如何使用 GSO/GRO 的文章, 最后从 Linux 内核中与 GSO/GR ...

  4. linux 网卡gso,网卡 offload 简介

    网卡 offload 简介 现在,越来越多的网卡设备支持 offload 特性,来提升网络收/发性能. offload 是将本来该操作系统进行的一些数据包处理(如分片.重组等)放到网卡硬件中去做, 降 ...

  5. IPv6的TSO/GRO/GSO及其Linux实现的不妥

    很明确的一件事是,IPv6不允许中间设备对报文分片.具体为什么这么设计,就是为了简单高效.因此,IPv6报头简洁了不少. 但TSO貌似并未违背取消IPv6分片的初衷,硬件把一些都处理的妥妥的,在路由软 ...

  6. DPDK2.2.0开发杂记一—— 网口抓包分片禁止及MTU配置

    1. 禁止网口抓包分片 DPDK收发包是基础核心模块,网卡需要应用进程进行配置并启动,测试过程中发现DPDK驱动igb_uio抓包可能会出现mbuf串.当网络包比较大时,DPDK驱动会把包进行分片放到 ...

  7. IP数据包分片重叠部分的重组问题

    原作者:Haboob Team 翻译:李华峰(邪灵) 介绍 本文将介绍 IDS 的工作原理和讨论 IP 数据包分片的重组过程,并研究不同操作系统在实现重组时的差异性. IDS(入侵检测系统)简介 ID ...

  8. mtu/mss 数据包分片详解

    MTU是啥 MTU是Maximum Transmission Unit的缩写,意思是最大传输单元,这个值是作用于网卡上的,表示的是数据报文经过网卡时的最大大小,默认情况下网卡的MTU值都是1500,当 ...

  9. 极速前进——DPDK GRO/GSO的转发性能提升实例

    通常,以太网的MTU是1500B,除去TCP/IP的协议首部,TCP的MSS(Max Segment Size)大小是1460B.一般情况下,协议栈会对超过1460B的TCP payload进行切片, ...

最新文章

  1. excel模糊匹配两列文字_高效便捷的Word、Excel操作技巧
  2. WISEGATE:SIEM的最佳实践讨论
  3. 云计算技术 — 容灾备份技术
  4. 音视频技术开发周刊 | 205
  5. leetcode1300. 转变数组后最接近目标值的数组和
  6. 学习笔记11-C语言-指针
  7. pythonxml库_对python 生成拼接xml报文的示例详解
  8. html中单选框重置,HTML表单和组件
  9. 美国OCC代理署长Brian Brooks将于今日离任,由首席运营官接任
  10. 每日一题题目26:选择排序(冒泡排序改进版)
  11. Linux使用命令 笔记
  12. Cookie的过期时间设置
  13. 关于Myeclipse自带JDK与本机安装JDK的的区别
  14. ELK filebeat和logstash使用:配置单个文件来源、配置多个文件来源
  15. AJAX培训第一讲:AJAX基础
  16. 联通光猫IPV6配置
  17. vue2.x和3.x中mock数据方式
  18. 华东师范计算机考研科目,华东师范大学计算机技术研究生考试科目和考研参考书目...
  19. 基础图像处理 python+opencv
  20. win10录屏有噪音_我的电脑是win10的,用Ev录屏有杂音,之前我调了声卡驱动,就没了,现在重装调了一下又有了...

热门文章

  1. pytorch apex +ddp 分布式训练+数据优化
  2. 优雅的使用MacBook(一些小技巧,你不会知道的)
  3. function() 与 $(function())
  4. 验证码显示不出来的问题
  5. MATLAB初阶绘图
  6. 教育教学类视频加密与安全(组图)
  7. 钢铁集团的混合云灾备
  8. 算法之克鲁斯卡尔(Kruskal)算法
  9. 这个小程序厉害了!一键生成花式昵称,让你的微信从此与众不同!
  10. python返回绝对值的函数_Python中用于返回绝对值的abs()方法