网络子系统29_桥接转发数据库

//	转发数据库
//		1.容量
//			net_bridge->hash[BR_HASH_SIZE],其中BR_HASH_SIZE为(1<<8),有256个bucket
//		2.老化机制,
//			2.1 gc函数,到期时会顺序遍历age_list上的转发项,修改gc函数下一次到期时间为age_list中第一个没有过期的转发项的剩余时间。
//			2.2 age_list链表,保存除本机l2地址以外的所有转发项,按照到期时间进行排序,新添加或更新的转发项保存在age_list尾部。

//	网桥转发数据库初始化
//	调用路径:br_init->br_fdb_init
1.1 void __init br_fdb_init(void)
{
	//创建转发项的SLAB cache
	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
					 sizeof(struct net_bridge_fdb_entry),
					 0,
					 SLAB_HWCACHE_ALIGN, NULL, NULL);
}

//	查询转发项
//		__br_fdb_xxx不会递增net_bridge_fdb_entry的引用计数,br_fdb_xxx会递增net_bridge_fdb_entry的引用计数
//	参数:
//		addr,目的l2地址
//	函数主要任务:
//		hash l2地址到正确的bucket,遍历bucket查找具有相同l2地址的转发项
2.1 struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
					  const unsigned char *addr)
{
	struct hlist_node *h;
	struct net_bridge_fdb_entry *fdb;
	//net_bridge->hash为转发数据库的hash表
	hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {//遍历对应的bucket的链表
		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {//比较转发项的地址与查询的地址
			if (unlikely(has_expired(br, fdb)))
				break;
			return fdb;//找到返回转发项
		}
	}

	return NULL;//否则返回null
}

//	添加转发项
//		转发数据库由hash_lock保护
2.2 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
		  const unsigned char *addr, int is_local)
{
	int ret;

	spin_lock_bh(&br->hash_lock);//获取hash表的锁,关下半部中断
	ret = fdb_insert(br, source, addr, is_local);//
	spin_unlock_bh(&br->hash_lock);
	return ret;
}
//	调用路径:br_fdb_insert->fdb_insert
//	函数主要任务:
//		1.遍历对应的bucket
//		2.如果对应的转发项已经存在
//			2.1 转发项为本机地址,添加的地址为本机地址,返回
//			2.2 转发项非本机,添加的地址为本机,更新已有的转发项
//			2.3 转发项非本机,添加的地址非本机
//				2.3.1 如果转发项静态配置,则不更新已有转发项
//				2.3.2 否则从age_list上删除转发项,更新已有转发项
//		3.转发项不存在,分配新的转发项,更新转发项,添加到hash表

//	对已有选项的更新:
//		1.设置转发项是否为本机
//		2.本机转发项设置为static
//		3.非本机转发项添加到age_list上
2.3 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
		  const unsigned char *addr, int is_local)
{
	struct hlist_node *h;
	struct net_bridge_fdb_entry *fdb;
	int hash = br_mac_hash(addr);

	if (!is_valid_ether_addr(addr))//非全0,非广播或多播地址
		return -EADDRNOTAVAIL;

	hlist_for_each_entry(fdb, h, &br->hash[hash], hlist) {//遍历对应的bucket
		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {//已存在l2地址对应的转发项
			if (fdb->is_local) {//转发项为本机地址
				if (is_local) //要添加的本机地址已经存在,直接返回
					return 0;

				return -EEXIST;//返回错误
			}

			if (is_local) {//转发项非本机地址,将此转发项修改为本机地址
				printk(KERN_WARNING "%s adding interface with same address "
				       "as a received packet\n",
				       source->dev->name);
				goto update;
			}

			if (fdb->is_static)//转发项静态配置
				return 0;

			list_del(&fdb->u.age_list);//将fdb从br->age_list链表上删除
			goto update;
		}
	}

	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);//分配新的转发项
	if (!fdb)
		return ENOMEM;

	memcpy(fdb->addr.addr, addr, ETH_ALEN);//复制l2地址
	atomic_set(&fdb->use_count, 1);
	hlist_add_head_rcu(&fdb->hlist, &br->hash[hash]);//添加到对应的bucket

	if (!timer_pending(&br->gc_timer)) {
		br->gc_timer.expires = jiffies + hold_time(br);
		add_timer(&br->gc_timer);//启动垃圾回收定时器
	}

 update:
	fdb->dst = source;//到达此l2地址的端口
	fdb->is_local = is_local;//指示是否为本机地址
	fdb->is_static = is_local;//本机地址为静态配置地址
	fdb->ageing_timer = jiffies;//最近一次被使用的时间
	if (!is_local)
		list_add_tail(&fdb->u.age_list, &br->age_list);//对于非本机地址的转发项,添加到br->age_list链表,执行垃圾回收机制

	return 0;
}

//	垃圾回收定时器
//		除本机地址外的所有转发项,链接在lru链表中,遍历链表,直到最后一个没有过期的转发项。
//	转发项到期时间:
//		1.正常情况下,300HZ
//		2.拓扑发生变化时,short aging机制,过期时间为15HZ

