summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/rde_sets.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd/rde_sets.c')
-rw-r--r--usr.sbin/bgpd/rde_sets.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/usr.sbin/bgpd/rde_sets.c b/usr.sbin/bgpd/rde_sets.c
new file mode 100644
index 00000000000..1d9e744ce50
--- /dev/null
+++ b/usr.sbin/bgpd/rde_sets.c
@@ -0,0 +1,239 @@
+/* $OpenBSD: rde_sets.c,v 1.1 2018/09/07 05:43:33 claudio Exp $ */
+
+/*
+ * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "rde.h"
+
+struct as_set {
+ char name[SET_NAME_LEN];
+ u_int32_t *set;
+ SIMPLEQ_ENTRY(as_set) entry;
+ size_t nmemb;
+ size_t max;
+ int dirty;
+};
+
+void
+as_sets_insert(struct as_set_head *as_sets, struct as_set *aset)
+{
+ SIMPLEQ_INSERT_TAIL(as_sets, aset, entry);
+}
+
+struct as_set *
+as_sets_lookup(struct as_set_head *as_sets, const char *name)
+{
+ struct as_set *aset;
+
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ if (strcmp(aset->name, name) == 0)
+ return aset;
+ }
+ return NULL;
+}
+
+static void
+as_set_free(struct as_set *aset)
+{
+ free(aset->set);
+ free(aset);
+}
+
+void
+as_sets_free(struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+
+ if (as_sets == NULL)
+ return;
+ while (!SIMPLEQ_EMPTY(as_sets)) {
+ aset = SIMPLEQ_FIRST(as_sets);
+ SIMPLEQ_REMOVE_HEAD(as_sets, entry);
+ as_set_free(aset);
+ }
+ free(as_sets);
+}
+
+void
+print_as_sets(struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+ size_t i;
+ int len = 0;;
+
+ if (as_sets == NULL)
+ return;
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ printf("as-set \"%s\" {", aset->name);
+ for (i = 0; i < aset->nmemb; i++) {
+ if (len == 0 || len > 72)
+ len = printf("\n\t");
+ len += printf("%u ", aset->set[i]);
+ }
+ printf("\n}\n\n");
+ }
+}
+
+int
+as_sets_send(struct imsgbuf *ibuf, struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+ struct ibuf *wbuf;
+ size_t i, l;
+
+ if (as_sets == NULL)
+ return 0;
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ if ((wbuf = imsg_create(ibuf, IMSG_RECONF_AS_SET, 0, 0,
+ sizeof(aset->nmemb) + sizeof(aset->name))) == NULL)
+ return -1;
+ if (imsg_add(wbuf, &aset->nmemb, sizeof(aset->nmemb)) == -1 ||
+ imsg_add(wbuf, aset->name, sizeof(aset->name)) == -1)
+ return -1;
+ imsg_close(ibuf, wbuf);
+
+ for (i = 0; i < aset->nmemb; i += l) {
+ l = (aset->nmemb - i > 1024 ? 1024 : aset->nmemb - i);
+
+ if (imsg_compose(ibuf, IMSG_RECONF_AS_SET_ITEMS, 0, 0,
+ -1, aset->set + i, l * sizeof(*aset->set)) == -1)
+ return -1;
+ }
+
+ if (imsg_compose(ibuf, IMSG_RECONF_AS_SET_DONE, 0, 0, -1,
+ NULL, 0) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+void
+as_sets_mark_dirty(struct as_set_head *old, struct as_set_head *new)
+{
+ struct as_set *n, *o;
+
+ SIMPLEQ_FOREACH(n, new, entry) {
+ if (old == NULL || (o = as_sets_lookup(old, n->name)) == NULL ||
+ !as_set_equal(n, o))
+ n->dirty = 1;
+ }
+}
+
+struct as_set *
+as_set_new(const char *name, size_t nmemb)
+{
+ struct as_set *aset;
+ size_t len;
+
+ aset = calloc(1, sizeof(*aset));
+ if (aset == NULL)
+ return NULL;
+
+ len = strlcpy(aset->name, name, sizeof(aset->name));
+ assert(len < sizeof(aset->name));
+
+ if (nmemb == 0)
+ nmemb = 16;
+
+ aset->max = nmemb;
+ aset->set = calloc(nmemb, sizeof(*aset->set));
+ if (aset->set == NULL) {
+ free(aset);
+ return NULL;
+ }
+
+ return aset;
+}
+
+int
+as_set_add(struct as_set *aset, u_int32_t *elms, size_t nelms)
+{
+ if (aset->max < nelms || aset->max - nelms < aset->nmemb) {
+ u_int32_t *s;
+ size_t new_size;
+
+ if (aset->nmemb >= SIZE_T_MAX - 4096 - nelms) {
+ errno = ENOMEM;
+ return -1;
+ }
+ for (new_size = aset->max; new_size < aset->nmemb + nelms; )
+ new_size += (new_size < 4096 ? new_size : 4096);
+
+ s = reallocarray(aset->set, new_size, sizeof(*aset->set));
+ if (s == NULL)
+ return -1;
+ aset->set = s;
+ aset->max = new_size;
+ }
+
+ memcpy(aset->set + aset->nmemb, elms, nelms * sizeof(*elms));
+ aset->nmemb += nelms;
+
+ return 0;
+}
+
+static int
+as_set_cmp(const void *ap, const void *bp)
+{
+ const u_int32_t *a = ap;
+ const u_int32_t *b = bp;
+
+ if (*a > *b)
+ return 1;
+ else if (*a < *b)
+ return -1;
+ return 0;
+}
+
+void
+as_set_prep(struct as_set *aset)
+{
+ qsort(aset->set, aset->nmemb, sizeof(*aset->set), as_set_cmp);
+}
+
+int
+as_set_match(const struct as_set *a, u_int32_t asnum)
+{
+ if (bsearch(&asnum, a->set, a->nmemb, sizeof(asnum), as_set_cmp))
+ return 1;
+ else
+ return 0;
+}
+
+int
+as_set_equal(const struct as_set *a, const struct as_set *b)
+{
+ if (a->nmemb != b->nmemb)
+ return 0;
+ if (memcmp(a->set, b->set, a->nmemb * sizeof(*a->set)) != 0)
+ return 0;
+ return 1;
+}
+
+int
+as_set_dirty(const struct as_set *a)
+{
+ return (a->dirty);
+}