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
ometric_head(struct parse_result * arg)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
ometric_neighbor_stats(struct peer * p,struct parse_result * arg)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
ometric_rib_mem_element(const char * v,uint64_t count,uint64_t size,uint64_t refs)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
ometric_rib_mem(struct rde_memstats * stats)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
ometric_tail(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