`
simohayha
  • 浏览: 1401106 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

网桥在内核的实现

阅读更多
我们知道netdevice有一个priv域,这个域用来保存设备的私有数据,当这个设备是一个网桥的时候,priv域也就指向一个struct net_bridge.

接下来看net_bridge以及相关的数据结构:
struct net_bridge
{
///自旋锁
	spinlock_t			lock;
///网桥所有端口的链表,其中每个元素都是一个net_bridge_port结构。
	struct list_head		port_list;
///加到这个网桥的物理设备
	struct net_device		*dev;
///这个锁是用来保护下面的那个hash链表。
	spinlock_t			hash_lock;
///保存forwarding database的一个hash链表(这个也就是地址学习的东东,所以通过hash能 快速定位),这里每个元素都是一个net_bridge_fsb_entry结构
	struct hlist_head		hash[BR_HASH_SIZE];
///这个结构没有被使用
	struct list_head		age_list;
	unsigned long			feature_mask;
#ifdef CONFIG_BRIDGE_NETFILTER
	struct rtable 			fake_rtable;
#endif
	unsigned long			flags;
#define BR_SET_MAC_ADDR		0x00000001

///stp相关的一些东西
	bridge_id			designated_root;
	bridge_id			bridge_id;
	u32				root_path_cost;
	unsigned long			max_age;
	unsigned long			hello_time;
	unsigned long			forward_delay;
	unsigned long			bridge_max_age;
	unsigned long			ageing_time;
	unsigned long			bridge_hello_time;
	unsigned long			bridge_forward_delay;

	u8				group_addr[ETH_ALEN];
	u16				root_port;
///当前使用的协议。
	enum {
		BR_NO_STP, 		/* no spanning tree */
		BR_KERNEL_STP,		/* old STP in kernel */
		BR_USER_STP,		/* new RSTP in userspace */
	} stp_enabled;

	unsigned char			topology_change;
	unsigned char			topology_change_detected;

///stp要用的一些定时器列表。
	struct timer_list		hello_timer;
	struct timer_list		tcn_timer;
	struct timer_list		topology_change_timer;
	struct timer_list		gc_timer;
	struct kobject			*ifobj;
};


struct net_bridge_port
{
///从属于的网桥设备
	struct net_bridge		*br;
///表示链接到这个端口的物理设备
	struct net_device		*dev;
	struct list_head		list;
///stp相关的一些参数。
	u8				priority;
	u8				state;
	u16				port_no;
	unsigned char			topology_change_ack;
	unsigned char			config_pending;
	port_id				port_id;
	port_id				designated_port;
	bridge_id			designated_root;
	bridge_id			designated_bridge;
	u32				path_cost;
	u32				designated_cost;
///端口定时器,也就是stp控制超时的一些定时器列表.(详细的需要去看stp的协议).
	struct timer_list		forward_delay_timer;
	struct timer_list		hold_timer;
	struct timer_list		message_age_timer;
	struct kobject			kobj;
	struct rcu_head			rcu;
};


struct net_bridge_fdb_entry
{
	struct hlist_node		hlist;
///桥的端口(最主要的两个域就是这个域和下面的mac地址域)
	struct net_bridge_port		*dst;
///当使用RCU策略,才用到
	struct rcu_head			rcu;
///引用计数
	atomic_t			use_count;
	unsigned long			ageing_timer;
///mac地址。
	mac_addr			addr;
	unsigned char			is_local;
	unsigned char			is_static;
};

通过下面的图能更好的理解这个结构:



接下来简要的介绍一下网桥的初始化。

网桥的初始化和一般网络设备的初始化很相似,只不过由于它是虚拟设备,因此这里还有一点不同。

首先来看内核的网络模块的初始化br_init,也就是初始化上面介绍的数据结构:

static int __init br_init(void)
{
	int err;
///stp的注册。
	err = stp_proto_register(&br_stp_proto);
	if (err < 0) {
		printk(KERN_ERR "bridge: can't register sap for STP\n");
		return err;
	}

///forwarding database的初始化
	err = br_fdb_init();
	if (err)
		goto err_out;
///网桥的netfilter钩子函数的初始化。
	err = br_netfilter_init();
	if (err)
		goto err_out1;
///注册到netdevice的通知链上
	err = register_netdevice_notifier(&br_device_notifier);
	if (err)
		goto err_out2;

	err = br_netlink_init();
	if (err)
		goto err_out3;
///安装网络设备的do_ioctl函数,也就是提供给用户空间ioctl接口。
	brioctl_set(br_ioctl_deviceless_stub);
	br_handle_frame_hook = br_handle_frame;

	br_fdb_get_hook = br_fdb_get;
	br_fdb_put_hook = br_fdb_put;

	return 0;
.........................................
	return err;
}


我们新建一个网桥,使用br_add_bridge,在这个函数中,主要是调用new_bridge_dev函数,下面我们主要就来看这个函数:

static struct net_device *new_bridge_dev(const char *name)
{
	struct net_bridge *br;
	struct net_device *dev;

///这里看到setup回调函数,是br_dev_setup(也就是网桥设备专用的)。setup函数的用途,可以看我以前写的网络设备初始化的blog。
	dev = alloc_netdev(sizeof(struct net_bridge), name,
			   br_dev_setup);

	if (!dev)
		return NULL;
///得到priv数据。
	br = netdev_priv(dev);

///接下来初始化br数据结构。
	br->dev = dev;

	spin_lock_init(&br->lock);
	INIT_LIST_HEAD(&br->port_list);
	spin_lock_init(&br->hash_lock);

///网桥优先级 32768(也就是默认是0x8000)
	br->bridge_id.prio[0] = 0x80;
	br->bridge_id.prio[1] = 0x00;

	memcpy(br->group_addr, br_group_address, ETH_ALEN);

	br->feature_mask = dev->features;
	br->stp_enabled = BR_NO_STP;
	br->designated_root = br->bridge_id;
	br->root_path_cost = 0;
	br->root_port = 0;
	br->bridge_max_age = br->max_age = 20 * HZ;
	br->bridge_hello_time = br->hello_time = 2 * HZ;
	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
	br->topology_change = 0;
	br->topology_change_detected = 0;
	br->ageing_time = 300 * HZ;
///初始化网桥设备的netfilter相关域。
	br_netfilter_rtable_init(br);

	INIT_LIST_HEAD(&br->age_list);

	br_stp_timer_init(br);

	return dev;
}


加一个新端口到一个网桥使用br_add_if方法。这里就不详细介绍这个方法了,不过这里要注意,他会在sys文件系统下,生成一些相关的东西。要看sysfs的介绍,去看kernel的文档。

最后来看一下网桥的子系统在这个网络子系统的位置:




可以看到这里有很多的hook在ip层,基本都是netfilter子系统的东西。

这里网桥的输入帧的处理是通过br_handle_frame来处理的。而网桥的输出帧是通过br_dev_xmit来处理的。

当网络帧通过NIC的设备驱动被接收了之后,skb->dev被实例化为真实的设备,然后这个帧被放入网络栈,然后当be_handle_frame_finish之后调用br_pass_frame_up。我们来看这个函数的实现:

引用
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
struct net_device *indev, *brdev = br->dev;

brdev->stats.rx_packets++;
brdev->stats.rx_bytes += skb->len;

indev = skb->dev;
///这步将真实的物理设备替换为虚拟的网桥设备。因此对3层来说就完全不知道物理设备的存在了。
skb->dev = brdev;
///调用netfiltel的相关hook。
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
}


当这个函数执行完毕后,会再次调用netif_receive_skb,他则会再次调用handle_bridge,而此时由于设备已经替换为虚拟的网桥设备,因此就会直接将包发往下层正确的协议处理。



  • 大小: 65 KB
  • 大小: 52.7 KB
  • 大小: 24.7 KB
1
0
分享到:
评论
1 楼 lenky0401 2009-09-22  
很强大 查这个内容找到你的博客
提供建议:麻烦你下次记得把你分析的linux代码的内核版本号写上,谢谢。

相关推荐

    Linux网桥的实现分析与使用

    Linux内核自2.2版本起内置了网桥功能,它通过软件实现了一种类似硬件网桥的机制,可以在多个网络接口(如以太网卡、无线网卡等)间进行数据包的交换。这种功能对于组建虚拟网络、实现网络负载均衡、隔离广播域等应用...

    网桥的原理及在linux内核中的实现.pdf

    网桥的原理及在linux内核中的实现.pdf

    Linux内核分析---网络[五]:网桥.doc

    在 Linux 内核中,网桥是通过一个名为 `bridge` 的模块来实现的。这个模块提供了一个虚拟网卡设备,可以将多个物理网卡连接起来,形成一个逻辑上的局域网。 创建网桥的过程可以分为两个步骤:首先,需要创建一个新...

    linux之透明网桥篇

    Linux透明网桥技术是一种在网络层实现数据包转发的方法,主要用于连接不同的局域网段,并在这些网段之间进行无感知的数据传输。相比于传统的路由器,透明网桥不需要进行复杂的路由表配置,也不需要为网桥本身分配IP...

    Linux内核分析-网络[五]:网桥.doc

    在Linux内核中,网桥(Bridge)是一种用于连接多个网络接口,使它们如同单一局域网(LAN)般工作的机制。网桥的功能类似于物理交换机,它接收数据包并根据MAC地址转发到正确的网络接口。这篇文档主要讨论了Linux内核...

    基于Linux的网桥和NAT网关集成的实现.pdf

    基于 Linux 的网桥实现是通过使用网桥设备来连接多个以太网段,使得不同的网段上的节点看起来就像在一个广播域一样。网桥的工作方式使得不同的网段上的节点可以相互通信,而不需要考虑以太网的冲突域。网桥的端口都...

    linux-2.6.28.8 网桥源码部分分析

    在Linux内核版本2.6.28.8中,网桥模块是网络连接和通信的重要组成部分,它允许多个网络接口共享一个物理网络连接。网桥功能使得在局域网内部署虚拟机或者构建复杂的网络拓扑变得可能。在这个源码分析中,我们将探讨...

    bridge-utils1.7.1网桥工具教程[内含软件包].zip

    在Docker的网络配置中,`bridge-utils`是一个至关重要的工具,它使得我们可以创建和管理Linux网桥,从而实现容器间的通信。本文将深入探讨`bridge-utils`的1.7.1版本及其在Docker中的应用。 首先,让我们理解什么是...

    Linux内核bridge浅析.doc

    Linux内核通过一个虚拟的网桥设备来实现桥接的,这个设备可以绑定若干个以太网接口设备,从而将它们桥接起来。网桥设备可以看作是一个虚拟的交换机,它可以将多个以太网接口设备连接起来,并将报文从一个接口转发到...

    kvm和qemu基于OVS网桥的安装和使用

    KVM(Kernel-based Virtual Machine)是Linux内核中的一个模块,它允许Linux系统直接运行虚拟机,从而实现高性能的虚拟化。QEMU(Quick Emulator)则是一个通用的机器模拟器,它可以模拟各种处理器架构,与KVM结合...

    Linux内核bridge浅析

    为了更深入理解Linux桥接的实现,可以参考"网桥的原理及在Linux内核中的实现.pdf"这份文档,它详细介绍了桥接的相关概念、工作流程以及内核中的具体实现细节。通过阅读这些资料,开发者和技术人员可以更好地掌握...

    9344 海康5.8G网桥编程器固件

    它的精简指令集和高效能使得ARM处理器能在低功耗下实现复杂运算,是嵌入式领域的主流选择。 "嵌入式硬件"指的是将计算能力集成到特定设备中的硬件系统,如海康5.8G网桥编程器。这类硬件设计的目标通常是满足特定的...

    Linux实战演练网桥 路由器 网关.pdf

    为满足中小规模的网络互联要求,本文将介绍应用 Linux 系统实现以太网桥、IP 路由器、IP 代理网关、Squid 代理网关等不同层次的网络互联技术。 一、多网卡安装 在 Linux 系统中,安装多个网卡是实现网络互联的前提...

    9344 编程器固件网桥

    标题中的“9344 编程器固件网桥”指的是一个针对AR9344芯片的编程器固件,用于实现特定的网络桥接功能。AR9344是一款基于ARM架构的处理器,常见于无线路由器和其他嵌入式系统中。这款编程器固件可能是为了更新或优化...

    linux内核协议栈桥功能详解

    Linux内核通过创建一个虚拟的网桥设备来实现桥接的功能。这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接在一起。例如,在一个典型的配置中,网桥设备`br0`可能绑定`eth0`和`eth1`两个以太网接口。从网络...

    linux网桥程序(bridge-utils-1.4)及帮助

    它允许用户将多个网络接口(如以太网卡)连接在一起,形成一个逻辑上的单一网络接口,从而实现不同网络之间的通信或者创建虚拟网络环境。这种技术在服务器集群、虚拟化环境以及某些特定的网络配置中非常常见。 首先...

Global site tag (gtag.js) - Google Analytics