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
16 #include <sys/types.h>
18 #include <sys/signal.h>
27 struct hash_entry
*next
;
28 struct hash_entry
*prev
;
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
)
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
);
52 /* looks in global hash table 'h' for given address, and return associated
54 void *find_in_hash(char *dst
)
56 struct hash_entry
*e
= find_entry(dst
);
57 if(e
== NULL
) return(NULL
);
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));
71 printlog(LOG_WARNING
,"Failed to malloc hash entry %s",strerror(errno
));
75 memcpy(&new->dst
, src
, ETH_ALEN
);
76 if(h
[k
] != NULL
) h
[k
]->prev
= new;
84 void update_entry_time(char *src
)
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
;
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
)
117 struct hash_entry
*e
, *next
;
119 for(i
= 0; i
< HASH_SIZE
; i
++){
120 for(e
= h
[i
]; e
; e
= next
){
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
{
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
)
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
)
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 */
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
));
221 kill(getpid(), SIGALRM
);