虚拟设备之linux网桥
前言:网桥设备作为一个虚拟设备,用于连接多个端口,可以构建一个局域网。与之相似的是vlan设备,在linux中,vlan设备是为了处理802.1q的添加和去除TAG的问题,这和传统交换机中vlan的功能—划分局域网,不太一样,在这里仅仅是处理了消息头,只是实现了隔离功能,并未实现交换功能,如果需要vlan内的数据转发,可以把vlan子接口挂接在网桥设备下。
网桥设备中添加的接口,在同一个二层域中。网桥在Linux中的实现如下:
Bridge-utils
工具的实现
先查看一下Bridge-utils
工具的工作原理,它是用于用户态配置网桥的工具,可以用于添加/删除网桥,往网桥添加/删除接口等操作。
在brctl.c
的main()中,读取了参数列表,这里使用了getopt_long()
函数,可以借鉴使用。之后进行br的初始化,主要就是创建一个socket接口,为之后IOCTL操作。然后调用command_lookup()
,查找到参数命令,最后调用cmd->func()
,执行命令。最后在内核中sock_ioctl()
会收到,然后调用br_ioctl_hook()
,从这里,就开始内核态的处理。
网桥设备的初始化
Br_init()
,br_init
是注册到内核进行初始化的,module_init(br_init)
,在br_init
中,主要做的事如下:
注册stp(生成树协议),初始化转发表,注册network namespace
(暂不知啥用),注册通知连,netlink的初始化,设置br_ioctl_hook
。
网桥的建立和操作
从br_ioctl_hook
调用开始,在br_init中注册的br_ioctl_hook
为
br_ioctl_deviceless_stub
,可以看到SIOCBRADDBR
添加和删除网桥。添加网桥中alloc_netdev()
分配了设备结构体,并进行了初始化设置br_dev_setup
,在初始化设置的时候,就填充了netdev_ops->br_netdev_ops
,这里就是对于设备的操作回调函数咯,重点关注br_dev_ioctl
,在这里,会用添加和删除接口的操作。等再次添加从接口设备到网桥时,此时网桥设备已经存在,调用br_netdev_ops
中的添加接口的回调函数,br_add_if
中注册了接收数据的处理函数:netdev_rx_handler_register(dev, br_handle_frame, p);br_handle_frame
就是处理函数咯。
网桥的数据流程
先附一张18摸公司的文章的图:
发送流程:
首先说一点是,网桥有自己的MAC地址,01:80:c2:00:00:0X,路由后发送函数dev_queue_xmit()
发送数据出去,因为此时通过路由,skb->dev
已经设置成为了br,所以,最后调用设备的发送回调ndo_start_xmit
,在br初始化时,设置为br_dev_xmit
,这样,最后的发送函数就是它咯。在发送中,确定目的地址是单播还是洪泛。
接收流程:
接收上,是从netif_receive_skb()
中接收报文,因为只有在attach到网桥的从接口注册了rx_handle
,即br_handle_frame
,也就是只有这些接口才会把数据往网桥上送。接着调用br_handle_frame
进行报文的处理,是consumed掉,还是转发等在这里完成。具体的代码就不分析咯。
注意事项:
网桥设备本身有自己的MAC,以及IP。发送和接收也正是通过路由后找到网桥接口的。
加入网桥的接口,其本身的IP和MAC地址都已经不再有效,路由并不会使用其中的地址,而是使用网桥的。