From 5a079e8eaeefcbc29d11d2ebc14d7aad13b24b79 Mon Sep 17 00:00:00 2001 From: Katerina Kubecova Date: Fri, 1 Dec 2023 14:43:24 +0100 Subject: [PATCH] cbor_cmds.c, ospf_for_cbor.c: ospf show topology looks working --- nest/cbor.c | 9 + nest/cbor_cmds.c | 142 +++++++-- nest/cbor_cmds.h | 18 ++ nest/cbor_parse.c | 80 +++-- nest/cli.c | 2 +- nest/proto.c | 6 + nest/protocol.h | 1 + proto/ospf/ospf_for_cbor.c | 610 +++++++++++++++++++++++++++++++++++++ yang/command.cbor | 2 +- yang/command.json | 2 +- yang/show_symbols.cbor | 2 +- 11 files changed, 817 insertions(+), 57 deletions(-) create mode 100644 nest/cbor_cmds.h create mode 100644 proto/ospf/ospf_for_cbor.c diff --git a/nest/cbor.c b/nest/cbor.c index 2c152439..924a6fa3 100644 --- a/nest/cbor.c +++ b/nest/cbor.c @@ -81,6 +81,15 @@ void cbor_add_string(struct cbor_writer *writer, const char *string) writer->pt+=length; } +void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, uint length) +{ + int length = strlen(string); + write_item(writer, 3, length); // 3 is major, then goes length of string and string + check_memory(writer, length); + memcpy(writer->cbor+writer->pt, string, length); + writer->pt+=length; +} + void write_item(struct cbor_writer *writer, int8_t major, int num) { major = major<<5; diff --git a/nest/cbor_cmds.c b/nest/cbor_cmds.c index 9a029227..9d46ee32 100644 --- a/nest/cbor_cmds.c +++ b/nest/cbor_cmds.c @@ -1,4 +1,4 @@ -#include "nest/cbor_shortcuts.c" + #include "nest/bird.h" #include "nest/protocol.h" #include "nest/route.h" @@ -6,15 +6,11 @@ #include "conf/conf.h" #include "lib/string.h" #include "filter/filter.h" +#include "nest/cbor_cmds.h" +#include "proto/ospf/ospf_for_cbor.c" -struct cbor_show_data { - int type; /* Symbols type to show */ - int name_length; - char *name; -}; - -uint compare_str(byte *str1, uint length, char *str2) { +uint compare_str(byte *str1, uint length, const char *str2) { if (length != strlen(str2)) { return 0; } @@ -32,10 +28,10 @@ extern pool *rta_pool; extern uint *pages_kept; uint -cmd_show_memory_cbor(byte *tbuf, uint capacity) +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_new(proto_pool)); + struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_memory:message"); @@ -75,9 +71,9 @@ extern int shutting_down; extern int configuring; uint -cmd_show_status_cbor(byte *tbuf, uint capacity) +cmd_show_status_cbor(byte *tbuf, uint capacity, struct linpool *lp) { - struct cbor_writer *w = cbor_init(tbuf, capacity, lp_new(proto_pool)); + struct cbor_writer *w = cbor_init(tbuf, capacity, lp); cbor_open_block_with_length(w, 1); cbor_add_string(w, "show_status:message"); @@ -112,15 +108,35 @@ cmd_show_status_cbor(byte *tbuf, uint capacity) return w->pt; } -int -cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct cbor_show_data show) +int parse_show_symbols_arg(struct argument *argument) { - struct cbor_writer *w = cbor_init(tbuf, capacity, lp_new(proto_pool)); + char *params[] = {"table", "filter", "function", "protocol", "template"}; + int param_vals[] = {SYM_TABLE, SYM_FILTER, SYM_FUNCTION, SYM_PROTO, SYM_TEMPLATE}; // 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); - if (show.type == -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); @@ -130,16 +146,16 @@ cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct cbor_show_data show) { HASH_WALK(scope->hash, next, sym) { - if (compare_str(show.name, show.name_length, sym->name)) + if (compare_str(args->args[args->pt - 1].arg, args->args[args->pt - 1].len, sym->name)) { - cbor_string_string(w, "name", show.name); + cbor_string_string(w, "name", args->args[args->pt - 1].arg); cbor_string_string(w, "type", cf_symbol_class_name(sym)); return w->pt; } } HASH_WALK_END; } - cbor_string_string(w, "name", show.name); + cbor_string_string(w, "name", args->args[args->pt - 1].arg); cbor_string_string(w, "type", "symbol not known"); return w->pt; } @@ -154,7 +170,7 @@ cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct cbor_show_data show) if (!sym->scope->active) continue; - if (show.type != SYM_VOID && (sym->class != show.type)) + if (show_type != SYM_VOID && (sym->class != show_type)) continue; cbor_open_block_with_length(w, 2); @@ -169,5 +185,91 @@ cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct cbor_show_data show) } +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; + } +} + diff --git a/nest/cbor_cmds.h b/nest/cbor_cmds.h new file mode 100644 index 00000000..a28c0c97 --- /dev/null +++ b/nest/cbor_cmds.h @@ -0,0 +1,18 @@ + + +struct argument { + char *arg; + uint len; +}; + +struct arg_list { + struct argument *args; + int capacity; + int pt; + struct linpool *lp; +}; + +uint cmd_show_memory_cbor(byte *tbuf, uint capacity, struct linpool *lp); +uint cmd_show_status_cbor(byte *tbuf, uint capacity, struct linpool *lp); +uint cmd_show_symbols_cbor(byte *tbuf, uint capacity, struct arg_list *args, struct linpool *lp); + diff --git a/nest/cbor_parse.c b/nest/cbor_parse.c index 3bc62e4e..974beb76 100644 --- a/nest/cbor_parse.c +++ b/nest/cbor_parse.c @@ -4,6 +4,7 @@ enum functions { SHOW_STATUS = 0, SHOW_MEMORY = 1, SHOW_SYMBOLS = 2, + SHOW_OSPF = 3, }; enum cbor_majors { @@ -29,6 +30,7 @@ struct buff_reader { uint size; }; + uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string) { if (length != strlen(string)) { return 0; @@ -39,7 +41,7 @@ uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string) { } } return 1; -} +}; struct value get_value(struct buff_reader *reader) @@ -105,16 +107,15 @@ void skip_optional_args(struct buff_reader *rbuf_read, int items_in_block) } } -void parse_show_symbols_args(struct buff_reader *rbuf_read, int items_in_block, struct cbor_show_data *arg) +struct arg_list *parse_args(struct buff_reader *rbuf_read, int items_in_block, struct linpool *lp) { - log("parse symbols args"); - char *params[] = {"table", "filter", "function", "protocol", "template"}; - int param_vals[] = {SYM_TABLE, SYM_FILTER, SYM_FUNCTION, SYM_PROTO, SYM_TEMPLATE}; // defined in conf.h - arg->type = SYM_VOID; // default option - arg->name = NULL; + // We are in opened block, which could be empty or contain arguments <"args":[{"arg":"string"}]> + struct arg_list *arguments = (struct arg_list*)lp_alloc(lp, sizeof(struct arg_list)); + arguments->capacity = 0; + arguments->pt = 0; if (items_in_block == 0) { // there should not be arg array - return; + return arguments; } struct value val = get_value(rbuf_read); if (val.major == TEXT) @@ -127,13 +128,24 @@ void parse_show_symbols_args(struct buff_reader *rbuf_read, int items_in_block, ASSERT(val.major == ARRAY); int num_array_items = val.val; log("num arr items %i", num_array_items); - for (int i = 0; i 0) + { + arguments->args = (struct argument*)lp_alloc(lp, sizeof(struct argument) * num_array_items); + arguments->capacity = num_array_items; + } + else if (num_array_items == -1) + { + arguments->args = (struct argument*)lp_alloc(lp, sizeof(struct argument) * 4); + arguments->capacity = 4; + } + for (int i = 0; i < num_array_items || num_array_items == -1; i++) { // There will be only one argument in struct cbor_show_data arg after parsing the array of args. Current bird cli is behaving this way too. val = get_value(rbuf_read); if (val_is_break(val)) { rbuf_read->pt--; + return arguments; } else if (val.major == BLOCK) { @@ -145,24 +157,20 @@ void parse_show_symbols_args(struct buff_reader *rbuf_read, int items_in_block, val = get_value(rbuf_read); ASSERT(compare_buff_str(rbuf_read, val.val, "arg")); rbuf_read->pt+=val.val; + val = get_value(rbuf_read); - ASSERT(val.major == TEXT); - int found = 0; - for (size_t j = 0; j < sizeof(params)/sizeof(char*) && found == 0; j++) + ASSERT(val.major == TEXT); // Now we have an argument in val + if (num_array_items == -1 && arguments->capacity == arguments->pt) { - if (compare_buff_str(rbuf_read, val.val, params[j])) - { - arg->type = param_vals[j]; - found = 1; - log("found %s, on %i val %i", params[j], j, param_vals[j]); - } - } - if (found == 0) - { - arg->type = -1; - arg->name = rbuf_read->buff + rbuf_read->pt; - arg->name_length = val.val; + struct argument *a = arguments->args; + arguments->args = (struct argument*)lp_alloc(lp, sizeof(struct argument) * 2 * arguments->capacity); + arguments->capacity = 2 * arguments->capacity; + memcpy(arguments->args, a, sizeof(struct argument) * arguments->pt); } + arguments->args[arguments->pt].arg = rbuf_read->buff + rbuf_read->pt; // pointer to actual position in rbuf_read buffer + arguments->args[arguments->pt].len = val.val; + arguments->pt++; + rbuf_read->pt+=val.val; if (wait_close) { @@ -177,28 +185,34 @@ void parse_show_symbols_args(struct buff_reader *rbuf_read, int items_in_block, } } else { - ASSERT(items_in_block == -1); // assert the block was not open to exact num of items, because it cant be just for command (we would returned) and we did not find more items. + ASSERT(items_in_block == -1); // assert the block was not open to exact num of items, because it cant be just for command (we would returned) and we did not found more items. rbuf_read->pt--; // we read one byte from future, we need to shift pointer back } + return arguments; } uint -do_command(struct buff_reader *rbuf_read, struct buff_reader *tbuf_read, int items_in_block) +do_command(struct buff_reader *rbuf_read, struct buff_reader *tbuf_read, int items_in_block, struct linpool *lp) { struct value val = get_value(rbuf_read); ASSERT(val.major == UINT); + struct arg_list * args; switch (val.val) { case SHOW_MEMORY: skip_optional_args(rbuf_read, items_in_block); - return cmd_show_memory_cbor(tbuf_read->buff, tbuf_read->size); + return cmd_show_memory_cbor(tbuf_read->buff, tbuf_read->size, lp); case SHOW_STATUS: skip_optional_args(rbuf_read, items_in_block); - return cmd_show_status_cbor(tbuf_read->buff, tbuf_read->size); + return cmd_show_status_cbor(tbuf_read->buff, tbuf_read->size, lp); case SHOW_SYMBOLS: - struct cbor_show_data arg; - parse_show_symbols_args(rbuf_read, items_in_block, &arg); - return cmd_show_symbols_cbor(tbuf_read->buff, tbuf_read->size, arg); + args = parse_args(rbuf_read, items_in_block, lp); + return cmd_show_symbols_cbor(tbuf_read->buff, tbuf_read->size, args, lp); + case SHOW_OSPF: + args = parse_args(rbuf_read, items_in_block, lp); + log("args %i, pt %i", args, args->pt); + return cmd_show_ospf_cbor(tbuf_read->buff, tbuf_read->size, args, lp); + return 0; default: return 0; } @@ -206,7 +220,7 @@ do_command(struct buff_reader *rbuf_read, struct buff_reader *tbuf_read, int ite uint -parse_cbor(uint size, byte *rbuf, byte *tbuf, uint tbsize) +parse_cbor(uint size, byte *rbuf, byte *tbuf, uint tbsize, struct linpool* lp) { log("cbor parse"); struct buff_reader rbuf_read; @@ -246,7 +260,7 @@ parse_cbor(uint size, byte *rbuf, byte *tbuf, uint tbsize) ASSERT(compare_buff_str(&rbuf_read, val.val, "command")); rbuf_read.pt+=val.val; - tbuf_read.pt = do_command(&rbuf_read, &tbuf_read, items_in_block); + tbuf_read.pt = do_command(&rbuf_read, &tbuf_read, items_in_block, lp); if (items_in_block == -1) { val = get_value(&rbuf_read); diff --git a/nest/cli.c b/nest/cli.c index 790acf8b..58b85ae9 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -338,7 +338,7 @@ cli_kick(cli *c) uint yi_process(uint size, byte *rbuf, byte *tbuf, uint tbsize) { - return parse_cbor(size, rbuf, tbuf, tbsize); + return parse_cbor(size, rbuf, tbuf, tbsize, lp_new(yi_pool)); } static list cli_log_hooks; diff --git a/nest/proto.c b/nest/proto.c index 04b53b06..9bc59f34 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -2382,6 +2382,12 @@ proto_get_named(struct symbol *sym, struct protocol *pr) return p; } +list +get_protolist_for_cbor(void) +{ + return proto_list; +} + struct proto * proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *old) { diff --git a/nest/protocol.h b/nest/protocol.h index c8ba68e1..39efba94 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -300,6 +300,7 @@ void proto_cmd_mrtdump(struct proto *, uintptr_t, int); void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg); struct proto *proto_get_named(struct symbol *, struct protocol *); +list get_protolist_for_cbor(void); struct proto *proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *old); #define PROTO_WALK_CMD(sym,pr,p) for(struct proto *p = NULL; p = proto_iterate_named(sym, pr, p); ) diff --git a/proto/ospf/ospf_for_cbor.c b/proto/ospf/ospf_for_cbor.c new file mode 100644 index 00000000..d779a525 --- /dev/null +++ b/proto/ospf/ospf_for_cbor.c @@ -0,0 +1,610 @@ + +/** + * There are cli functions from ospf.c adapted for cbor. + */ + +#include +#include "ospf.h" +#include "nest/cbor_shortcuts.c" + + +static inline void +show_lsa_distance_cbor(struct cbor_writer *w, struct top_hash_entry *he) +{ + if (he->color == INSPF) + cbor_string_int(w, "distance", he->dist); + else + cbor_string_string(w, "distance", "unreachable"); +} + +static inline void +show_lsa_router_cbor(struct cbor_writer *w, struct ospf_proto *p, struct top_hash_entry *he, int verbose) +{ + struct ospf_lsa_rt_walk rtl; + + cbor_add_string(w, "lsa_router"); + cbor_open_block(w); + cbor_string_int(w, "router", he->lsa.rt); + show_lsa_distance_cbor(w, he); + + cbor_add_string(w, "vlink"); + cbor_open_list(w); + lsa_walk_rt_init(p, he, &rtl); + while (lsa_walk_rt(&rtl)) + { + if (rtl.type == LSART_VLNK) + { + cbor_open_block_with_length(w, 2); + cbor_string_int(w, "vlink", rtl.id); + cbor_string_int(w, "metric", rtl.metric); + } + } + cbor_close_block_or_list(w); + + cbor_add_string(w, "router_metric"); + cbor_open_list(w); + lsa_walk_rt_init(p, he, &rtl); + while (lsa_walk_rt(&rtl)) + { + if (rtl.type == LSART_PTP) + { + cbor_open_block_with_length(w, 2); + cbor_string_int(w, "router", rtl.id); + cbor_string_int(w, "metric", rtl.metric); + } + } + cbor_close_block_or_list(w); + + cbor_add_string(w, "network"); + cbor_open_list(w); + lsa_walk_rt_init(p, he, &rtl); + while (lsa_walk_rt(&rtl)) + { + if (rtl.type == LSART_NET) + { + if (ospf_is_v2(p)) + { + /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */ + struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id); + + if (net_he && (net_he->lsa.age < LSA_MAXAGE)) + { + 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_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_string_int(w, "network", rtl.id); + cbor_string_int(w, "metric", rtl.metric); + } + } + else + { + cbor_open_block_with_length(w, 3); + cbor_string_int(w, "network", rtl.id); + cbor_string_int(w, "nif", rtl.nif); + cbor_string_int(w, "metric", rtl.metric); + } + } + } + cbor_close_block_or_list(w); + + if (ospf_is_v2(p) && verbose) + { + cbor_add_string(w, "stubnet"); + cbor_open_list(w); + lsa_walk_rt_init(p, he, &rtl); + while (lsa_walk_rt(&rtl)) + { + if (rtl.type == LSART_STUB) + { + cbor_open_block_with_length(w, 3); + cbor_string_int(w, "stubnet", rtl.id); + cbor_string_int(w, "len", u32_masklen(rtl.data)); + cbor_string_int(w, "metric", rtl.metric); + } + } + cbor_close_block_or_list(w); + } + cbor_close_block_or_list(w); +} + +static inline void +show_lsa_network_cbor(struct cbor_writer *w, struct top_hash_entry *he, int ospf2) +{ + cbor_add_string(w, "lsa_network"); + cbor_open_block_with_length(w, 3); + struct ospf_lsa_header *lsa = &(he->lsa); + struct ospf_lsa_net *ln = he->lsa_body; + u32 i; + + if (ospf2) + { + cbor_add_string(w, "ospf2"); + cbor_open_block_with_length(w, 3); + cbor_string_int(w, "network", lsa->id & ln->optx); + cbor_string_int(w, "optx", u32_masklen(ln->optx)); + cbor_string_int(w, "dr", lsa->rt); + } + else + { + cbor_add_string(w, "ospf"); + cbor_open_block_with_length(w, 2); + cbor_string_int(w, "network", lsa->rt); + cbor_string_int(w, "lsa_id", lsa->id); + } + + show_lsa_distance_cbor(w, he); + + cbor_add_string(w, "routers"); + cbor_open_list(w); + for (i = 0; i < lsa_net_count(lsa); i++) + cbor_string_int(w, "router", ln->routers[i]); + + cbor_close_block_or_list(w); +} + +static inline void +show_lsa_sum_net_cbor(struct cbor_writer *w, struct top_hash_entry *he, int ospf2, int af) +{ + char str[IPA_MAX_TEXT_LENGTH + 8] = ""; + net_addr net; + u8 pxopts; + u32 metric; + + lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric); + cbor_add_string(w, "lsa_sum_net"); + cbor_open_block_with_length(w, 2); + bsprintf(str, "%N", &net); + cbor_string_string(w, "net", str); + cbor_string_int(w, "metric", metric); +} + +static inline void +show_lsa_sum_rt_cbor(struct cbor_writer *w, struct top_hash_entry *he, int ospf2) +{ + u32 metric; + u32 dst_rid; + u32 options; + + lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options); + + cbor_add_string(w, "lsa_sum_rt"); + cbor_open_block_with_length(w, 2); + cbor_string_int(w, "router", dst_rid); + cbor_string_int(w, "metric", metric); +} + +static inline void +show_lsa_external_cbor(struct cbor_writer *w, struct top_hash_entry *he, int ospf2, int af) +{ + struct ospf_lsa_ext_local rt; + char str[IPA_MAX_TEXT_LENGTH + 8] = ""; + + cbor_add_string(w, "lsa_external"); + cbor_open_block(w); + if (he->lsa_type == LSA_T_EXT) + he->domain = 0; /* Unmark the LSA */ + + lsa_parse_ext(he, ospf2, af, &rt); + + if (rt.fbit) + { + bsprintf(str, "%N", rt.fwaddr); + cbor_string_string(w, "via", str); + } + + if (rt.tag) + cbor_string_int(w, "tag", rt.tag); + + if (he->lsa_type == LSA_T_NSSA) + { + cbor_string_string(w, "lsa_type", "nssa-ext"); + } else { + cbor_string_string(w, "lsa_type", "external"); + } + + bsprintf(str, "%N", rt.net); + cbor_string_string(w, "rt_net", str); + + if(rt.ebit) + { + cbor_string_int(w, "lsa_type", 2); + } + cbor_string_int(w, "metric", rt.metric); + cbor_close_block_or_list(w); +} + + +static inline void +show_lsa_prefix_cbor(struct cbor_writer *w, struct top_hash_entry *he, struct top_hash_entry *cnode, int af) +{ + struct ospf_lsa_prefix *px = he->lsa_body; + u32 *buf; + int i; + cbor_add_string(w, "lsa_prefix"); + cbor_open_block(w); + + /* We check whether given prefix-LSA is related to the current node */ + if ((px->ref_type != cnode->lsa.type_raw) || (px->ref_rt != cnode->lsa.rt)) + { + cbor_close_block_or_list(w); + return; + } + + if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0)) + { + cbor_close_block_or_list(w); + return; + } + + if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->lsa.id)) + { + cbor_close_block_or_list(w); + return; + } + + buf = px->rest; + + cbor_add_string(w, "prexixes"); + cbor_open_list(w); + char str[IPA_MAX_TEXT_LENGTH + 8] = ""; + for (i = 0; i < px->pxcount; i++) + { + net_addr net; + u8 pxopts; + u16 metric; + + cbor_open_block(w); + + buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric); + + if (px->ref_type == LSA_T_RT) + { + bsprintf(str, "%N", &net); + cbor_string_string(w, "stubnet", str); + cbor_string_int(w, "metric", metric); + } + else{ + bsprintf(str, "%N", &net); + cbor_string_string(w, "stubnet", str); + } + cbor_close_block_or_list(w); + } + cbor_close_block_or_list(w); + cbor_close_block_or_list(w); +} + +static struct ospf_lsa_header * +fake_lsa_from_prefix_lsa_cbor(struct ospf_lsa_header *dst, struct ospf_lsa_header *src, + struct ospf_lsa_prefix *px) +{ + dst->age = src->age; + dst->type_raw = px->ref_type; + dst->id = px->ref_id; + dst->rt = px->ref_rt; + dst->sn = src->sn; + + return dst; +} + +static int lsa_compare_ospf3_cbor; + +static int +lsa_compare_for_state_cbor(const void *p1, const void *p2) +{ + struct top_hash_entry *he1 = * (struct top_hash_entry **) p1; + struct top_hash_entry *he2 = * (struct top_hash_entry **) p2; + struct ospf_lsa_header *lsa1 = &(he1->lsa); + struct ospf_lsa_header *lsa2 = &(he2->lsa); + struct ospf_lsa_header lsatmp1, lsatmp2; + u16 lsa1_type = he1->lsa_type; + u16 lsa2_type = he2->lsa_type; + + if (he1->domain < he2->domain) + return -1; + if (he1->domain > he2->domain) + return 1; + + + /* px1 or px2 assumes OSPFv3 */ + int px1 = (lsa1_type == LSA_T_PREFIX); + int px2 = (lsa2_type == LSA_T_PREFIX); + + if (px1) + { + lsa1 = fake_lsa_from_prefix_lsa_cbor(&lsatmp1, lsa1, he1->lsa_body); + lsa1_type = lsa1->type_raw; /* FIXME: handle unknown ref_type */ + } + + if (px2) + { + lsa2 = fake_lsa_from_prefix_lsa_cbor(&lsatmp2, lsa2, he2->lsa_body); + lsa2_type = lsa2->type_raw; + } + + + int nt1 = (lsa1_type == LSA_T_NET); + int nt2 = (lsa2_type == LSA_T_NET); + + if (nt1 != nt2) + return nt1 - nt2; + + if (nt1) + { + /* In OSPFv3, networks are named based on ID of DR */ + if (lsa_compare_ospf3_cbor) + { + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; + } + + /* For OSPFv2, this is IP of the network, + for OSPFv3, this is interface ID */ + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; + + if (px1 != px2) + return px1 - px2; + + return lsa1->sn - lsa2->sn; + } + else + { + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; + + if (lsa1_type < lsa2_type) + return -1; + if (lsa1_type > lsa2_type) + return 1; + + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; + + if (px1 != px2) + return px1 - px2; + + return lsa1->sn - lsa2->sn; + } +} + +static int +ext_compare_for_state_cbor(const void *p1, const void *p2) +{ + struct top_hash_entry * he1 = * (struct top_hash_entry **) p1; + struct top_hash_entry * he2 = * (struct top_hash_entry **) p2; + struct ospf_lsa_header *lsa1 = &(he1->lsa); + struct ospf_lsa_header *lsa2 = &(he2->lsa); + + if (lsa1->rt < lsa2->rt) + return -1; + if (lsa1->rt > lsa2->rt) + return 1; + + if (lsa1->id < lsa2->id) + return -1; + if (lsa1->id > lsa2->id) + return 1; + + return lsa1->sn - lsa2->sn; +} + + +void +ospf_sh_state_cbor(struct cbor_writer *w, struct proto *P, int verbose, int reachable) +{ + log("in ospf_state"); + struct ospf_proto *p = (struct ospf_proto *) P; + int ospf2 = ospf_is_v2(p); + int af = ospf_get_af(p); + uint i, ix, j1, jx; + u32 last_area = 0xFFFFFFFF; + + if (p->p.proto_state != PS_UP) + { + cbor_string_string(w, "error", "protocol is not up"); + return; + } + + /* We store interesting area-scoped LSAs in array hea and + global-scoped (LSA_T_EXT) LSAs in array hex */ + + uint num = p->gr->hash_entries; + struct top_hash_entry *hea[num]; + struct top_hash_entry **hex = verbose ? alloca(num * sizeof(struct top_hash_entry *)) : NULL; + struct top_hash_entry *he; + struct top_hash_entry *cnode = NULL; + + j1 = jx = 0; + WALK_SLIST(he, p->lsal) + { + int accept; + + if (he->lsa.age == LSA_MAXAGE) + continue; + + switch (he->lsa_type) + { + case LSA_T_RT: + case LSA_T_NET: + accept = 1; + break; + + case LSA_T_SUM_NET: + case LSA_T_SUM_RT: + case LSA_T_NSSA: + case LSA_T_PREFIX: + accept = verbose; + break; + + case LSA_T_EXT: + if (verbose) + { + he->domain = 1; /* Abuse domain field to mark the LSA */ + hex[jx++] = he; + } + /* fallthrough */ + default: + accept = 0; + } + + if (accept) + hea[j1++] = he; + } + + ASSERT(j1 <= num && jx <= num); + + lsa_compare_ospf3_cbor = !ospf2; + qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state_cbor); + + if (verbose) + qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state_cbor); + + /* + * This code is a bit tricky, we have a primary LSAs (router and + * network) that are presented as a node, and secondary LSAs that + * are presented as a part of a primary node. cnode represents an + * currently opened node (whose header was presented). The LSAs are + * sorted to get secondary LSAs just after related primary LSA (if + * available). We present secondary LSAs only when related primary + * LSA is opened. + * + * AS-external LSAs are stored separately as they might be presented + * several times (for each area when related ASBR is opened). When + * the node is closed, related external routes are presented. We + * also have to take into account that in OSPFv3, there might be + * more router-LSAs and only the first should be considered as a + * primary. This is handled by not closing old router-LSA when next + * one is processed (which is not opened because there is already + * one opened). + */ + + cbor_add_string(w, "areas"); + cbor_open_list_with_length(w, j1); + ix = 0; + for (i = 0; i < j1; i++) + { + cbor_open_block(w); + he = hea[i]; + + /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */ + if (!cnode) + { + if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET)) + && ((he->color == INSPF) || !reachable)) + { + cnode = he; + + if (he->domain != last_area) + { + cbor_string_int(w, "area", he->domain); + last_area = he->domain; + ix = 0; + } + } + else + continue; + } + + ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt)); + + switch (he->lsa_type) + { + case LSA_T_RT: + if (he->lsa.id == cnode->lsa.id) + show_lsa_router_cbor(w, p, he, verbose); + break; + + case LSA_T_NET: + show_lsa_network_cbor(w, he, ospf2); + break; + + case LSA_T_SUM_NET: + if (cnode->lsa_type == LSA_T_RT) + show_lsa_sum_net_cbor(w, he, ospf2, af); + break; + + case LSA_T_SUM_RT: + if (cnode->lsa_type == LSA_T_RT) + show_lsa_sum_rt_cbor(w, he, ospf2); + break; + + case LSA_T_EXT: + case LSA_T_NSSA: + show_lsa_external_cbor(w, he, ospf2, af); + break; + + case LSA_T_PREFIX: + show_lsa_prefix_cbor(w, he, cnode, af); + break; + } + + /* In these cases, we close the current node */ + if ((i+1 == j1) + || (hea[i+1]->domain != last_area) + || (hea[i+1]->lsa.rt != cnode->lsa.rt) + || (hea[i+1]->lsa_type == LSA_T_NET)) + { + while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt)) + ix++; + + while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt)) + show_lsa_external_cbor(w, hex[ix++], ospf2, af); + + cnode = NULL; + } + cbor_close_block_or_list(w); + } + int hdr = 0; + u32 last_rt = 0xFFFFFFFF; + cbor_add_string(w, "asbrs"); + cbor_open_list(w); + for (ix = 0; ix < jx; ix++) + { + he = hex[ix]; + /* If it is still marked, we show it now. */ + if (he->domain) + { + cbor_add_string(w, "asbr"); + cbor_open_block(w); + + he->domain = 0; + + if ((he->color != INSPF) && reachable) + continue; + + if (!hdr) + { + cbor_add_string(w, "other_ASBRs"); + cbor_open_list_with_length(w, 0); + hdr = 1; + } + + if (he->lsa.rt != last_rt) + { + cbor_string_int(w, "router", he->lsa.rt); + last_rt = he->lsa.rt; + } + + show_lsa_external_cbor(w, he, ospf2, af); + cbor_close_block_or_list(w); + } + } + cbor_close_block_or_list(w); +} + diff --git a/yang/command.cbor b/yang/command.cbor index b32db975..2598a2ab 100644 --- a/yang/command.cbor +++ b/yang/command.cbor @@ -1 +1 @@ -”jcommand:do¢gcommanddargs”carghprotocol \ No newline at end of file +”jcommand:do¢gcommanddargs‚”carghtopology”cargeospf6 \ No newline at end of file diff --git a/yang/command.json b/yang/command.json index e43f8f3c..d9e76253 100644 --- a/yang/command.json +++ b/yang/command.json @@ -1,2 +1,2 @@ -{"command:do":{"command": 2, "args":[{"arg":"protocol"}]}} +{"command:do":{"command": 3, "args":[{"arg":"topology"}, {"arg":"ospf6"}]}} diff --git a/yang/show_symbols.cbor b/yang/show_symbols.cbor index 6dd443c5..a7063ceb 100644 --- a/yang/show_symbols.cbor +++ b/yang/show_symbols.cbor @@ -1 +1 @@ -”tshow_symbols:message”etableŸ¢dnamegebgp4_1dtypehprotocol¢dnamegebgp6_1dtypehprotocol¢dnamegebgp4_2dtypehprotocol¢dnamegebgp6_2dtypehprotocol¢dnamegstatic6dtypehprotocol¢dnamegstatic4dtypehprotocol¢dnamegkernel6dtypehprotocol¢dnamegkernel4dtypehprotocol¢dnamegdevice1dtypehprotocol’ \ No newline at end of file +”tshow_symbols:message”etableŸ¢dnamehips_sitedtypehconstant¢dnamejipt_unspecdtypehconstant¢dnamehipp_xorpdtypehconstant¢dnamehipp_dhcpdtypehconstant¢dnamehipp_birddtypehconstant¢dnamegmaster5dtypemrouting table¢dnamegmaster4dtypemrouting table¢dnamegmaster6dtypemrouting table¢dnamehipp_bootdtypehconstant¢dnamehipt_maindtypehconstant¢dnamehips_linkdtypehconstant¢dnamehipp_isisdtypehconstant¢dnameeospf6dtypehprotocol¢dnameeospf5dtypehprotocol¢dnameeospf4dtypehprotocol¢dnamejips_globaldtypehconstant¢dnamegstatic6dtypehprotocol¢dnamegstatic5dtypehprotocol¢dnamegstatic4dtypehprotocol¢dnamejipp_kerneldtypehconstant¢dnamehips_hostdtypehconstant¢dnamekips_nowheredtypehconstant¢dnamelipp_dnrouteddtypehconstant¢dnamegkernel6dtypehprotocol¢dnamegkernel5dtypehprotocol¢dnamegkernel4dtypehprotocol¢dnamegipp_ntkdtypehconstant¢dnamegipp_mrtdtypehconstant¢dnamejipr_cosmosdtypehconstant¢dnameiipp_babeldtypehconstant¢dnamelipp_redirectdtypehconstant¢dnamenipp_keepaliveddtypehconstant¢dnameiipt_localdtypehconstant¢dnamegipp_bgpdtypehconstant¢dnameiipp_zebradtypehconstant¢dnameiipp_gateddtypehconstant¢dnameiipp_openrdtypehconstant¢dnameiipp_eigrpdtypehconstant¢dnamegipp_ripdtypehconstant¢dnamegdevice1dtypehprotocol¢dnamekipt_defaultdtypehconstant¢dnamejipp_staticdtypehconstant¢dnamefipp_radtypehconstant¢dnamehipp_ospfdtypehconstant¢dnamejipp_unspecdtypehconstant’ \ No newline at end of file