2 * Inter process networking (virtual distributed ethernet) module
3 * Hash table for Ethernet management
4 * (part of the View-OS project: wiki.virtualsquare.org)
6 * Copyright (C) 2007 Renzo Davoli (renzo@cs.unibo.it)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * Due to this file being licensed under the GPL there is controversy over
14 * whether this permits you to write a module that #includes this file
15 * without placing your module under the GPL. Please consult a lawyer for
16 * advice before doing this.
18 * WARNING: THIS CODE IS ALREADY EXTREEEEMELY EXPERIMENTAL
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/timer.h>
26 #include <linux/list.h>
27 #include <linux/jiffies.h>
28 #include "../af_ipn.h"
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("VIEW-OS TEAM");
33 MODULE_DESCRIPTION("Ethernet hash table Kernel Module");
35 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
41 static struct kmem_cache
*ipn_hash_elem_cache
;
42 static void ipn_hash_timer_expired(unsigned long arg
);
44 struct ipn_hash_elem
{
45 struct hlist_node hashnode
;
46 struct list_head lrunode
;
52 static inline int po2round(int vx
)
56 for (x
=vx
-1; x
; x
>>=1)
61 static inline int hashfun(u16
*key
,u16 vlan
,int mask
)
63 register int x
=key
[0] * 0x03050000 + key
[1] * 0x0709 +
64 key
[2] * 0x0b0d0000 + vlan
*0x1113;
65 x
= (x
^ x
>> 12 ^ x
>> 8 ^ x
>> 4) & mask
;
69 int ipn_hash_new(struct ipn_hash
*vdeh
,int size
,unsigned long timeout
)
71 if (size
<=0 || timeout
<=0)
73 vdeh
->hashtable
=kzalloc(sizeof(struct hlist_head
)*size
,GFP_KERNEL
);
76 INIT_LIST_HEAD(&vdeh
->lrulist
);
77 vdeh
->mask
=po2round(size
)-1;
78 vdeh
->timeout
=timeout
* HZ
;
79 spin_lock_init(&vdeh
->hashlock
);
80 setup_timer(&vdeh
->hashtimer
,ipn_hash_timer_expired
,
81 (unsigned long) vdeh
);
85 static void _ipn_hash_flush(struct ipn_hash
*vdeh
)
87 struct list_head
*node
;
88 struct list_head
*temp
;
89 list_for_each_safe(node
,temp
,&vdeh
->lrulist
) {
90 struct ipn_hash_elem
*elem
=list_entry(node
,struct ipn_hash_elem
,lrunode
);
92 printk("HASH DELETED FLUSH %x %x %x %x\n", elem
->key
[0], elem
->key
[1], elem
->key
[2], elem
->key
[3]);
94 list_del(&elem
->lrunode
);
95 hlist_del(&elem
->hashnode
);
96 kmem_cache_free(ipn_hash_elem_cache
,elem
);
100 void ipn_hash_flush(struct ipn_hash
*vdeh
)
102 spin_lock(&vdeh
->hashlock
);
103 _ipn_hash_flush(vdeh
);
104 spin_unlock(&vdeh
->hashlock
);
107 void ipn_hash_flush_key(struct ipn_hash
*vdeh
,u16
*key
,u16
*vlan
)
109 struct list_head
*node
;
110 struct list_head
*temp
;
111 spin_lock(&vdeh
->hashlock
);
112 list_for_each_safe(node
,temp
,&vdeh
->lrulist
) {
113 struct ipn_hash_elem
*elem
=list_entry(node
,struct ipn_hash_elem
,lrunode
);
114 if ((!key
|| (elem
->key
[0]==key
[0] &&
115 elem
->key
[1]==key
[1] &&
116 elem
->key
[2]==key
[2])) ||
117 (!vlan
|| elem
->key
[3]==*vlan
)) {
119 printk("HASH DELETED FLUSH KEY %x %x %x %x\n", elem
->key
[0], elem
->key
[1], elem
->key
[2], elem
->key
[3]);
121 list_del(&elem
->lrunode
);
122 hlist_del(&elem
->hashnode
);
123 kmem_cache_free(ipn_hash_elem_cache
,elem
);
126 spin_unlock(&vdeh
->hashlock
);
129 void ipn_hash_flush_port(struct ipn_hash
*vdeh
,int port
)
131 struct list_head
*node
;
132 struct list_head
*temp
;
133 spin_lock(&vdeh
->hashlock
);
134 list_for_each_safe(node
,temp
,&vdeh
->lrulist
) {
135 struct ipn_hash_elem
*elem
=list_entry(node
,struct ipn_hash_elem
,lrunode
);
136 if (elem
->port
==port
) {
138 printk("HASH DELETED FLUSH PORT %x %x %x %x\n", elem
->key
[0], elem
->key
[1], elem
->key
[2], elem
->key
[3]);
140 list_del(&elem
->lrunode
);
141 hlist_del(&elem
->hashnode
);
142 kmem_cache_free(ipn_hash_elem_cache
,elem
);
145 spin_unlock(&vdeh
->hashlock
);
148 void ipn_hash_free(struct ipn_hash
*vdeh
)
150 spin_lock(&vdeh
->hashlock
);
151 _ipn_hash_flush(vdeh
);
152 del_timer_sync(&vdeh
->hashtimer
);
153 kfree(vdeh
->hashtable
);
154 spin_unlock(&vdeh
->hashlock
);
157 static void ipn_hash_timer_expired(unsigned long arg
)
159 struct ipn_hash
*vdeh
=(struct ipn_hash
*) arg
;
160 struct list_head
*node
;
161 struct list_head
*temp
;
163 spin_lock(&vdeh
->hashlock
);
164 jiffies64
=get_jiffies_64();
166 printk("HASH TIMER %lld\n",jiffies64
);
168 list_for_each_safe(node
,temp
,&vdeh
->lrulist
) {
169 struct ipn_hash_elem
*elem
=list_entry(node
,struct ipn_hash_elem
,lrunode
);
170 long next
=elem
->expiretime
-jiffies64
;
173 printk("HASH DELETED TIMER %x %x %x %x\n", elem
->key
[0], elem
->key
[1], elem
->key
[2], elem
->key
[3]);
175 list_del(&elem
->lrunode
);
176 hlist_del(&elem
->hashnode
);
177 kmem_cache_free(ipn_hash_elem_cache
,elem
);
179 mod_timer(&vdeh
->hashtimer
,jiffies
+(unsigned long)next
);
183 spin_unlock(&vdeh
->hashlock
);
186 void ipn_hash_add(struct ipn_hash
*vdeh
,u16
*key
,u16 vlan
,int port
)
188 struct ipn_hash_elem
*elem
=NULL
;
189 int hashvalue
=hashfun(key
,vlan
,vdeh
->mask
);
191 spin_lock(&vdeh
->hashlock
);
193 struct hlist_node
*node
;
194 hlist_for_each_entry(elem
, node
,
195 &vdeh
->hashtable
[hashvalue
], hashnode
)
197 hlist_for_each_entry(elem
,
198 &vdeh
->hashtable
[hashvalue
], hashnode
)
201 if (elem
->key
[0]==key
[0] && elem
->key
[1]==key
[1] &&
202 elem
->key
[2]==key
[2] && elem
->key
[3]==vlan
) {
209 printk("FOUND SENDER %x %x %x %x (%d) <- %d (was %d)\n", key
[0], key
[1], key
[2], vlan
,hashvalue
,port
,elem
->port
);
211 list_del(&elem
->lrunode
);
212 hlist_del(&elem
->hashnode
);
213 } else if (vdeh
->timeout
>0){ /* vdeh->timeout == 0 means HUB */
215 printk("NEW HASH %x %x %x %x (%d) <- %d\n", key
[0], key
[1], key
[2], vlan
, hashvalue
,port
);
217 elem
=kmem_cache_alloc(ipn_hash_elem_cache
,GFP_KERNEL
);
219 elem
->key
[0]=key
[0]; elem
->key
[1]=key
[1];
220 elem
->key
[2]=key
[2]; elem
->key
[3]=vlan
;
225 list_add_tail(&elem
->lrunode
,&vdeh
->lrulist
);
226 hlist_add_head(&elem
->hashnode
,&vdeh
->hashtable
[hashvalue
]);
227 if (!timer_pending(&vdeh
->hashtimer
))
228 mod_timer(&vdeh
->hashtimer
,jiffies
+ vdeh
->timeout
);
229 elem
->expiretime
=get_jiffies_64() + vdeh
->timeout
;
231 spin_unlock(&vdeh
->hashlock
);
234 int ipn_hash_find(struct ipn_hash
*vdeh
,u16
*key
,u16 vlan
)
236 struct ipn_hash_elem
*elem
;
238 int hashvalue
=hashfun(key
,vlan
,vdeh
->mask
);
240 spin_lock(&vdeh
->hashlock
);
242 printk("SEARCH HASH %x %x %x %x \n", key
[0], key
[1], key
[2], vlan
);
245 struct hlist_node
*node
;
246 hlist_for_each_entry(elem
, node
,
247 &vdeh
->hashtable
[hashvalue
], hashnode
)
249 hlist_for_each_entry(elem
,
250 &vdeh
->hashtable
[hashvalue
], hashnode
)
253 if (elem
->key
[0]==key
[0] && elem
->key
[1]==key
[1] &&
254 elem
->key
[2]==key
[2] && elem
->key
[3]==vlan
) {
257 printk("FOUND HASH %x %x %x %x -> %d\n", key
[0], key
[1], key
[2], vlan
, rv
);
262 spin_unlock(&vdeh
->hashlock
);
266 int ipn_hash_init(void)
268 ipn_hash_elem_cache
=kmem_cache_create("ipn_hash",sizeof(struct ipn_hash_elem
),0,0,NULL
);
269 if (ipn_hash_elem_cache
)
275 void ipn_hash_fini(void)
277 if (ipn_hash_elem_cache
)
278 kmem_cache_destroy(ipn_hash_elem_cache
);
281 EXPORT_SYMBOL_GPL(ipn_hash_new
);
282 EXPORT_SYMBOL_GPL(ipn_hash_flush
);
283 EXPORT_SYMBOL_GPL(ipn_hash_flush_key
);
284 EXPORT_SYMBOL_GPL(ipn_hash_flush_port
);
285 EXPORT_SYMBOL_GPL(ipn_hash_free
);
286 EXPORT_SYMBOL_GPL(ipn_hash_add
);
287 EXPORT_SYMBOL_GPL(ipn_hash_find
);
289 module_init(ipn_hash_init
);
290 module_exit(ipn_hash_fini
);