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