]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
CLI: Dumping internal data structures to files, not to debug output
authorMaria Matejka <mq@ucw.cz>
Thu, 14 Nov 2024 19:43:35 +0000 (20:43 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 2 Dec 2024 05:54:54 +0000 (06:54 +0100)
All the 'dump something' CLI commands now have a new mandatory
argument -- name of the file where to dump the data. This allows
for more flexible dumping even for production deployments where
the debug output is by default off.

Also the dump commands are now restricted (they weren't before)
to assure that only the appropriate users can run these time consuming
commands.

37 files changed:
doc/bird.sgml
doc/reply_codes
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/f-util.c
filter/filter.c
filter/filter.h
lib/birdlib.h
lib/event.c
lib/mempool.c
lib/resource.c
lib/resource.h
lib/slab.c
lib/socket.h
lib/timer.c
nest/config.Y
nest/iface.c
nest/iface.h
nest/locks.c
nest/neighbor.c
nest/proto.c
nest/protocol.h
nest/route.h
nest/rt-attr.c
nest/rt-table.c
proto/babel/babel.c
proto/bfd/bfd.c
proto/bmp/bmp.c
proto/ospf/ospf.c
proto/rip/rip.c
proto/static/static.c
sysdep/unix/alloc.c
sysdep/unix/io.c
sysdep/unix/krt.c
sysdep/unix/main.c
sysdep/unix/unix.h

index b6b77691e95c55f6b545d0664f4a6d5b5c490ae9..5393edb2e248037d8038386aced493c53c20219f 100644 (file)
@@ -1454,8 +1454,12 @@ This argument can be omitted if there exists only a single instance.
        <tag><label id="cli-debug">debug <m/protocol/|<m/pattern/|all all|off|{ states|routes|filters|events|packets [, <m/.../] }</tag>
        Control protocol debugging.
 
-       <tag><label id="cli-dump">dump resources|sockets|interfaces|neighbors|attributes|routes|protocols</tag>
-       Dump contents of internal data structures to the debugging output.
+       <tag><label id="cli-dump">dump resources|sockets|interfaces|neighbors|attributes|routes|protocols "<m/file/"</tag>
+       Truncates the given file and dumps contents of internal data structures
+       there. By sending SIGUSR1, you get all of these concatenated to
+       <cf/bird.dump/ in the current directory. The file is only readable for
+       the user running the daemon. The format of dump files is internal and
+       could change in the future.
 
        <tag><label id="cli-echo">echo all|off|{ <m/list of log classes/ } [ <m/buffer-size/ ]</tag>
        Control echoing of log messages to the command-line output.
index 6e7e588746c6440a329b392e3de07899af6ddc47..aa95820e53ef61d0819fc626d1871974d46cd0aa 100644 (file)
@@ -72,6 +72,7 @@ Reply codes of BIRD command-line interface
 8006   Reload failed
 8007   Access denied
 8008   Evaluation runtime error
+8009   Failed to open file
 
 9000   Command too long
 9001   Parse error
index ea0b0995a5c39cd46127b6ca492d45d8c537c607..a435cf7a0f4aff25c1455a30d1ab0778d42c733f 100644 (file)
@@ -97,7 +97,7 @@ if ($3) return 0;
 ]])
 m4_ifelse($4,,,[[
 FID_DUMP_BODY()m4_dnl
-debug("%s" $4 "\n", INDENT, $5);
+RDUMP("%s" $4 "\n", INDENT, $5);
 ]])
 FID_INTERPRET_EXEC()m4_dnl
 const $1 $2 = whati->$2
@@ -168,7 +168,7 @@ FID_LINEARIZE_BODY()m4_dnl
   pos = linearize(dest, whati->fvar, pos);
   item->varcount = whati->varcount;
 FID_DUMP_BODY()m4_dnl
-  debug("%snumber of varargs %u\n", INDENT, item->varcount);
+  RDUMP("%snumber of varargs %u\n", INDENT, item->varcount);
 FID_SAME_BODY()m4_dnl
   if (f1->varcount != f2->varcount) return 0;
 FID_INTERPRET_BODY()
@@ -240,7 +240,7 @@ FID_NEW_METHOD()m4_dnl
   args = NULL; /* The rest is the line itself */
 FID_METHOD_CALL()    , arg$1
 FID_DUMP_BODY()m4_dnl
-f_dump_line(item->fl$1, indent + 1);
+f_dump_line(dreq, item->fl$1, indent + 1);
 FID_LINEARIZE_BODY()m4_dnl
 item->fl$1 = f_linearize(whati->f$1, $2);
 FID_SAME_BODY()m4_dnl
@@ -433,13 +433,13 @@ m4_undivert(113)
 
 ]])m4_dnl
 
-FID_DUMP_CALLER()m4_dnl                         Case in another big switch used in instruction dumping (debug)
-case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break;
+FID_DUMP_CALLER()m4_dnl                         Case in another big switch used in instruction dumping
+case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(dreq, item, indent + 1); break;
 
 FID_DUMP()m4_dnl                        The dumper itself
 m4_ifdef([[FID_DUMP_BODY_EXISTS]],
-[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]],
-[[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]])
+[[static inline void f_dump_line_item_]]INST_NAME()[[(struct dump_request *dreq, const struct f_line_item *item_, const int indent)]],
+[[static inline void f_dump_line_item_]]INST_NAME()[[(struct dump_request *dreq UNUSED, const struct f_line_item *item UNUSED, const int indent UNUSED)]])
 m4_undefine([[FID_DUMP_BODY_EXISTS]])
 {
 #define item (&(item_->i_]]INST_NAME()[[))
@@ -676,22 +676,22 @@ static const char f_dump_line_indent_str[] = "                                ";
 
 FID_WR_PUT(6)
 
-void f_dump_line(const struct f_line *dest, uint indent)
+void f_dump_line(struct dump_request *dreq, const struct f_line *dest, uint indent)
 {
   if (!dest) {
-    debug("%sNo filter line (NULL)\n", INDENT);
+    RDUMP("%sNo filter line (NULL)\n", INDENT);
     return;
   }
-  debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
+  RDUMP("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
   for (uint i=0; i<dest->len; i++) {
     const struct f_line_item *item = &dest->items[i];
-    debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name_(item->fi_code), item->lineno);
+    RDUMP("%sInstruction %s at line %u\n", INDENT, f_instruction_name_(item->fi_code), item->lineno);
     switch (item->fi_code) {
 FID_WR_PUT(7)
       default: bug("Unknown instruction %x in f_dump_line", item->fi_code);
     }
   }
-  debug("%sFilter line %p dump done\n", INDENT, dest);
+  RDUMP("%sFilter line %p dump done\n", INDENT, dest);
 }
 
 /* Linearize */
@@ -721,10 +721,6 @@ f_linearize_concat(const struct f_inst * const inst[], uint count, uint results)
     out->len = linearize(out, inst[i], out->len);
 
   out->results = results;
-
-#ifdef LOCAL_DEBUG
-  f_dump_line(out, 0);
-#endif
   return out;
 }
 
index 8529ad621f9ea6467a5966e6d1d5e3a100c9854d..efc82d2fe9e6979f2147854611382b4604de0795 100644 (file)
  *     m4_dnl  This structure is returned from the linearizer (105).
  *     m4_dnl  For writing directly to this structure, use FID_LINE_IN.
  *
- *     m4_dnl          f_dump_line_item_FI_EXAMPLE(const struct f_line_item *item, const int indent)
+ *     m4_dnl          f_dump_line_item_FI_EXAMPLE(struct dump_request *dreq, const struct f_line_item *item, const int indent)
  *     m4_dnl          {
  *     m4_dnl  (104)     [[ put it here ]]
  *     m4_dnl          }
- *     m4_dnl  This code dumps the instruction on debug. Note that the argument
+ *     m4_dnl  This code dumps the instruction via RDUMP. Note that the argument
  *     m4_dnl  is the linearized instruction; if the instruction has arguments,
  *     m4_dnl  their code has already been linearized and their value is taken
  *     m4_dnl  from the value stack.
