xref: /openbsd-src/usr.sbin/bgpd/rde_sets.c (revision e386eeb169001ba40fb5933f7e7f4e432772e268)
1*e386eeb1Sclaudio /*	$OpenBSD: rde_sets.c,v 1.13 2024/09/10 09:38:45 claudio Exp $ */
2a8e18e82Sclaudio 
3a8e18e82Sclaudio /*
4a8e18e82Sclaudio  * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org>
5a8e18e82Sclaudio  *
6a8e18e82Sclaudio  * Permission to use, copy, modify, and distribute this software for any
7a8e18e82Sclaudio  * purpose with or without fee is hereby granted, provided that the above
8a8e18e82Sclaudio  * copyright notice and this permission notice appear in all copies.
9a8e18e82Sclaudio  *
10a8e18e82Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a8e18e82Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a8e18e82Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a8e18e82Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a8e18e82Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a8e18e82Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a8e18e82Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a8e18e82Sclaudio  */
18a8e18e82Sclaudio #include <sys/types.h>
19a8e18e82Sclaudio #include <sys/queue.h>
20a8e18e82Sclaudio 
21a8e18e82Sclaudio #include <assert.h>
22a8e18e82Sclaudio #include <errno.h>
23a8e18e82Sclaudio #include <limits.h>
24a8e18e82Sclaudio #include <stdlib.h>
25a8e18e82Sclaudio #include <stdio.h>
26a8e18e82Sclaudio #include <string.h>
27a8e18e82Sclaudio 
28a8e18e82Sclaudio #include "rde.h"
29a8e18e82Sclaudio 
3059e404fbSclaudio struct set_table {
3178355a53Sclaudio 	void			*set;
32a8e18e82Sclaudio 	size_t			 nmemb;
3378355a53Sclaudio 	size_t			 size;
34a8e18e82Sclaudio 	size_t			 max;
35a8e18e82Sclaudio };
36a8e18e82Sclaudio 
3759e404fbSclaudio struct as_set *
3859e404fbSclaudio as_sets_new(struct as_set_head *as_sets, const char *name, size_t nmemb,
3959e404fbSclaudio     size_t size)
40a8e18e82Sclaudio {
4159e404fbSclaudio 	struct as_set *aset;
4259e404fbSclaudio 	size_t len;
4359e404fbSclaudio 
4459e404fbSclaudio 	aset = calloc(1, sizeof(*aset));
4559e404fbSclaudio 	if (aset == NULL)
4659e404fbSclaudio 		return NULL;
4759e404fbSclaudio 
4859e404fbSclaudio 	len = strlcpy(aset->name, name, sizeof(aset->name));
4959e404fbSclaudio 	assert(len < sizeof(aset->name));
5059e404fbSclaudio 
5159e404fbSclaudio 	aset->set = set_new(nmemb, size);
5259e404fbSclaudio 	if (aset->set == NULL) {
5359e404fbSclaudio 		free(aset);
5459e404fbSclaudio 		return NULL;
5559e404fbSclaudio 	}
5659e404fbSclaudio 
57a8e18e82Sclaudio 	SIMPLEQ_INSERT_TAIL(as_sets, aset, entry);
5859e404fbSclaudio 	return aset;
59a8e18e82Sclaudio }
60a8e18e82Sclaudio 
61a8e18e82Sclaudio struct as_set *
62a8e18e82Sclaudio as_sets_lookup(struct as_set_head *as_sets, const char *name)
63a8e18e82Sclaudio {
64a8e18e82Sclaudio 	struct as_set *aset;
65a8e18e82Sclaudio 
66a8e18e82Sclaudio 	SIMPLEQ_FOREACH(aset, as_sets, entry) {
67a8e18e82Sclaudio 		if (strcmp(aset->name, name) == 0)
68a8e18e82Sclaudio 			return aset;
69a8e18e82Sclaudio 	}
70a8e18e82Sclaudio 	return NULL;
71a8e18e82Sclaudio }
72a8e18e82Sclaudio 
73a8e18e82Sclaudio 
74a8e18e82Sclaudio void
75a8e18e82Sclaudio as_sets_free(struct as_set_head *as_sets)
76a8e18e82Sclaudio {
77a8e18e82Sclaudio 	struct as_set *aset;
78a8e18e82Sclaudio 
79a8e18e82Sclaudio 	if (as_sets == NULL)
80a8e18e82Sclaudio 		return;
81a8e18e82Sclaudio 	while (!SIMPLEQ_EMPTY(as_sets)) {
82a8e18e82Sclaudio 		aset = SIMPLEQ_FIRST(as_sets);
83a8e18e82Sclaudio 		SIMPLEQ_REMOVE_HEAD(as_sets, entry);
8459e404fbSclaudio 		set_free(aset->set);
8559e404fbSclaudio 		free(aset);
86a8e18e82Sclaudio 	}
87a8e18e82Sclaudio }
88a8e18e82Sclaudio 
89a8e18e82Sclaudio void
90a8e18e82Sclaudio as_sets_mark_dirty(struct as_set_head *old, struct as_set_head *new)
91a8e18e82Sclaudio {
92a8e18e82Sclaudio 	struct as_set	*n, *o;
93a8e18e82Sclaudio 
94a8e18e82Sclaudio 	SIMPLEQ_FOREACH(n, new, entry) {
95a8e18e82Sclaudio 		if (old == NULL || (o = as_sets_lookup(old, n->name)) == NULL ||
967ff9bf35Sclaudio 		    !set_equal(n->set, o->set)) {
97a8e18e82Sclaudio 			n->dirty = 1;
987ff9bf35Sclaudio 			n->lastchange = getmonotime();
997ff9bf35Sclaudio 		} else
1007ff9bf35Sclaudio 			n->lastchange = o->lastchange;
101a8e18e82Sclaudio 	}
102a8e18e82Sclaudio }
103a8e18e82Sclaudio 
10459e404fbSclaudio int
10539386878Sclaudio as_set_match(const struct as_set *aset, uint32_t asnum)
106a8e18e82Sclaudio {
10759e404fbSclaudio 	return set_match(aset->set, asnum) != NULL;
10859e404fbSclaudio }
109a8e18e82Sclaudio 
11059e404fbSclaudio struct set_table *
11159e404fbSclaudio set_new(size_t nmemb, size_t size)
11259e404fbSclaudio {
11359e404fbSclaudio 	struct set_table *set;
11459e404fbSclaudio 
11559e404fbSclaudio 	set = calloc(1, sizeof(*set));
11659e404fbSclaudio 	if (set == NULL)
117a8e18e82Sclaudio 		return NULL;
118a8e18e82Sclaudio 
119a8e18e82Sclaudio 	if (nmemb == 0)
12078355a53Sclaudio 		nmemb = 4;
121a8e18e82Sclaudio 
12259e404fbSclaudio 	set->size = size;
12359e404fbSclaudio 	set->max = nmemb;
12459e404fbSclaudio 	set->set = calloc(nmemb, set->size);
12559e404fbSclaudio 	if (set->set == NULL) {
12659e404fbSclaudio 		free(set);
127a8e18e82Sclaudio 		return NULL;
128a8e18e82Sclaudio 	}
129a8e18e82Sclaudio 
130e5b62a74Sclaudio 	rdemem.aset_cnt++;
131e5b62a74Sclaudio 	rdemem.aset_size += sizeof(*set);
1322762ea3aSclaudio 	rdemem.aset_size += set->size * set->max;
13359e404fbSclaudio 	return set;
134a8e18e82Sclaudio }
135a8e18e82Sclaudio 
13678355a53Sclaudio void
13759e404fbSclaudio set_free(struct set_table *set)
13878355a53Sclaudio {
13959e404fbSclaudio 	if (set == NULL)
14078355a53Sclaudio 		return;
141e5b62a74Sclaudio 	rdemem.aset_cnt--;
142e5b62a74Sclaudio 	rdemem.aset_size -= sizeof(*set);
143e5b62a74Sclaudio 	rdemem.aset_size -= set->size * set->max;
144e5b62a74Sclaudio 	rdemem.aset_nmemb -= set->nmemb;
14559e404fbSclaudio 	free(set->set);
14659e404fbSclaudio 	free(set);
14778355a53Sclaudio }
14878355a53Sclaudio 
149a8e18e82Sclaudio int
15059e404fbSclaudio set_add(struct set_table *set, void *elms, size_t nelms)
151a8e18e82Sclaudio {
152*e386eeb1Sclaudio 	if (nelms == 0)		/* nothing todo */
153*e386eeb1Sclaudio 		return 0;
154*e386eeb1Sclaudio 
15559e404fbSclaudio 	if (set->max < nelms || set->max - nelms < set->nmemb) {
15639386878Sclaudio 		uint32_t *s;
157a8e18e82Sclaudio 		size_t new_size;
158a8e18e82Sclaudio 
159a985ac10Sclaudio 		if (set->nmemb >= SIZE_MAX - 4096 - nelms) {
160a8e18e82Sclaudio 			errno = ENOMEM;
161a8e18e82Sclaudio 			return -1;
162a8e18e82Sclaudio 		}
16359e404fbSclaudio 		for (new_size = set->max; new_size < set->nmemb + nelms; )
164a8e18e82Sclaudio 			new_size += (new_size < 4096 ? new_size : 4096);
165a8e18e82Sclaudio 
16659e404fbSclaudio 		s = reallocarray(set->set, new_size, set->size);
167a8e18e82Sclaudio 		if (s == NULL)
168a8e18e82Sclaudio 			return -1;
169e5b62a74Sclaudio 		rdemem.aset_size += set->size * (new_size - set->max);
17059e404fbSclaudio 		set->set = s;
17159e404fbSclaudio 		set->max = new_size;
172a8e18e82Sclaudio 	}
173a8e18e82Sclaudio 
17439386878Sclaudio 	memcpy((uint8_t *)set->set + set->nmemb * set->size, elms,
17559e404fbSclaudio 	    nelms * set->size);
17659e404fbSclaudio 	set->nmemb += nelms;
177e5b62a74Sclaudio 	rdemem.aset_nmemb += nelms;
178a8e18e82Sclaudio 
179a8e18e82Sclaudio 	return 0;
180a8e18e82Sclaudio }
181a8e18e82Sclaudio 
18259e404fbSclaudio void *
18359e404fbSclaudio set_get(struct set_table *set, size_t *nelms)
18459e404fbSclaudio {
18559e404fbSclaudio 	*nelms = set->nmemb;
18659e404fbSclaudio 	return set->set;
18759e404fbSclaudio }
18859e404fbSclaudio 
189a8e18e82Sclaudio static int
19059e404fbSclaudio set_cmp(const void *ap, const void *bp)
191a8e18e82Sclaudio {
19239386878Sclaudio 	const uint32_t *a = ap;
19339386878Sclaudio 	const uint32_t *b = bp;
194a8e18e82Sclaudio 
195a8e18e82Sclaudio 	if (*a > *b)
196a8e18e82Sclaudio 		return 1;
197a8e18e82Sclaudio 	else if (*a < *b)
198a8e18e82Sclaudio 		return -1;
199a8e18e82Sclaudio 	return 0;
200a8e18e82Sclaudio }
201a8e18e82Sclaudio 
202a8e18e82Sclaudio void
20359e404fbSclaudio set_prep(struct set_table *set)
204a8e18e82Sclaudio {
20559e404fbSclaudio 	if (set == NULL)
20678355a53Sclaudio 		return;
20759e404fbSclaudio 	qsort(set->set, set->nmemb, set->size, set_cmp);
208a8e18e82Sclaudio }
209a8e18e82Sclaudio 
21078355a53Sclaudio void *
21139386878Sclaudio set_match(const struct set_table *a, uint32_t asnum)
212a8e18e82Sclaudio {
21378355a53Sclaudio 	if (a == NULL)
21478355a53Sclaudio 		return NULL;
21559e404fbSclaudio 	return bsearch(&asnum, a->set, a->nmemb, a->size, set_cmp);
216a8e18e82Sclaudio }
217a8e18e82Sclaudio 
218a8e18e82Sclaudio int
21959e404fbSclaudio set_equal(const struct set_table *a, const struct set_table *b)
220a8e18e82Sclaudio {
22159e404fbSclaudio 	/* allow NULL pointers to be passed */
22259e404fbSclaudio 	if (a == NULL && b == NULL)
22359e404fbSclaudio 		return 1;
22459e404fbSclaudio 	if (a == NULL || b == NULL)
22559e404fbSclaudio 		return 0;
22659e404fbSclaudio 
227a8e18e82Sclaudio 	if (a->nmemb != b->nmemb)
228a8e18e82Sclaudio 		return 0;
22978355a53Sclaudio 	if (memcmp(a->set, b->set, a->nmemb * a->size) != 0)
230a8e18e82Sclaudio 		return 0;
231a8e18e82Sclaudio 	return 1;
232a8e18e82Sclaudio }
2337ff9bf35Sclaudio 
2347ff9bf35Sclaudio size_t
2357ff9bf35Sclaudio set_nmemb(const struct set_table *set)
2367ff9bf35Sclaudio {
2377ff9bf35Sclaudio 	return set->nmemb;
2387ff9bf35Sclaudio }
239