⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 br_fdb.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* *	Forwarding database *	Linux ethernet bridge * *	Authors: *	Lennert Buytenhek		<buytenh@gnu.org> * *	$Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $ * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the License, or (at your option) any later version. */#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/if_bridge.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include "br_private.h"static __inline__ unsigned long __timeout(struct net_bridge *br){	unsigned long timeout;	timeout = jiffies - br->ageing_time;	if (br->topology_change)		timeout = jiffies - br->forward_delay;	return timeout;}static __inline__ int has_expired(struct net_bridge *br,				  struct net_bridge_fdb_entry *fdb){	if (!fdb->is_static &&	    time_before_eq(fdb->ageing_timer, __timeout(br)))		return 1;	return 0;}static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f){	memset(ent, 0, sizeof(struct __fdb_entry));	memcpy(ent->mac_addr, f->addr.addr, ETH_ALEN);	ent->port_no = f->dst?f->dst->port_no:0;	ent->is_local = f->is_local;	ent->ageing_timer_value = 0;	if (!f->is_static)		ent->ageing_timer_value = jiffies - f->ageing_timer;}static __inline__ int br_mac_hash(unsigned char *mac){	unsigned long x;	x = mac[0];	x = (x << 2) ^ mac[1];	x = (x << 2) ^ mac[2];	x = (x << 2) ^ mac[3];	x = (x << 2) ^ mac[4];	x = (x << 2) ^ mac[5];	x ^= x >> 8;	return x & (BR_HASH_SIZE - 1);}static __inline__ void __hash_link(struct net_bridge *br,				   struct net_bridge_fdb_entry *ent,				   int hash){	ent->next_hash = br->hash[hash];	if (ent->next_hash != NULL)		ent->next_hash->pprev_hash = &ent->next_hash;	br->hash[hash] = ent;	ent->pprev_hash = &br->hash[hash];}static __inline__ void __hash_unlink(struct net_bridge_fdb_entry *ent){	*(ent->pprev_hash) = ent->next_hash;	if (ent->next_hash != NULL)		ent->next_hash->pprev_hash = ent->pprev_hash;	ent->next_hash = NULL;	ent->pprev_hash = NULL;}void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr){	struct net_bridge *br;	int i;	br = p->br;	write_lock_bh(&br->hash_lock);	for (i=0;i<BR_HASH_SIZE;i++) {		struct net_bridge_fdb_entry *f;		f = br->hash[i];		while (f != NULL) {			if (f->dst == p && f->is_local) {				__hash_unlink(f);				memcpy(f->addr.addr, newaddr, ETH_ALEN);				__hash_link(br, f, br_mac_hash(newaddr));				write_unlock_bh(&br->hash_lock);				return;			}			f = f->next_hash;		}	}	write_unlock_bh(&br->hash_lock);}void br_fdb_cleanup(struct net_bridge *br){	int i;	unsigned long timeout;	timeout = __timeout(br);	write_lock_bh(&br->hash_lock);	for (i=0;i<BR_HASH_SIZE;i++) {		struct net_bridge_fdb_entry *f;		f = br->hash[i];		while (f != NULL) {			struct net_bridge_fdb_entry *g;			g = f->next_hash;			if (!f->is_static &&			    time_before_eq(f->ageing_timer, timeout)) {				__hash_unlink(f);				br_fdb_put(f);			}			f = g;		}	}	write_unlock_bh(&br->hash_lock);}void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p){	int i;	write_lock_bh(&br->hash_lock);	for (i=0;i<BR_HASH_SIZE;i++) {		struct net_bridge_fdb_entry *f;		f = br->hash[i];		while (f != NULL) {			struct net_bridge_fdb_entry *g;			g = f->next_hash;			if (f->dst == p) {				__hash_unlink(f);				br_fdb_put(f);			}			f = g;		}	}	write_unlock_bh(&br->hash_lock);}struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr){	struct net_bridge_fdb_entry *fdb;	read_lock_bh(&br->hash_lock);	fdb = br->hash[br_mac_hash(addr)];	while (fdb != NULL) {		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {			if (!has_expired(br, fdb)) {				atomic_inc(&fdb->use_count);				read_unlock_bh(&br->hash_lock);				return fdb;			}			read_unlock_bh(&br->hash_lock);			return NULL;		}		fdb = fdb->next_hash;	}	read_unlock_bh(&br->hash_lock);	return NULL;}void br_fdb_put(struct net_bridge_fdb_entry *ent){	if (atomic_dec_and_test(&ent->use_count))		kfree(ent);}int br_fdb_get_entries(struct net_bridge *br,		       unsigned char *_buf,		       int maxnum,		       int offset){	int i;	int num;	struct __fdb_entry *walk;	num = 0;	walk = (struct __fdb_entry *)_buf;	read_lock_bh(&br->hash_lock);	for (i=0;i<BR_HASH_SIZE;i++) {		struct net_bridge_fdb_entry *f;		f = br->hash[i];		while (f != NULL && num < maxnum) {			struct __fdb_entry ent;			int err;			struct net_bridge_fdb_entry *g;			struct net_bridge_fdb_entry **pp; 			if (has_expired(br, f)) {				f = f->next_hash;				continue;			}			if (offset) {				offset--;				f = f->next_hash;				continue;			}			copy_fdb(&ent, f);			atomic_inc(&f->use_count);			read_unlock_bh(&br->hash_lock);			err = copy_to_user(walk, &ent, sizeof(struct __fdb_entry));			read_lock_bh(&br->hash_lock);			g = f->next_hash;			pp = f->pprev_hash;			br_fdb_put(f);			if (err)				goto out_fault;			if (g == NULL && pp == NULL)				goto out_disappeared;			num++;			walk++;			f = g;		}	} out:	read_unlock_bh(&br->hash_lock);	return num; out_disappeared:	num = -EAGAIN;	goto out; out_fault:	num = -EFAULT;	goto out;}static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,					      struct net_bridge_port *source,					      int is_local){	if (!fdb->is_static || is_local) {		fdb->dst = source;		fdb->is_local = is_local;		fdb->is_static = is_local;		fdb->ageing_timer = jiffies;	}}void br_fdb_insert(struct net_bridge *br,		   struct net_bridge_port *source,		   unsigned char *addr,		   int is_local){	struct net_bridge_fdb_entry *fdb;	int hash;	hash = br_mac_hash(addr);	write_lock_bh(&br->hash_lock);	fdb = br->hash[hash];	while (fdb != NULL) {		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {			__fdb_possibly_replace(fdb, source, is_local);			write_unlock_bh(&br->hash_lock);			return;		}		fdb = fdb->next_hash;	}	fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);	if (fdb == NULL) {		write_unlock_bh(&br->hash_lock);		return;	}	memcpy(fdb->addr.addr, addr, ETH_ALEN);	atomic_set(&fdb->use_count, 1);	fdb->dst = source;	fdb->is_local = is_local;	fdb->is_static = is_local;	fdb->ageing_timer = jiffies;	__hash_link(br, fdb, hash);	write_unlock_bh(&br->hash_lock);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -