updated version, consistent with the kernel patch.
[vde.git] / vde / hash.c
blob7817ba7849a24c37410f3dd7ea198681ed67a8d9
1 /* Copyright 2002 Yon Uriarte and Jeff Dike
2 * Licensed under the GPL
3 * This file is part of the original uml_switch code
4 * Modified 2003 Renzo Davoli
5 */
7 #include <config.h>
8 #include <stddef.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <time.h>
15 #include <syslog.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/signal.h>
20 #include <switch.h>
21 #include <hash.h>
23 #define HASH_SIZE 128
24 #define HASH_MOD 11
26 struct hash_entry {
27 struct hash_entry *next;
28 struct hash_entry *prev;
29 time_t last_seen;
30 void *port;
31 unsigned char dst[ETH_ALEN];
34 static struct hash_entry *h[HASH_SIZE];
36 static int calc_hash(char *src)
38 return ((*(u_int32_t *) &src[0] % HASH_MOD) ^ src[4] ^ src[5] ) % HASH_SIZE ;
41 static struct hash_entry *find_entry(char *dst)
43 struct hash_entry *e;
44 int k = calc_hash(dst);
46 for(e = h[k]; e; e = e->next){
47 if(!memcmp(&e->dst, dst, ETH_ALEN)) return(e);
49 return(NULL);
52 /* looks in global hash table 'h' for given address, and return associated
53 * port */
54 void *find_in_hash(char *dst)
56 struct hash_entry *e = find_entry(dst);
57 if(e == NULL) return(NULL);
58 return(e->port);
61 void insert_into_hash(char *src, void *port)
63 struct hash_entry *new;
64 int k = calc_hash(src);
66 new = find_in_hash(src);
67 if(new != NULL) return;
69 new = malloc(sizeof(*new));
70 if(new == NULL){
71 printlog(LOG_WARNING,"Failed to malloc hash entry %s",strerror(errno));
72 return;
75 memcpy(&new->dst, src, ETH_ALEN );
76 if(h[k] != NULL) h[k]->prev = new;
77 new->next = h[k];
78 new->prev = NULL;
79 new->port = port;
80 new->last_seen = 0;
81 h[k] = new;
84 void update_entry_time(char *src)
86 struct hash_entry *e;
88 e = find_entry(src);
89 if(e == NULL) return;
90 e->last_seen = time(NULL);
93 /* removes given hash entry from the global table 'h' */
94 static void delete_hash_entry(struct hash_entry *old)
96 int k = calc_hash(old->dst);
98 if(old->prev != NULL) old->prev->next = old->next;
99 if(old->next != NULL) old->next->prev = old->prev;
100 if(h[k] == old) h[k] = old->next;
101 free(old);
104 void delete_hash(char *dst)
106 struct hash_entry *old = find_entry(dst);
108 if(old == NULL) return;
109 delete_hash_entry(old);
112 /* for each entry of the global hash table 'h', calls function f, passing to it
113 * the hash entry and the additional arg 'arg' */
114 static void for_all_hash(void (*f)(struct hash_entry *, void *), void *arg)
116 int i;
117 struct hash_entry *e, *next;
119 for(i = 0; i < HASH_SIZE; i++){
120 for(e = h[i]; e; e = next){
121 next = e->next;
122 (*f)(e, arg);
127 struct printer {
128 time_t now;
129 char *(*port_id)(void *);
132 static void print_hash_entry(struct hash_entry *e, void *arg)
134 struct printer *p = arg;
136 printf("Hash: %d Addr: %02x:%02x:%02x:%02x:%02x:%02x to port: %s "
137 "age %ld secs\n", calc_hash(e->dst),
138 e->dst[0], e->dst[1], e->dst[2], e->dst[3], e->dst[4], e->dst[5],
139 (*p->port_id)(e->port), (int) p->now - e->last_seen);
142 void print_hash(char *(*port_id)(void *))
144 struct printer p = ((struct printer) { now : time(NULL),
145 port_id : port_id });
147 for_all_hash(print_hash_entry, &p);
150 struct reassign_data {
151 void *port;
152 void *newport;
155 static void reassing_iterator (struct hash_entry *e, void *arg)
157 struct reassign_data *p=arg;
159 if (e->port == p->port)
160 e->port = p->newport;
163 void hash_reassign (void *port, void *newport)
165 struct reassign_data p=((struct reassign_data) { port : port,
166 newport : newport });
167 for_all_hash(reassing_iterator, &p);
170 static void delete_port_iterator (struct hash_entry *e, void *arg)
172 if (e->port == arg)
173 delete_hash_entry(e);
176 void hash_delete_port (void *port)
178 for_all_hash(delete_port_iterator,port);
182 #define GC_INTERVAL 2
183 #define GC_EXPIRE 100
185 /* clean from the hash table entries older than GC_EXPIRE seconds, given that
186 * 'now' points to a time_t structure describing the current time */
187 static void gc(struct hash_entry *e, void *now)
189 time_t t = *(time_t *) now;
191 if(e->last_seen + GC_EXPIRE < t)
192 delete_hash_entry(e);
195 /* clean old entries in the hash table 'h', and prepare the timer to be called
196 * again between GC_INTERVAL seconds */
197 static void sig_alarm(int sig)
199 struct itimerval it;
200 time_t t = time(NULL);
201 for_all_hash(&gc, &t);
203 it.it_value.tv_sec = GC_INTERVAL;
204 it.it_value.tv_usec = 0 ;
205 it.it_interval.tv_sec = 0;
206 it.it_interval.tv_usec = 0 ;
207 setitimer(ITIMER_REAL, &it, NULL);
210 /* sets sig_alarm as handler for SIGALRM, and run it a first time */
211 void hash_init(void)
213 struct sigaction sa;
215 sa.sa_handler = sig_alarm;
216 sa.sa_flags = SA_RESTART;
217 if(sigaction(SIGALRM, &sa, NULL) < 0){
218 printlog(LOG_WARNING,"Setting handler for SIGALRM %s", strerror(errno));
219 return;
221 kill(getpid(), SIGALRM);