概览
在前一篇文章中,我描述了Linux 网桥(bridge)的配置,并展示了一个实验,其中使用Wireshark来分析流量。在本文中,我将讨论当创建一个网桥时会发生什么,以及Linux 网桥(bridge)的工作原理。
与网桥(bridge)相关的源代码可以在这里找到。
网桥设备
摘自《深入理解LINUX网络内幕》:
在Linux中,网桥(bridge)是一个虚拟设备。因此,除非你将其与一个或多个实际设备绑定,否则它无法接收或传输任何数据。
阅读上一篇文章后,有人问我,既然网桥(bridge)是一个第2层设备,为什么我们在运行ifconfig br0
时会看到一个IP地址与之相关联呢?答案是,Linux的实现将网桥(bridge)和路由器(router)的功能结合在了一起。我们知道,网桥(bridge)有一个上行链路,它可以连接到路由器。而在Linux网桥(bridge)中,这种连接被内置于内核内部。这个路由器实际上就是网桥(bridge)所绑定的实际设备。我们稍后会详细讨论这部分内容。为了理解网桥(bridge),我们可以简单地将这个IP地址视为网桥(bridge)的默认网关。如果我们想要一个私有网桥(bridge)的话,这个IP地址并不是必需的。
注:在Linux网络模型中,网桥(bridge)虽然本质上是二层设备,但其设计允许它拥有IP地址并执行层三的功能,主要是因为Linux将网桥(bridge)与路由器的部分功能进行了融合。这样做的目的是为了提供更加灵活的网络配置能力。然而,对于纯粹的层二桥接需求,这个IP地址可以忽略,因为桥接器的主要任务是在同一广播域内的设备之间转发数据包。
网桥数据结构
net_bridge 结构体的定义可以在这里找到。
下面仅列出了一些重要的字段:
struct net_bridge
{
spinlock_t lock;
struct list_head port_list;
struct net_device *dev;
spinlock_t hash_lock;
struct hlist_head hash[BR_HASH_SIZE];
bridge_id bridge_id;
...
}
port_list
是桥接器所拥有的端口列表。每个桥接器最多可以拥有 BR_MAX_PORTS(1024)个端口。dev
是指向表示桥接设备的 net_device
结构的指针。hash
是一个具有 BR_HASH_SIZE(256)个条目的转发哈希表。以便于快速查找和转发数据包。
创建网桥设备
可以通过命令 brctl addbr br0
来创建一个网桥。最终,这会调用带有请求 SIOCBRADDBR
的 ioctl
函数。
通过strace跟踪创建网桥的系统调用:
# strace brctl addbr br0
execve("/sbin/brctl", ["brctl", "addbr", "br0"], [/* 17 vars */]) = 0
...
ioctl(3