xref: /openbsd-src/usr.sbin/bgpctl/output_ometric.c (revision 19aa870f79fc97a04d4f99a85689c21fd48d4ad5)
1*19aa870fSclaudio /*	$OpenBSD: output_ometric.c,v 1.13 2024/01/23 15:55:20 claudio Exp $ */
277a10e6fSclaudio 
377a10e6fSclaudio /*
477a10e6fSclaudio  * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
577a10e6fSclaudio  *
677a10e6fSclaudio  * Permission to use, copy, modify, and distribute this software for any
777a10e6fSclaudio  * purpose with or without fee is hereby granted, provided that the above
877a10e6fSclaudio  * copyright notice and this permission notice appear in all copies.
977a10e6fSclaudio  *
1077a10e6fSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1177a10e6fSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1277a10e6fSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1377a10e6fSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1477a10e6fSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1577a10e6fSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1677a10e6fSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1777a10e6fSclaudio  */
1877a10e6fSclaudio 
19ca6da2b3Scheloha #include <sys/time.h>
20ca6da2b3Scheloha 
2177a10e6fSclaudio #include <err.h>
2277a10e6fSclaudio #include <limits.h>
2377a10e6fSclaudio #include <stdio.h>
2477a10e6fSclaudio #include <stdlib.h>
2577a10e6fSclaudio #include <string.h>
26ca6da2b3Scheloha #include <time.h>
2777a10e6fSclaudio #include <unistd.h>
2877a10e6fSclaudio 
2977a10e6fSclaudio #include "bgpd.h"
3077a10e6fSclaudio #include "session.h"
3177a10e6fSclaudio #include "rde.h"
3277a10e6fSclaudio #include "version.h"
3377a10e6fSclaudio 
3477a10e6fSclaudio #include "bgpctl.h"
3577a10e6fSclaudio #include "parser.h"
3677a10e6fSclaudio #include "ometric.h"
3777a10e6fSclaudio 
3877a10e6fSclaudio struct ometric *bgpd_info, *bgpd_scrape_time;
3937aeb3f3Sclaudio struct ometric *peer_info, *peer_state, *peer_state_raw, *peer_last_change,
4037aeb3f3Sclaudio 		    *peer_last_read, *peer_last_write;
4177a10e6fSclaudio struct ometric *peer_prefixes_transmit, *peer_prefixes_receive;
426efd4b13Sclaudio struct ometric *peer_message_transmit, *peer_message_receive;
4377a10e6fSclaudio struct ometric *peer_update_transmit, *peer_update_pending,
4477a10e6fSclaudio 		    *peer_update_receive;
4577a10e6fSclaudio struct ometric *peer_withdraw_transmit, *peer_withdraw_pending,
4677a10e6fSclaudio 		    *peer_withdraw_receive;
4777a10e6fSclaudio struct ometric *peer_rr_req_transmit, *peer_rr_req_receive;
4877a10e6fSclaudio struct ometric *peer_rr_borr_transmit, *peer_rr_borr_receive;
4977a10e6fSclaudio struct ometric *peer_rr_eorr_transmit, *peer_rr_eorr_receive;
5077a10e6fSclaudio struct ometric *rde_mem_size, *rde_mem_count, *rde_mem_ref_count;
5177a10e6fSclaudio struct ometric *rde_set_size, *rde_set_count, *rde_table_count;
5277a10e6fSclaudio 
53ca6da2b3Scheloha struct timespec start_time, end_time;
5477a10e6fSclaudio 
5577a10e6fSclaudio static void
ometric_head(struct parse_result * arg)5677a10e6fSclaudio ometric_head(struct parse_result *arg)
5777a10e6fSclaudio {
5877a10e6fSclaudio 	struct olabels *ol = NULL;
5977a10e6fSclaudio 	const char *keys[4] = { "nodename", "domainname", "release", NULL };
6077a10e6fSclaudio 	const char *values[4];
6177a10e6fSclaudio 	char hostname[HOST_NAME_MAX + 1];
6277a10e6fSclaudio 	char *domainname;
6377a10e6fSclaudio 
64ca6da2b3Scheloha 	clock_gettime(CLOCK_MONOTONIC, &start_time);
65ca6da2b3Scheloha 
660584fd62Sclaudio 	bgpd_info = ometric_new(OMT_INFO, "bgpd", "bgpd information");
6777a10e6fSclaudio 	bgpd_scrape_time = ometric_new(OMT_GAUGE, "bgpd_scrape_seconds",
6877a10e6fSclaudio 	    "bgpd scrape time in seconds");
6977a10e6fSclaudio 
7077a10e6fSclaudio 	if (gethostname(hostname, sizeof(hostname)))
7177a10e6fSclaudio 		err(1, "gethostname");
7277a10e6fSclaudio 	if ((domainname = strchr(hostname, '.')))
7377a10e6fSclaudio 		*domainname++ = '\0';
7477a10e6fSclaudio 
7577a10e6fSclaudio 	values[0] = hostname;
7677a10e6fSclaudio 	values[1] = domainname;
7777a10e6fSclaudio 	values[2] = BGPD_VERSION;
7877a10e6fSclaudio 	values[3] = NULL;
7977a10e6fSclaudio 
8077a10e6fSclaudio 	ol = olabels_new(keys, values);
8177a10e6fSclaudio 	ometric_set_info(bgpd_info, NULL, NULL, ol);
8277a10e6fSclaudio 	olabels_free(ol);
8377a10e6fSclaudio 
8477a10e6fSclaudio 	/*
8577a10e6fSclaudio 	 * per neighbor stats: attrs will be remote_as, remote_addr,
8677a10e6fSclaudio 	 * description and group
8777a10e6fSclaudio 	 */
880584fd62Sclaudio 	peer_info = ometric_new(OMT_INFO, "bgpd_peer",
8977a10e6fSclaudio 	    "peer information");
9077a10e6fSclaudio 	peer_state = ometric_new_state(statenames,
9177a10e6fSclaudio 	    sizeof(statenames) / sizeof(statenames[0]), "bgpd_peer_state",
9277a10e6fSclaudio 	    "peer session state");
9377a10e6fSclaudio 	peer_state_raw = ometric_new(OMT_GAUGE, "bgpd_peer_state_raw",
9477a10e6fSclaudio 	    "peer session state raw int value");
9537aeb3f3Sclaudio 	peer_last_change = ometric_new(OMT_GAUGE,
9637aeb3f3Sclaudio 	    "bgpd_peer_last_change_seconds",
9737aeb3f3Sclaudio 	    "time in seconds since peer's last up/down state change");
9877a10e6fSclaudio 	peer_last_read = ometric_new(OMT_GAUGE, "bgpd_peer_last_read_seconds",
9977a10e6fSclaudio 	    "peer time since last read in seconds");
10077a10e6fSclaudio 	peer_last_write = ometric_new(OMT_GAUGE, "bgpd_peer_last_write_seconds",
10177a10e6fSclaudio 	    "peer time since last write in seconds");
10277a10e6fSclaudio 
10377a10e6fSclaudio 	peer_prefixes_transmit = ometric_new(OMT_GAUGE,
10477a10e6fSclaudio 	    "bgpd_peer_prefixes_transmit",
10577a10e6fSclaudio 	    "number of prefixes sent to peer");
10677a10e6fSclaudio 	peer_prefixes_receive = ometric_new(OMT_GAUGE,
10777a10e6fSclaudio 	    "bgpd_peer_prefixes_receive",
10877a10e6fSclaudio 	    "number of prefixes received from peer");
10977a10e6fSclaudio 
11077a10e6fSclaudio 	peer_message_transmit = ometric_new(OMT_COUNTER,
1110584fd62Sclaudio 	    "bgpd_peer_message_transmit",
112f4123069Smbuhl 	    "per message type count of transmitted messages");
1136efd4b13Sclaudio 	peer_message_receive = ometric_new(OMT_COUNTER,
1140584fd62Sclaudio 	    "bgpd_peer_message_receive",
11577a10e6fSclaudio 	    "per message type count of received messages");
11677a10e6fSclaudio 
11777a10e6fSclaudio 	peer_update_transmit = ometric_new(OMT_COUNTER,
1180584fd62Sclaudio 	    "bgpd_peer_update_transmit",
11977a10e6fSclaudio 	    "number of prefixes sent as update");
12077a10e6fSclaudio 	peer_update_pending = ometric_new(OMT_COUNTER,
1210584fd62Sclaudio 	    "bgpd_peer_update_pending",
12277a10e6fSclaudio 	    "number of pending update prefixes");
12377a10e6fSclaudio 	peer_update_receive = ometric_new(OMT_COUNTER,
1240584fd62Sclaudio 	    "bgpd_peer_update_receive",
12577a10e6fSclaudio 	    "number of prefixes received as update");
12677a10e6fSclaudio 
12777a10e6fSclaudio 	peer_withdraw_transmit = ometric_new(OMT_COUNTER,
1280584fd62Sclaudio 	    "bgpd_peer_withdraw_transmit",
129f4123069Smbuhl 	    "number of withdrawn prefixes sent to peer");
13077a10e6fSclaudio 	peer_withdraw_pending = ometric_new(OMT_COUNTER,
1310584fd62Sclaudio 	    "bgpd_peer_withdraw_pending",
13277a10e6fSclaudio 	    "number of pending withdrawn prefixes");
13377a10e6fSclaudio 	peer_withdraw_receive = ometric_new(OMT_COUNTER,
1340584fd62Sclaudio 	    "bgpd_peer_withdraw_receive",
13577a10e6fSclaudio 	    "number of withdrawn prefixes received from peer");
13677a10e6fSclaudio 
13777a10e6fSclaudio 	peer_rr_req_transmit = ometric_new(OMT_COUNTER,
1380584fd62Sclaudio 	    "bgpd_peer_route_refresh_req_transmit",
13977a10e6fSclaudio 	    "number of route-refresh request transmitted to peer");
14077a10e6fSclaudio 	peer_rr_req_receive = ometric_new(OMT_COUNTER,
1410584fd62Sclaudio 	    "bgpd_peer_route_refresh_req_receive",
14277a10e6fSclaudio 	    "number of route-refresh request received from peer");
14377a10e6fSclaudio 	peer_rr_borr_transmit = ometric_new(OMT_COUNTER,
1440584fd62Sclaudio 	    "bgpd_peer_route_refresh_borr_transmit",
14577a10e6fSclaudio 	    "number of ext. route-refresh BORR messages transmitted to peer");
14677a10e6fSclaudio 	peer_rr_borr_receive = ometric_new(OMT_COUNTER,
1470584fd62Sclaudio 	    "bgpd_peer_route_refresh_borr_receive",
14877a10e6fSclaudio 	    "number of ext. route-refresh BORR messages received from peer");
14977a10e6fSclaudio 	peer_rr_eorr_transmit = ometric_new(OMT_COUNTER,
1500584fd62Sclaudio 	    "bgpd_peer_route_refresh_eorr_transmit",
15177a10e6fSclaudio 	    "number of ext. route-refresh EORR messages transmitted to peer");
15277a10e6fSclaudio 	peer_rr_eorr_receive = ometric_new(OMT_COUNTER,
1530584fd62Sclaudio 	    "bgpd_peer_route_refresh_eorr_receive",
15477a10e6fSclaudio 	    "number of ext. route-refresh EORR messages received from peer");
15577a10e6fSclaudio 
15677a10e6fSclaudio 	/* RDE memory statistics */
15777a10e6fSclaudio 	rde_mem_size = ometric_new(OMT_GAUGE,
15877a10e6fSclaudio 	    "bgpd_rde_memory_usage_bytes", "memory usage in bytes");
15977a10e6fSclaudio 	rde_mem_count = ometric_new(OMT_GAUGE,
1600584fd62Sclaudio 	    "bgpd_rde_memory_usage_objects", "number of object in use");
16177a10e6fSclaudio 	rde_mem_ref_count = ometric_new(OMT_GAUGE,
1620584fd62Sclaudio 	    "bgpd_rde_memory_usage_references", "number of references held");
16377a10e6fSclaudio 
16477a10e6fSclaudio 	rde_set_size = ometric_new(OMT_GAUGE,
16577a10e6fSclaudio 	    "bgpd_rde_set_usage_bytes", "memory usage of set in bytes");
16677a10e6fSclaudio 	rde_set_count = ometric_new(OMT_GAUGE,
1670584fd62Sclaudio 	    "bgpd_rde_set_usage_objects", "number of object in set");
16877a10e6fSclaudio 	rde_table_count = ometric_new(OMT_GAUGE,
1690584fd62Sclaudio 	    "bgpd_rde_set_usage_tables", "number of as_set tables");
17077a10e6fSclaudio }
17177a10e6fSclaudio 
17277a10e6fSclaudio static void
ometric_neighbor_stats(struct peer * p,struct parse_result * arg)17377a10e6fSclaudio ometric_neighbor_stats(struct peer *p, struct parse_result *arg)
17477a10e6fSclaudio {
17577a10e6fSclaudio 	struct olabels *ol = NULL;
17677a10e6fSclaudio 	const char *keys[5] = {
17777a10e6fSclaudio 	    "remote_addr", "remote_as", "description", "group", NULL };
17877a10e6fSclaudio 	const char *values[5];
17977a10e6fSclaudio 
18077a10e6fSclaudio 	/* skip neighbor templates */
18177a10e6fSclaudio 	if (p->conf.template)
18277a10e6fSclaudio 		return;
18377a10e6fSclaudio 
18477a10e6fSclaudio 	values[0] = log_addr(&p->conf.remote_addr);
18577a10e6fSclaudio 	values[1] = log_as(p->conf.remote_as);
18677a10e6fSclaudio 	values[2] = p->conf.descr;
18777a10e6fSclaudio 	values[3] = p->conf.group;
18877a10e6fSclaudio 	values[4] = NULL;
18977a10e6fSclaudio 
19077a10e6fSclaudio 	ol = olabels_new(keys, values);
19177a10e6fSclaudio 
19277a10e6fSclaudio 	ometric_set_info(peer_info, NULL, NULL, ol);
19377a10e6fSclaudio 	ometric_set_state(peer_state, statenames[p->state], ol);
19477a10e6fSclaudio 	ometric_set_int(peer_state_raw, p->state, ol);
19577a10e6fSclaudio 
19637aeb3f3Sclaudio 	ometric_set_int(peer_last_change, get_monotime(p->stats.last_updown),
19737aeb3f3Sclaudio 	    ol);
19837aeb3f3Sclaudio 
19977a10e6fSclaudio 	if (p->state == STATE_ESTABLISHED) {
20077a10e6fSclaudio 		ometric_set_int(peer_last_read,
20177a10e6fSclaudio 		    get_monotime(p->stats.last_read), ol);
20277a10e6fSclaudio 		ometric_set_int(peer_last_write,
20377a10e6fSclaudio 		    get_monotime(p->stats.last_write), ol);
20437aeb3f3Sclaudio 	}
20577a10e6fSclaudio 
20677a10e6fSclaudio 	ometric_set_int(peer_prefixes_transmit, p->stats.prefix_out_cnt, ol);
20777a10e6fSclaudio 	ometric_set_int(peer_prefixes_receive, p->stats.prefix_cnt, ol);
20877a10e6fSclaudio 
209e70d5757Sclaudio 	ometric_set_int_with_labels(peer_message_transmit,
210e70d5757Sclaudio 	    p->stats.msg_sent_open, OKV("messages"), OKV("open"), ol);
211e70d5757Sclaudio 	ometric_set_int_with_labels(peer_message_transmit,
212e70d5757Sclaudio 	    p->stats.msg_sent_notification, OKV("messages"),
213e70d5757Sclaudio 	    OKV("notification"), ol);
214e70d5757Sclaudio 	ometric_set_int_with_labels(peer_message_transmit,
215e70d5757Sclaudio 	    p->stats.msg_sent_update, OKV("messages"), OKV("update"), ol);
216e70d5757Sclaudio 	ometric_set_int_with_labels(peer_message_transmit,
217e70d5757Sclaudio 	    p->stats.msg_sent_keepalive, OKV("messages"), OKV("keepalive"), ol);
218e70d5757Sclaudio 	ometric_set_int_with_labels(peer_message_transmit,
219e70d5757Sclaudio 	    p->stats.msg_sent_rrefresh, OKV("messages"), OKV("route_refresh"),
220e70d5757Sclaudio 	    ol);
22177a10e6fSclaudio 
2226efd4b13Sclaudio 	ometric_set_int_with_labels(peer_message_receive,
223e70d5757Sclaudio 	    p->stats.msg_rcvd_open, OKV("messages"), OKV("open"), ol);
2246efd4b13Sclaudio 	ometric_set_int_with_labels(peer_message_receive,
225e70d5757Sclaudio 	    p->stats.msg_rcvd_notification, OKV("messages"),
226e70d5757Sclaudio 	    OKV("notification"), ol);
2276efd4b13Sclaudio 	ometric_set_int_with_labels(peer_message_receive,
228e70d5757Sclaudio 	    p->stats.msg_rcvd_update, OKV("messages"), OKV("update"), ol);
2296efd4b13Sclaudio 	ometric_set_int_with_labels(peer_message_receive,
230e70d5757Sclaudio 	    p->stats.msg_rcvd_keepalive, OKV("messages"), OKV("keepalive"), ol);
2316efd4b13Sclaudio 	ometric_set_int_with_labels(peer_message_receive,
232e70d5757Sclaudio 	    p->stats.msg_rcvd_rrefresh, OKV("messages"), OKV("route_refresh"),
233e70d5757Sclaudio 	    ol);
23477a10e6fSclaudio 
23577a10e6fSclaudio 	ometric_set_int(peer_update_transmit, p->stats.prefix_sent_update, ol);
23677a10e6fSclaudio 	ometric_set_int(peer_update_pending, p->stats.pending_update, ol);
23777a10e6fSclaudio 	ometric_set_int(peer_update_receive, p->stats.prefix_rcvd_update, ol);
23877a10e6fSclaudio 	ometric_set_int(peer_withdraw_transmit, p->stats.prefix_sent_withdraw,
23977a10e6fSclaudio 	    ol);
24077a10e6fSclaudio 	ometric_set_int(peer_withdraw_pending, p->stats.pending_withdraw, ol);
24177a10e6fSclaudio 	ometric_set_int(peer_withdraw_receive, p->stats.prefix_rcvd_withdraw,
24277a10e6fSclaudio 	    ol);
24377a10e6fSclaudio 
24477a10e6fSclaudio 	ometric_set_int(peer_rr_req_transmit, p->stats.refresh_sent_req, ol);
24577a10e6fSclaudio 	ometric_set_int(peer_rr_req_receive, p->stats.refresh_rcvd_req, ol);
24677a10e6fSclaudio 	ometric_set_int(peer_rr_borr_transmit, p->stats.refresh_sent_borr, ol);
24777a10e6fSclaudio 	ometric_set_int(peer_rr_borr_receive, p->stats.refresh_rcvd_borr, ol);
24877a10e6fSclaudio 	ometric_set_int(peer_rr_eorr_transmit, p->stats.refresh_sent_eorr, ol);
24977a10e6fSclaudio 	ometric_set_int(peer_rr_eorr_receive, p->stats.refresh_rcvd_eorr, ol);
25077a10e6fSclaudio 
25177a10e6fSclaudio 	olabels_free(ol);
25277a10e6fSclaudio }
25377a10e6fSclaudio 
25477a10e6fSclaudio static void
ometric_rib_mem_element(const char * v,uint64_t count,uint64_t size,uint64_t refs)25577a10e6fSclaudio ometric_rib_mem_element(const char *v, uint64_t count, uint64_t size,
25677a10e6fSclaudio     uint64_t refs)
25777a10e6fSclaudio {
25877a10e6fSclaudio 	if (count != UINT64_MAX)
259e70d5757Sclaudio 		ometric_set_int_with_labels(rde_mem_count, count,
260e70d5757Sclaudio 		    OKV("type"), OKV(v), NULL);
26177a10e6fSclaudio 	if (size != UINT64_MAX)
262e70d5757Sclaudio 		ometric_set_int_with_labels(rde_mem_size, size,
263e70d5757Sclaudio 		    OKV("type"), OKV(v), NULL);
26477a10e6fSclaudio 	if (refs != UINT64_MAX)
265e70d5757Sclaudio 		ometric_set_int_with_labels(rde_mem_ref_count, refs,
266e70d5757Sclaudio 		    OKV("type"), OKV(v), NULL);
26777a10e6fSclaudio }
26877a10e6fSclaudio 
26977a10e6fSclaudio static void
ometric_rib_mem(struct rde_memstats * stats)27077a10e6fSclaudio ometric_rib_mem(struct rde_memstats *stats)
27177a10e6fSclaudio {
27277a10e6fSclaudio 	size_t pts = 0;
27377a10e6fSclaudio 	int i;
27477a10e6fSclaudio 
27577a10e6fSclaudio 	for (i = 0; i < AID_MAX; i++) {
27677a10e6fSclaudio 		if (stats->pt_cnt[i] == 0)
27777a10e6fSclaudio 			continue;
278093d1e70Sclaudio 		pts += stats->pt_size[i];
27977a10e6fSclaudio 		ometric_rib_mem_element(aid_vals[i].name, stats->pt_cnt[i],
280093d1e70Sclaudio 		    stats->pt_size[i], UINT64_MAX);
28177a10e6fSclaudio 	}
28277a10e6fSclaudio 	ometric_rib_mem_element("rib", stats->rib_cnt,
28377a10e6fSclaudio 	    stats->rib_cnt * sizeof(struct rib_entry), UINT64_MAX);
28477a10e6fSclaudio 	ometric_rib_mem_element("prefix", stats->prefix_cnt,
28577a10e6fSclaudio 	    stats->prefix_cnt * sizeof(struct prefix), UINT64_MAX);
28677a10e6fSclaudio 	ometric_rib_mem_element("rde_aspath", stats->path_cnt,
28777a10e6fSclaudio 	    stats->path_cnt * sizeof(struct rde_aspath),
28877a10e6fSclaudio 	    stats->path_refs);
28977a10e6fSclaudio 	ometric_rib_mem_element("aspath", stats->aspath_cnt,
29077a10e6fSclaudio 	    stats->aspath_size, UINT64_MAX);
29177a10e6fSclaudio 	ometric_rib_mem_element("community_entries", stats->comm_cnt,
29277a10e6fSclaudio 	    stats->comm_cnt * sizeof(struct rde_community), UINT64_MAX);
29377a10e6fSclaudio 	ometric_rib_mem_element("community", stats->comm_nmemb,
29477a10e6fSclaudio 	    stats->comm_size * sizeof(struct community), stats->comm_refs);
29577a10e6fSclaudio 	ometric_rib_mem_element("attributes_entries", stats->attr_cnt,
29677a10e6fSclaudio 	    stats->attr_cnt * sizeof(struct attr), stats->attr_refs);
29777a10e6fSclaudio 	ometric_rib_mem_element("attributes", stats->attr_dcnt,
29877a10e6fSclaudio 	    stats->attr_data, UINT64_MAX);
29977a10e6fSclaudio 
30077a10e6fSclaudio 	ometric_rib_mem_element("total", UINT64_MAX,
30177a10e6fSclaudio 	    pts + stats->prefix_cnt * sizeof(struct prefix) +
30277a10e6fSclaudio 	    stats->rib_cnt * sizeof(struct rib_entry) +
30377a10e6fSclaudio 	    stats->path_cnt * sizeof(struct rde_aspath) +
30477a10e6fSclaudio 	    stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
30577a10e6fSclaudio 	    stats->attr_data, UINT64_MAX);
30677a10e6fSclaudio 
30777a10e6fSclaudio 	ometric_set_int(rde_table_count, stats->aset_cnt, NULL);
308e70d5757Sclaudio 
309e70d5757Sclaudio 	ometric_set_int_with_labels(rde_set_size, stats->aset_size,
310e70d5757Sclaudio 	    OKV("type"), OKV("as_set"), NULL);
311e70d5757Sclaudio 	ometric_set_int_with_labels(rde_set_count, stats->aset_nmemb,
312e70d5757Sclaudio 	    OKV("type"), OKV("as_set"), NULL);
313e70d5757Sclaudio 	ometric_set_int_with_labels(rde_set_size, stats->pset_size,
314e70d5757Sclaudio 	    OKV("type"), OKV("prefix_set"), NULL);
315e70d5757Sclaudio 	ometric_set_int_with_labels(rde_set_count, stats->pset_cnt,
316e70d5757Sclaudio 	    OKV("type"), OKV("prefix_set"), NULL);
31777a10e6fSclaudio 	ometric_rib_mem_element("set_total", UINT64_MAX,
31877a10e6fSclaudio 	    stats->aset_size + stats->pset_size, UINT64_MAX);
31977a10e6fSclaudio }
32077a10e6fSclaudio 
32177a10e6fSclaudio static void
ometric_tail(void)32277a10e6fSclaudio ometric_tail(void)
32377a10e6fSclaudio {
324ca6da2b3Scheloha 	struct timespec elapsed_time;
32577a10e6fSclaudio 
326ca6da2b3Scheloha 	clock_gettime(CLOCK_MONOTONIC, &end_time);
327ca6da2b3Scheloha 	timespecsub(&end_time, &start_time, &elapsed_time);
32877a10e6fSclaudio 
32981e584e8Sclaudio 	ometric_set_timespec(bgpd_scrape_time, &elapsed_time, NULL);
33060a4dc80Sclaudio 	ometric_output_all(stdout);
33177a10e6fSclaudio 
33277a10e6fSclaudio 	ometric_free_all();
33377a10e6fSclaudio }
33477a10e6fSclaudio 
33577a10e6fSclaudio const struct output ometric_output = {
33677a10e6fSclaudio 	.head = ometric_head,
33777a10e6fSclaudio 	.neighbor = ometric_neighbor_stats,
33877a10e6fSclaudio 	.rib_mem = ometric_rib_mem,
33977a10e6fSclaudio 	.tail = ometric_tail,
34077a10e6fSclaudio };
341