0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 01:31:55 +00:00

CLI: Dumping internal data structures to files, not to debug output

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.
This commit is contained in:
Maria Matejka 2024-11-14 20:43:35 +01:00 committed by Ondrej Zajicek
parent 4dd5b3d90e
commit da8a23277e
37 changed files with 463 additions and 261 deletions

View 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.

View 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

View 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;
}

View File

@ -182,11 +182,11 @@
* 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.

View 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 */

View 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);
}

View 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);
}
}
}

View 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)

View 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

View 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");

View 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,

View 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 *

View 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 */

View 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

View 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 */

View 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");
}

View 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)); } ;

View 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

View 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 *);

View 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 = {

View 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

View 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);
}
}

View 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 */

View 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);

View 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

View 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);
}

View 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;
}

View 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 = {

View 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)

View 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 *

View 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);
}

View 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 )

View 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)
{

View 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));
}
}

View 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

View File

@ -48,21 +48,38 @@
* Debugging
*/
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)
{
RDUMP("ASYNC STATE DUMP\n");
rdump(dreq, &root_pool);
sk_dump_all(dreq);
// XXXX tm_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)
{
debug("INTERNAL STATE DUMP\n\n");
rdump(&root_pool);
sk_dump_all();
// XXXX tm_dump_all();
if_dump_all();
neigh_dump_all();
rta_dump_all();
rt_dump_all();
protos_dump_all();
debug("\n");
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);
}
/*

View 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);