我以前写过一篇介绍 tunnel 的文章,只是做了大体的介绍。里面多数 tunnel 是很容易理解的,因为它们多是一对一的,换句话说,是直接从一端到另一端。比如 IPv6 over IPv4 的 tunnel,也就是 SIT,它的原理如下图所示:

显然,除了端点的 host A 和 host B之外,中间经过的任何设备都是看不到里面的 IPv6 的头,对于它们来说,经过 sit 发出的包和其它的 IPv4 的包没有任何区别。

GRE tunnel 却不一样了,它的原理从根本上和 sit,ipip 这样的 tunnel 就不一样。除了外层的 IP 头和内层的 IP 头之间多了一个 GRE 头之外,它最大的不同是,tunnel 不是建立在最终的 host 上,而是在中间的 router 上!换句话说,对于端点 host A 和 host B 来说,该 tunnel 是透明的(对比上面的 sit tunnel)。这是网上很多教程里没有直接告诉你的。理解这一点非常关键,正是因为它这么设计的,所以它才能解决 ipip tunnel 解决不了的问题。

所以,经过 GRE tunnel 发送的包(从 host A 发送到 host B)大体过程是这样子的(仍然借用了LARTC 中的例子):

我们可以看出,从 host A 发出的包其实就是一个很普通的 IP 包,除了目的地址不直接可达外。该 GRE tunnel 的一端是建立在 router A上,另一段是建立在 router B上,所以添加外部的 IP 头是在 router A 上完成的,而去掉外面的 IP 头是在 router B上完成的,两个端点的 host 上几乎什么都不用做(除了配置路由,把发送到 10.0.2.0 的包路由到 router A)!

这么设计的好处也就很容易看出来了,ipip tunnel 是端对端的,通信也就只能是点对点的,而 GRE tunnel 却可以进行多播。

现在让我们看看Linux内核是怎么实现的,我们必须假设 router A 和 B 上都是运行的 Linux,而 host A 和 B上运行什么是无所谓的。

发送过程是很简单的,因为 router A 上配置了一条路由规则,凡是发往 10.0.2.0 网络的包都要经过 netb 这个 tunnel 设备,在内核中经过 forward 之后就最终到达这个 GRE tunnel 设备的 ndo_start_xmit(),也就是 ipgre_tunnel_xmit() 函数。这个函数所做的事情无非就是通过 tunnel 的 header_ops 构造一个新的头,并把对应的外部 IP 地址填进去,最后发送出去。

稍微难理解的是接收过程,即 router B 上面进行的操作。这里需要指出的一点是,GRE tunnel 自己定义了一个新的 IP proto,也就是 IPPROTO_GRE。当 router B 收到从 router A 过来的这个包时,它暂时还不知道这个是 GRE 的包,它首先会把它当作普通的 IP 包处理。因为外部的 IP 头的目的地址是该路由器的地址,所以它自己会接收这个包,把它交给上层,到了 IP 层之后才发现这个包不是 TCP,UDP,而是 GRE,这时内核会转交给 GRE 模块处理。

GRE 模块注册了一个 hook:

PLAIN TEXT

C:

  1. static const struct gre_protocol ipgre_protocol = {

  2.         .handler = ipgre_rcv,

  3.         .err_handler = ipgre_err,

  4. };

所以真正处理这个包的函数是 ipgre_rcv() 。ipgre_rcv() 所做的工作是:通过外层IP 头找到对应的 tunnel,然后剥去外层 IP 头,把这个“新的”包重新交给 IP 栈去处理,像接收到普通 IP 包一样。到了这里,“新的”包处理和其它普通的 IP 包已经没有什么两样了:根据 IP 头中目的地址转发给相应的 host。注意:这里我所谓的“新的”包其实并不新,内核用的还是同一个copy,只是skbuff 里相应的指针变了。

以上就是Linux 内核对 GRE tunnel 的整个处理过程。另外,GRE 的头如下所示(图片来自这里):

IP header in GRE tunnel

GRE header

