#include "nest/bird.h" #include "nest/protocol.h" #include "nest/route.h" #include "nest/cli.h" #include "conf/conf.h" #include "lib/string.h" #include "filter/filter.h" #include "nest/cbor_cmds.h" #include "proto/ospf/ospf_for_cbor.c" uint compare_str(byte *str1, uint length, const char *str2) { if (length != strlen(str2)) { return 0; } for (size_t i = 0; i < length; i++) { if (str1[i]!=str2[i]) { return 0; } } return 1; } int64_t preprocess_time(btime t) { return tm_get_real_time(t) TO_S ; } extern pool *rt_table_pool; extern pool *rta_pool; extern uint *pages_kept; uint cmd_show_memory_cbor(byte *tbuf, uint capacity, struct linpool *lp) { log("in cmd_show_memory_cbor"); struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_memory:message"); cbor_open_block_with_length(w, 2); cbor_string_string(w, "header", "BIRD memory usage"); cbor_add_string(w, "body"); cbor_open_block(w); struct resmem memory = rmemsize(rt_table_pool); cbor_named_block_two_ints(w, "routing_tables", "effective", memory.effective, "overhead", memory.overhead); memory = rmemsize(rta_pool); cbor_named_block_two_ints(w, "route_attributes", "effective", memory.effective, "overhead", memory.overhead); memory = rmemsize(proto_pool); cbor_named_block_two_ints(w, "protocols", "effective", memory.effective, "overhead", memory.overhead); memory = rmemsize(config_pool); cbor_named_block_two_ints(w, "current_config", "effective", memory.effective, "overhead", memory.overhead); memory = rmemsize(&root_pool); #ifdef HAVE_MMAP cbor_named_block_two_ints(w, "standby_memory", "effective", 0, "overhead", page_size * *pages_kept); #endif memory.overhead += page_size * *pages_kept; cbor_named_block_two_ints(w, "total", "effective", memory.effective, "overhead", memory.overhead); cbor_close_block_or_list(w); // we do not know for sure, that standby memory will be printed, so we do not know number of block items. If we know that, we open the block for 6 (or 5) items and we do not close anything cbor_write_to_file(w, "show_memory.cbor"); return w->pt; } extern int shutting_down; extern int configuring; uint cmd_show_status_cbor(byte *tbuf, uint capacity, struct linpool *lp) { log("show status"); struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_status:message"); cbor_open_block_with_length(w, 3); cbor_string_string(w, "version", BIRD_VERSION); cbor_add_string(w, "body"); cbor_open_block(w); cbor_string_ipv4(w, "router_id", config->router_id); cbor_string_string(w, "hostname", config->hostname); cbor_string_int(w, "server_time", preprocess_time(current_time())); cbor_string_int(w, "last_reboot", preprocess_time(boot_time)); cbor_string_int(w, "last_reconfiguration", preprocess_time(config->load_time)); if (is_gr_active()) { log("graceful restart"); cbor_add_string(w, "gr_restart"); cbor_open_block_with_length(w, 2); cbor_string_int(w, "waiting_for_n_channels_to_recover", get_graceful_restart_locks_num()); cbor_add_string(w, "wait_timer"); cbor_open_block_with_length(w, 2); cbor_string_int(w, "remains", get_tm_remains_gr_wait_timer()); cbor_string_int(w, "count_time", get_config_gr_wait()); } cbor_close_block_or_list(w); cbor_add_string(w, "state"); if (shutting_down) cbor_add_string(w, "Shutdown in progress"); else if (configuring) cbor_add_string(w, "Reconfiguration in progress"); else cbor_add_string(w, "Daemon is up and running"); cbor_write_to_file(w, "test.cbor"); log("leaving show status"); return w->pt; } int parse_show_symbols_arg(struct argument *argument) { char *params[] = {"table", "filter", "function", "protocol", "template", "constant", "variable"}; int param_vals[] = {SYM_TABLE, SYM_FILTER, SYM_FUNCTION, SYM_PROTO, SYM_TEMPLATE, SYM_CONSTANT, SYM_VARIABLE}; // defined in conf.h for (size_t j = 0; j < sizeof(params)/sizeof(char*); j++) { if (compare_str(argument->arg, argument->len, params[j])) { return param_vals[j]; } } return -1; } uint cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct arg_list *args, struct linpool *lp) { struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_symbols:message"); cbor_open_block_with_length(w, 1); int show_type = SYM_VOID; if (args->pt > 0) { show_type = parse_show_symbols_arg(&args->args[args->pt - 1]); // Takes just the last one argument. Current bird cli answers only last argument too, but can fail on previous. } if (show_type == -1) { cbor_add_string(w, "table"); cbor_open_list_with_length(w, 1); cbor_open_block_with_length(w, 2); for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next) { HASH_WALK(scope->hash, next, sym) { if (compare_str(args->args[args->pt - 1].arg, args->args[args->pt - 1].len, sym->name)) { cbor_add_string(w, "name"); cbor_nonterminated_string(w, args->args[args->pt - 1].arg, args->args[args->pt - 1].len); cbor_string_string(w, "type", cf_symbol_class_name(sym)); return w->pt; } } HASH_WALK_END; } cbor_add_string(w, "name"); cbor_nonterminated_string(w, args->args[args->pt - 1].arg, args->args[args->pt - 1].len); cbor_string_string(w, "type", "symbol not known"); return w->pt; } else { cbor_add_string(w, "table"); cbor_open_list(w); for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next) HASH_WALK(scope->hash, next, sym) { if (!sym->scope->active) continue; if (show_type == SYM_VARIABLE || show_type == SYM_CONSTANT) { if (!(show_type == (int)(sym->class & 0xffffff00))) continue; } else if (show_type != SYM_VOID && (sym->class != show_type)) continue; cbor_open_block_with_length(w, 2); cbor_string_string(w, "name", sym->name); cbor_string_string(w, "type", cf_symbol_class_name(sym)); } HASH_WALK_END; cbor_close_block_or_list(w); return w->pt; } } struct proto * cbor_get_proto_type(enum protocol_class proto_type, struct cbor_writer *w) { log("in type"); struct proto *p, *q; p = NULL; WALK_LIST(q, proto_list) if ((q->proto->class == proto_type) && (q->proto_state != PS_DOWN)) { if (p) { cbor_string_string(w, "error", "multiple protocols running"); return NULL; } p = q; } if (!p) { cbor_string_string(w, "error", "no such protocols running"); return NULL; } return p; } struct proto * cbor_get_proto_name(struct argument *arg, enum protocol_class proto_type, struct cbor_writer *w) { log("in name"); struct proto *q; WALK_LIST(q, proto_list) { log("%s %s %i %i %i", arg->arg, q->name, compare_str(arg->arg, arg->len, q->name) , (q->proto_state != PS_DOWN) , (q->proto->class == proto_type)); if (compare_str(arg->arg, arg->len, q->name) && (q->proto_state != PS_DOWN) && (q->proto->class == proto_type)) { return q; } } cbor_add_string(w, "not found"); cbor_nonterminated_string(w, arg->arg, arg->len); return NULL; } uint cmd_show_ospf_cbor(byte *tbuf, uint capacity, struct arg_list *args, struct linpool *lp) { log("in ospf args %i, pt %i", args, args->pt); struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_ospf:message"); if (args->pt == 0) { cbor_open_block_with_length(w, 1); cbor_string_string(w, "not implemented", "show everything about ospf"); return w->pt; } if (compare_str(args->args[0].arg, args->args[0].len, "topology")) { cbor_open_block(w); struct proto *proto; int all_ospf = (args->pt > 1) && compare_str(args->args[1].arg, args->args[1].len, "all"); if (args->pt - all_ospf > 1) // if there is protocol name { proto = cbor_get_proto_name(&args->args[args->pt -1], PROTOCOL_OSPF, w); } else { proto = cbor_get_proto_type(PROTOCOL_OSPF, w); } if (proto == NULL) { cbor_close_block_or_list(w); return w->pt; } ospf_sh_state_cbor(w, proto, 0, all_ospf); cbor_close_block_or_list(w); return w->pt; } else { cbor_open_block_with_length(w, 1); cbor_add_string(w, "not implemented"); cbor_nonterminated_string(w, args->args[0].arg, args->args[0].len); return w->pt; } }