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