-# $OpenBSD: Makefile,v 1.17 2020/05/02 14:33:33 claudio Exp $
+# $OpenBSD: Makefile,v 1.18 2022/10/17 12:01:19 claudio Exp $
.PATH: ${.CURDIR}/../bgpd
PROG= bgpctl
-SRCS= bgpctl.c output.c output_json.c parser.c mrtparser.c util.c json.c
+SRCS= bgpctl.c output.c output_json.c output_ometric.c parser.c \
+ mrtparser.c util.c json.c ometric.c
CFLAGS+= -Wall
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
-/* $OpenBSD: bgpctl.c,v 1.284 2022/10/07 09:20:30 claudio Exp $ */
+/* $OpenBSD: bgpctl.c,v 1.285 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
main(int argc, char *argv[])
{
struct sockaddr_un sa_un;
- int fd, n, done, ch, verbose = 0;
+ int fd, n, done, numdone, ch, verbose = 0;
struct imsg imsg;
struct network_config net;
struct parse_result *res;
case SHOW_RIB_MEM:
imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
break;
+ case SHOW_METRIC:
+ output = &ometric_output;
+ numdone = 2;
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
+ imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
+ break;
case RELOAD:
imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
res->reason, sizeof(res->reason));
break;
}
+ output->head(res);
+
+ again:
while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
+ if (msgbuf_write(&ibuf->w) <= 0)
err(1, "write error");
- output->head(res);
-
while (!done) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- err(1, "imsg_read error");
- if (n == 0)
- errx(1, "pipe closed");
-
while (!done) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
err(1, "imsg_get error");
done = show(&imsg, res);
imsg_free(&imsg);
}
+
+ if (done)
+ break;
+
+ if ((n = imsg_read(ibuf)) == -1)
+ err(1, "imsg_read error");
+ if (n == 0)
+ errx(1, "pipe closed");
+
+ }
+
+ if (res->action == SHOW_METRIC && --numdone > 0) {
+ done = 0;
+ goto again;
}
output->tail();
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NEIGHBOR:
+ if (output->neighbor == NULL)
+ break;
p = imsg->data;
output->neighbor(p, res);
break;
case IMSG_CTL_SHOW_TIMER:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(t))
errx(1, "wrong imsg len");
+ if (output->timer == NULL)
+ break;
memcpy(&t, imsg->data, sizeof(t));
if (t.type > 0 && t.type < Timer_Max)
output->timer(&t);
break;
case IMSG_CTL_SHOW_INTERFACE:
+ if (output->interface == NULL)
+ break;
iface = imsg->data;
output->interface(iface);
break;
case IMSG_CTL_SHOW_NEXTHOP:
+ if (output->nexthop == NULL)
+ break;
nh = imsg->data;
output->nexthop(nh);
break;
case IMSG_CTL_SHOW_NETWORK:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
errx(1, "wrong imsg len");
+ if (output->fib == NULL)
+ break;
kf = imsg->data;
output->fib(kf);
break;
case IMSG_CTL_SHOW_FIB_TABLES:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
errx(1, "wrong imsg len");
+ if (output->fib_table == NULL)
+ break;
kt = imsg->data;
output->fib_table(kt);
break;
case IMSG_CTL_SHOW_RIB:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rib))
errx(1, "wrong imsg len");
+ if (output->rib == NULL)
+ break;
memcpy(&rib, imsg->data, sizeof(rib));
aslen = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof(rib);
asdata = imsg->data;
warnx("bad IMSG_CTL_SHOW_RIB_COMMUNITIES received");
break;
}
+ if (output->communities == NULL)
+ break;
output->communities(imsg->data, ilen, res);
break;
case IMSG_CTL_SHOW_RIB_ATTR:
warnx("bad IMSG_CTL_SHOW_RIB_ATTR received");
break;
}
+ if (output->attr == NULL)
+ break;
output->attr(imsg->data, ilen, res->flags, 0);
break;
case IMSG_CTL_SHOW_RIB_MEM:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(stats))
errx(1, "wrong imsg len");
+ if (output->rib_mem == NULL)
+ break;
memcpy(&stats, imsg->data, sizeof(stats));
output->rib_mem(&stats);
return (1);
case IMSG_CTL_SHOW_SET:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(set))
errx(1, "wrong imsg len");
+ if (output->set == NULL)
+ break;
memcpy(&set, imsg->data, sizeof(set));
output->set(&set);
break;
case IMSG_CTL_SHOW_RTR:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rtr))
errx(1, "wrong imsg len");
+ if (output->rtr == NULL)
+ break;
memcpy(&rtr, imsg->data, sizeof(rtr));
output->rtr(&rtr);
break;
warnx("got IMSG_CTL_RESULT with wrong len");
break;
}
+ if (output->result == NULL)
+ break;
memcpy(&rescode, imsg->data, sizeof(rescode));
output->result(rescode);
return (1);
-/* $OpenBSD: bgpctl.h,v 1.16 2022/08/31 15:00:53 claudio Exp $ */
+/* $OpenBSD: bgpctl.h,v 1.17 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
void (*tail)(void);
};
-extern const struct output show_output, json_output;
+extern const struct output show_output, json_output, ometric_output;
extern const size_t pt_sizes[];
#define EOL0(flag) ((flag & F_CTL_SSV) ? ';' : '\n')
--- /dev/null
+/* $OpenBSD: ometric.c,v 1.1 2022/10/17 12:01:19 claudio Exp $ */
+
+/*
+ * Copyright (c) 2022 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/queue.h>
+
+#include <err.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ometric.h"
+
+struct olabel {
+ STAILQ_ENTRY(olabel) entry;
+ const char *key;
+ char *value;
+};
+
+struct olabels {
+ STAILQ_HEAD(, olabel) labels;
+ struct olabels *next;
+ int refcnt;
+};
+
+enum ovalue_type {
+ OVT_INTEGER,
+ OVT_DOUBLE,
+};
+
+struct ovalue {
+ STAILQ_ENTRY(ovalue) entry;
+ struct olabels *labels;
+ union {
+ uint64_t i;
+ double f;
+ } value;
+ enum ovalue_type valtype;
+};
+
+STAILQ_HEAD(ovalues, ovalue);
+
+struct ometric {
+ STAILQ_ENTRY(ometric) entry;
+ struct ovalues vals;
+ const char *name;
+ const char *help;
+ const char *const *stateset;
+ size_t setsize;
+ enum ometric_type type;
+};
+
+STAILQ_HEAD(, ometric) ometrics = STAILQ_HEAD_INITIALIZER(ometrics);
+
+/*
+ * Allocate and return new ometric. The name and help string need to remain
+ * valid until the ometric is freed. Normally constant strings should be used.
+ */
+struct ometric *
+ometric_new(enum ometric_type type, const char *name, const char *help)
+{
+ struct ometric *om;
+
+ if ((om = calloc(1, sizeof(*om))) == NULL)
+ err(1, NULL);
+
+ om->name = name;
+ om->help = help;
+ om->type = type;
+ STAILQ_INIT(&om->vals);
+
+ STAILQ_INSERT_TAIL(&ometrics, om, entry);
+
+ return om;
+}
+
+/*
+ * Same as above but for a stateset. The states is an array of constant strings
+ * with statecnt elements. The states, name and help pointers need to remain
+ * valid until the ometric is freed.
+ */
+struct ometric *
+ometric_new_state(const char * const *states, size_t statecnt, const char *name,
+ const char *help)
+{
+ struct ometric *om;
+
+ if ((om = calloc(1, sizeof(*om))) == NULL)
+ err(1, NULL);
+
+ om->name = name;
+ om->help = help;
+ om->type = OMT_STATESET;
+ om->stateset = states;
+ om->setsize = statecnt;
+ STAILQ_INIT(&om->vals);
+
+ STAILQ_INSERT_TAIL(&ometrics, om, entry);
+
+ return om;
+}
+
+void
+ometric_free_all(void)
+{
+ struct ometric *om;
+ struct ovalue *ov;
+
+ while ((om = STAILQ_FIRST(&ometrics)) != NULL) {
+ STAILQ_REMOVE_HEAD(&ometrics, entry);
+ while ((ov = STAILQ_FIRST(&om->vals)) != NULL) {
+ STAILQ_REMOVE_HEAD(&om->vals, entry);
+ olabels_free(ov->labels);
+ free(ov);
+ }
+ free(om);
+ }
+}
+
+static struct olabels *
+olabels_ref(struct olabels *ol)
+{
+ struct olabels *x = ol;
+
+ while (x != NULL) {
+ x->refcnt++;
+ x = x->next;
+ }
+
+ return ol;
+}
+
+/*
+ * Create a new set of labels based on keys and values arrays.
+ * keys must end in a NULL element. values needs to hold as many elements
+ * but the elements can be NULL. values are copied for the olabel but
+ * keys needs to point to constant memory.
+ */
+struct olabels *
+olabels_new(const char * const *keys, const char **values)
+{
+ struct olabels *ol;
+ struct olabel *l;
+
+ if ((ol = malloc(sizeof(*ol))) == NULL)
+ err(1, NULL);
+ STAILQ_INIT(&ol->labels);
+ ol->refcnt = 1;
+ ol->next = NULL;
+
+ while (*keys != NULL) {
+ if (*values && **values != '\0') {
+ if ((l = malloc(sizeof(*l))) == NULL)
+ err(1, NULL);
+ l->key = *keys;
+ if ((l->value = strdup(*values)) == NULL)
+ err(1, NULL);
+ STAILQ_INSERT_TAIL(&ol->labels, l, entry);
+ }
+
+ keys++;
+ values++;
+ }
+
+ return ol;
+}
+
+/*
+ * Free olables once nothing uses them anymore.
+ */
+void
+olabels_free(struct olabels *ol)
+{
+ struct olabels *next;
+ struct olabel *l;
+
+ for ( ; ol != NULL; ol = next) {
+ next = ol->next;
+
+ if (--ol->refcnt == 0) {
+ while ((l = STAILQ_FIRST(&ol->labels)) != NULL) {
+ STAILQ_REMOVE_HEAD(&ol->labels, entry);
+ free(l->value);
+ free(l);
+ }
+ free(ol);
+ }
+ }
+}
+
+/*
+ * Add one extra label onto the label stack. Once no longer used the
+ * value needs to be freed with olabels_free().
+ */
+static struct olabels *
+olabels_add_extra(struct olabels *ol, const char *key, const char *value)
+{
+ const char *keys[2] = { key, NULL };
+ const char *values[2] = { value, NULL };
+ struct olabels *new;
+
+ if (value == NULL || *value == '\0')
+ return ol;
+
+ new = olabels_new(keys, values);
+ new->next = olabels_ref(ol);
+
+ return new;
+}
+
+/*
+ * Output function called last.
+ */
+static const char *
+ometric_type(enum ometric_type type)
+{
+ switch (type) {
+ case OMT_GAUGE:
+ return "gauge";
+ case OMT_COUNTER:
+ return "counter";
+ case OMT_STATESET:
+ return "stateset";
+ case OMT_HISTOGRAM:
+ return "histogram";
+ case OMT_SUMMARY:
+ return "summary";
+ default:
+ return "unknown";
+ }
+}
+
+static void
+ometric_output_labels(const struct olabels *ol)
+{
+ struct olabel *l;
+ const char *comma = "";
+
+ if (ol == NULL) {
+ printf(" ");
+ return;
+ }
+
+ printf("{");
+
+ while (ol != NULL) {
+ STAILQ_FOREACH(l, &ol->labels, entry) {
+ printf("%s%s=\"%s\"", comma, l->key, l->value);
+ comma = ",";
+ }
+ ol = ol->next;
+ }
+
+ printf("} ");
+}
+
+static void
+ometric_output_value(const struct ovalue *ov)
+{
+ switch (ov->valtype) {
+ case OVT_INTEGER:
+ printf("%llu", ov->value.i);
+ return;
+ case OVT_DOUBLE:
+ printf("%g", ov->value.f);
+ return;
+ }
+}
+
+/*
+ * Output all metric values with TYPE and optional HELP strings.
+ */
+void
+ometric_output_all(void)
+{
+ struct ometric *om;
+ struct ovalue *ov;
+
+ STAILQ_FOREACH(om, &ometrics, entry) {
+ if (om->help)
+ printf("# HELP %s %s\n", om->name, om->help);
+ printf("# TYPE %s %s\n", om->name, ometric_type(om->type));
+
+ STAILQ_FOREACH(ov, &om->vals, entry) {
+ printf("%s", om->name);
+ ometric_output_labels(ov->labels);
+ ometric_output_value(ov);
+ printf("\n");
+ }
+ }
+
+ printf("# EOF\n");
+}
+
+/*
+ * Value setters
+ */
+static void
+ometric_set_int_value(struct ometric *om, uint64_t val, struct olabels *ol)
+{
+ struct ovalue *ov;
+
+ if ((ov = malloc(sizeof(*ov))) == NULL)
+ err(1, NULL);
+
+ ov->value.i = val;
+ ov->valtype = OVT_INTEGER;
+ ov->labels = olabels_ref(ol);
+
+ STAILQ_INSERT_TAIL(&om->vals, ov, entry);
+}
+
+/*
+ * Set an integer value with label ol. ol can be NULL.
+ */
+void
+ometric_set_int(struct ometric *om, uint64_t val, struct olabels *ol)
+{
+ if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
+ errx(1, "%s incorrect ometric type", __func__);
+
+ ometric_set_int_value(om, val, ol);
+}
+
+/*
+ * Set a floating point value with label ol. ol can be NULL.
+ */
+void
+ometric_set_float(struct ometric *om, double val, struct olabels *ol)
+{
+ struct ovalue *ov;
+
+ if (om->type != OMT_COUNTER && om->type != OMT_GAUGE)
+ errx(1, "%s incorrect ometric type", __func__);
+
+ if ((ov = malloc(sizeof(*ov))) == NULL)
+ err(1, NULL);
+
+ ov->value.f = val;
+ ov->valtype = OVT_DOUBLE;
+ ov->labels = olabels_ref(ol);
+
+ STAILQ_INSERT_TAIL(&om->vals, ov, entry);
+}
+
+/*
+ * Add an info value (which is the value 1 but with extra key-value pairs).
+ */
+void
+ometric_set_info(struct ometric *om, const char **keys, const char **values,
+ struct olabels *ol)
+{
+ struct olabels *extra = NULL;
+
+ if (om->type != OMT_INFO)
+ errx(1, "%s incorrect ometric type", __func__);
+
+ if (keys != NULL) {
+ extra = olabels_new(keys, values);
+ extra->next = olabels_ref(ol);
+ }
+
+ ometric_set_int_value(om, 1, extra != NULL ? extra : ol);
+ olabels_free(extra);
+}
+
+/*
+ * Set a stateset to one of its states.
+ */
+void
+ometric_set_state(struct ometric *om, const char *state, struct olabels *ol)
+{
+ struct olabels *extra;
+ size_t i;
+ int val;
+
+ if (om->type != OMT_STATESET)
+ errx(1, "%s incorrect ometric type", __func__);
+
+ for (i = 0; i < om->setsize; i++) {
+ if (strcasecmp(state, om->stateset[i]) == 0)
+ val = 1;
+ else
+ val = 0;
+
+ extra = olabels_add_extra(ol, om->name, om->stateset[i]);
+ ometric_set_int_value(om, val, extra);
+ olabels_free(extra);
+ }
+}
+
+/*
+ * Set a value with an extra label, the key should be a constant string while
+ * the value is copied into the extra label.
+ */
+void
+ometric_set_int_with_label(struct ometric *om, uint64_t val, const char *key,
+ const char *value, struct olabels *ol)
+{
+ struct olabels *extra;
+
+ extra = olabels_add_extra(ol, key, value);
+ ometric_set_int(om, val, extra);
+ olabels_free(extra);
+}
--- /dev/null
+/* $OpenBSD: ometric.h,v 1.1 2022/10/17 12:01:19 claudio Exp $ */
+
+/*
+ * Copyright (c) 2022 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.
+ */
+
+enum ometric_type {
+ OMT_UNKNOWN,
+ OMT_GAUGE,
+ OMT_COUNTER,
+ OMT_STATESET,
+ OMT_HISTOGRAM,
+ OMT_SUMMARY,
+ OMT_INFO,
+};
+
+struct ometric;
+struct olabels;
+
+struct ometric *ometric_new(enum ometric_type, const char *, const char *);
+struct ometric *ometric_new_state(const char * const *, size_t, const char *,
+ const char *);
+void ometric_free_all(void);
+struct olabels *olabels_new(const char * const *, const char **);
+void olabels_free(struct olabels *);
+
+void ometric_output_all(void);
+
+/* XXX how to pass attributes */
+/* functions to set gauge and counter metrics */
+void ometric_set_int(struct ometric *, uint64_t, struct olabels *);
+void ometric_set_float(struct ometric *, double, struct olabels *);
+void ometric_set_info(struct ometric *, const char **, const char **,
+ struct olabels *);
+void ometric_set_state(struct ometric *, const char *, struct olabels *);
+void ometric_set_int_with_label(struct ometric *, uint64_t, const char *,
+ const char *, struct olabels *);
-/* $OpenBSD: output.c,v 1.29 2022/08/31 15:00:53 claudio Exp $ */
+/* $OpenBSD: output.c,v 1.30 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
.set = show_rib_set,
.rtr = show_rtr,
.result = show_result,
- .tail = show_tail
+ .tail = show_tail,
};
-/* $OpenBSD: output_json.c,v 1.23 2022/08/31 15:00:53 claudio Exp $ */
+/* $OpenBSD: output_json.c,v 1.24 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
.set = json_rib_set,
.rtr = json_rtr,
.result = json_result,
- .tail = json_tail
+ .tail = json_tail,
};
--- /dev/null
+/* $OpenBSD: output_ometric.c,v 1.1 2022/10/17 12:01:19 claudio Exp $ */
+
+/*
+ * Copyright (c) 2022 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 <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bgpd.h"
+#include "session.h"
+#include "rde.h"
+#include "version.h"
+
+#include "bgpctl.h"
+#include "parser.h"
+#include "ometric.h"
+
+struct ometric *bgpd_info, *bgpd_scrape_time;
+struct ometric *peer_info, *peer_state, *peer_state_raw, *peer_up_time,
+ *peer_down_time, *peer_last_read, *peer_last_write;
+struct ometric *peer_prefixes_transmit, *peer_prefixes_receive;
+struct ometric *peer_message_transmit, *peer_message_recieve;
+struct ometric *peer_update_transmit, *peer_update_pending,
+ *peer_update_receive;
+struct ometric *peer_withdraw_transmit, *peer_withdraw_pending,
+ *peer_withdraw_receive;
+struct ometric *peer_rr_req_transmit, *peer_rr_req_receive;
+struct ometric *peer_rr_borr_transmit, *peer_rr_borr_receive;
+struct ometric *peer_rr_eorr_transmit, *peer_rr_eorr_receive;
+struct ometric *rde_mem_size, *rde_mem_count, *rde_mem_ref_count;
+struct ometric *rde_set_size, *rde_set_count, *rde_table_count;
+
+struct timeval start_time, end_time;
+
+static void
+ometric_head(struct parse_result *arg)
+{
+ struct olabels *ol = NULL;
+ const char *keys[4] = { "nodename", "domainname", "release", NULL };
+ const char *values[4];
+ char hostname[HOST_NAME_MAX + 1];
+ char *domainname;
+
+ bgpd_info = ometric_new(OMT_INFO, "bgpd_info", "bgpd information");
+ bgpd_scrape_time = ometric_new(OMT_GAUGE, "bgpd_scrape_seconds",
+ "bgpd scrape time in seconds");
+
+ gettimeofday(&start_time, NULL);
+
+ if (gethostname(hostname, sizeof(hostname)))
+ err(1, "gethostname");
+ if ((domainname = strchr(hostname, '.')))
+ *domainname++ = '\0';
+
+ values[0] = hostname;
+ values[1] = domainname;
+ values[2] = BGPD_VERSION;
+ values[3] = NULL;
+
+ ol = olabels_new(keys, values);
+
+ ometric_set_info(bgpd_info, NULL, NULL, ol);
+
+ olabels_free(ol);
+
+ /*
+ * per neighbor stats: attrs will be remote_as, remote_addr,
+ * description and group
+ */
+ peer_info = ometric_new(OMT_INFO, "bgpd_peer_info",
+ "peer information");
+ peer_state = ometric_new_state(statenames,
+ sizeof(statenames) / sizeof(statenames[0]), "bgpd_peer_state",
+ "peer session state");
+ peer_state_raw = ometric_new(OMT_GAUGE, "bgpd_peer_state_raw",
+ "peer session state raw int value");
+ peer_up_time = ometric_new(OMT_GAUGE, "bgpd_peer_up_seconds",
+ "peer session up time in seconds");
+ peer_down_time = ometric_new(OMT_GAUGE, "bgpd_peer_down_seconds",
+ "peer session down time in seconds");
+ peer_last_read = ometric_new(OMT_GAUGE, "bgpd_peer_last_read_seconds",
+ "peer time since last read in seconds");
+ peer_last_write = ometric_new(OMT_GAUGE, "bgpd_peer_last_write_seconds",
+ "peer time since last write in seconds");
+
+ peer_prefixes_transmit = ometric_new(OMT_GAUGE,
+ "bgpd_peer_prefixes_transmit",
+ "number of prefixes sent to peer");
+ peer_prefixes_receive = ometric_new(OMT_GAUGE,
+ "bgpd_peer_prefixes_receive",
+ "number of prefixes received from peer");
+
+ peer_message_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_message_transmit_total",
+ "per message type count of tranmitted messages");
+ peer_message_recieve = ometric_new(OMT_COUNTER,
+ "bgpd_peer_message_receive_total",
+ "per message type count of received messages");
+
+ peer_update_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_update_transmit_total",
+ "number of prefixes sent as update");
+ peer_update_pending = ometric_new(OMT_COUNTER,
+ "bgpd_peer_update_pending_total",
+ "number of pending update prefixes");
+ peer_update_receive = ometric_new(OMT_COUNTER,
+ "bgpd_peer_update_receive_total",
+ "number of prefixes received as update");
+
+ peer_withdraw_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_withdraw_transmit_total",
+ "number of witdrawn prefixes sent to peer");
+ peer_withdraw_pending = ometric_new(OMT_COUNTER,
+ "bgpd_peer_withdraw_pending_total",
+ "number of pending withdrawn prefixes");
+ peer_withdraw_receive = ometric_new(OMT_COUNTER,
+ "bgpd_peer_withdraw_receive_total",
+ "number of withdrawn prefixes received from peer");
+
+ peer_rr_req_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_req_transmit_total",
+ "number of route-refresh request transmitted to peer");
+ peer_rr_req_receive = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_req_receive_total",
+ "number of route-refresh request received from peer");
+ peer_rr_borr_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_borr_transmit_total",
+ "number of ext. route-refresh BORR messages transmitted to peer");
+ peer_rr_borr_receive = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_borr_receive_total",
+ "number of ext. route-refresh BORR messages received from peer");
+ peer_rr_eorr_transmit = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_eorr_transmit_total",
+ "number of ext. route-refresh EORR messages transmitted to peer");
+ peer_rr_eorr_receive = ometric_new(OMT_COUNTER,
+ "bgpd_peer_route_refresh_eorr_receive_total",
+ "number of ext. route-refresh EORR messages received from peer");
+
+ /* RDE memory statistics */
+ rde_mem_size = ometric_new(OMT_GAUGE,
+ "bgpd_rde_memory_usage_bytes", "memory usage in bytes");
+ rde_mem_count = ometric_new(OMT_GAUGE,
+ "bgpd_rde_memory_count", "number of object in use");
+ rde_mem_ref_count = ometric_new(OMT_GAUGE,
+ "bgpd_rde_memory_reference_count", "number of references held");
+
+ rde_set_size = ometric_new(OMT_GAUGE,
+ "bgpd_rde_set_usage_bytes", "memory usage of set in bytes");
+ rde_set_count = ometric_new(OMT_GAUGE,
+ "bgpd_rde_set_count", "number of object in set");
+ rde_table_count = ometric_new(OMT_GAUGE,
+ "bgpd_rde_table_count", "number of as_set tables");
+}
+
+static void
+ometric_neighbor_stats(struct peer *p, struct parse_result *arg)
+{
+ struct olabels *ol = NULL;
+ const char *keys[5] = {
+ "remote_addr", "remote_as", "description", "group", NULL };
+ const char *values[5];
+
+ /* skip neighbor templates */
+ if (p->conf.template)
+ return;
+
+ values[0] = log_addr(&p->conf.remote_addr);
+ values[1] = log_as(p->conf.remote_as);
+ values[2] = p->conf.descr;
+ values[3] = p->conf.group;
+ values[4] = NULL;
+
+ ol = olabels_new(keys, values);
+
+ ometric_set_info(peer_info, NULL, NULL, ol);
+ ometric_set_state(peer_state, statenames[p->state], ol);
+ ometric_set_int(peer_state_raw, p->state, ol);
+
+ if (p->state == STATE_ESTABLISHED) {
+ ometric_set_int(peer_up_time,
+ get_monotime(p->stats.last_updown), ol);
+ ometric_set_int(peer_last_read,
+ get_monotime(p->stats.last_read), ol);
+ ometric_set_int(peer_last_write,
+ get_monotime(p->stats.last_write), ol);
+ } else if (p->stats.last_updown != 0)
+ ometric_set_int(peer_down_time,
+ get_monotime(p->stats.last_updown), ol);
+
+ ometric_set_int(peer_prefixes_transmit, p->stats.prefix_out_cnt, ol);
+ ometric_set_int(peer_prefixes_receive, p->stats.prefix_cnt, ol);
+
+ ometric_set_int_with_label(peer_message_transmit,
+ p->stats.msg_sent_open, "message", "open", ol);
+ ometric_set_int_with_label(peer_message_transmit,
+ p->stats.msg_sent_notification, "message", "notification", ol);
+ ometric_set_int_with_label(peer_message_transmit,
+ p->stats.msg_sent_update, "message", "update", ol);
+ ometric_set_int_with_label(peer_message_transmit,
+ p->stats.msg_sent_keepalive, "message", "keepalive", ol);
+ ometric_set_int_with_label(peer_message_transmit,
+ p->stats.msg_sent_rrefresh, "message", "route_refresh", ol);
+
+ ometric_set_int_with_label(peer_message_recieve,
+ p->stats.msg_rcvd_open, "message", "open", ol);
+ ometric_set_int_with_label(peer_message_recieve,
+ p->stats.msg_rcvd_notification, "message", "notification", ol);
+ ometric_set_int_with_label(peer_message_recieve,
+ p->stats.msg_rcvd_update, "message", "update", ol);
+ ometric_set_int_with_label(peer_message_recieve,
+ p->stats.msg_rcvd_keepalive, "message", "keepalive", ol);
+ ometric_set_int_with_label(peer_message_recieve,
+ p->stats.msg_rcvd_rrefresh, "message", "route_refresh", ol);
+
+ ometric_set_int(peer_update_transmit, p->stats.prefix_sent_update, ol);
+ ometric_set_int(peer_update_pending, p->stats.pending_update, ol);
+ ometric_set_int(peer_update_receive, p->stats.prefix_rcvd_update, ol);
+ ometric_set_int(peer_withdraw_transmit, p->stats.prefix_sent_withdraw,
+ ol);
+ ometric_set_int(peer_withdraw_pending, p->stats.pending_withdraw, ol);
+ ometric_set_int(peer_withdraw_receive, p->stats.prefix_rcvd_withdraw,
+ ol);
+
+ ometric_set_int(peer_rr_req_transmit, p->stats.refresh_sent_req, ol);
+ ometric_set_int(peer_rr_req_receive, p->stats.refresh_rcvd_req, ol);
+ ometric_set_int(peer_rr_borr_transmit, p->stats.refresh_sent_borr, ol);
+ ometric_set_int(peer_rr_borr_receive, p->stats.refresh_rcvd_borr, ol);
+ ometric_set_int(peer_rr_eorr_transmit, p->stats.refresh_sent_eorr, ol);
+ ometric_set_int(peer_rr_eorr_receive, p->stats.refresh_rcvd_eorr, ol);
+
+ olabels_free(ol);
+}
+
+static void
+ometric_rib_mem_element(const char *v, uint64_t count, uint64_t size,
+ uint64_t refs)
+{
+ if (count != UINT64_MAX)
+ ometric_set_int_with_label(rde_mem_count, count, "type", v,
+ NULL);
+ if (size != UINT64_MAX)
+ ometric_set_int_with_label(rde_mem_size, size, "type", v, NULL);
+ if (refs != UINT64_MAX)
+ ometric_set_int_with_label(rde_mem_ref_count, refs, "type", v,
+ NULL);
+}
+
+static void
+ometric_rib_mem(struct rde_memstats *stats)
+{
+ size_t pts = 0;
+ int i;
+
+ for (i = 0; i < AID_MAX; i++) {
+ if (stats->pt_cnt[i] == 0)
+ continue;
+ pts += stats->pt_cnt[i] * pt_sizes[i];
+ ometric_rib_mem_element(aid_vals[i].name, stats->pt_cnt[i],
+ stats->pt_cnt[i] * pt_sizes[i], UINT64_MAX);
+ }
+ ometric_rib_mem_element("rib", stats->rib_cnt,
+ stats->rib_cnt * sizeof(struct rib_entry), UINT64_MAX);
+ ometric_rib_mem_element("prefix", stats->prefix_cnt,
+ stats->prefix_cnt * sizeof(struct prefix), UINT64_MAX);
+ ometric_rib_mem_element("rde_aspath", stats->path_cnt,
+ stats->path_cnt * sizeof(struct rde_aspath),
+ stats->path_refs);
+ ometric_rib_mem_element("aspath", stats->aspath_cnt,
+ stats->aspath_size, UINT64_MAX);
+ ometric_rib_mem_element("community_entries", stats->comm_cnt,
+ stats->comm_cnt * sizeof(struct rde_community), UINT64_MAX);
+ ometric_rib_mem_element("community", stats->comm_nmemb,
+ stats->comm_size * sizeof(struct community), stats->comm_refs);
+ ometric_rib_mem_element("attributes_entries", stats->attr_cnt,
+ stats->attr_cnt * sizeof(struct attr), stats->attr_refs);
+ ometric_rib_mem_element("attributes", stats->attr_dcnt,
+ stats->attr_data, UINT64_MAX);
+
+ ometric_rib_mem_element("total", UINT64_MAX,
+ pts + stats->prefix_cnt * sizeof(struct prefix) +
+ stats->rib_cnt * sizeof(struct rib_entry) +
+ stats->path_cnt * sizeof(struct rde_aspath) +
+ stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
+ stats->attr_data, UINT64_MAX);
+
+ ometric_set_int(rde_table_count, stats->aset_cnt, NULL);
+ ometric_set_int_with_label(rde_set_size, stats->aset_size,
+ "type", "as_set", NULL);
+ ometric_set_int_with_label(rde_set_count, stats->aset_nmemb,
+ "type", "as_set", NULL);
+ ometric_set_int_with_label(rde_set_size, stats->pset_size,
+ "type", "prefix_set", NULL);
+ ometric_set_int_with_label(rde_set_count, stats->pset_cnt,
+ "type", "prefix_set", NULL);
+ ometric_rib_mem_element("set_total", UINT64_MAX,
+ stats->aset_size + stats->pset_size, UINT64_MAX);
+}
+
+static void
+ometric_tail(void)
+{
+ struct timeval elapsed_time;
+ double scrape;
+
+ gettimeofday(&end_time, NULL);
+ timersub(&end_time, &start_time, &elapsed_time);
+
+ scrape = (double)elapsed_time.tv_sec +
+ (double)elapsed_time.tv_usec / 1000000;
+
+ ometric_set_float(bgpd_scrape_time, scrape, NULL);
+ ometric_output_all();
+
+ ometric_free_all();
+}
+
+const struct output ometric_output = {
+ .head = ometric_head,
+ .neighbor = ometric_neighbor_stats,
+ .rib_mem = ometric_rib_mem,
+ .tail = ometric_tail,
+};
-/* $OpenBSD: parser.c,v 1.114 2022/08/17 15:16:12 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.115 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
{ KEYWORD, "sets", SHOW_SET, NULL},
{ KEYWORD, "rtr", SHOW_RTR, NULL},
{ KEYWORD, "mrt", SHOW_MRT, t_show_mrt},
+ { KEYWORD, "metric", SHOW_METRIC, NULL},
{ ENDTOKEN, "", NONE, NULL}
};
-/* $OpenBSD: parser.h,v 1.42 2022/02/06 09:52:32 claudio Exp $ */
+/* $OpenBSD: parser.h,v 1.43 2022/10/17 12:01:19 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
SHOW_RIB_MEM,
SHOW_NEXTHOP,
SHOW_INTERFACE,
+ SHOW_METRIC,
RELOAD,
FIB,
FIB_COUPLE,