]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
cbor_cmds.c, ospf_for_cbor.c: ospf show topology looks working
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Fri, 1 Dec 2023 13:43:24 +0000 (14:43 +0100)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Fri, 1 Dec 2023 13:43:24 +0000 (14:43 +0100)
nest/cbor.c
nest/cbor_cmds.c
nest/cbor_cmds.h [new file with mode: 0644]
nest/cbor_parse.c
nest/cli.c
nest/proto.c
nest/protocol.h
proto/ospf/ospf_for_cbor.c [new file with mode: 0644]
yang/command.cbor
yang/command.json
yang/show_symbols.cbor

index 2c1524395e0e1de70d33dadb4dcde0d4286910a2..924a6fa3bd41f2c5f1ac5c803a440e0525717119 100644 (file)
@@ -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;
index 9a029227d77811b8c23ae6182b0114ddf151c5e6..9d46ee329dda61318849334e7f8865e49322644c 100644 (file)
@@ -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 (file)
index 0000000..a28c0c9
--- /dev/null
@@ -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);
+
index 3bc62e4e6934d7cbb5fe660bebf2ba4d2930bd5b..974beb7682be8160fe4fc7c0747be6a1c746cf32 100644 (file)
@@ -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<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)
       {
@@ -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++)
-        {
-          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)
         {
@@ -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);
index 790acf8bff0721911b0d04b5e22014fac6ae4f8b..58b85ae990909429834fc7a03fd36e4296b6efb6 100644 (file)
@@ -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;
index 04b53b06ce8fc68cbfa48e4a453b8262386111f6..9bc59f34bcc033cbf875ea8c0638915a205b9ad0 100644 (file)
@@ -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)
 {
index c8ba68e1eb178913f412e3b3d82208d9f8541c97..39efba94a11c63d258fd156ed2260a9a10c996aa 100644 (file)
@@ -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 (file)
index 0000000..d779a52
--- /dev/null
@@ -0,0 +1,610 @@
+
+/**
+ * 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);
+}
+
index b32db975ca6200e8bfc0213a42f5c36510c16345..2598a2abceddd058c0eaade45e981d1a172ec42f 100644 (file)
@@ -1 +1 @@
-¡jcommand:do¢gcommand\ 2dargs\81¡carghprotocol
\ No newline at end of file
+¡jcommand:do¢gcommand\ 3dargs\82¡carghtopology¡cargeospf6
\ No newline at end of file
index e43f8f3ce80ba1ce7ed08a5b84ae3da9292238ad..d9e76253bf8f61ff4be8e1074280ba2d53204424 100644 (file)
@@ -1,2 +1,2 @@
-{"command:do":{"command": 2, "args":[{"arg":"protocol"}]}}
+{"command:do":{"command": 3, "args":[{"arg":"topology"}, {"arg":"ospf6"}]}}
 
index 6dd443c5b3fc52ec4d921065f6a57356bf9c0c1b..a7063cebe45c6978d248c11a98f3f1afd7c554c9 100644 (file)
@@ -1 +1 @@
-¡tshow_symbols:message¡etable\9f¢dnamegebgp4_1dtypehprotocol¢dnamegebgp6_1dtypehprotocol¢dnamegebgp4_2dtypehprotocol¢dnamegebgp6_2dtypehprotocol¢dnamegstatic6dtypehprotocol¢dnamegstatic4dtypehprotocol¢dnamegkernel6dtypehprotocol¢dnamegkernel4dtypehprotocol¢dnamegdevice1dtypehprotocolÿ
\ No newline at end of file
+¡tshow_symbols:message¡etable\9f¢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