index 955cfbdc76f43e0409ca35a43b76af0d7c04ce02..1b498e1583390054cd669d5139633cf654dbce22 100644 (file)
@@ -68,7 +68,7 @@ struct f_line *f_linearize_concat(const struct f_inst * const inst[], uint count
 static inline struct f_line *f_linearize(const struct f_inst *root, uint results)
 { return f_linearize_concat(&root, 1, results); }
 
-void f_dump_line(const struct f_line *, uint indent);
+void f_dump_line(struct dump_request *, const struct f_line *, uint indent);
 
 
 /* Recursive iteration over filter instructions */
index 6fbdacbaca21a0c318cfd937c8a2c03c26173922..680f2f54e094f34a3463b4c703c501cb7310e4d4 100644 (file)
@@ -251,10 +251,10 @@ ca_free(resource *r)
 }
 
 static void
-ca_dump(resource *r)
+ca_dump(struct dump_request *dreq, resource *r)
 {
   struct custom_attribute *ca = (void *) r;
-  debug("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n",
+  RDUMP("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n",
       ca->name, ca->fda->ea_code, ca->fda->type, ca->fda->f_type);
 }
 
index 560778a846c73bb5ccb1a2d92e175e49316077b1..f17de58c227b3b8992f85b1c7e6d84d12d03ca23 100644 (file)
@@ -181,11 +181,6 @@ interpret(struct filter_state *fs, const struct f_line *line, uint argc, const s
 #define curline fstk->estk[fstk->ecnt-1]
 #define prevline fstk->estk[fstk->ecnt-2]
 
-#ifdef LOCAL_DEBUG
-  debug("Interpreting line.");
-  f_dump_line(line, 1);
-#endif
-
   while (fstk->ecnt > 0) {
     while (curline.pos < curline.line->len) {
       const struct f_line_item *what = &(curline.line->items[curline.pos++]);
@@ -474,37 +469,37 @@ filter_commit(struct config *new, struct config *old)
     }
 }
 
-void filters_dump_all(void)
+void filters_dump_all(struct dump_request *dreq)
 {
   struct symbol *sym;
   WALK_LIST(sym, config->symbols) {
     switch (sym->class) {
       case SYM_FILTER:
-       debug("Named filter %s:\n", sym->name);
-       f_dump_line(sym->filter->root, 1);
+       RDUMP("Named filter %s:\n", sym->name);
+       f_dump_line(dreq, sym->filter->root, 1);
        break;
       case SYM_FUNCTION:
-       debug("Function %s:\n", sym->name);
-       f_dump_line(sym->function, 1);
+       RDUMP("Function %s:\n", sym->name);
+       f_dump_line(dreq, sym->function, 1);
        break;
       case SYM_PROTO:
        {
-         debug("Protocol %s:\n", sym->name);
+         RDUMP("Protocol %s:\n", sym->name);
          struct channel *c;
          WALK_LIST(c, sym->proto->proto->channels) {
-           debug(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
+           RDUMP(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
            if (c->in_filter == FILTER_ACCEPT)
-             debug(" ALL\n");
+             RDUMP(" ALL\n");
            else if (c->in_filter == FILTER_REJECT)
-             debug(" NONE\n");
+             RDUMP(" NONE\n");
            else if (c->in_filter == FILTER_UNDEF)
-             debug(" UNDEF\n");
+             RDUMP(" UNDEF\n");
            else if (c->in_filter->sym) {
              ASSERT(c->in_filter->sym->filter == c->in_filter);
-             debug(" named filter %s\n", c->in_filter->sym->name);
+             RDUMP(" named filter %s\n", c->in_filter->sym->name);
            } else {
-             debug("\n");
-             f_dump_line(c->in_filter->root, 2);
+             RDUMP("\n");
+             f_dump_line(dreq, c->in_filter->root, 2);
            }
          }
        }
index 18ff0874f56f35ddb9175d31263959ad56199cfa..efb4979fb73314c6fe9514b01d0beebfca66c5c2 100644 (file)
@@ -65,7 +65,7 @@ int f_same(const struct f_line *f1, const struct f_line *f2);
 
 void filter_commit(struct config *new, struct config *old);
 
-void filters_dump_all(void);
+void filters_dump_all(struct dump_request *);
 
 #define FILTER_ACCEPT NULL
 #define FILTER_REJECT ((struct filter *) 1)
index 4fea3f9f0c30a0e27f7fa8e742e37213405fb228..762c5fa42dcc10a919a279d0fd0f309dee04f2b8 100644 (file)
@@ -242,4 +242,15 @@ static inline u64 u64_hash0(u64 v, u32 p, u64 acc)
 static inline u32 u64_hash(u64 v)
 { return hash_value(u64_hash0(v, HASH_PARAM, 0)); }
 
+/* Dumping */
+struct dump_request {
+  u64 size;
+  btime begin;
+  uint indent, offset;
+  void (*write)(struct dump_request *, const char *fmt, ...);
+  void (*report)(struct dump_request *, int state, const char *fmt, ...);
+};
+
+#define RDUMP(...)  dreq->write(dreq, __VA_ARGS__)
+
 #endif
index 33dc00b01350f2bb90c95a30db01b706f0cba492..6f17a61808d5511cd37317d709c02a1565317c54 100644 (file)
@@ -36,11 +36,11 @@ ev_postpone(event *e)
 }
 
 static void
-ev_dump(resource *r)
+ev_dump(struct dump_request *dreq, resource *r)
 {
   event *e = (event *) r;
 
-  debug("(code %p, data %p, %s)\n",
+  RDUMP("(code %p, data %p, %s)\n",
        e->hook,
        e->data,
        e->n.next ? "scheduled" : "inactive");
index 9d4404f7cab4c567c01e625324400ad35385f89b..28bdff1d753c98681dd88ddc154828ac0b2b7cf6 100644 (file)
@@ -44,7 +44,7 @@ struct linpool {
 _Thread_local linpool *tmp_linpool;
 
 static void lp_free(resource *);
-static void lp_dump(resource *);
+static void lp_dump(struct dump_request *, resource *);
 static resource *lp_lookup(resource *, unsigned long);
 static struct resmem lp_memsize(resource *r);
 
@@ -271,7 +271,7 @@ lp_free(resource *r)
 }
 
 static void
-lp_dump(resource *r)
+lp_dump(struct dump_request *dreq, resource *r)
 {
   linpool *m = (linpool *) r;
   struct lp_chunk *c;
@@ -281,7 +281,7 @@ lp_dump(resource *r)
     ;
   for(cntl=0, c=m->first_large; c; c=c->next, cntl++)
     ;
-  debug("(count=%d+%d total=%d+%d)\n",
+  RDUMP("(count=%d+%d total=%d+%d)\n",
        cnt,
        cntl,
        m->total,
index 89e559b4818a2ecae118e7e9b5370c6c05fedc65..b1a3df1053c782d2045330271070925b6fa56a7c 100644 (file)
@@ -35,7 +35,7 @@ struct pool {
   const char *name;
 };
 
-static void pool_dump(resource *);
+static void pool_dump(struct dump_request *, resource *);
 static void pool_free(resource *);
 static resource *pool_lookup(resource *, unsigned long);
 static struct resmem pool_memsize(resource *P);
@@ -51,8 +51,6 @@ static struct resclass pool_class = {
 
 pool root_pool;
 
-static int indent;
-
 /**
  * rp_new - create a resource pool
  * @p: parent pool
@@ -100,16 +98,16 @@ pool_free(resource *P)
 }
 
 static void
-pool_dump(resource *P)
+pool_dump(struct dump_request *dreq, resource *P)
 {
   pool *p = (pool *) P;
   resource *r;
 
-  debug("%s\n", p->name);
-  indent += 3;
+  RDUMP("%s\n", p->name);
+  dreq->indent += 3;
   WALK_LIST(r, p->inside)
-    rdump(r);
-  indent -= 3;
+    rdump(dreq, r);
+  dreq->indent -= 3;
 }
 
 static struct resmem
@@ -199,20 +197,28 @@ rfree(void *res)
  * It works by calling a class-specific dump function.
  */
 void
-rdump(void *res)
+rdump(struct dump_request *dreq, void *res)
 {
   char x[16];
   resource *r = res;
 
-  bsprintf(x, "%%%ds%%p ", indent);
-  debug(x, "", r);
+  bsprintf(x, "%%%ds%%p ", dreq->indent);
+  RDUMP(x, "", r);
   if (r)
     {
-      debug("%s ", r->class->name);
-      r->class->dump(r);
+      RDUMP("%s ", r->class->name);
+      r->class->dump(dreq, r);
     }
   else
-    debug("NULL\n");
+    RDUMP("NULL\n");
+}
+
+void page_dump(struct dump_request *req);
+
+void resource_dump(struct dump_request *req)
+{
+  rdump(req, &root_pool);
+  page_dump(req);
 }
 
 struct resmem
@@ -251,6 +257,7 @@ ralloc(pool *p, struct resclass *c)
   return r;
 }
 
+#if 0
 /**
  * rlookup - look up a memory location
  * @a: memory address
@@ -273,6 +280,7 @@ rlookup(unsigned long a)
   else
     debug("Not found.\n");
 }
+#endif
 
 /**
  * resource_init - initialize the resource manager
@@ -316,11 +324,11 @@ static void mbl_free(resource *r UNUSED)
 {
 }
 
-static void mbl_debug(resource *r)
+static void mbl_debug(struct dump_request *dreq, resource *r)
 {
   struct mblock *m = (struct mblock *) r;
 
-  debug("(size=%d)\n", m->size);
+  RDUMP("(size=%d)\n", m->size);
 }
 
 static resource *
index 1e9a7b78bd513dcf5e3e30de20dd385f2aeea47c..1e8e2d2cedae5ba3409ff53cc21c2774da5b2030 100644 (file)
@@ -30,7 +30,7 @@ struct resclass {
   char *name;                          /* Resource class name */
   unsigned size;                       /* Standard size of single resource */
   void (*free)(resource *);            /* Freeing function */
-  void (*dump)(resource *);            /* Dump to debug output */
+  void (*dump)(struct dump_request *, resource *);     /* Dump to debug output */
   resource *(*lookup)(resource *, unsigned long);      /* Look up address (only for debugging) */
   struct resmem (*memsize)(resource *);        /* Return size of memory used by the resource, may be NULL */
 };
@@ -46,7 +46,10 @@ void resource_init(void);
 pool *rp_new(pool *, const char *);    /* Create new pool */
 pool *rp_newf(pool *, const char *, ...);      /* Create a new pool with a formatted string as its name */
 void rfree(void *);                    /* Free single resource */
-void rdump(void *);                    /* Dump to debug output */
+
+struct dump_request;
+void rdump(struct dump_request *, void *);     /* Dump to debug output */
+void resource_dump(struct dump_request *);     /* Dump the root pool */
 struct resmem rmemsize(void *res);             /* Return size of memory used by the resource */
 void rlookup(unsigned long);           /* Look up address (only for debugging) */
 void rmove(void *, pool *);            /* Move to a different pool */
index 38d1062696944843ea790774877b6ac6f2fd3ce2..571a3d957e9fef17ca99fb80f32426e05f54f21c 100644 (file)
@@ -41,7 +41,7 @@
 #endif
 
 static void slab_free(resource *r);
-static void slab_dump(resource *r);
+static void slab_dump(struct dump_request *dreq, resource *r);
 static resource *slab_lookup(resource *r, unsigned long addr);
 static struct resmem slab_memsize(resource *r);
 
@@ -378,7 +378,7 @@ slab_free(resource *r)
 }
 
 static void
-slab_dump(resource *r)
+slab_dump(struct dump_request *dreq, resource *r)
 {
   slab *s = (slab *) r;
   int ec=0, pc=0, fc=0;
@@ -389,7 +389,7 @@ slab_dump(resource *r)
     pc++;
   WALK_TLIST(sl_head, h, &s->full_heads)
     fc++;
-  debug("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size);
+  RDUMP("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size);
 }
 
 static struct resmem
index 3417423f6091c15e283cc55fa7d7ff4f209ca660..edd90b9f3953d1b49c292573ba17bbb498c68097 100644 (file)
@@ -92,7 +92,7 @@ void sk_reallocate(sock *);           /* Free and allocate tbuf & rbuf */
 void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */
 void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */
 void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
-void sk_dump_all(void);
+void sk_dump_all(struct dump_request *);
 
 int sk_is_ipv4(sock *s);               /* True if socket is IPv4 */
 int sk_is_ipv6(sock *s);               /* True if socket is IPv6 */
index 92da5061d6de9a56c131404ae460ee37e68671fa..b94c43ca085ee558d579151865696595955476f3 100644 (file)
@@ -102,19 +102,19 @@ tm_free(resource *r)
 }
 
 static void
-tm_dump(resource *r)
+tm_dump(struct dump_request *dreq, resource *r)
 {
   timer *t = (void *) r;
 
-  debug("(code %p, data %p, ", t->hook, t->data);
+  RDUMP("(code %p, data %p, ", t->hook, t->data);
   if (t->randomize)
-    debug("rand %d, ", t->randomize);
+    RDUMP("rand %d, ", t->randomize);
   if (t->recurrent)
-    debug("recur %ld, ", t->recurrent);
+    RDUMP("recur %ld, ", t->recurrent);
   if (t->expires)
-    debug("expires in %ld ms)\n", (t->expires - current_time()) TO_MS);
+    RDUMP("expires in %ld ms)\n", (t->expires - current_time()) TO_MS);
   else
-    debug("inactive)\n");
+    RDUMP("inactive)\n");
 }
 
 
index 5d75571577c39a57006c69dfea345a87e2c6ecb8..47fef3d7951466f417a9c0969a2f62d307121df7 100644 (file)
@@ -863,26 +863,25 @@ sym_args:
  | sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; }
  ;
 
-
-CF_CLI_HELP(DUMP, ..., [[Dump debugging information]])
-CF_CLI(DUMP RESOURCES,,, [[Dump all allocated resource]])
-{ rdump(&root_pool); cli_msg(0, ""); } ;
-CF_CLI(DUMP SOCKETS,,, [[Dump open sockets]])
-{ sk_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP EVENTS,,, [[Dump event log]])
-{ io_log_dump(); cli_msg(0, ""); } ;
-CF_CLI(DUMP INTERFACES,,, [[Dump interface information]])
-{ if_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]])
-{ neigh_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]])
-{ rta_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP ROUTES,,, [[Dump routing table]])
-{ rt_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
-{ protos_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]])
-{ filters_dump_all(); cli_msg(0, ""); } ;
+CF_CLI_HELP(DUMP, ..., [[Dump debugging information to the given file]])
+CF_CLI(DUMP RESOURCES, text,, [[Dump all allocated resource]])
+{ cmd_dump_file(this_cli, $3, "resources", resource_dump); } ;
+CF_CLI(DUMP SOCKETS, text,, [[Dump open sockets]])
+{ cmd_dump_file(this_cli, $3, "sockets", sk_dump_all); } ;
+CF_CLI(DUMP EVENTS, text,, [[Dump event log]])
+{ cmd_dump_file(this_cli, $3, "event log", io_log_dump); } ;
+CF_CLI(DUMP INTERFACES, text,, [[Dump interface information]])
+{ cmd_dump_file(this_cli, $3, "interfaces", if_dump_all); } ;
+CF_CLI(DUMP NEIGHBORS, text,, [[Dump neighbor cache]])
+{ cmd_dump_file(this_cli, $3, "neighbor cache", neigh_dump_all); } ;
+CF_CLI(DUMP ATTRIBUTES, text,, [[Dump attribute cache]])
+{ cmd_dump_file(this_cli, $3, "attribute cache", rta_dump_all); } ;
+CF_CLI(DUMP ROUTES, text,, [[Dump routing table]])
+{ cmd_dump_file(this_cli, $3, "routing tables", rt_dump_all); } ;
+CF_CLI(DUMP PROTOCOLS, text,, [[Dump protocol information]])
+{ cmd_dump_file(this_cli, $3, "protocols", protos_dump_all); } ;
+CF_CLI(DUMP FILTER ALL, text,, [[Dump all filters in linearized form]])
+{ cmd_dump_file(this_cli, $4, "filter bytecode", filters_dump_all); } ;
 
 CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
 { cmd_eval(f_linearize($2, 1)); } ;
index 6c84cbcf0977b509f5e2e68db9e9a6f7244811b3..499822b6455f28185b0373df9680a07085bd7d9a 100644 (file)
@@ -47,9 +47,9 @@ static void if_recalc_preferred(struct iface *i);
  * This function dumps contents of an &ifa to the debug output.
  */
 void
-ifa_dump(struct ifa *a)
+ifa_dump(struct dump_request *dreq, struct ifa *a)
 {
-  debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
+  RDUMP("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
        (a->flags & IA_PRIMARY) ? " PRIMARY" : "",
        (a->flags & IA_SECONDARY) ? " SEC" : "",
        (a->flags & IA_HOST) ? " HOST" : "",
@@ -64,35 +64,35 @@ ifa_dump(struct ifa *a)
  * network interface to the debug output.
  */
 void
-if_dump(struct iface *i)
+if_dump(struct dump_request *dreq, struct iface *i)
 {
   struct ifa *a;
 
-  debug("IF%d: %s", i->index, i->name);
+  RDUMP("IF%d: %s", i->index, i->name);
   if (i->flags & IF_SHUTDOWN)
-    debug(" SHUTDOWN");
+    RDUMP(" SHUTDOWN");
   if (i->flags & IF_UP)
-    debug(" UP");
+    RDUMP(" UP");
   else
-    debug(" DOWN");
+    RDUMP(" DOWN");
   if (i->flags & IF_ADMIN_UP)
-    debug(" LINK-UP");
+    RDUMP(" LINK-UP");
   if (i->flags & IF_MULTIACCESS)
-    debug(" MA");
+    RDUMP(" MA");
   if (i->flags & IF_BROADCAST)
-    debug(" BC");
+    RDUMP(" BC");
   if (i->flags & IF_MULTICAST)
-    debug(" MC");
+    RDUMP(" MC");
   if (i->flags & IF_LOOPBACK)
-    debug(" LOOP");
+    RDUMP(" LOOP");
   if (i->flags & IF_IGNORE)
-    debug(" IGN");
+    RDUMP(" IGN");
   if (i->flags & IF_TMP_DOWN)
-    debug(" TDOWN");
-  debug(" MTU=%d\n", i->mtu);
+    RDUMP(" TDOWN");
+  RDUMP(" MTU=%d\n", i->mtu);
   WALK_LIST(a, i->addrs)
     {
-      ifa_dump(a);
+      ifa_dump(dreq, a);
       ASSERT(!!(a->flags & IA_PRIMARY) ==
             ((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
     }
@@ -105,14 +105,14 @@ if_dump(struct iface *i)
  * interfaces to the debug output.
  */
 void
-if_dump_all(void)
+if_dump_all(struct dump_request *dreq)
 {
   struct iface *i;
 
-  debug("Known network interfaces:\n");
+  RDUMP("Known network interfaces:\n");
   WALK_LIST(i, iface_list)
-    if_dump(i);
-  debug("Router ID: %08x\n", config->router_id);
+    if_dump(dreq, i);
+  RDUMP("Router ID: %08x\n", config->router_id);
 }
 
 static inline unsigned
index f8e9285053c11afe013666747920edbcc65168ea..1e4225eeda0ea6b6b0a9dae62bedcbff4e535112 100644 (file)
@@ -101,9 +101,9 @@ struct iface {
 #define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
 
 void if_init(void);
-void if_dump(struct iface *);
-void if_dump_all(void);
-void ifa_dump(struct ifa *);
+void if_dump(struct dump_request *dreq, struct iface *);
+void if_dump_all(struct dump_request *);
+void ifa_dump(struct dump_request *dreq, struct ifa *);
 void if_show(void);
 void if_show_summary(void);
 struct iface *if_update(struct iface *);
@@ -148,8 +148,8 @@ typedef struct neighbor {
 
 neighbor *neigh_find(struct proto *p, ip_addr a, struct iface *ifa, uint flags);
 
-void neigh_dump(neighbor *);
-void neigh_dump_all(void);
+void neigh_dump(struct dump_request *, neighbor *);
+void neigh_dump_all(struct dump_request *);
 void neigh_prune(void);
 void neigh_if_up(struct iface *);
 void neigh_if_down(struct iface *);
index 637f2c159632503d8ce1487ce89ceaaa369140fb..1776852502dd9187a1bef514d85f291629859431 100644 (file)
@@ -87,14 +87,14 @@ olock_free(resource *r)
 }
 
 static void
-olock_dump(resource *r)
+olock_dump(struct dump_request *dreq, resource *r)
 {
   struct object_lock *l = (struct object_lock *) r;
   static char *olock_states[] = { "free", "locked", "waiting", "event" };
 
-  debug("(%d:%s:%I:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->addr_local, l->port, l->inst, olock_states[l->state]);
+  RDUMP("(%d:%s:%I:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->addr_local, l->port, l->inst, olock_states[l->state]);
   if (!EMPTY_LIST(l->waiters))
-    debug(" [wanted]\n");
+    RDUMP(" [wanted]\n");
 }
 
 static struct resclass olock_class = {
index 63c07f83f800235d62cdb7a1a67b3ad14cb13d19..7db73accbd3c43a0f8291758ccb2f5371dd947e8 100644 (file)
@@ -275,17 +275,17 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
  * This functions dumps the contents of a given neighbor entry to debug output.
  */
 void
-neigh_dump(neighbor *n)
+neigh_dump(struct dump_request *dreq, neighbor *n)
 {
-  debug("%p %I %s %s ", n, n->addr,
+  RDUMP("%p %I %s %s ", n, n->addr,
        n->iface ? n->iface->name : "[]",
        n->ifreq ? n->ifreq->name : "[]");
-  debug("%s %p %08x scope %s", n->proto->name, n->data, n->aux, ip_scope_text(n->scope));
+  RDUMP("%s %p %08x scope %s", n->proto->name, n->data, n->aux, ip_scope_text(n->scope));
   if (n->flags & NEF_STICKY)
-    debug(" STICKY");
+    RDUMP(" STICKY");
   if (n->flags & NEF_ONLINK)
-    debug(" ONLINK");
-  debug("\n");
+    RDUMP(" ONLINK");
+  RDUMP("\n");
 }
 
 /**
@@ -294,16 +294,16 @@ neigh_dump(neighbor *n)
  * This function dumps the contents of the neighbor cache to debug output.
  */
 void
-neigh_dump_all(void)
+neigh_dump_all(struct dump_request *dreq)
 {
   neighbor *n;
   int i;
 
-  debug("Known neighbors:\n");
+  RDUMP("Known neighbors:\n");
   for(i=0; i<NEIGH_HASH_SIZE; i++)
     WALK_LIST(n, neigh_hash_table[i])
-      neigh_dump(n);
-  debug("\n");
+      neigh_dump(dreq, n);
+  RDUMP("\n");
 }
 
 static inline void
index 36c5b576a1600b201174f4e761680b3308a4f0e5..e4caffe1dc120e7c62b2fcab90d7c770f223bc52 100644 (file)
@@ -1693,27 +1693,27 @@ channel_graceful_restart_unlock(struct channel *c)
  * the internals.
  */
 void
-protos_dump_all(void)
+protos_dump_all(struct dump_request *dreq)
 {
-  debug("Protocols:\n");
+  RDUMP("Protocols:\n");
 
   struct proto *p;
   WALK_LIST(p, proto_list)
   {
-    debug("  protocol %s state %s\n", p->name, p_states[p->proto_state]);
+    RDUMP("  protocol %s state %s\n", p->name, p_states[p->proto_state]);
 
     struct channel *c;
     WALK_LIST(c, p->channels)
     {
-      debug("\tTABLE %s\n", c->table->name);
+      RDUMP("\tTABLE %s\n", c->table->name);
       if (c->in_filter)
-       debug("\tInput filter: %s\n", filter_name(c->in_filter));
+       RDUMP("\tInput filter: %s\n", filter_name(c->in_filter));
       if (c->out_filter)
-       debug("\tOutput filter: %s\n", filter_name(c->out_filter));
+       RDUMP("\tOutput filter: %s\n", filter_name(c->out_filter));
     }
 
     if (p->proto->dump && (p->proto_state != PS_DOWN))
-      p->proto->dump(p);
+      p->proto->dump(p, dreq);
   }
 }
 
index c87d38148005deaea1ced73545fb291540031335..d577820eec7a4569928525a2c77e0bbef274085a 100644 (file)
@@ -77,7 +77,7 @@ struct protocol {
   void (*postconfig)(struct proto_config *);                   /* After configuring each instance */
   struct proto * (*init)(struct proto_config *);               /* Create new instance */
   int (*reconfigure)(struct proto *, struct proto_config *);   /* Try to reconfigure instance, returns success */
-  void (*dump)(struct proto *);                        /* Debugging dump */
+  void (*dump)(struct proto *, struct dump_request *);         /* Debugging dump */
   int (*start)(struct proto *);                        /* Start the instance */
   int (*shutdown)(struct proto *);             /* Stop the instance */
   void (*cleanup)(struct proto *);             /* Called after shutdown when protocol became hungry/down */
@@ -93,7 +93,7 @@ void proto_build(struct protocol *);  /* Called from protocol to register itself
 void protos_preconfig(struct config *);
 void protos_commit(struct config *new, struct config *old, int force_restart, int type);
 struct proto * proto_spawn(struct proto_config *cf, uint disabled);
-void protos_dump_all(void);
+void protos_dump_all(struct dump_request *);
 
 #define GA_UNKNOWN     0               /* Attribute not recognized */
 #define GA_NAME                1               /* Result = name */
index 81efebebebe79b63b7c1931fa3d5d8e3458037fa..be3d759e770975c1822b54505d7cd962c24f8f1b 100644 (file)
@@ -332,13 +332,13 @@ void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
 void rt_modify_stale(rtable *t, struct channel *c);
 void rt_schedule_prune(rtable *t);
-void rte_dump(rte *);
+void rte_dump(struct dump_request *, rte *);
 void rte_free(rte *);
 rte *rte_do_cow(rte *);
 static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
 rte *rte_cow_rta(rte *r, linpool *lp);
-void rt_dump(rtable *);
-void rt_dump_all(void);
+void rt_dump(struct dump_request *, rtable *);
+void rt_dump_all(struct dump_request *);
 int rt_feed_channel(struct channel *c);
 void rt_feed_channel_abort(struct channel *c);
 int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
@@ -608,7 +608,7 @@ struct ea_walk_state {
 eattr *ea_find(ea_list *, unsigned ea);
 eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
 uintptr_t ea_get_int(ea_list *, unsigned ea, uintptr_t def);
-void ea_dump(ea_list *);
+void ea_dump(struct dump_request *, ea_list *);
 void ea_sort(ea_list *);               /* Sort entries in all sub-lists */
 unsigned ea_scan(ea_list *);           /* How many bytes do we need for merged ea_list */
 void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffer */
@@ -718,8 +718,8 @@ void rta__free(rta *r);
 static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
 rta *rta_do_cow(rta *o, linpool *lp);
 static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; }
-void rta_dump(rta *);
-void rta_dump_all(void);
+void rta_dump(struct dump_request *, rta *);
+void rta_dump_all(struct dump_request *);
 void rta_show(struct cli *, rta *);
 
 u32 rt_get_igp_metric(rte *rt);
index 0917663268ab69094778d574b4db673492fe891b..a567720edad93ce02b14e71a4d69f506c23212d9 100644 (file)
@@ -1044,40 +1044,40 @@ ea_show(struct cli *c, const eattr *e)
  * the debug output.
  */
 void
-ea_dump(ea_list *e)
+ea_dump(struct dump_request *dreq, ea_list *e)
 {
   int i;
 
   if (!e)
     {
-      debug("NONE");
+      RDUMP("NONE");
       return;
     }
   while (e)
     {
-      debug("[%c%c%c]",
+      RDUMP("[%c%c%c]",
            (e->flags & EALF_SORTED) ? 'S' : 's',
            (e->flags & EALF_BISECT) ? 'B' : 'b',
            (e->flags & EALF_CACHED) ? 'C' : 'c');
       for(i=0; i<e->count; i++)
        {
          eattr *a = &e->attrs[i];
-         debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
-         debug("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]);
+         RDUMP(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags);
+         RDUMP("=%c", "?iO?I?P???S?????" [a->type & EAF_TYPE_MASK]);
          if (a->originated)
-           debug("o");
+           RDUMP("o");
          if (a->type & EAF_EMBEDDED)
-           debug(":%08x", a->u.data);
+           RDUMP(":%08x", a->u.data);
          else
            {
              int j, len = a->u.ptr->length;
-             debug("[%d]:", len);
+             RDUMP("[%d]:", len);
              for(j=0; j<len; j++)
-               debug("%02x", a->u.ptr->data[j]);
+               RDUMP("%02x", a->u.ptr->data[j]);
            }
        }
       if (e = e->next)
-       debug(" | ");
+       RDUMP(" | ");
     }
 }
 
@@ -1317,7 +1317,7 @@ rta_do_cow(rta *o, linpool *lp)
  * This function takes a &rta and dumps its contents to the debug output.
  */
 void
-rta_dump(rta *a)
+rta_dump(struct dump_request *dreq, rta *a)
 {
   static char *rts[] = { "", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
                         "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
@@ -1326,25 +1326,25 @@ rta_dump(rta *a)
                         "RTS_RPKI", "RTS_PERF", "RTS_AGGREGATED", };
   static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
 
-  debug("pref=%d uc=%d %s %s%s h=%04x",
+  RDUMP("pref=%d uc=%d %s %s%s h=%04x",
        a->pref, a->uc, rts[a->source], ip_scope_text(a->scope),
        rtd[a->dest], a->hash_key);
   if (!a->cached)
-    debug(" !CACHED");
-  debug(" <-%I", a->from);
+    RDUMP(" !CACHED");
+  RDUMP(" <-%I", a->from);
   if (a->dest == RTD_UNICAST)
     for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
       {
-       if (ipa_nonzero(nh->gw)) debug(" ->%I", nh->gw);
-       if (nh->labels) debug(" L %d", nh->label[0]);
+       if (ipa_nonzero(nh->gw)) RDUMP(" ->%I", nh->gw);
+       if (nh->labels) RDUMP(" L %d", nh->label[0]);
        for (int i=1; i<nh->labels; i++)
-         debug("/%d", nh->label[i]);
-       debug(" [%s]", nh->iface ? nh->iface->name : "???");
+         RDUMP("/%d", nh->label[i]);
+       RDUMP(" [%s]", nh->iface ? nh->iface->name : "???");
       }
   if (a->eattrs)
     {
-      debug(" EA: ");
-      ea_dump(a->eattrs);
+      RDUMP(" EA: ");
+      ea_dump(dreq, a->eattrs);
     }
 }
 
@@ -1355,20 +1355,20 @@ rta_dump(rta *a)
  * to the debug output.
  */
 void
-rta_dump_all(void)
+rta_dump_all(struct dump_request *dreq)
 {
   rta *a;
   uint h;
 
-  debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
+  RDUMP("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit);
   for(h=0; h<rta_cache_size; h++)
     for(a=rta_hash_table[h]; a; a=a->next)
       {
-       debug("%p ", a);
-       rta_dump(a);
-       debug("\n");
+       RDUMP("%p ", a);
+       rta_dump(dreq, a);
+       RDUMP("\n");
       }
-  debug("\n");
+  RDUMP("\n");
 }
 
 void
index 8fa79f029c15f14aad8a18fd3599f19908ee929d..ee3f11882fd613c43eb4c87be9e9f5217d9699fc 100644 (file)
@@ -1751,13 +1751,13 @@ rt_modify_stale(rtable *t, struct channel *c)
  * This functions dumps contents of a &rte to debug output.
  */
 void
-rte_dump(rte *e)
+rte_dump(struct dump_request *dreq, rte *e)
 {
   net *n = e->net;
-  debug("%-1N ", n->n.addr);
-  debug("PF=%02x ", e->pflags);
-  rta_dump(e->attrs);
-  debug("\n");
+  RDUMP("%-1N ", n->n.addr);
+  RDUMP("PF=%02x ", e->pflags);
+  rta_dump(dreq, e->attrs);
+  RDUMP("\n");
 }
 
 /**
@@ -1767,9 +1767,9 @@ rte_dump(rte *e)
  * This function dumps contents of a given routing table to debug output.
  */
 void
-rt_dump(rtable *t)
+rt_dump(struct dump_request *dreq, rtable *t)
 {
-  debug("Dump of routing table <%s>\n", t->name);
+  RDUMP("Dump of routing table <%s>\n", t->name);
 #ifdef DEBUGGING
   fib_check(&t->fib);
 #endif
@@ -1777,10 +1777,10 @@ rt_dump(rtable *t)
     {
       rte *e;
       for(e=n->routes; e; e=e->next)
-       rte_dump(e);
+       rte_dump(dreq, e);
     }
   FIB_WALK_END;
-  debug("\n");
+  RDUMP("\n");
 }
 
 /**
@@ -1789,13 +1789,13 @@ rt_dump(rtable *t)
  * This function dumps contents of all routing tables to debug output.
  */
 void
-rt_dump_all(void)
+rt_dump_all(struct dump_request *dreq)
 {
   rtable *t;
   node *n;
 
   WALK_LIST2(t, n, routing_tables, n)
-    rt_dump(t);
+    rt_dump(dreq, t);
 }
 
 static inline void
@@ -2057,10 +2057,10 @@ rt_free(resource *_r)
 }
 
 static void
-rt_res_dump(resource *_r)
+rt_res_dump(struct dump_request *dreq, resource *_r)
 {
   rtable *r = (rtable *) _r;
-  debug("name \"%s\", addr_type=%s, rt_count=%u, use_count=%d\n",
+  RDUMP("name \"%s\", addr_type=%s, rt_count=%u, use_count=%d\n",
       r->name, net_label[r->addr_type], r->rt_count, r->use_count);
 }
 
index 4187d258aa3b596f710217d2c8500909c8d1b2dc..fe5c0599a3312a1ebedefc034d1c480374405b28 100644 (file)
@@ -2103,82 +2103,82 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
  */
 
 static void
-babel_dump_source(struct babel_source *s)
+babel_dump_source(struct dump_request *dreq, struct babel_source *s)
 {
-  debug("Source router_id %lR seqno %d metric %d expires %t\n",
+  RDUMP("Source router_id %lR seqno %d metric %d expires %t\n",
        s->router_id, s->seqno, s->metric,
        s->expires ? s->expires - current_time() : 0);
 }
 
 static void
-babel_dump_route(struct babel_route *r)
+babel_dump_route(struct dump_request *dreq, struct babel_route *r)
 {
-  debug("Route neigh %I if %s seqno %d metric %d/%d router_id %lR expires %t\n",
+  RDUMP("Route neigh %I if %s seqno %d metric %d/%d router_id %lR expires %t\n",
        r->neigh->addr, r->neigh->ifa->ifname, r->seqno, r->advert_metric, r->metric,
        r->router_id, r->expires ? r->expires - current_time() : 0);
 }
 
 static void
-babel_dump_entry(struct babel_entry *e)
+babel_dump_entry(struct dump_request *dreq, struct babel_entry *e)
 {
   struct babel_source *s;
   struct babel_route *r;
 
-  debug("Babel: Entry %N:\n", e->n.addr);
+  RDUMP("Babel: Entry %N:\n", e->n.addr);
 
   WALK_LIST(s,e->sources)
-  { debug(" "); babel_dump_source(s); }
+  { RDUMP(" "); babel_dump_source(dreq, s); }
 
   WALK_LIST(r,e->routes)
   {
-    debug(" ");
-    if (r == e->selected) debug("*");
-    babel_dump_route(r);
+    RDUMP(" ");
+    if (r == e->selected) RDUMP("*");
+    babel_dump_route(dreq, r);
   }
 }
 
 static void
-babel_dump_neighbor(struct babel_neighbor *n)
+babel_dump_neighbor(struct dump_request *dreq, struct babel_neighbor *n)
 {
-  debug("Neighbor %I txcost %d hello_map %x next seqno %d expires %t/%t\n",
+  RDUMP("Neighbor %I txcost %d hello_map %x next seqno %d expires %t/%t\n",
        n->addr, n->txcost, n->hello_map, n->next_hello_seqno,
        n->hello_expiry ? n->hello_expiry - current_time() : 0,
         n->ihu_expiry ? n->ihu_expiry - current_time() : 0);
 }
 
 static void
-babel_dump_iface(struct babel_iface *ifa)
+babel_dump_iface(struct dump_request *dreq, struct babel_iface *ifa)
 {
   struct babel_neighbor *n;
 
-  debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %t %t",
+  RDUMP("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %t %t",
        ifa->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno,
        ifa->cf->hello_interval, ifa->cf->update_interval);
-  debug(" next hop v4 %I next hop v6 %I\n", ifa->next_hop_ip4, ifa->next_hop_ip6);
+  RDUMP(" next hop v4 %I next hop v6 %I\n", ifa->next_hop_ip4, ifa->next_hop_ip6);
 
   WALK_LIST(n, ifa->neigh_list)
-  { debug(" "); babel_dump_neighbor(n); }
+  { RDUMP(" "); babel_dump_neighbor(dreq, n); }
 }
 
 static void
-babel_dump(struct proto *P)
+babel_dump(struct proto *P, struct dump_request *dreq)
 {
   struct babel_proto *p = (struct babel_proto *) P;
   struct babel_iface *ifa;
 
-  debug("Babel: router id %lR update seqno %d\n", p->router_id, p->update_seqno);
+  RDUMP("Babel: router id %lR update seqno %d\n", p->router_id, p->update_seqno);
 
   WALK_LIST(ifa, p->interfaces)
-    babel_dump_iface(ifa);
+    babel_dump_iface(dreq, ifa);
 
   FIB_WALK(&p->ip4_rtable, struct babel_entry, e)
   {
-    babel_dump_entry(e);
+    babel_dump_entry(dreq, e);
   }
   FIB_WALK_END;
   FIB_WALK(&p->ip6_rtable, struct babel_entry, e)
   {
-    babel_dump_entry(e);
+    babel_dump_entry(dreq, e);
   }
   FIB_WALK_END;
 }
index cde7f11b516ed0a79f615da18752d3d3910e49da..a4d186ec07fef8e6de787ef070fed9d955c36dbf 100644 (file)
@@ -826,11 +826,11 @@ bfd_request_free(resource *r)
 }
 
 static void
-bfd_request_dump(resource *r)
+bfd_request_dump(struct dump_request *dreq, resource *r)
 {
   struct bfd_request *req = (struct bfd_request *) r;
 
-  debug("(code %p, data %p)\n", req->hook, req->data);
+  RDUMP("(code %p, data %p)\n", req->hook, req->data);
 }
 
 static struct resclass bfd_request_class = {
index 9603c4e8a28513e3b57158154682e24c88158bf8..ae768a7c9bb20cdeba90eca533a669adab3bfe1f 100644 (file)
@@ -237,7 +237,7 @@ static void
 bmp_tx_resource_free(resource *r UNUSED) {}
 
 static void
-bmp_tx_resource_dump(resource *r UNUSED) {}
+bmp_tx_resource_dump(struct dump_request *dreq UNUSED, resource *r UNUSED) {}
 
 static struct resmem
 bmp_tx_resource_memsize(resource *r)
index ad4b2d14ddcb73bce601848e6b1b40cc87a8ad56..da29e6c4e70fe75012f039ee9370b080bab90038 100644 (file)
@@ -333,32 +333,31 @@ ospf_start(struct proto *P)
 }
 
 static void
-ospf_dump(struct proto *P)
+ospf_dump(struct proto *P, struct dump_request *dreq)
 {
   struct ospf_proto *p = (struct ospf_proto *) P;
   struct ospf_iface *ifa;
   struct ospf_neighbor *n;
 
-  OSPF_TRACE(D_EVENTS, "Area number: %d", p->areano);
+  RDUMP("Area number: %d\n", p->areano);
 
   WALK_LIST(ifa, p->iface_list)
   {
-    OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
-    OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
-    OSPF_TRACE(D_EVENTS, "DR:  %R", ifa->drid);
-    OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid);
+    RDUMP("Interface: %s\n", ifa->ifname);
+    RDUMP("state: %u\n", ifa->state);
+    RDUMP("DR:  %R\n", ifa->drid);
+    RDUMP("BDR: %R\n", ifa->bdrid);
     WALK_LIST(n, ifa->neigh_list)
     {
-      OSPF_TRACE(D_EVENTS, "  neighbor %R in state %u", n->rid, n->state);
+      RDUMP("  neighbor %R in state %u\n", n->rid, n->state);
     }
   }
 
   /*
-  OSPF_TRACE(D_EVENTS, "LSA graph dump start:");
+  RDUMP("LSA graph dump start:");
   ospf_top_dump(p->gr, p);
-  OSPF_TRACE(D_EVENTS, "LSA graph dump finished");
+  RDUMP("LSA graph dump finished");
   */
-  neigh_dump_all();
 }
 
 static struct proto *
index 4bfb57561be93ac200b020a5125f3317b1f24bc9..b70b6e8ec9c80c6997c1a047a57bff38bccab953 100644 (file)
@@ -1315,7 +1315,7 @@ rip_show_neighbors(struct proto *P, const char *iff)
 }
 
 static void
-rip_dump(struct proto *P)
+rip_dump(struct proto *P, struct dump_request *dreq)
 {
   struct rip_proto *p = (struct rip_proto *) P;
   struct rip_iface *ifa;
@@ -1324,12 +1324,12 @@ rip_dump(struct proto *P)
   i = 0;
   FIB_WALK(&p->rtable, struct rip_entry, en)
   {
-    debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
+    RDUMP("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
          i++, en->n.addr, en->next_hop, en->iface ? en->iface->name : "(null)",
          en->valid, en->metric, current_time() - en->changed);
 
     for (struct rip_rte *e = en->routes; e; e = e->next)
-      debug("RIP:   via %I metric %d expires %t\n",
+      RDUMP("RIP:   via %I metric %d expires %t\n",
            e->next_hop, e->metric, e->expires - current_time());
   }
   FIB_WALK_END;
@@ -1337,7 +1337,7 @@ rip_dump(struct proto *P)
   i = 0;
   WALK_LIST(ifa, p->iface_list)
   {
-    debug("RIP: interface #%d: %s, %I, up = %d, busy = %d\n",
+    RDUMP("RIP: interface #%d: %s, %I, up = %d, busy = %d\n",
          i++, ifa->iface->name, ifa->sk ? ifa->sk->daddr : IPA_NONE,
          ifa->up, ifa->tx_active);
   }
index 661d04aa701a774d13cff4bfdcfaafac6a11057f..3101db2fc431a7f16abb1e5f782165b4cbdadc5e 100644 (file)
@@ -613,27 +613,27 @@ static_cleanup(struct proto *P)
 }
 
 static void
-static_dump_rte(struct static_route *r)
+static_dump_rte(struct dump_request *dreq, struct static_route *r)
 {
-  debug("%-1N (%u): ", r->net, r->index);
+  RDUMP("%-1N (%u): ", r->net, r->index);
   if (r->dest == RTD_UNICAST)
     if (r->iface && ipa_zero(r->via))
-      debug("dev %s\n", r->iface->name);
+      RDUMP("dev %s\n", r->iface->name);
     else
-      debug("via %I%J\n", r->via, r->iface);
+      RDUMP("via %I%J\n", r->via, r->iface);
   else
-    debug("rtd %d\n", r->dest);
+    RDUMP("rtd %d\n", r->dest);
 }
 
 static void
-static_dump(struct proto *P)
+static_dump(struct proto *P, struct dump_request *dreq)
 {
   struct static_config *c = (void *) P->cf;
   struct static_route *r;
 
-  debug("Static routes:\n");
+  RDUMP("Static routes:\n");
   WALK_LIST(r, c->routes)
-    static_dump_rte(r);
+    static_dump_rte(dreq, r);
 }
 
 #define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
index 08fc99801b3c4760380e40041b1d20a45a233d97..2117d919df74c6d157cf7539f20c640942cb529a 100644 (file)
@@ -226,6 +226,26 @@ global_free_pages_cleanup_event(void *data UNUSED)
 }
 #endif
 
+void
+page_dump(struct dump_request *dreq)
+{
+#ifdef HAVE_MMAP
+  RDUMP("Hot pages:\n");
+  node *n;
+  WALK_LIST(n, global_free_pages.pages)
+    RDUMP("  %p\n", n);
+
+  RDUMP("Cold pages:\n");
+  WALK_LIST(n, global_free_pages.empty)
+  {
+    struct empty_pages *ep = SKIP_BACK(struct empty_pages, n, n);
+    RDUMP("  %p (index)\n", ep);
+    for (uint i=0; i<ep->pos; i++)
+      RDUMP("    %p\n", ep->pages[i]);
+  }
+#endif
+}
+
 void
 resource_sys_init(void)
 {
index 59b33ef1804e71ac62f98c21a54bc26a621e658a..b06324860058d2523c9c0bb87dee2c5ec0c31af9 100644 (file)
@@ -19,6 +19,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/uio.h>
 #include <sys/un.h>
 #include <poll.h>
@@ -40,6 +41,7 @@
 #include "lib/timer.h"
 #include "lib/string.h"
 #include "nest/iface.h"
+#include "nest/cli.h"
 #include "conf/conf.h"
 
 #include "sysdep/unix/unix.h"
@@ -75,11 +77,11 @@ rf_free(resource *r)
 }
 
 static void
-rf_dump(resource *r)
+rf_dump(struct dump_request *dreq, resource *r)
 {
   struct rfile *a = (struct rfile *) r;
 
-  debug("(FILE *%p)\n", a->f);
+  RDUMP("(FILE *%p)\n", a->f);
 }
 
 static struct resclass rf_class = {
@@ -129,6 +131,147 @@ rf_fileno(struct rfile *f)
   return fileno(f->f);
 }
 
+/*
+ *     Dumping to files
+ */
+
+struct dump_request_file {
+  struct dump_request dr;
+  uint pos, max; int fd;
+  uint last_progress_info;
+  char data[0];
+};
+
+static void
+dump_to_file_flush(struct dump_request_file *req)
+{
+  if (req->fd < 0)
+    return;
+
+  for (uint sent = 0; sent < req->pos; )
+  {
+    int e = write(req->fd, &req->data[sent], req->pos - sent);
+    if (e <= 0)
+    {
+      req->dr.report(&req->dr, 8009, "Failed to write data: %m");
+      close(req->fd);
+      req->fd = -1;
+      return;
+    }
+    sent += e;
+  }
+
+  req->dr.size += req->pos;
+  req->pos = 0;
+
+  for (uint reported = 0; req->dr.size >> req->last_progress_info; req->last_progress_info++)
+    if (!reported++)
+      req->dr.report(&req->dr, -13, "... dumped %lu bytes in %t s",
+         req->dr.size, current_time_now() - req->dr.begin);
+}
+
+static void
+dump_to_file_write(struct dump_request *dr, const char *fmt, ...)
+{
+  struct dump_request_file *req = SKIP_BACK(struct dump_request_file, dr, dr);
+
+  for (uint phase = 0; (req->fd >= 0) && (phase < 2); phase++)
+  {
+    va_list args;
+    va_start(args, fmt);
+    int i = bvsnprintf(&req->data[req->pos], req->max - req->pos, fmt, args);
+    va_end(args);
+
+    if (i >= 0)
+    {
+      req->pos += i;
+      return;
+    }
+    else
+      dump_to_file_flush(req);
+  }
+
+  bug("Too long dump call");
+}
+
+struct dump_request *
+dump_to_file_init(off_t offset)
+{
+  ASSERT_DIE(offset + sizeof(struct dump_request_file) + 1024 < (unsigned long) page_size);
+
+  struct dump_request_file *req = alloc_page() + offset;
+  *req = (struct dump_request_file) {
+    .dr = {
+      .write = dump_to_file_write,
+      .begin = current_time_now(),
+      .offset = offset,
+    },
+    .max = page_size - offset - OFFSETOF(struct dump_request_file, data[0]),
+    .fd = -1,
+  };
+
+  return &req->dr;
+}
+
+void
+dump_to_file_run(struct dump_request *dr, const char *file, const char *what, void (*dump)(struct dump_request *))
+{
+  struct dump_request_file *req = SKIP_BACK(struct dump_request_file, dr, dr);
+  req->fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR);
+
+  if (req->fd < 0)
+  {
+    dr->report(dr, 8009, "Failed to open file %s: %m", file);
+    goto cleanup;
+  }
+
+  dr->report(dr, -13, "Dumping %s to %s", what, file);
+
+  dump(dr);
+
+  if (req->fd >= 0)
+  {
+    dump_to_file_flush(req);
+    close(req->fd);
+  }
+
+  btime end = current_time_now();
+  dr->report(dr, 13, "Dumped %lu bytes in %t s", dr->size, end - dr->begin);
+
+cleanup:
+  free_page(((void *) req) - dr->offset);
+}
+
+struct dump_request_cli {
+  cli *cli;
+  struct dump_request dr;
+};
+
+static void
+cmd_dump_report(struct dump_request *dr, int state, const char *fmt, ...)
+{
+  struct dump_request_cli *req = SKIP_BACK(struct dump_request_cli, dr, dr);
+  va_list args;
+  va_start(args, fmt);
+  cli_vprintf(req->cli, state, fmt, args);
+  va_end(args);
+}
+
+void
+cmd_dump_file(struct cli *cli, const char *file, const char *what, void (*dump)(struct dump_request *))
+{
+  if (cli->restricted)
+    return cli_printf(cli, 8007, "Access denied");
+
+  struct dump_request_cli *req = SKIP_BACK(struct dump_request_cli, dr,
+      dump_to_file_init(OFFSETOF(struct dump_request_cli, dr)));
+
+  req->cli = cli;
+  req->dr.report = cmd_dump_report;
+
+  dump_to_file_run(&req->dr, file, what, dump);
+}
+
 
 /*
  *     Time clock
@@ -932,12 +1075,12 @@ sk_reallocate(sock *s)
 }
 
 static void
-sk_dump(resource *r)
+sk_dump(struct dump_request *dreq, resource *r)
 {
   sock *s = (sock *) r;
   static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "SSH>", "SSH", "DEL!" };
 
-  debug("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
+  RDUMP("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
        sk_type_names[s->type],
        s->data,
        s->saddr,
@@ -2088,19 +2231,19 @@ sk_err(sock *s, int revents)
 }
 
 void
-sk_dump_all(void)
+sk_dump_all(struct dump_request *dreq)
 {
   node *n;
   sock *s;
 
-  debug("Open sockets:\n");
+  RDUMP("Open sockets:\n");
   WALK_LIST(n, sock_list)
   {
     s = SKIP_BACK(sock, n, n);
-    debug("%p ", s);
-    sk_dump(&s->r);
+    RDUMP("%p ", s);
+    sk_dump(dreq, &s->r);
   }
-  debug("\n");
+  RDUMP("\n");
 }
 
 
@@ -2191,16 +2334,16 @@ io_close_event(void)
 }
 
 void
-io_log_dump(void)
+io_log_dump(struct dump_request *dreq)
 {
   int i;
 
-  log(L_DEBUG "Event log:");
+  RDUMP("Event log:");
   for (i = 0; i < EVENT_LOG_LENGTH; i++)
   {
     struct event_log_entry *en = event_log + (event_log_pos + i) % EVENT_LOG_LENGTH;
     if (en->hook)
-      log(L_DEBUG "  Event 0x%p 0x%p at %8d for %d ms", en->hook, en->data,
+      RDUMP("  Event 0x%p 0x%p at %8d for %d ms", en->hook, en->data,
          (int) ((last_time - en->timestamp) TO_MS), (int) (en->duration TO_MS));
   }
 }
index 0664f4c1dde5f348bf539b6c1fb0ef5c75f53656..51d0718c150ac9b58e9d01509124ae8deab96a78 100644 (file)
@@ -532,14 +532,14 @@ krt_learn_init(struct krt_proto *p)
 }
 
 static void
-krt_dump(struct proto *P)
+krt_dump(struct proto *P, struct dump_request *dreq)
 {
   struct krt_proto *p = (struct krt_proto *) P;
 
   if (!KRT_CF->learn)
     return;
-  debug("KRT: Table of inheritable routes\n");
-  rt_dump(p->krt_table);
+  RDUMP("KRT: Table of inheritable routes\n");
+  rt_dump(dreq, p->krt_table);
 }
 
 #endif
index b825a1f31a7a11e587eccd2a4192833a550919b1..85acc21864b0a26fd5d8d4d3f475f0629e253d0b 100644 (file)
  *     Debugging
  */
 
-void
-async_dump(void)
+static void
+async_dump_report(struct dump_request *dr UNUSED, int state, const char *fmt, ...)
+{
+  va_list args;
+  va_start(args, fmt);
+  vlog(((state > 1000) ? L_ERR : L_INFO)[0], fmt, args);
+  va_end(args);
+}
+
+static void
+async_dump_run(struct dump_request *dreq)
 {
-  debug("INTERNAL STATE DUMP\n\n");
+  RDUMP("ASYNC STATE DUMP\n");
 
-  rdump(&root_pool);
-  sk_dump_all();
+  rdump(dreq, &root_pool);
+  sk_dump_all(dreq);
   // XXXX tm_dump_all();
-  if_dump_all();
-  neigh_dump_all();
-  rta_dump_all();
-  rt_dump_all();
-  protos_dump_all();
+  if_dump_all(dreq);
+  neigh_dump_all(dreq);
+  rta_dump_all(dreq);
+  rt_dump_all(dreq);
+  protos_dump_all(dreq);
 
   debug("\n");
 }
 
+void
+async_dump(void)
+{
+  struct dump_request *dr = dump_to_file_init(0);
+  dr->report = async_dump_report;
+  dump_to_file_run(dr, "bird.dump", "async dump", async_dump_run);
+}
+
 /*
  *     Dropping privileges
  */
index 33ece06cd9b61027d39b832b308712bf7a8ce6d9..2b3c5d4ea99c7be193a6c0342d1edb08e0a8b871 100644 (file)
@@ -16,6 +16,7 @@ struct pool;
 struct iface;
 struct birdsock;
 struct rfile;
+struct cli;
 
 /* main.c */
 
@@ -106,7 +107,7 @@ extern volatile sig_atomic_t async_shutdown_flag;
 
 void io_init(void);
 void io_loop(void);
-void io_log_dump(void);
+void io_log_dump(struct dump_request *);
 int sk_open_unix(struct birdsock *s, const char *name);
 struct rfile *rf_open(struct pool *, const char *name, const char *mode);
 struct rfile *rf_fdopen(pool *p, int fd, const char *mode);
@@ -115,6 +116,11 @@ int rf_fileno(struct rfile *f);
 void test_old_bird(const char *path);
 ip_addr resolve_hostname(const char *host, int type, const char **err_msg);
 
+struct dump_request *dump_to_file_init(off_t offset);
+void dump_to_file_run(struct dump_request *dr, const char *file, const char *what, void (*dump)(struct dump_request *));
+
+void cmd_dump_file(struct cli *cli, const char *file, const char *what, void (*dump)(struct dump_request *));
+
 /* krt.c bits */
 
 void krt_io_init(void);