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

📄 lec.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
static void lec_arp_init(struct lec_priv *priv){	unsigned short i;	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);	}	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);	INIT_HLIST_HEAD(&priv->lec_no_forward);	INIT_HLIST_HEAD(&priv->mcast_fwds);	spin_lock_init(&priv->lec_arp_lock);	INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);}static void lec_arp_clear_vccs(struct lec_arp_table *entry){	if (entry->vcc) {		struct atm_vcc *vcc = entry->vcc;		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);		struct net_device *dev = (struct net_device *)vcc->proto_data;		vcc->pop = vpriv->old_pop;		if (vpriv->xoff)			netif_wake_queue(dev);		kfree(vpriv);		vcc->user_back = NULL;		vcc->push = entry->old_push;		vcc_release_async(vcc, -EPIPE);		entry->vcc = NULL;	}	if (entry->recv_vcc) {		entry->recv_vcc->push = entry->old_recv_push;		vcc_release_async(entry->recv_vcc, -EPIPE);		entry->recv_vcc = NULL;	}}/* * Insert entry to lec_arp_table * LANE2: Add to the end of the list to satisfy 8.1.13 */static inline voidlec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry){	struct hlist_head *tmp;	tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];	hlist_add_head(&entry->next, tmp);	pr_debug("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",		0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1],		0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3],		0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]);}/* * Remove entry from lec_arp_table */static intlec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove){	struct hlist_node *node;	struct lec_arp_table *entry;	int i, remove_vcc = 1;	if (!to_remove) {		return -1;	}	hlist_del(&to_remove->next);	del_timer(&to_remove->timer);	/* If this is the only MAC connected to this VCC, also tear down the VCC */	if (to_remove->status >= ESI_FLUSH_PENDING) {		/*		 * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT		 */		for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {			hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {				if (memcmp(to_remove->atm_addr,					   entry->atm_addr, ATM_ESA_LEN) == 0) {					remove_vcc = 0;					break;				}			}		}		if (remove_vcc)			lec_arp_clear_vccs(to_remove);	}	skb_queue_purge(&to_remove->tx_wait);	/* FIXME: good place for this? */	pr_debug("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",		0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1],		0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3],		0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]);	return 0;}#if DEBUG_ARP_TABLEstatic char *get_status_string(unsigned char st){	switch (st) {	case ESI_UNKNOWN:		return "ESI_UNKNOWN";	case ESI_ARP_PENDING:		return "ESI_ARP_PENDING";	case ESI_VC_PENDING:		return "ESI_VC_PENDING";	case ESI_FLUSH_PENDING:		return "ESI_FLUSH_PENDING";	case ESI_FORWARD_DIRECT:		return "ESI_FORWARD_DIRECT";	default:		return "<UNKNOWN>";	}}static void dump_arp_table(struct lec_priv *priv){	struct hlist_node *node;	struct lec_arp_table *rulla;	char buf[256];	int i, j, offset;	printk("Dump %p:\n", priv);	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {		hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) {			offset = 0;			offset += sprintf(buf, "%d: %p\n", i, rulla);			offset += sprintf(buf + offset, "Mac:");			for (j = 0; j < ETH_ALEN; j++) {				offset += sprintf(buf + offset,						  "%2.2x ",						  rulla->mac_addr[j] & 0xff);			}			offset += sprintf(buf + offset, "Atm:");			for (j = 0; j < ATM_ESA_LEN; j++) {				offset += sprintf(buf + offset,						  "%2.2x ",						  rulla->atm_addr[j] & 0xff);			}			offset += sprintf(buf + offset,					  "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",					  rulla->vcc ? rulla->vcc->vpi : 0,					  rulla->vcc ? rulla->vcc->vci : 0,					  rulla->recv_vcc ? rulla->recv_vcc->					  vpi : 0,					  rulla->recv_vcc ? rulla->recv_vcc->					  vci : 0, rulla->last_used,					  rulla->timestamp, rulla->no_tries);			offset +=			    sprintf(buf + offset,				    "Flags:%x, Packets_flooded:%x, Status: %s ",				    rulla->flags, rulla->packets_flooded,				    get_status_string(rulla->status));			printk("%s\n", buf);		}	}	if (!hlist_empty(&priv->lec_no_forward))		printk("No forward\n");	hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {		offset = 0;		offset += sprintf(buf + offset, "Mac:");		for (j = 0; j < ETH_ALEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->mac_addr[j] & 0xff);		}		offset += sprintf(buf + offset, "Atm:");		for (j = 0; j < ATM_ESA_LEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->atm_addr[j] & 0xff);		}		offset += sprintf(buf + offset,				  "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",				  rulla->vcc ? rulla->vcc->vpi : 0,				  rulla->vcc ? rulla->vcc->vci : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vci : 0,				  rulla->last_used,				  rulla->timestamp, rulla->no_tries);		offset += sprintf(buf + offset,				  "Flags:%x, Packets_flooded:%x, Status: %s ",				  rulla->flags, rulla->packets_flooded,				  get_status_string(rulla->status));		printk("%s\n", buf);	}	if (!hlist_empty(&priv->lec_arp_empty_ones))		printk("Empty ones\n");	hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {		offset = 0;		offset += sprintf(buf + offset, "Mac:");		for (j = 0; j < ETH_ALEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->mac_addr[j] & 0xff);		}		offset += sprintf(buf + offset, "Atm:");		for (j = 0; j < ATM_ESA_LEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->atm_addr[j] & 0xff);		}		offset += sprintf(buf + offset,				  "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",				  rulla->vcc ? rulla->vcc->vpi : 0,				  rulla->vcc ? rulla->vcc->vci : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vci : 0,				  rulla->last_used,				  rulla->timestamp, rulla->no_tries);		offset += sprintf(buf + offset,				  "Flags:%x, Packets_flooded:%x, Status: %s ",				  rulla->flags, rulla->packets_flooded,				  get_status_string(rulla->status));		printk("%s", buf);	}	if (!hlist_empty(&priv->mcast_fwds))		printk("Multicast Forward VCCs\n");	hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {		offset = 0;		offset += sprintf(buf + offset, "Mac:");		for (j = 0; j < ETH_ALEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->mac_addr[j] & 0xff);		}		offset += sprintf(buf + offset, "Atm:");		for (j = 0; j < ATM_ESA_LEN; j++) {			offset += sprintf(buf + offset, "%2.2x ",					  rulla->atm_addr[j] & 0xff);		}		offset += sprintf(buf + offset,				  "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",				  rulla->vcc ? rulla->vcc->vpi : 0,				  rulla->vcc ? rulla->vcc->vci : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,				  rulla->recv_vcc ? rulla->recv_vcc->vci : 0,				  rulla->last_used,				  rulla->timestamp, rulla->no_tries);		offset += sprintf(buf + offset,				  "Flags:%x, Packets_flooded:%x, Status: %s ",				  rulla->flags, rulla->packets_flooded,				  get_status_string(rulla->status));		printk("%s\n", buf);	}}#else#define dump_arp_table(priv) do { } while (0)#endif/* * Destruction of arp-cache */static void lec_arp_destroy(struct lec_priv *priv){	unsigned long flags;	struct hlist_node *node, *next;	struct lec_arp_table *entry;	int i;	cancel_rearming_delayed_work(&priv->lec_arp_work);	/*	 * Remove all entries	 */	spin_lock_irqsave(&priv->lec_arp_lock, flags);	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {		hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {			lec_arp_remove(priv, entry);			lec_arp_put(entry);		}		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);	}	hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {		del_timer_sync(&entry->timer);		lec_arp_clear_vccs(entry);		hlist_del(&entry->next);		lec_arp_put(entry);	}	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);	hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {		del_timer_sync(&entry->timer);		lec_arp_clear_vccs(entry);		hlist_del(&entry->next);		lec_arp_put(entry);	}	INIT_HLIST_HEAD(&priv->lec_no_forward);	hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {		/* No timer, LANEv2 7.1.20 and 2.3.5.3 */		lec_arp_clear_vccs(entry);		hlist_del(&entry->next);		lec_arp_put(entry);	}	INIT_HLIST_HEAD(&priv->mcast_fwds);	priv->mcast_vcc = NULL;	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);}/* * Find entry by mac_address */static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,					  unsigned char *mac_addr){	struct hlist_node *node;	struct hlist_head *head;	struct lec_arp_table *entry;	pr_debug("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",		mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff,		mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff);	head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];	hlist_for_each_entry(entry, node, head, next) {		if (!compare_ether_addr(mac_addr, entry->mac_addr)) {			return entry;		}	}	return NULL;}static struct lec_arp_table *make_entry(struct lec_priv *priv,					unsigned char *mac_addr){	struct lec_arp_table *to_return;	to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);	if (!to_return) {		printk("LEC: Arp entry kmalloc failed\n");		return NULL;	}	memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);	INIT_HLIST_NODE(&to_return->next);	init_timer(&to_return->timer);	to_return->timer.function = lec_arp_expire_arp;	to_return->timer.data = (unsigned long)to_return;	to_return->last_used = jiffies;	to_return->priv = priv;	skb_queue_head_init(&to_return->tx_wait);	atomic_set(&to_return->usage, 1);	return to_return;}/* Arp sent timer expired */static void lec_arp_expire_arp(unsigned long data){	struct lec_arp_table *entry;	entry = (struct lec_arp_table *)data;	pr_debug("lec_arp_expire_arp\n");	if (entry->status == ESI_ARP_PENDING) {		if (entry->no_tries <= entry->priv->max_retry_count) {			if (entry->is_rdesc)				send_to_lecd(entry->priv, l_rdesc_arp_xmt,					     entry->mac_addr, NULL, NULL);			else				send_to_lecd(entry->priv, l_arp_xmt,					     entry->mac_addr, NULL, NULL);			entry->no_tries++;		}		mod_timer(&entry->timer, jiffies + (1 * HZ));	}}/* Unknown/unused vcc expire, remove associated entry */static void lec_arp_expire_vcc(unsigned long data){	unsigned long flags;	struct lec_arp_table *to_remove = (struct lec_arp_table *)data;	struct lec_priv *priv = (struct lec_priv *)to_remove->priv;	del_timer(&to_remove->timer);	pr_debug("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",		to_remove, priv,		to_remove->vcc ? to_remove->recv_vcc->vpi : 0,		to_remove->vcc ? to_remove->recv_vcc->vci : 0);	spin_lock_irqsave(&priv->lec_arp_lock, flags);	hlist_del(&to_remove->next);	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);	lec_arp_clear_vccs(to_remove);	lec_arp_put(to_remove);}/* * Expire entries. * 1. Re-set timer * 2. For each entry, delete entries that have aged past the age limit. * 3. For each entry, depending on the status of the entry, perform *    the following maintenance. *    a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the *       tick_count is above the max_unknown_frame_time, clear *       the tick_count to zero and clear the packets_flooded counter *       to zero. This supports the packet rate limit per address *       while flooding unknowns. *    b. If the status is ESI_FLUSH_PENDING and the tick_count is greater *       than or equal to the path_switching_delay, change the status *       to ESI_FORWARD_DIRECT. This causes the flush period to end *       regardless of the progress of the flush protocol. */static void lec_arp_check_expire(struct work_struct *work){	unsigned long flags;	struct lec_priv *priv =		container_of(work, struct lec_priv, lec_arp_work.work);	struct hlist_node *node, *next;	struct lec_arp_table *entry;	unsigned long now;	unsigned long time_to_check;	int i;	pr_debug("lec_arp_check_expire %p\n", priv);	now = jiffies;restart:	spin_lock_irqsave(&priv->lec_arp_lock, flags);	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {		hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {			if ((entry->flags) & LEC_REMOTE_FLAG &&			    priv->topology_change)				time_to_check = priv->forward_delay_time;			else				time_to_check = priv->aging_time;			pr_debug("About to expire: %lx - %lx > %lx\n",				now, entry->last_used, time_to_check);			if (time_after(now, entry->last_used + time_to_check)			    && !(entry->flags & LEC_PERMANENT_FLAG)			    && !(entry->mac_addr[0] & 0x01)) {	/* LANE2: 7.1.20 */				/* Remove entry */				pr_debug("LEC:Entry timed out\n");				lec_arp_remove(priv, entry);				lec_arp_put(entry);			} else {				/* Something else */				if ((entry->status == ESI_VC_PENDING ||				     entry->status == ESI_ARP_PENDING)				    && time_after_eq(now,						     entry->timestamp +						     priv->						     max_unknown_frame_time)) {					entry->timestamp = jiffies;					entry->packets_flooded = 0;					if (entry->status == ESI_VC_PENDING)						send_to_lecd(priv, l_svc_setup,							     entry->mac_addr,							     entry->atm_addr,							     NULL);				}				if (entry->status == ESI_FLUSH_PENDING				    &&				    time_after_eq(now, entry->timestamp +						  priv->path_switching_delay)) {					struct sk_buff *skb;					struct atm_vcc *vcc = entry->vcc;					lec_arp_hold(entry);					spin_unlock_irqrestore(&priv->lec_arp_lock, flags);					while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)						lec_send(vcc, skb, entry->priv);					entry->last_used = jiffies;					entry->status = ESI_FORWARD_DIRECT;					lec_arp_put(entry);					goto restart;				}			}		}	}	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);}/* * Try to find vcc where mac_address is attached. *

⌨️ 快捷键说明

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