[转]深入理解 GRE tunnel的更多相关文章

  1. 深入理解 GRE tunnel

    深入理解 GRE tunnel 时间 2012-11-08 19:05:22  A Geek's Page 原文  http://wangcong.org/blog/archives/2149 主题  ...

  2. gre tunnel

    http://searchenterprisewan.techtarget.com/tip/GRE-tunnel-vs-IPsec-tunnel-What-is-the-difference Enca ...

  3. GRE tunnel 2

    1.GRE简介 通用路由封装协议GRE(Generic Routing Encapsulation)可以对某些网络层协议(如IPX.ATM.IPv6.AppleTalk等)的数据报文进行封装,使这些被 ...

  4. gre tunnel搭建

    应用场景: 客户端(client)与服务器A在同一个运营商网络,应用部署在服务器B,服务器A .B之间建立tunnel,A设置dnat,client通过访问A的8000端口来访问服务器B,B返回的响应 ...

  5. 两个局域网(办公网-IDC)安全互通方案2:by GRE and linux server&深入理解GRE

    (0)gre的turnel的打通 1. 这个过程就是双方建立turnel的过程.           (1)局域网路由过程 1.主机A发送一个源为192.168.1.2,目的为10.1.1.2的包 ( ...

  6. Centos7 GRE Tunnel

    一.关闭防火墙及selinux 二.CentOS7默认不加载gre内核模块,加载gre内核模块 # modprobe ip_gre   临时加载gre模块(重启后失效) # lsmod |grep g ...

  7. nvgre

    GRE RFC2784 工作原理 Structure of a GRE Encapsulated Packet A GRE encapsulated packet has the form: ---- ...

  8. Neutron 理解 (3): Open vSwitch + GRE/VxLAN 组网 [Netruon Open vSwitch + GRE/VxLAN Virutal Network]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  9. Neutron 理解 (1): Neutron 所实现的虚拟化网络 [How Netruon Virtualizes Network]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

随机推荐

  1. 基于centos7+nginx+uwsgi+python3+django2.0部署Django项目

    0.序言 本文讲解如何基于centos7+nginx+uwsgi+python3+django2.0把windows上的本地项目部署到云服务器上. 本文服务器上的django项目和虚拟环境的路径将建立 ...

  2. 【算法】BM算法

    目录 BM算法 一. 字符串比较的分析 二.BM算法的思想 三.算法实现 BM算法 @ 一. 字符串比较的分析 如果要判定长度为\(n\)两个字符串相等,比较中要进行\(n\)比较,但是如果要判定两个 ...

  3. 《剑指Offer》第1题(Java实现):在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

    一.题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该 ...

  4. Taro 列表循环--点赞功能图片切换

    图片,未点击与点击 页面编写如下, 绑定我们的事件,继续: 附带注:Taro中不能使用 catchEvent 的方式阻止事件冒泡.你必须明确的使用 stopPropagation. 列表中点赞图片的切 ...

  5. centos安装python3.7和yum报错解决方法

    参考网址 https://www.cnblogs.com/simuhunluo/p/7704765.html https://www.cnblogs.com/linkxu1989/p/6955137. ...

  6. ubuntu 中 vim 的使用

    安装 sudo apt install vim vim  file_name #创建或者打开文件 vim file_name 定位到文件开头 vim file_name + 定位到文件末尾 vim f ...

  7. c#gridcontrol 的一些设置

    1:单元格变色,当鼠标点击到单元格的时候, 可能我们是想选择整个行,而此时gridview 默认设置是点击单元格整个行变色,这个点击的单元格变白色, 整行选择感觉有断层 于是和可以这么设置 设置Gri ...

  8. 7C - 折线分割平面

    我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目.比如,一条折线可以将平面分成两部分,两条折线最多可以将平面分成7部分,具体如下所示.  Input ...

  9. clientdataset新增append新增多条记录的时候报错 key valation

    在前面加上两句 adsDetail.Active := False; adsDetail.CreateDataSet;

  10. 数据库镜像转移Failover Partner

    数据库主体镜像转换:任务 - 镜像 - 故障转移 sqlserver2008 数据库镜像服务配置完成后,大家会发现我们有了两个数据库服务,这两个服务可以实现自动故障转移,那么我们的程序如何实现自动连接 ...