Linux Bridge 和 Tap 关系详解
本文分享自天翼云开发者社区《Linux Bridge和Tap关系详解》,作者:x****n
Linux Bridge 介绍
Bridge(桥)是 Linux 上用来做 TCP/IP 二层协议交换的设备,与现实世界中的交换机功能相似。Bridge 设备实例可以和 Linux 上其他网络设备实例连接,既 attach 一个从设备,类似于在现实世界中的交换机和一个用户终端之间连接一根网线。当有数据到达时,Bridge 会根据报文中的 MAC 信息进行广播、转发、丢弃处理。
![](https://static001.geekbang.org/infoq/9b/9b59c88476a3fe623b235fd0db7178e8.png)
如图所示,Bridge 的功能主要在内核里实现。当一个从设备被 attach 到 Bridge 上时,相当于现实世界里交换机的端口被插入了一根连有终端的网线。这时在内核程序里,netdev_rx_handler_register()被调用,一个用于接受数据的回调函数被注册。以后每当这个从设备收到数据时都会调用这个函数可以把数据转发到 Bridge 上。当 Bridge 接收到此数据时,br_handle_frame()被调用,进行一个和现实世界中的交换机类似的处理过程:判断包的类别(广播/单点),查找内部 MAC 端口映射表,定位目标端口号,将数据转发到目标端口或丢弃,自动更新内部 MAC 端口映射表以自我学习。
Linux 内核支持网口的桥接(目前只支持以太网接口)。但是与单纯的交换机不同,交换机只是一个二层设备,对于接收到的报文,要么转发、要么丢弃。小型的交换机里面只需要一块交换芯片即可,并不需要 CPU。而运行着 Linux 内核的机器本身就是一台主机,有可能就是网络报文的目的地。其收到的报文除了转 发和丢弃,还可能被送到网络协议栈的上层(网络层),从而被自己消化。
网桥的功能
概括来说,网桥实现最重要的两点:
1.MAC 学习:学习 MAC 地址,起初,网桥是没有任何地址与端口的对应关系的,它发送数据,还是得想 HUB 一样,但是每发送一个数据,它都会关心数据包的来源 MAC 是从自己的哪个端口来的,由于学习,建立地址-端口的对照表(CAM 表)。
2.报文转发:每发送一个数据包,网桥都会提取其目的 MAC 地址,从自己的地址-端口对照表(CAM 表)中查找由哪个端口把数据包发送出去。
网桥配置 ip
Bridge 可以设置 IP 地址,当一个 bridge0 拥有 IP 后,Linux 便可以通过路由表或者 IP 表规则在三层定位 bridge0,此时相当于 Linux 拥有了另外一个隐藏的虚拟网卡和 Bridge 的隐藏端口相连。当一个设备被 attach 到 Bridge 上时,那个设备的 IP 会变的无效,Linux 不再使用那个 IP 在三层接受数据。
对于一个被 attach 到 Bridge 上的设备来说,只有它收到数据时,此包数据才会被转发到 Bridge 上,进而完成查表广播等后续操作。当请求是发送类型时,数据是不会被转发到 Bridge 上的,它会寻找下一个发送出口。
网桥处理包原则
网桥需要维护一个 MAC 地址-端口映射表(CAM),端口是指网桥自身提供的端口,而 MAC 地址是指与端口相连的另一端的 MAC 地址。
网桥处理包遵循以下几条原则:
1.在一个接口上接收的包不会再在那个接口上发送这个数据包;
2.每个接收到的数据包都要学习其源地址;
3.如果数据包是多播或广播包,则要在同一个网段中除了接收端口外的其他所有端口发送这个数据包,如果上层协议栈对多播包感兴趣,则需要把数据包提交给上层协议栈;
4.如果数据包的目的 MAC 地址不能再 CAM 表中找到,则要在同一个网段中除了接收端口外的其他所有端口发送这个数据包;
5.如果能够在 CAM 表中查询到目的 MAC 地址,则在特定的端口上发送这个数据包,如果发送端口和接收端口是同一端口则不发送。
Tap 设备介绍
TAP 设备是一种让用户态程序向内核协议栈注入数据的设备,工作在二层。做为虚拟网卡驱动,Tap 驱动程序的数据接收和发送并不直接和真实网卡打交道,而是通过用户态来转交。Tap 驱动是利用设备文件实现用户态和核心态的数据交互。
从结构上来说,Tap 驱动并不单纯是实现网卡驱动,同时它还实现了字符设备驱动部分。以字符设备的方式连接用户态和核心态。下面是示意图:
![](https://static001.geekbang.org/infoq/99/99170856ad328bc2b37d0a9368e15ecf.png)
Tap 驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动部分。利用网卡驱动部分接收来自 TCP/IP 协议栈的网络分包并发送或者反过来将接收到的网络分包传给协议栈处理,而字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。Tap 驱动很好的实现了两种驱动的结合。
Tap 驱动处理流程
![](https://static001.geekbang.org/infoq/0e/0e3e1d8a973b2fe3c76b9372612b77ea.png)
如图所示,当一个 TAP 设备被创建时,在 Linux 设备文件目录下将会生成一个对应 char 设备,用户程序可以像打开普通文件一样打开这个文件进行读写;Linux protocol statck 是 Linux 内核的 tcp/ip 协议栈。当执行 write()操作时,数据进入 TAP 设备,此时对于 Linux 网络层来说,相当于 TAP 设备收到了一包数据,请求内核接受它,如同普通的物理网卡从外界收到一包数据一样,不同的是其实数据来自 Linux 上的一个用户程序。Linux 收到此数据后将根据网络配置进行后续处理,从而完成了用户程序向 Linux 内核网络层注入数据的功能。当用户程序执行 read()请求时,相当于向内核查询 TAP 设备上是否有需要被发送出去的数据,有的话取出到用户程序里,完成 TAP 设备的发送数据功能。针对 TAP 设备的一个形象的比喻是:使用 TAP 设备的应用程序相当于另外一台计算机,TAP 设备是本机的一个网卡,他们之间相互连接。应用程序通过 read()/write()操作,和本机网络核心进行通讯。
评论