xref: /openbsd/usr.sbin/bgpctl/output_ometric.c (revision 9ea232b5)
1 /*	$OpenBSD: output_ometric.c,v 1.13 2024/01/23 15:55:20 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/time.h>
20 
21 #include <err.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include "bgpd.h"
30 #include "session.h"
31 #include "rde.h"
32 #include "version.h"
33 
34 #include "bgpctl.h"
35 #include "parser.h"
36 #include "ometric.h"
37 
38 struct ometric *bgpd_info, *bgpd_scrape_time;
39 struct ometric *peer_info, *peer_state, *peer_state_raw, *peer_last_change,
40 		    *peer_last_read, *peer_last_write;
41 struct ometric *peer_prefixes_transmit, *peer_prefixes_receive;
42 struct ometric *peer_message_transmit, *peer_message_receive;
43 struct ometric *peer_update_transmit, *peer_update_pending,
44 		    *peer_update_receive;
45 struct ometric *peer_withdraw_transmit, *peer_withdraw_pending,
46 		    *peer_withdraw_receive;
47 struct ometric *peer_rr_req_transmit, *peer_rr_req_receive;
48 struct ometric *peer_rr_borr_transmit, *peer_rr_borr_receive;
49 struct ometric *peer_rr_eorr_transmit, *peer_rr_eorr_receive;
50 struct ometric *rde_mem_size, *rde_mem_count, *rde_mem_ref_count;
51 struct ometric *rde_set_size, *rde_set_count, *rde_table_count;
52 
53 struct timespec start_time, end_time;
54 
55 static void
56 ometric_head(struct parse_result *arg)
57 {
58 	struct olabels *ol = NULL;
59 	const char *keys[4] = { "nodename", "domainname", "release", NULL };
60 	const char *values[4];
61 	char hostname[HOST_NAME_MAX + 1];
62 	char *domainname;
63 
64 	clock_gettime(CLOCK_MONOTONIC, &start_time);
65 
66 	bgpd_info = ometric_new(OMT_INFO, "bgpd", "bgpd information");
67 	bgpd_scrape_time = ometric_new(OMT_GAUGE, "bgpd_scrape_seconds",
68 	    "bgpd scrape time in seconds");
69 
70 	if (gethostname(hostname, sizeof(hostname)))
71 		err(1, "gethostname");
72 	if ((domainname = strchr(hostname, '.')))
73 		*domainname++ = '\0';
74 
75 	values[0] = hostname;
76 	values[1] = domainname;
77 	values[2] = BGPD_VERSION;
78 	values[3] = NULL;
79 
80 	ol = olabels_new(keys, values);
81 	ometric_set_info(bgpd_info, NULL, NULL, ol);
82 	olabels_free(ol);
83 
84 	/*
85 	 * per neighbor stats: attrs will be remote_as, remote_addr,
86 	 * description and group
87 	 */
88 	peer_info = ometric_new(OMT_INFO, "bgpd_peer",
89 	    "peer information");
90 	peer_state = ometric_new_state(statenames,
91 	    sizeof(statenames) / sizeof(statenames[0]), "bgpd_peer_state",
92 	    "peer session state");
93 	peer_state_raw = ometric_new(OMT_GAUGE, "bgpd_peer_state_raw",
94 	    "peer session state raw int value");
95 	peer_last_change = ometric_new(OMT_GAUGE,
96 	    "bgpd_peer_last_change_seconds",
97 	    "time in seconds since peer's last up/down state change");
98 	peer_last_read = ometric_new(OMT_GAUGE, "bgpd_peer_last_read_seconds",
99 	    "peer time since last read in seconds");
100 	peer_last_write = ometric_new(OMT_GAUGE, "bgpd_peer_last_write_seconds",
101 	    "peer time since last write in seconds");
102 
103 	peer_prefixes_transmit = ometric_new(OMT_GAUGE,
104 	    "bgpd_peer_prefixes_transmit",
105 	    "number of prefixes sent to peer");
106 	peer_prefixes_receive = ometric_new(OMT_GAUGE,
107 	    "bgpd_peer_prefixes_receive",
108 	    "number of prefixes received from peer");
109 
110 	peer_message_transmit = ometric_new(OMT_COUNTER,
111 	    "bgpd_peer_message_transmit",
112 	    "per message type count of transmitted messages");
113 	peer_message_receive = ometric_new(OMT_COUNTER,
114 	    "bgpd_peer_message_receive",
115 	    "per message type count of received messages");
116 
117 	peer_update_transmit = ometric_new(OMT_COUNTER,
118 	    "bgpd_peer_update_transmit",
119 	    "number of prefixes sent as update");
120 	peer_update_pending = ometric_new(OMT_COUNTER,
121 	    "bgpd_peer_update_pending",
122 	    "number of pending update prefixes");
123 	peer_update_receive = ometric_new(OMT_COUNTER,
124 	    "bgpd_peer_update_receive",
125 	    "number of prefixes received as update");
126 
127 	peer_withdraw_transmit = ometric_new(OMT_COUNTER,
128 	    "bgpd_peer_withdraw_transmit",
129 	    "number of withdrawn prefixes sent to peer");
130 	peer_withdraw_pending = ometric_new(OMT_COUNTER,
131 	    "bgpd_peer_withdraw_pending",
132 	    "number of pending withdrawn prefixes");
133 	peer_withdraw_receive = ometric_new(OMT_COUNTER,
134 	    "bgpd_peer_withdraw_receive",
135 	    "number of withdrawn prefixes received from peer");
136 
137 	peer_rr_req_transmit = ometric_new(OMT_COUNTER,
138 	    "bgpd_peer_route_refresh_req_transmit",
139 	    "number of route-refresh request transmitted to peer");
140 	peer_rr_req_receive = ometric_new(OMT_COUNTER,
141 	    "bgpd_peer_route_refresh_req_receive",
142 	    "number of route-refresh request received from peer");
143 	peer_rr_borr_transmit = ometric_new(OMT_COUNTER,
144 	    "bgpd_peer_route_refresh_borr_transmit",
145 	    "number of ext. route-refresh BORR messages transmitted to peer");
146 	peer_rr_borr_receive = ometric_new(OMT_COUNTER,
147 	    "bgpd_peer_route_refresh_borr_receive",
148 	    "number of ext. route-refresh BORR messages received from peer");
149 	peer_rr_eorr_transmit = ometric_new(OMT_COUNTER,
150 	    "bgpd_peer_route_refresh_eorr_transmit",
151 	    "number of ext. route-refresh EORR messages transmitted to peer");
152 	peer_rr_eorr_receive = ometric_new(OMT_COUNTER,
153 	    "bgpd_peer_route_refresh_eorr_receive",
154 	    "number of ext. route-refresh EORR messages received from peer");
155 
156 	/* RDE memory statistics */
157 	rde_mem_size = ometric_new(OMT_GAUGE,
158 	    "bgpd_rde_memory_usage_bytes", "memory usage in bytes");
159 	rde_mem_count = ometric_new(OMT_GAUGE,
160 	    "bgpd_rde_memory_usage_objects", "number of object in use");
161 	rde_mem_ref_count = ometric_new(OMT_GAUGE,
162 	    "bgpd_rde_memory_usage_references", "number of references held");
163 
164 	rde_set_size = ometric_new(OMT_GAUGE,
165 	    "bgpd_rde_set_usage_bytes", "memory usage of set in bytes");
166 	rde_set_count = ometric_new(OMT_GAUGE,
167 	    "bgpd_rde_set_usage_objects", "number of object in set");
168 	rde_table_count = ometric_new(OMT_GAUGE,
169 	    "bgpd_rde_set_usage_tables", "number of as_set tables");
170 }
171 
172 static void
173 ometric_neighbor_stats(struct peer *p, struct parse_result *arg)
174 {
175 	struct olabels *ol = NULL;
176 	const char *keys[5] = {
177 	    "remote_addr", "remote_as", "description", "group", NULL };
178 	const char *values[5];
179 
180 	/* skip neighbor templates */
181 	if (p->conf.template)
182 		return;
183 
184 	values[0] = log_addr(&p->conf.remote_addr);
185 	values[1] = log_as(p->conf.remote_as);
186 	values[2] = p->conf.descr;
187 	values[3] = p->conf.group;
188 	values[4] = NULL;
189 
190 	ol = olabels_new(keys, values);
191 
192 	ometric_set_info(peer_info, NULL, NULL, ol);
193 	ometric_set_state(peer_state, statenames[p->state], ol);
194 	ometric_set_int(peer_state_raw, p->state, ol);
195 
196 	ometric_set_int(peer_last_change, get_monotime(p->stats.last_updown),
197 	    ol);
198 
199 	if (p->state == STATE_ESTABLISHED) {
200 		ometric_set_int(peer_last_read,
201 		    get_monotime(p->stats.last_read), ol);
202 		ometric_set_int(peer_last_write,
203 		    get_monotime(p->stats.last_write), ol);
204 	}
205 
206 	ometric_set_int(peer_prefixes_transmit, p->stats.prefix_out_cnt, ol);
207 	ometric_set_int(peer_prefixes_receive, p->stats.prefix_cnt, ol);
208 
209 	ometric_set_int_with_labels(peer_message_transmit,
210 	    p->stats.msg_sent_open, OKV("messages"), OKV("open"), ol);
211 	ometric_set_int_with_labels(peer_message_transmit,
212 	    p->stats.msg_sent_notification, OKV("messages"),
213 	    OKV("notification"), ol);
214 	ometric_set_int_with_labels(peer_message_transmit,
215 	    p->stats.msg_sent_update, OKV("messages"), OKV("update"), ol);
216 	ometric_set_int_with_labels(peer_message_transmit,
217 	    p->stats.msg_sent_keepalive, OKV("messages"), OKV("keepalive"), ol);
218 	ometric_set_int_with_labels(peer_message_transmit,
219 	    p->stats.msg_sent_rrefresh, OKV("messages"), OKV("route_refresh"),
220 	    ol);
221 
222 	ometric_set_int_with_labels(peer_message_receive,
223 	    p->stats.msg_rcvd_open, OKV("messages"), OKV("open"), ol);
224 	ometric_set_int_with_labels(peer_message_receive,
225 	    p->stats.msg_rcvd_notification, OKV("messages"),
226 	    OKV("notification"), ol);
227 	ometric_set_int_with_labels(peer_message_receive,
228 	    p->stats.msg_rcvd_update, OKV("messages"), OKV("update"), ol);
229 	ometric_set_int_with_labels(peer_message_receive,
230 	    p->stats.msg_rcvd_keepalive, OKV("messages"), OKV("keepalive"), ol);
231 	ometric_set_int_with_labels(peer_message_receive,
232 	    p->stats.msg_rcvd_rrefresh, OKV("messages"), OKV("route_refresh"),
233 	    ol);
234 
235 	ometric_set_int(peer_update_transmit, p->stats.prefix_sent_update, ol);
236 	ometric_set_int(peer_update_pending, p->stats.pending_update, ol);
237 	ometric_set_int(peer_update_receive, p->stats.prefix_rcvd_update, ol);
238 	ometric_set_int(peer_withdraw_transmit, p->stats.prefix_sent_withdraw,
239 	    ol);
240 	ometric_set_int(peer_withdraw_pending, p->stats.pending_withdraw, ol);
241 	ometric_set_int(peer_withdraw_receive, p->stats.prefix_rcvd_withdraw,
242 	    ol);
243 
244 	ometric_set_int(peer_rr_req_transmit, p->stats.refresh_sent_req, ol);
245 	ometric_set_int(peer_rr_req_receive, p->stats.refresh_rcvd_req, ol);
246 	ometric_set_int(peer_rr_borr_transmit, p->stats.refresh_sent_borr, ol);
247 	ometric_set_int(peer_rr_borr_receive, p->stats.refresh_rcvd_borr, ol);
248 	ometric_set_int(peer_rr_eorr_transmit, p->stats.refresh_sent_eorr, ol);
249 	ometric_set_int(peer_rr_eorr_receive, p->stats.refresh_rcvd_eorr, ol);
250 
251 	olabels_free(ol);
252 }
253 
254 static void
255 ometric_rib_mem_element(const char *v, uint64_t count, uint64_t size,
256     uint64_t refs)
257 {
258 	if (count != UINT64_MAX)
259 		ometric_set_int_with_labels(rde_mem_count, count,
260 		    OKV("type"), OKV(v), NULL);
261 	if (size != UINT64_MAX)
262 		ometric_set_int_with_labels(rde_mem_size, size,
263 		    OKV("type"), OKV(v), NULL);
264 	if (refs != UINT64_MAX)
265 		ometric_set_int_with_labels(rde_mem_ref_count, refs,
266 		    OKV("type"), OKV(v), NULL);
267 }
268 
269 static void
270 ometric_rib_mem(struct rde_memstats *stats)
271 {
272 	size_t pts = 0;
273 	int i;
274 
275 	for (i = 0; i < AID_MAX; i++) {
276 		if (stats->pt_cnt[i] == 0)
277 			continue;
278 		pts += stats->pt_size[i];
279 		ometric_rib_mem_element(aid_vals[i].name, stats->pt_cnt[i],
280 		    stats->pt_size[i], UINT64_MAX);
281 	}
282 	ometric_rib_mem_element("rib", stats->rib_cnt,
283 	    stats->rib_cnt * sizeof(struct rib_entry), UINT64_MAX);
284 	ometric_rib_mem_element("prefix", stats->prefix_cnt,
285 	    stats->prefix_cnt * sizeof(struct prefix), UINT64_MAX);
286 	ometric_rib_mem_element("rde_aspath", stats->path_cnt,
287 	    stats->path_cnt * sizeof(struct rde_aspath),
288 	    stats->path_refs);
289 	ometric_rib_mem_element("aspath", stats->aspath_cnt,
290 	    stats->aspath_size, UINT64_MAX);
291 	ometric_rib_mem_element("community_entries", stats->comm_cnt,
292 	    stats->comm_cnt * sizeof(struct rde_community), UINT64_MAX);
293 	ometric_rib_mem_element("community", stats->comm_nmemb,
294 	    stats->comm_size * sizeof(struct community), stats->comm_refs);
295 	ometric_rib_mem_element("attributes_entries", stats->attr_cnt,
296 	    stats->attr_cnt * sizeof(struct attr), stats->attr_refs);
297 	ometric_rib_mem_element("attributes", stats->attr_dcnt,
298 	    stats->attr_data, UINT64_MAX);
299 
300 	ometric_rib_mem_element("total", UINT64_MAX,
301 	    pts + stats->prefix_cnt * sizeof(struct prefix) +
302 	    stats->rib_cnt * sizeof(struct rib_entry) +
303 	    stats->path_cnt * sizeof(struct rde_aspath) +
304 	    stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
305 	    stats->attr_data, UINT64_MAX);
306 
307 	ometric_set_int(rde_table_count, stats->aset_cnt, NULL);
308 
309 	ometric_set_int_with_labels(rde_set_size, stats->aset_size,
310 	    OKV("type"), OKV("as_set"), NULL);
311 	ometric_set_int_with_labels(rde_set_count, stats->aset_nmemb,
312 	    OKV("type"), OKV("as_set"), NULL);
313 	ometric_set_int_with_labels(rde_set_size, stats->pset_size,
314 	    OKV("type"), OKV("prefix_set"), NULL);
315 	ometric_set_int_with_labels(rde_set_count, stats->pset_cnt,
316 	    OKV("type"), OKV("prefix_set"), NULL);
317 	ometric_rib_mem_element("set_total", UINT64_MAX,
318 	    stats->aset_size + stats->pset_size, UINT64_MAX);
319 }
320 
321 static void
322 ometric_tail(void)
323 {
324 	struct timespec elapsed_time;
325 
326 	clock_gettime(CLOCK_MONOTONIC, &end_time);
327 	timespecsub(&end_time, &start_time, &elapsed_time);
328 
329 	ometric_set_timespec(bgpd_scrape_time, &elapsed_time, NULL);
330 	ometric_output_all(stdout);
331 
332 	ometric_free_all();
333 }
334 
335 const struct output ometric_output = {
336 	.head = ometric_head,
337 	.neighbor = ometric_neighbor_stats,
338 	.rib_mem = ometric_rib_mem,
339 	.tail = ometric_tail,
340 };
341