Linux内核中有两种获取网络设备的桥接口方法,其中一种是在控制路径上;另一种是在数据路径上。
控制路径
用户平面的程序brctl下发控制命令,比如setpathcost和setportprio命令以port number为参数下发到内核,内核使用br_get_port函数遍历网桥上的接口列表,最终找到对应的网桥接口。br_get_port函数需要在获得了网桥spinlock锁后调用,防止对port_list操作的不一致发送。
Usage: brctl [commands] commands: setpathcost <bridge> <port> <cost> set path cost setportprio <bridge> <port> <prio> set port priority struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no) { struct net_bridge_port *p; list_for_each_entry_rcu(p, &br->port_list, list) { if (p->port_no == port_no) return p; } }
数据路径
在数据路径上,调用函数br_port_get_rcu获取对应网桥接口,效率高于控制路径上的br_get_port函数。首先在添加桥接口时(br_add_if),调用函数(netdev_rx_handler_register)注册rx_handler,将网桥接口赋值给rx_handler_data变量,在数据路径上,比如br_handle_frame_finish中,使用br_port_get_rcu可直接获得网桥接口结构体。
static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev) { return rcu_dereference(dev->rx_handler_data); } int netdev_rx_handler_register(struct net_device *dev, rx_handler_func_t *rx_handler, void *rx_handler_data) { rcu_assign_pointer(dev->rx_handler_data, rx_handler_data); rcu_assign_pointer(dev->rx_handler, rx_handler); } int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; p = new_nbp(br, dev); err = netdev_rx_handler_register(dev, br_handle_frame, p); }
内核版本
Linux-3.10.0