//	函数主要任务:
//		1.遍历age_list,释放过期的转发项
//		2.修改gc下一次到期时间为最近到期的邻居项的到期时间。
2.5 void br_fdb_cleanup(unsigned long _data)
{
	struct net_bridge *br = (struct net_bridge *)_data;
	struct list_head *l, *n;
	unsigned long delay;
	//在获取转发数据库的锁之后进行清理操作
	spin_lock_bh(&br->hash_lock);
	//1.当拓扑发生改变时,启动short aging机制,过期时间为15HZ,转发数据库中的项很快过期
	//2.在正常情况下,过期时间为300HZ
	delay = hold_time(br);

	list_for_each_safe(l, n, &br->age_list) {//安全方式遍历age_list
		struct net_bridge_fdb_entry *f;
		unsigned long expires;

		f = list_entry(l, struct net_bridge_fdb_entry, u.age_list);
		expires = f->ageing_timer + delay;//转发项的到期时间

		if (time_before_eq(expires, jiffies)) {//如果转发项到期
			WARN_ON(f->is_static);
			pr_debug("expire age %lu jiffies %lu\n",
				 f->ageing_timer, jiffies);
			fdb_delete(f);
		} else {
			mod_timer(&br->gc_timer, expires);//第一个没有过期的转发项,之后的所有转发项都不会过期,则调整gc_timer的下一次运行时间,返回
			break;
		}
	}
	spin_unlock_bh(&br->hash_lock);
}

//	调用路径br_fdb_cleanup->fdb_delete
2.6 static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)
{
	hlist_del_rcu(&f->hlist);//从hash表上删除此转发项
	if (!f->is_static)//is_static=1,说明为本机地址,本机地址不会出现在age_list上
		list_del(&f->u.age_list);//从age_list上删除此转发项

	br_fdb_put(f);//递减引用计数,为0时,直接释放
}
时间: 2024-08-02 21:06:28

网络子系统29_桥接转发数据库的相关文章

网络子系统27_桥接子系统初始化

//桥接子系统以模块的形式提供 //函数主要任务: // 1.转发数据库slab缓存 // 2.向socket的ioctl添加回调函数 // 3.在netif_receive_skb中路径上添加回调函数 // 4.向netdev_chain注册监听块 1.1 static int __init br_init(void) { //转发数据库初始化 br_fdb_init(); //桥接子系统中有关netfilter的初始化 ... //向socket的ioctl注册回调函数,处理对网桥的io命令

网络子系统30_桥接子系统通用接口

// 添加网桥设备 // 参数: // name,需要全局唯一 // 调用路径:socket ioctl->br_add_bridge // 函数主要任务: // 1.创建一个新的网络设备 // 2.初始化网络设备的通用字段以及网桥设备的字段 // 3.向系统注册网络设备 1.1 int br_add_bridge(const char *name) { struct net_device *dev;//net_bridge->dev int ret; dev = new_bridge_dev

网络子系统28_桥接ioctl

// 1.网桥子系统向用户空间提供的接口: // 1.1 通过socket ioctl创建网桥 // 1.2 通过网桥的特殊设备文件ioctl添加网桥端口 // 桥接在socket ioctl中的衔接处理 // 处理的命令类型: // 1.获取网桥信息 // 2.设置网桥信息 // 3.添加网桥 // 4.删除网桥 1.1 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { ... case S

网络子系统24_桥接概念

//网桥:l2层设备,每个接口都指定一个链路层地址,然后把所有不是自己的数据帧转发出去 //网桥的作用:合并LAN,linux网桥只用于桥接ethernet端口. //网桥消费入口帧的情况: // 1.将帧传往上层l3协议,并且入口帧的目的地址就是该接口的l2地址 // 2.将帧传给某个协议处理程序,如生成树协议 //网桥具备的能力: // 1.地址学习,被动学习,不需要用户配置或协议帮助 // 2.数据转发,当目的地址(l2地址)为为单播地址时,如果网桥知道通往该地址的接口,则会从该接口将数据

网络子系统25_生成树协议

//参考 深入理解linux网络技术内幕 //生成树协议(Spanning Tree Protocol, STP)是用于消除环路拓扑的分布式算法. //生成树协议的基本元素: // 1.链路开销,当链路没有指定开销,或者都设置成相同开销时,一个节点到达根的距离用网络跃点数来测量. // 2.BPDU,STP通过让各个网桥之间交换称为网络协议数据单元(BPDU)的特殊帧来传递配置信息. // 3.根网桥,唯一能产生BPDU的网桥,其他网桥只有在接收到BPDU时才会传输BPDU(当网桥第一次加入时,

网络子系统34_网桥设备的传输与接收

// 网桥设备驱动程序的hard_start_xmit函数 // 函数主要任务: // 1.广播或多播地址,在所有端口上扩散 // 2.存在转发项,在指定端口上发送 // 3.没有找到转发项,在所有端口上扩散 1.1 int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); const unsigned char *dest = skb->dat

Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介

原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理子系统.网络子系统.虚拟文件系统在这个阶段进行分析的,但是为了让大家对内核有个整体的把握,今天还是简单的介绍一下剩余的几个子系统,我们对这几个子系统的分析,只要了解其作用和部分内容即可,不必深究,等我们写上几个驱动,到时候按照驱动再来分析这几个子系统我们就清晰多了. 在http://www.cnbl

网络子系统37_网桥、端口定时器

// 网桥定时器初始化 // 在添加网桥时,同时创建网桥使用的定时器 // 调用路径:br_add_bridge->new_bridge_dev->br_stp_timer_init // 网桥使用的定时器:hello, tcn, tc, gc 1.1 void br_stp_timer_init(struct net_bridge *br) { //根网桥周期性向通过指定端口向其他网桥发送配置BPDU setup_timer(&br->hello_timer, br_hello

visual studio-vs新建网络工程怎么访问oracleXE数据库

问题描述 vs新建网络工程怎么访问oracleXE数据库 vs建一个web工程,无法连接到oracleXE数据库,在使用窗体应用的时候,数据库都可以正常连接,突然换了web工程就连接不上了,connectionString = ""Data Source=127.0.0.1/XE;Persist Security Info=True;User ID=czb;Password=123456;Unicode=True;"";我的数据库连接语句是这样的,求大神指点 解决方