From 78750e197f2c3fb298ab144efd5bdcd9fb38bb73 Mon Sep 17 00:00:00 2001 From: Katerina Kubecova Date: Wed, 6 Dec 2023 08:40:40 +0100 Subject: [PATCH] birdc.py: first complete cbor to cbor commands, cbor saving int64 fix --- lib/timer.c | 8 ++ lib/timer.h | 1 + nest/cbor.c | 30 +++++- nest/cbor_cmds.c | 18 +++- nest/cbor_parse.c | 11 +- nest/cbor_shortcuts.c | 7 +- nest/cmds.c | 2 +- proto/ospf/ospf_for_cbor.c | 20 ++-- yang/birdc.py | 200 +++++++++++++++++++++++++++++++++++++ yang/command.cbor | 2 +- yang/command.json | 2 +- yang/show_ospf.yang | 50 ++++------ yang/show_status.yang | 6 +- yang/yang-library.json | 6 ++ 14 files changed, 309 insertions(+), 54 deletions(-) create mode 100644 yang/birdc.py diff --git a/lib/timer.c b/lib/timer.c index c47e0bbc..21e813ae 100644 --- a/lib/timer.c +++ b/lib/timer.c @@ -310,6 +310,14 @@ tm_format_time(char *x, struct timeformat *fmt, btime t) strcpy(x, ""); } +btime +tm_get_real_time(btime t) +{ + btime dt = current_time() - t; + btime rt = current_real_time() - dt; + return rt; +} + /* Replace %f in format string with usec scaled to requested precision */ static int strfusec(char *buf, int size, const char *fmt, uint usec) diff --git a/lib/timer.h b/lib/timer.h index 0f87852b..a742bc09 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -125,6 +125,7 @@ struct timeformat { btime tm_parse_time(const char *x); void tm_format_time(char *x, struct timeformat *fmt, btime t); +btime tm_get_real_time(btime t); int tm_format_real_time(char *x, size_t max, const char *fmt, btime t); #endif diff --git a/nest/cbor.c b/nest/cbor.c index 1dba7fc9..fc813a93 100644 --- a/nest/cbor.c +++ b/nest/cbor.c @@ -9,7 +9,7 @@ struct cbor_writer { struct linpool *lp; }; -void write_item(struct cbor_writer *writer, int8_t major, int num); +void write_item(struct cbor_writer *writer, int8_t major, u64 num); void check_memory(struct cbor_writer *writer, int add_size); @@ -55,7 +55,7 @@ void cbor_open_list_with_length(struct cbor_writer *writer, int length) } -void cbor_add_int(struct cbor_writer *writer, int item) +void cbor_add_int(struct cbor_writer *writer, int64_t item) { if (item >= 0) { @@ -63,10 +63,15 @@ void cbor_add_int(struct cbor_writer *writer, int item) } else { - write_item(writer, 1, item); + write_item(writer, 1, -item); } } +void cbor_add_uint(struct cbor_writer *writer, u64 item) +{ + write_item(writer, 0, item); +} + void cbor_add_tag(struct cbor_writer *writer, int item) { write_item(writer, 6, item); @@ -89,10 +94,26 @@ void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, u writer->pt+=length; } -void write_item(struct cbor_writer *writer, int8_t major, int num) +void write_item(struct cbor_writer *writer, int8_t major, u64 num) { major = major<<5; check_memory(writer, 10); + log("writing %li %lx max for lower %lx ", num, num, ((u64)1<<(4*8))-1); + if (num > ((u64)1<<(4*8))-1) + { // We need 8 bytes to encode the num + log("loong num"); + major += 0x1b; // reserving those bytes + writer->cbor[writer->pt] = major; + writer->pt++; + for (int i = 7; i>=0; i--) + { // write n-th byte of num + uint8_t to_write = (num>>(i*8)) & 0xff; + log("%x", to_write); + writer->cbor[writer->pt] = to_write; + writer->pt++; + } + return; + } if (num > (1<<(2*8))-1) { // We need 4 bytes to encode the num major += 0x1a; // reserving those bytes @@ -101,6 +122,7 @@ void write_item(struct cbor_writer *writer, int8_t major, int num) for (int i = 3; i>=0; i--) { // write n-th byte of num uint8_t to_write = (num>>(i*8)) & 0xff; + log("%x", to_write); writer->cbor[writer->pt] = to_write; writer->pt++; } diff --git a/nest/cbor_cmds.c b/nest/cbor_cmds.c index 9d46ee32..01a508c1 100644 --- a/nest/cbor_cmds.c +++ b/nest/cbor_cmds.c @@ -22,6 +22,9 @@ uint compare_str(byte *str1, uint length, const char *str2) { 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; @@ -73,6 +76,7 @@ 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"); @@ -83,11 +87,12 @@ cmd_show_status_cbor(byte *tbuf, uint capacity, struct linpool *lp) cbor_open_block(w); cbor_string_int(w, "router_id", config->router_id); cbor_string_string(w, "hostname", config->hostname); - cbor_string_int(w, "server_time", current_time()); - cbor_string_int(w, "last_reboot", boot_time); - cbor_string_int(w, "last_reconfiguration", config->load_time); + 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()); @@ -105,6 +110,7 @@ cmd_show_status_cbor(byte *tbuf, uint capacity, struct linpool *lp) else cbor_add_string(w, "Daemon is up and running"); cbor_write_to_file(w, "test.cbor"); + log("leaving show status"); return w->pt; } @@ -148,14 +154,16 @@ cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct arg_list *args, struct l { if (compare_str(args->args[args->pt - 1].arg, args->args[args->pt - 1].len, sym->name)) { - cbor_string_string(w, "name", args->args[args->pt - 1].arg); + 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_string_string(w, "name", args->args[args->pt - 1].arg); + 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; } diff --git a/nest/cbor_parse.c b/nest/cbor_parse.c index 974beb76..b2c23098 100644 --- a/nest/cbor_parse.c +++ b/nest/cbor_parse.c @@ -21,7 +21,7 @@ enum cbor_majors { struct value { int major; - int val; + int64_t val; }; struct buff_reader { @@ -49,7 +49,8 @@ get_value(struct buff_reader *reader) struct value val; byte *buff = reader->buff; val.major = buff[reader->pt]>>5; - log("in get value"); + log("in get value are zou here?"); + log("major is %x", val.major); int first_byte_val = buff[reader->pt] - (val.major<<5); if (first_byte_val <=23) { val.val = first_byte_val; @@ -66,6 +67,12 @@ get_value(struct buff_reader *reader) { val.val = buff[reader->pt+1]>>24 + buff[reader->pt+2]>>16 + buff[reader->pt+3]>>8 + buff[reader->pt+4]; reader->pt+=5; + } else if (first_byte_val == 0x1b) + { + for(int i = 1; i<=8; i++) { + val.val += buff[reader->pt+i]>>(64-(i*8)); + } + reader->pt+=9; } else if (first_byte_val == 0xff) { val.val = -1; diff --git a/nest/cbor_shortcuts.c b/nest/cbor_shortcuts.c index 5c8955ca..15adf460 100644 --- a/nest/cbor_shortcuts.c +++ b/nest/cbor_shortcuts.c @@ -9,11 +9,16 @@ void cbor_string_string(struct cbor_writer *writer, char *key, const char *value cbor_add_string(writer, value); } -void cbor_string_int(struct cbor_writer *writer, char *key, int value) { +void cbor_string_int(struct cbor_writer *writer, char *key, int64_t value) { cbor_add_string(writer, key); cbor_add_int(writer, value); } +void cbor_string_uint(struct cbor_writer *writer, char *key, u64 value) { + cbor_add_string(writer, key); + cbor_add_uint(writer, value); +} + void cbor_named_block_two_ints(struct cbor_writer *writer, char *key, char *name1, int val1, char *name2, int val2) { cbor_add_string(writer, key); cbor_open_block_with_length(writer, 2); diff --git a/nest/cmds.c b/nest/cmds.c index 8214db5f..d49bbc53 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -26,7 +26,7 @@ cmd_show_status(void) cli_msg(-1000, "BIRD " BIRD_VERSION); tm_format_time(tim, &config->tf_base, current_time()); - cli_msg(-1011, "Router ID is %R %i %x", config->router_id, config->router_id, config->router_id); + cli_msg(-1011, "Router ID is %R", config->router_id); cli_msg(-1011, "Hostname is %s", config->hostname); cli_msg(-1011, "Current server time is %s", tim); tm_format_time(tim, &config->tf_base, boot_time); diff --git a/proto/ospf/ospf_for_cbor.c b/proto/ospf/ospf_for_cbor.c index 46590ce4..9c8d1984 100644 --- a/proto/ospf/ospf_for_cbor.c +++ b/proto/ospf/ospf_for_cbor.c @@ -58,6 +58,7 @@ show_lsa_router_cbor(struct cbor_writer *w, struct ospf_proto *p, struct top_has cbor_add_string(w, "network"); cbor_open_list(w); lsa_walk_rt_init(p, he, &rtl); + int dummy_id = 0; while (lsa_walk_rt(&rtl)) { if (rtl.type == LSART_NET) @@ -72,26 +73,30 @@ show_lsa_router_cbor(struct cbor_writer *w, struct ospf_proto *p, struct top_has struct ospf_lsa_header *net_lsa = &(net_he->lsa); struct ospf_lsa_net *net_ln = net_he->lsa_body; - cbor_open_block_with_length(w, 3); + cbor_open_block_with_length(w, 4); + cbor_string_int(w, "dummy_yang_id", dummy_id); cbor_string_int(w, "network", net_lsa->id & net_ln->optx); cbor_string_int(w, "len", u32_masklen(net_ln->optx)); cbor_string_int(w, "metric", rtl.metric); } else { - cbor_open_block_with_length(w, 2); + cbor_open_block_with_length(w, 3); + cbor_string_int(w, "dummy_yang_id", dummy_id); cbor_string_int(w, "network", rtl.id); cbor_string_int(w, "metric", rtl.metric); } } else { - cbor_open_block_with_length(w, 3); + cbor_open_block_with_length(w, 4); + cbor_string_int(w, "dummy_yang_id", dummy_id); cbor_string_int(w, "network", rtl.id); cbor_string_int(w, "nif", rtl.nif); cbor_string_int(w, "metric", rtl.metric); } } + dummy_id++; } cbor_close_block_or_list(w); @@ -145,7 +150,10 @@ show_lsa_network_cbor(struct cbor_writer *w, struct top_hash_entry *he, int ospf cbor_add_string(w, "routers"); cbor_open_list(w); for (i = 0; i < lsa_net_count(lsa); i++) + { + cbor_open_block_with_length(w, 1); cbor_string_int(w, "router", ln->routers[i]); + } cbor_close_block_or_list(w); } @@ -215,7 +223,7 @@ show_lsa_external_cbor(struct cbor_writer *w, struct top_hash_entry *he, int osp if(rt.ebit) { - cbor_string_int(w, "lsa_type", 2); + cbor_string_int(w, "lsa_type_num", 2); } cbor_string_int(w, "metric", rt.metric); cbor_close_block_or_list(w); @@ -252,7 +260,7 @@ show_lsa_prefix_cbor(struct cbor_writer *w, struct top_hash_entry *he, struct to buf = px->rest; - cbor_add_string(w, "prexixes"); + cbor_add_string(w, "prefixes"); cbor_open_list(w); char str[IPA_MAX_TEXT_LENGTH + 8] = ""; for (i = 0; i < px->pxcount; i++) @@ -500,6 +508,7 @@ ospf_sh_state_cbor(struct cbor_writer *w, struct proto *P, int verbose, int reac for (i = 0; i < j1; i++) { cbor_open_block(w); + cbor_string_int(w, "dummy_yang_id", i); he = hea[i]; /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */ @@ -580,7 +589,6 @@ ospf_sh_state_cbor(struct cbor_writer *w, struct proto *P, int verbose, int reac /* If it is still marked, we show it now. */ if (he->domain) { - cbor_add_string(w, "asbr"); cbor_open_block(w); he->domain = 0; diff --git a/yang/birdc.py b/yang/birdc.py new file mode 100644 index 00000000..6b01d31d --- /dev/null +++ b/yang/birdc.py @@ -0,0 +1,200 @@ +import cbor +import json +import sys +import os +import socket, struct +import datetime + + +class Command: + num = -1 + def addr_to_str(self, addr): + return socket.inet_ntoa(struct.pack('!L', addr)) + + def print_answer(self, answer): + print(answer) + +class Memory(Command): + num = 1 + def nums_to_str(self, answer, key): + + e = answer["show_memory:message"]["body"][key]["effective"] + o = answer["show_memory:message"]["body"][key]["overhead"] + j_e = " B" + j_o = " B" + if e > 9999: + e = e/1000 + j_e = "kB" + if o > 9999: + o = o/1000 + j_o = "kB" + return f"{e:>7} {j_e} {o:>7} {j_o}" + + def print_answer(self, answer): + print() + print("BIRD memory usage") + keys = answer["show_memory:message"]["body"].keys() + first_column_width = len("route attributes ") + print(" " * (first_column_width+4), "Effective ", "Overhead") + for key in keys: + name = key.replace("_", " ") + print(name,":", " "*(first_column_width - len(name)), self.nums_to_str(answer, key)) + + +class Status(Command): + num = 0 + + def print_answer(self, answer): + print(answer) + print() + print("BIRD", answer["show_status:message"]["version"]) + for key in answer["show_status:message"]["body"].keys(): + name = key.replace("_", " ") + if key == "router_id": + print(name, self.addr_to_str( answer["show_status:message"]["body"][key])) + elif key in "server_time last_reboot last_reconfiguration": + print(name, datetime.datetime.fromtimestamp(answer["show_status:message"]["body"][key])) + else: + print(name, answer["show_status:message"]["body"][key]) + print(answer["show_status:message"]["state"]) + + +class Symbols(Command): + num = 2 + + def print_answer(self, answer): + print() + for item in answer["show_symbols:message"]["table"]: + print(f"{item['name']:<15} {item['type']}") + + +class Ospf(Command): + num = 3 + + def print_lsa_router(self, area): + print ("\trouter", self.addr_to_str(area['router'])) + print("\t\tdistance", area['distance']) + if ('vlink' in area.keys()): + for vlink in area['vlink']: + print(f"\t\tvlink {self.addr_to_str( vlink['vlink'])} metric {vlink['metric']}") + if ('router_metric' in area.keys()): + for router in area['router_metric']: + print(f"\t\trouter {self.addr_to_str( router['router'])} metric {router['metric']}") + for network in area['network']: + addr = self.addr_to_str(network['network']) + if('nif' in network): + print(f"\t\tnetwork [{addr}-{network['nif']}] metric {network['metric']}") + elif('len' in area.keys()): + print(f"\t\tnetwork {addr}/{network['len']} metric {network['metric']}") + else: + print(f"\t\tnetwork [{addr}] metric {network['metric']}") + if ('stubnet' in area.keys()): + for stubnet in area['stubnet']: + print(f"\t\tstubnet {self.addr_to_str(stubnet['stubnet'])}/{stubnet['len']} metric {stubnet['metric']}") + + def print_lsa_network(self, area): + if ('ospf2' in area.keys()): + print(f"\tnetwork {self.addr_to_str(area['ospf2']['network'])}/{area['ospf2']['optx']}") + print(f"\t\tdr {self.addr_to_str(area['ospf2']['dr'])}") + elif ('ospf' in area.keys()): + print(f"\tnetwork [{self.addr_to_str(area['ospf']['network'])}-{area['ospf']['lsa_id']}]") + print("\t\tdistance", area['distance']) + for router in area['routers']: + print(f"\t\trouter {self.addr_to_str(router['router'])}") + + def print_lsa_sum_net(self, area): + print(f"\t\txnetwork {area['net']} metric {area['metric']}") + + def print_lsa_sum_rt(self, area): + print(f"\t\txrouter {self.addr_to_str(area['router'])} metric {area['metric']}") + + def print_lsa_external(self, area): + if('lsa_type_num' in area.keys()): + print(f"\t\t{area['lsa_type']} {self.addr_to_str(area['rt_net'])} metric{area[lsa_type_num]} {area['metric']}%s%s") + else: + print(f"\t\t{area['lsa_type']} {self.addr_to_str(area['rt_net'])} metric {area['metric']}{area['via']}{area['tag']}") + + def print_lsa_prefix(self, area): + for prefix in area['prefixes']: + if 'metric' in prefix.keys(): + print(f"\t\tstubnet {self.addr_to_str(prefix['stubnet'])} metric {prefix['metric']}") + + def print_answer(self, answer): + print() + if ("error" in answer["show_ospf:message"].keys()): + print("error: ", answer["show_ospf:message"]["error"]) + return + if ("not implemented" in answer["show_ospf:message"].keys()): + print("not implemented: ", answer["show_ospf:message"]["not implemented"]) + return + for area in answer["show_ospf:message"]["areas"]: + if 'area' in area.keys(): + print ("area", self.addr_to_str(area['area'])) + print() + if 'lsa_router' in area.keys(): + self.print_lsa_router(area['lsa_router']) + elif 'lsa_network' in area.keys(): + self.print_lsa_network(area['lsa_network']) + elif 'lsa_sum_net' in area.keys(): + self.print_lsa_sum_net(area['lsa_sum_net']) + elif 'lsa_sum_rt' in area.keys(): + self.print_lsa_sum_rt(area['lsa_sum_rt']) + elif 'lsa_external' in area.keys(): + self.print_lsa_external(area['lsa_external']) + elif 'lsa_prefix' in area.keys(): + self.print_lsa_prefix(area['lsa_prefix']) + if('asbrs' in area.keys()): + for asbr in area['asbrs']: + if('other_ABSRs' in asbr.keys()): + print("other ASBRs") + print("other ASBRs") + print(f"\trouter {self.addr_to_str(asbr['router'])}") + +command_dictionary = {"status":0, "memory":1, "symbols":2, "ospf":3} + +def get_command_class(string): + if string == "status": + return Status() + if string == "memory": + return Memory() + if string == "symbols": + return Symbols() + if string == "ospf": + return Ospf() + raise Exception(f"Command {string} not known. Expected status, memory, symbols or ospf") + +def run_on_machine(dev, cmd): + ws = os.system(f"ip netns exec {dev} {cmd}") + if os.WIFEXITED(ws): + ec = os.WEXITSTATUS(ws) + else: + ec = False + + if ec != 0: + raise Exception(f"Command {cmd} exited with exit code {ws}") + + +arguments = sys.argv +if (len(sys.argv) <= 2): + raise Exception("Expected command, no argunents given.") +if (len(sys.argv) == 3): + raise Exception(f"only one ({sys.argv[2]}) command given, that is not implemented") +if(sys.argv[2] != "show"): + raise Exception(f"Expected 'dev show status/memory/symbols/ospf', unknown {sys.argv[2]}.") +comm = get_command_class(sys.argv[3]) + +command = {"command:do":{"command":comm.num, "args":[]}} +for i in range (4, len(sys.argv)): + command["command:do"]["args"].append({"arg": sys.argv[i]}) +print(command) + +with open(os.getcwd()+"/command.cbor", "wb") as of: + cbor.dump(command, of) + +run_on_machine(sys.argv[1], f"cat command.cbor | sudo socat UNIX-CONNECT:{os.getcwd()}/bird-yang.ctl STDIO > answer.cbor") + + +with open("answer.cbor", "br") as cbor_file: + answer = cbor.load(cbor_file) + + comm.print_answer(answer) diff --git a/yang/command.cbor b/yang/command.cbor index 2598a2ab..cb0468eb 100644 --- a/yang/command.cbor +++ b/yang/command.cbor @@ -1 +1 @@ -¡jcommand:do¢gcommanddargs‚¡carghtopology¡cargeospf6 \ No newline at end of file +¡jcommand:do¢gcommanddargs„¡cargculg¡cargbui¡cargb76¡cargbkl \ No newline at end of file diff --git a/yang/command.json b/yang/command.json index d9e76253..4ff5a5e2 100644 --- a/yang/command.json +++ b/yang/command.json @@ -1,2 +1,2 @@ -{"command:do":{"command": 3, "args":[{"arg":"topology"}, {"arg":"ospf6"}]}} +{"command:do":{"command": 3, "args":[{"arg":"topology"}, {"arg":"ospf4"}]}} diff --git a/yang/show_ospf.yang b/yang/show_ospf.yang index 68c256e3..cf8d808c 100644 --- a/yang/show_ospf.yang +++ b/yang/show_ospf.yang @@ -37,9 +37,7 @@ module show_ospf { leaf vlink { type int32; } - leaf metric { - type int32; - } + uses metric; } list router_metric { @@ -49,7 +47,10 @@ module show_ospf { } list network { - key "network"; + key "dummy_yang_id"; + leaf dummy_yang_id { + type int32; + } leaf network { type int32; } @@ -148,7 +149,7 @@ module show_ospf { leaf rt_net { type string; } - leaf lsa_type { + leaf lsa_type_num { type int32; } uses metric; @@ -158,20 +159,25 @@ module show_ospf { grouping lsa_prefix { container lsa_prefix { list prefixes { + key "stubnet"; leaf stubnet { - type string; + type int32; } uses metric; } } } - container ospf { + container message { leaf error { mandatory false; type string; } list areas { + key "dummy_yang_id"; + leaf dummy_yang_id { + type int32; + } leaf area { type int32; } @@ -197,31 +203,15 @@ module show_ospf { } } list asbrs { - container asbr { - leaf other_ABSRs { - type none; - } - uses router; - uses lsa_external; + key "router"; + + leaf other_ABSRs { + type empty; } + uses router; + uses lsa_external; + } } } - - - - - - - - - - - - - - - - - diff --git a/yang/show_status.yang b/yang/show_status.yang index 14a42da0..cbae232e 100644 --- a/yang/show_status.yang +++ b/yang/show_status.yang @@ -35,13 +35,13 @@ module show_status { type string; } leaf server_time { - type int32; + type int64; } leaf last_reboot { - type int32; + type int64; } leaf last_reconfiguration { - type int32; + type int64; } container gr_restart { leaf waiting_for_n_channels_to_recover { diff --git a/yang/yang-library.json b/yang/yang-library.json index 216545c3..611d149c 100644 --- a/yang/yang-library.json +++ b/yang/yang-library.json @@ -20,6 +20,12 @@ "revision": "", "conformance-type": "implement" }, + { + "name": "show_ospf", + "namespace": "https://bird.nic.cz/yang/v2.15/cli-debug", + "revision": "", + "conformance-type": "implement" + }, { "name": "show_protocols", "namespace": "https://bird.nic.cz/yang/v2.15/cli-debug",