-#include "nest/cbor_shortcuts.c"
+
#include "nest/bird.h"
#include "nest/protocol.h"
#include "nest/route.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"
-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;
}
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");
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");
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);
{
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;
}
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);
}
+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;
+ }
+}
SHOW_STATUS = 0,
SHOW_MEMORY = 1,
SHOW_SYMBOLS = 2,
+ SHOW_OSPF = 3,
};
enum cbor_majors {
uint size;
};
+
uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string) {
if (length != strlen(string)) {
return 0;
}
}
return 1;
-}
+};
struct value
get_value(struct buff_reader *reader)
}
}
-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)
ASSERT(val.major == ARRAY);
int num_array_items = val.val;
log("num arr items %i", num_array_items);
- for (int i = 0; i<num_array_items || (num_array_items == -1 && !val_is_break(val)); i++)
+ if (num_array_items > 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)
{
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++)
- {
- 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)
+ ASSERT(val.major == TEXT); // Now we have an argument in val
+ if (num_array_items == -1 && arguments->capacity == arguments->pt)
{
- 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)
{
}
} 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;
}
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;
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);
--- /dev/null
+
+/**
+ * There are cli functions from ospf.c adapted for cbor.
+ */
+
+#include <stdlib.h>
+#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);
+}
+