File: vde_hashtable.c

package info (click to toggle)
vdeplug4 4.0.1-5.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 464 kB
  • sloc: ansic: 4,280; makefile: 19
file content (144 lines) | stat: -rw-r--r-- 3,580 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <libvdeplug_mod.h>

struct vde_hashtable {
	size_t payload_size;
	unsigned int hash_mask;
	uint64_t seed;
	/* plus the table here */
	char ht[];
};

struct ht_elem {
	uint64_t edst;
	time_t last_seen;
	char payload[];
};
#define sizeof_ht_elem(payload_size) (sizeof(struct ht_elem) + payload_size)

static inline __attribute__((always_inline)) struct ht_elem *ht_get(struct vde_hashtable *table, int index) {
	return (void *) (table->ht + index * sizeof_ht_elem(table->payload_size));
}

static inline __attribute__((always_inline)) int calc_hash(uint64_t src, unsigned int hash_mask, uint64_t seed)
{
	src ^= src >> 33 ^ seed; 
	src *= 0xff51afd7ed558ccd; 
	src ^= src >> 33;
	src *= 0xc4ceb9fe1a85ec53; 
	src ^= src >> 33;
	return src & hash_mask;
}

#define extmac(MAC,VLAN) \
	((*(uint32_t *) &((MAC)[0])) + ((uint64_t) ((*(uint16_t *) &((MAC)[4]))+ ((uint64_t) (VLAN) << 16)) << 32))


/* look in global hash table for given address, and return associated address */
void *vde_find_in_hash(struct vde_hashtable *table, unsigned char *dst, int vlan, time_t too_old)
{
	if (__builtin_expect(table == NULL, 0))
		return NULL;
	else {
		uint64_t edst;
		int index;
		struct ht_elem *entry;

		if ((dst[0] & 1) == 1) /* broadcast */
			return NULL;
		edst = extmac(dst,vlan);
		index = calc_hash(edst, table->hash_mask, table->seed);
		//printf("index %d\n",index);
		entry = ht_get(table, index);
		if (entry->edst == edst && entry->last_seen >= too_old)
			return &(entry->payload);
		else
			return NULL;
	}
}

void vde_find_in_hash_update(struct vde_hashtable *table, unsigned char *src, int vlan, void *payload, time_t now)
{
	if (__builtin_expect(table == NULL, 0))
		return;
	else {
		uint64_t esrc;
		int index;
		struct ht_elem *entry;

		if ((src[0] & 1) == 1) /* broadcast */
			return;

		esrc = extmac(src,vlan);
		index = calc_hash(esrc, table->hash_mask, table->seed);
		//printf("index %d\n",index);

		entry = ht_get(table, index);
		entry->edst = esrc;
		memcpy(&(entry->payload),payload,table->payload_size);
		entry->last_seen = now;
	}
}

void vde_hash_delete(struct vde_hashtable *table, void *payload)
{
	if (__builtin_expect(table == NULL, 0))
		return;
	else {
		unsigned int i;
		for (i = 0; i < table->hash_mask + 1; i++) {
			struct ht_elem *entry =  ht_get(table, i);
			if (memcmp(entry->payload, payload, table->payload_size) == 0)
				entry->last_seen = 0;
		}
	}
}

// #define vde_hash_init(type, hash_mask, seed) _vde_hash_init(sizeof(type), (hash_mask), (seed))

struct vde_hashtable *_vde_hash_init(size_t payload_size, unsigned int hashsize, uint64_t seed)
{
	struct vde_hashtable *retval;
	if (hashsize == 0)
		return NULL;
	hashsize = (2 << (sizeof(hashsize) * 8 - __builtin_clz(hashsize - 1) - 1));

	retval = calloc(1, sizeof(struct vde_hashtable) 
			+ hashsize * sizeof_ht_elem(payload_size));
	if (retval) {
		retval->payload_size = payload_size;
		retval->hash_mask = hashsize - 1;
		retval->seed = seed;
	}
	return retval;
}

void vde_hash_fini(struct vde_hashtable *table)
{
	free(table);
}

#if 0
int main() {
	struct vde_hashtable *ht = vde_hash_init(int, 15, 0);

	while(1) {
		unsigned char mac[7];
		unsigned int port;
		scanf("%6s %u",mac,&port);
		printf("%s %d \n",mac,port);
		if (port == 0) {
			int *pport = vde_find_in_hash(ht, mac, 0, time(NULL)-20);
			if (pport)
				printf("-> %d\n", *pport);
			else
				printf("-> not found\n");
		} else
			vde_find_in_hash_update(ht, mac, 0, &port, time(NULL));
	}
}
#endif