0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Merge commit 'd85fa48e' into thread-next

The resource dumping routines needed to be updated in v3 to use the new
API introduced in v2.

Conflicts:
	filter/f-util.c
	filter/filter.c
	lib/birdlib.h
	lib/event.c
	lib/mempool.c
	lib/resource.c
	lib/resource.h
	lib/slab.c
	lib/timer.c
	nest/config.Y
	nest/iface.c
	nest/iface.h
	nest/locks.c
	nest/neighbor.c
	nest/proto.c
	nest/route.h
	nest/rt-attr.c
	nest/rt-table.c
	proto/bfd/bfd.c
	proto/bmp/bmp.c
	sysdep/unix/io.c
	sysdep/unix/krt.c
	sysdep/unix/main.c
	sysdep/unix/unix.h
This commit is contained in:
Maria Matejka 2024-12-13 15:23:01 +01:00
commit 731593685b
36 changed files with 545 additions and 326 deletions

View File

@ -1507,8 +1507,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> <tag><label id="cli-debug">debug <m/protocol/|<m/pattern/|all all|off|{ states|routes|filters|events|packets [, <m/.../] }</tag>
Control protocol debugging. Control protocol debugging.
<tag><label id="cli-dump">dump resources|sockets|interfaces|neighbors|attributes|routes|protocols</tag> <tag><label id="cli-dump">dump resources|sockets|interfaces|neighbors|attributes|routes|protocols "<m/file/"</tag>
Dump contents of internal data structures to the debugging output. 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> <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. Control echoing of log messages to the command-line output.

View File

@ -73,6 +73,7 @@ Reply codes of BIRD command-line interface
8006 Reload failed 8006 Reload failed
8007 Access denied 8007 Access denied
8008 Evaluation runtime error 8008 Evaluation runtime error
8009 Failed to open file
9000 Command too long 9000 Command too long
9001 Parse error 9001 Parse error

View File

@ -97,7 +97,7 @@ if ($3) return 0;
]]) ]])
m4_ifelse($4,,,[[ m4_ifelse($4,,,[[
FID_DUMP_BODY()m4_dnl FID_DUMP_BODY()m4_dnl
debug("%s" $4 "\n", INDENT, $5); RDUMP("%s" $4 "\n", INDENT, $5);
]]) ]])
FID_INTERPRET_EXEC()m4_dnl FID_INTERPRET_EXEC()m4_dnl
$1 $2 = whati->$2 $1 $2 = whati->$2
@ -168,7 +168,7 @@ FID_LINEARIZE_BODY()m4_dnl
pos = linearize(dest, whati->fvar, pos); pos = linearize(dest, whati->fvar, pos);
item->varcount = whati->varcount; item->varcount = whati->varcount;
FID_DUMP_BODY()m4_dnl 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 FID_SAME_BODY()m4_dnl
if (f1->varcount != f2->varcount) return 0; if (f1->varcount != f2->varcount) return 0;
FID_INTERPRET_BODY() FID_INTERPRET_BODY()
@ -241,7 +241,7 @@ FID_NEW_METHOD()m4_dnl
args = NULL; /* The rest is the line itself */ args = NULL; /* The rest is the line itself */
FID_METHOD_CALL() , arg$1 FID_METHOD_CALL() , arg$1
FID_DUMP_BODY()m4_dnl 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 FID_LINEARIZE_BODY()m4_dnl
item->fl$1 = f_linearize(whati->f$1, $2); item->fl$1 = f_linearize(whati->f$1, $2);
FID_SAME_BODY()m4_dnl FID_SAME_BODY()m4_dnl
@ -434,13 +434,13 @@ m4_undivert(113)
]])m4_dnl ]])m4_dnl
FID_DUMP_CALLER()m4_dnl Case in another big switch used in instruction dumping (debug) FID_DUMP_CALLER()m4_dnl Case in another big switch used in instruction dumping
case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(dreq, item, indent + 1); break;
FID_DUMP()m4_dnl The dumper itself FID_DUMP()m4_dnl The dumper itself
m4_ifdef([[FID_DUMP_BODY_EXISTS]], 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()[[(struct dump_request *dreq, 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 UNUSED, const struct f_line_item *item UNUSED, const int indent UNUSED)]])
m4_undefine([[FID_DUMP_BODY_EXISTS]]) m4_undefine([[FID_DUMP_BODY_EXISTS]])
{ {
#define item (&(item_->i_]]INST_NAME()[[)) #define item (&(item_->i_]]INST_NAME()[[))
@ -681,22 +681,22 @@ static const char f_dump_line_indent_str[] = " ";
FID_WR_PUT(6) 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) { if (!dest) {
debug("%sNo filter line (NULL)\n", INDENT); RDUMP("%sNo filter line (NULL)\n", INDENT);
return; 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++) { for (uint i=0; i<dest->len; i++) {
const struct f_line_item *item = &dest->items[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) { switch (item->fi_code) {
FID_WR_PUT(7) FID_WR_PUT(7)
default: bug("Unknown instruction %x in f_dump_line", item->fi_code); 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 */ /* Linearize */
@ -726,10 +726,6 @@ f_linearize_concat(const struct f_inst * const inst[], uint count, uint results)
out->len = linearize(out, inst[i], out->len); out->len = linearize(out, inst[i], out->len);
out->results = results; out->results = results;
#ifdef LOCAL_DEBUG
f_dump_line(out, 0);
#endif
return out; return out;
} }

View File

@ -181,11 +181,11 @@
* m4_dnl This structure is returned from the linearizer (105). * m4_dnl This structure is returned from the linearizer (105).
* m4_dnl For writing directly to this structure, use FID_LINE_IN. * 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 {
* m4_dnl (104) [[ put it here ]] * m4_dnl (104) [[ put it here ]]
* m4_dnl } * 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 is the linearized instruction; if the instruction has arguments,
* m4_dnl their code has already been linearized and their value is taken * m4_dnl their code has already been linearized and their value is taken
* m4_dnl from the value stack. * 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) static inline struct f_line *f_linearize(const struct f_inst *root, uint results)
{ return f_linearize_concat(&root, 1, 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 */ /* Recursive iteration over filter instructions */

View File

@ -144,11 +144,6 @@ interpret(struct filter_state *fs, const struct f_line *line, uint argc, const s
#define curline fstk->estk[fstk->ecnt-1] #define curline fstk->estk[fstk->ecnt-1]
#define prevline fstk->estk[fstk->ecnt-2] #define prevline fstk->estk[fstk->ecnt-2]
#ifdef LOCAL_DEBUG
debug("Interpreting line.");
f_dump_line(line, 1);
#endif
while (fstk->ecnt > 0) { while (fstk->ecnt > 0) {
while (curline.pos < curline.line->len) { while (curline.pos < curline.line->len) {
const struct f_line_item *what = &(curline.line->items[curline.pos++]); const struct f_line_item *what = &(curline.line->items[curline.pos++]);
@ -393,46 +388,46 @@ filter_commit(struct config *new, struct config *old)
} }
} }
void channel_filter_dump(const struct filter *f) void channel_filter_dump(struct dump_request *dreq, const struct filter *f)
{ {
if (f == FILTER_ACCEPT) if (f == FILTER_ACCEPT)
debug(" ALL"); RDUMP(" ALL");
else if (f == FILTER_REJECT) else if (f == FILTER_REJECT)
debug(" NONE"); RDUMP(" NONE");
else if (f == FILTER_UNDEF) else if (f == FILTER_UNDEF)
debug(" UNDEF"); RDUMP(" UNDEF");
else if (f->sym) { else if (f->sym) {
ASSERT(f->sym->filter == f); ASSERT(f->sym->filter == f);
debug(" named filter %s", f->sym->name); RDUMP(" named filter %s", f->sym->name);
} else { } else {
debug("\n"); RDUMP("\n");
f_dump_line(f->root, 2); f_dump_line(dreq, f->root, 2);
} }
} }
void filters_dump_all(void) void filters_dump_all(struct dump_request *dreq)
{ {
struct symbol *sym; struct symbol *sym;
WALK_LIST(sym, OBSREF_GET(config)->symbols) { WALK_LIST(sym, OBSREF_GET(config)->symbols) {
switch (sym->class) { switch (sym->class) {
case SYM_FILTER: case SYM_FILTER:
debug("Named filter %s:\n", sym->name); RDUMP("Named filter %s:\n", sym->name);
f_dump_line(sym->filter->root, 1); f_dump_line(dreq, sym->filter->root, 1);
break; break;
case SYM_FUNCTION: case SYM_FUNCTION:
debug("Function %s:\n", sym->name); RDUMP("Function %s:\n", sym->name);
f_dump_line(sym->function, 1); f_dump_line(dreq, sym->function, 1);
break; break;
case SYM_PROTO: case SYM_PROTO:
{ {
debug("Protocol %s:\n", sym->name); RDUMP("Protocol %s:\n", sym->name);
struct channel *c; struct channel *c;
WALK_LIST(c, sym->proto->proto->channels) { 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]);
channel_filter_dump(c->in_filter); channel_filter_dump(dreq, c->in_filter);
debug(" EXPORT", c->name, net_label[c->net_type]); RDUMP(" EXPORT", c->name, net_label[c->net_type]);
channel_filter_dump(c->out_filter); channel_filter_dump(dreq, c->out_filter);
debug("\n"); RDUMP("\n");
} }
} }
} }

View File

@ -73,7 +73,7 @@ int f_same(const struct f_line *f1, const struct f_line *f2);
void filter_preconfig(struct config *new); void filter_preconfig(struct config *new);
void filter_commit(struct config *new, struct config *old); 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_ACCEPT NULL
#define FILTER_REJECT ((struct filter *) 1) #define FILTER_REJECT ((struct filter *) 1)

View File

@ -310,4 +310,15 @@ static inline u32 u64_hash(u64 v)
void birdloop_yield(void); void birdloop_yield(void);
/* 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 #endif

View File

@ -173,11 +173,11 @@ ev_postpone(event *e)
} }
static void static void
ev_dump(resource *r, unsigned indent UNUSED) ev_dump(struct dump_request *dreq, resource *r)
{ {
event *e = (event *) r; event *e = (event *) r;
debug("(code %p, data %p, %s)\n", RDUMP("(code %p, data %p, %s)\n",
e->hook, e->hook,
e->data, e->data,
atomic_load_explicit(&e->next, memory_order_relaxed) ? "scheduled" : "inactive"); atomic_load_explicit(&e->next, memory_order_relaxed) ? "scheduled" : "inactive");

View File

@ -46,7 +46,7 @@ struct linpool {
static void *lp_alloc_slow(struct linpool *, uint); static void *lp_alloc_slow(struct linpool *, uint);
static void lp_free(resource *); static void lp_free(resource *);
static void lp_dump(resource *, unsigned); static void lp_dump(struct dump_request *, resource *);
static resource *lp_lookup(resource *, unsigned long); static resource *lp_lookup(resource *, unsigned long);
static struct resmem lp_memsize(resource *r); static struct resmem lp_memsize(resource *r);
@ -278,30 +278,27 @@ lp_free(resource *r)
} }
static void static void
lp_dump(resource *r, unsigned indent) lp_dump(struct dump_request *dreq, resource *r)
{ {
linpool *m = (linpool *) r; linpool *m = (linpool *) r;
struct lp_chunk *c;
int cnt, cntl;
char x[32];
for(cnt=0, c=m->first; c; c=c->next, cnt++) int chunks = 0, large = 0;
;
for(cntl=0, c=m->first_large; c; c=c->next, cntl++)
;
debug("(count=%d+%d total=%d+%d)\n",
cnt,
cntl,
m->total,
m->total_large);
bsprintf(x, "%%%dschunk %%p\n", indent + 2); RDUMP("\n%*schunks:\n", dreq->indent+3, "");
for (c=m->first; c; c=c->next) for (struct lp_chunk *c = m->first; c; c = c->next)
debug(x, "", c); {
RDUMP("%*s%p\n", dreq->indent+6, "", c);
chunks++;
}
RDUMP("%*scount=%d total=%d\n", dreq->indent+3, "", chunks, m->total);
bsprintf(x, "%%%dslarge %%p\n", indent + 2); RDUMP("%*slarge:\n", dreq->indent+3, "");
for (c=m->first_large; c; c=c->next) for (struct lp_chunk *c = m->first_large; c; c = c->next)
debug(x, "", c); {
RDUMP("%*s%p\n", dreq->indent+6, "", c);
large++;
}
RDUMP("%*scount=%d total=%d\n", dreq->indent+3, "", large, m->total_large);
} }
static struct resmem static struct resmem

View File

@ -30,7 +30,7 @@
* is freed upon shutdown of the module. * is freed upon shutdown of the module.
*/ */
static void pool_dump(resource *, unsigned); static void pool_dump(struct dump_request *, resource *);
static void pool_free(resource *); static void pool_free(resource *);
static resource *pool_lookup(resource *, unsigned long); static resource *pool_lookup(resource *, unsigned long);
static struct resmem pool_memsize(resource *P); static struct resmem pool_memsize(resource *P);
@ -135,17 +135,18 @@ pool_free(resource *P)
POOL_UNLOCK; POOL_UNLOCK;
} }
static void static void
pool_dump(resource *P, unsigned indent) pool_dump(struct dump_request *dreq, resource *P)
{ {
pool *p = (pool *) P; pool *p = (pool *) P;
POOL_LOCK; POOL_LOCK;
debug("%s\n", p->name); RDUMP("%s\n", p->name);
dreq->indent += 3;
WALK_TLIST_DELSAFE(resource, r, &p->inside) WALK_TLIST_DELSAFE(resource, r, &p->inside)
rdump(r, indent + 3); rdump(dreq, r);
dreq->indent -= 3;
POOL_UNLOCK; POOL_UNLOCK;
} }
@ -246,20 +247,28 @@ rfree(void *res)
* It works by calling a class-specific dump function. * It works by calling a class-specific dump function.
*/ */
void void
rdump(void *res, unsigned indent) rdump(struct dump_request *dreq, void *res)
{ {
char x[16]; char x[16];
resource *r = res; resource *r = res;
bsprintf(x, "%%%ds%%p ", indent); bsprintf(x, "%%%ds%%p ", dreq->indent);
debug(x, "", r); RDUMP(x, "", r);
if (r) if (r)
{ {
debug("%s ", r->class->name); RDUMP("%s ", r->class->name);
r->class->dump(r, indent); r->class->dump(dreq, r);
} }
else 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 struct resmem
@ -300,6 +309,7 @@ ralloc(pool *p, struct resclass *c)
return r; return r;
} }
#if 0
/** /**
* rlookup - look up a memory location * rlookup - look up a memory location
* @a: memory address * @a: memory address
@ -322,6 +332,7 @@ rlookup(unsigned long a)
else else
debug("Not found.\n"); debug("Not found.\n");
} }
#endif
/** /**
* resource_init - initialize the resource manager * resource_init - initialize the resource manager
@ -384,11 +395,11 @@ static void mbl_free(resource *r UNUSED)
{ {
} }
static void mbl_debug(resource *r, unsigned indent UNUSED) static void mbl_debug(struct dump_request *dreq, resource *r)
{ {
struct mblock *m = (struct mblock *) r; struct mblock *m = (struct mblock *) r;
debug("(size=%d)\n", m->size); RDUMP("(size=%d)\n", m->size);
} }
static resource * static resource *

View File

@ -42,7 +42,7 @@ struct resclass {
char *name; /* Resource class name */ char *name; /* Resource class name */
unsigned size; /* Standard size of single resource */ unsigned size; /* Standard size of single resource */
void (*free)(resource *); /* Freeing function */ void (*free)(resource *); /* Freeing function */
void (*dump)(resource *, unsigned indent); /* 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) */ 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 */ struct resmem (*memsize)(resource *); /* Return size of memory used by the resource, may be NULL */
}; };
@ -62,7 +62,10 @@ typedef struct pool {
void resource_init(void); void resource_init(void);
void rfree(void *); /* Free single resource */ void rfree(void *); /* Free single resource */
void rdump(void *, unsigned indent); /* 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 */ struct resmem rmemsize(void *res); /* Return size of memory used by the resource */
void rlookup(unsigned long); /* Look up address (only for debugging) */ void rlookup(unsigned long); /* Look up address (only for debugging) */
void rmove(void *, pool *); /* Move to a different pool */ void rmove(void *, pool *); /* Move to a different pool */

View File

@ -134,7 +134,7 @@ static inline void rt_unlock_source(struct rte_src *src)
void rt_init_sources(struct rte_owner *, const char *name, event_list *list); void rt_init_sources(struct rte_owner *, const char *name, event_list *list);
void rt_destroy_sources(struct rte_owner *, event *); void rt_destroy_sources(struct rte_owner *, event *);
void rt_dump_sources(struct rte_owner *); void rt_dump_sources(struct dump_request *, struct rte_owner *);
/* /*
* Route Attributes * Route Attributes
@ -350,7 +350,6 @@ static inline eattr *ea_find_by_name(ea_list *l, const char *name)
}) })
eattr *ea_walk(struct ea_walk_state *s, uint id, uint max); eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
void ea_dump(ea_list *);
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */ int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
uint ea_hash(ea_list *e); /* Calculate attributes hash value */ uint ea_hash(ea_list *e); /* Calculate attributes hash value */
ea_list *ea_append(ea_list *to, ea_list *what); ea_list *ea_append(ea_list *to, ea_list *what);
@ -639,8 +638,8 @@ static inline ea_list *ea_strip_to(ea_list *r, u32 strip_to)
return r; return r;
} }
void ea_dump(ea_list *); void ea_dump(struct dump_request *, ea_list *);
void ea_dump_all(void); void ea_dump_all(struct dump_request *);
void ea_show_list(struct cli *, ea_list *); void ea_show_list(struct cli *, ea_list *);
#endif #endif

View File

@ -41,7 +41,7 @@
#endif #endif
static void slab_free(resource *r); static void slab_free(resource *r);
static void slab_dump(resource *r, unsigned indent); static void slab_dump(struct dump_request *dreq, resource *r);
static resource *slab_lookup(resource *r, unsigned long addr); static resource *slab_lookup(resource *r, unsigned long addr);
static struct resmem slab_memsize(resource *r); static struct resmem slab_memsize(resource *r);
@ -393,27 +393,38 @@ slab_free(resource *r)
} }
static void static void
slab_dump(resource *r, unsigned indent UNUSED) slab_dump(struct dump_request *dreq, resource *r)
{ {
slab *s = (slab *) r; slab *s = (slab *) r;
int ec=0, pc=0, fc=0; int ec=0, pc=0, fc=0;
WALK_TLIST(sl_head, h, &s->empty_heads) RDUMP("(%d objs per %d bytes in page)\n",
ec++; s->objs_per_slab, s->obj_size);
WALK_TLIST(sl_head, h, &s->partial_heads)
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);
char x[16]; RDUMP("%*sempty:\n", dreq->indent+3, "");
bsprintf(x, "%%%ds%%s %%p\n", indent + 2);
WALK_TLIST(sl_head, h, &s->full_heads)
debug(x, "", "full", h);
WALK_TLIST(sl_head, h, &s->partial_heads)
debug(x, "", "partial", h);
WALK_TLIST(sl_head, h, &s->empty_heads) WALK_TLIST(sl_head, h, &s->empty_heads)
debug(x, "", "empty", h); {
RDUMP("%*s%p\n", dreq->indent+6, "", h);
ec++;
}
RDUMP("%*spartial:\n", dreq->indent+3, "");
WALK_TLIST(sl_head, h, &s->partial_heads)
{
RDUMP("%*s%p (", dreq->indent+6, "", h);
for (uint i=1; i<=s->head_bitfield_len; i++)
RDUMP("%08x", h->used_bits[s->head_bitfield_len-i]);
RDUMP(")\n");
pc++;
}
RDUMP("%*sfull:\n", dreq->indent+3, "");
WALK_TLIST(sl_head, h, &s->full_heads)
{
RDUMP("%*s%p\n", dreq->indent+6, "", h);
fc++;
}
RDUMP("%*sempty=%d partial=%d total=%d\n", dreq->indent+3, "", ec, pc, fc);
} }
static struct resmem static struct resmem

View File

@ -100,7 +100,7 @@ void sk_resume_rx(struct birdloop *loop, sock *s, int (*hook)(sock *, uint));
void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */ 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_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_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_ipv4(sock *s); /* True if socket is IPv4 */
int sk_is_ipv6(sock *s); /* True if socket is IPv6 */ int sk_is_ipv6(sock *s); /* True if socket is IPv6 */

View File

@ -60,19 +60,19 @@ tm_free(resource *r)
} }
static void static void
tm_dump(resource *r, unsigned indent UNUSED) tm_dump(struct dump_request *dreq, resource *r)
{ {
timer *t = (void *) 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) if (t->randomize)
debug("rand %d, ", t->randomize); RDUMP("rand %d, ", t->randomize);
if (t->recurrent) if (t->recurrent)
debug("recur %ld, ", t->recurrent); RDUMP("recur %ld, ", t->recurrent);
if (t->expires) if (t->expires)
debug("in loop %p expires in %ld ms)\n", t->loop, (t->expires - current_time()) TO_MS); RDUMP("in loop %p expires in %ld ms)\n", t->loop, (t->expires - current_time()) TO_MS);
else else
debug("inactive)\n"); RDUMP("inactive)\n");
} }

View File

@ -932,28 +932,27 @@ sym_args:
| sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; } | sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; }
; ;
CF_CLI_HELP(DUMP, ..., [[Dump debugging information to the given file]])
CF_CLI_HELP(DUMP, ..., [[Dump debugging information]]) CF_CLI(DUMP RESOURCES, text,, [[Dump all allocated resource]])
CF_CLI(DUMP RESOURCES,,, [[Dump all allocated resource]]) { cmd_dump_file(this_cli, $3, "resources", resource_dump); } ;
{ rdump(&root_pool, 0); cli_msg(0, ""); } ; CF_CLI(DUMP SOCKETS, text,, [[Dump open sockets]])
CF_CLI(DUMP SOCKETS,,, [[Dump open sockets]]) { cmd_dump_file(this_cli, $3, "sockets", sk_dump_all); } ;
{ sk_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP EVENTS, text,, [[Dump event log]])
CF_CLI(DUMP EVENTS,,, [[Dump event log]]) { cmd_dump_file(this_cli, $3, "event log", io_log_dump); } ;
{ io_log_dump(); cli_msg(0, ""); } ; CF_CLI(DUMP INTERFACES, text,, [[Dump interface information]])
CF_CLI(DUMP INTERFACES,,, [[Dump interface information]]) { cmd_dump_file(this_cli, $3, "interfaces", if_dump_all); } ;
{ if_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP NEIGHBORS, text,, [[Dump neighbor cache]])
CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]]) { cmd_dump_file(this_cli, $3, "neighbor cache", neigh_dump_all); } ;
{ neigh_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP ATTRIBUTES, text,, [[Dump attribute cache]])
CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]]) { cmd_dump_file(this_cli, $3, "attribute cache", ea_dump_all); } ;
{ ea_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP ROUTES, text,, [[Dump routes]])
CF_CLI(DUMP ROUTES,,, [[Dump routes]]) { cmd_dump_file(this_cli, $3, "routing tables", rt_dump_all); } ;
{ rt_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP TABLES, text,, [[Dump table connections]])
CF_CLI(DUMP TABLES,,, [[Dump table connections]]) { cmd_dump_file(this_cli, $3, "table connections", rt_dump_hooks_all); } ;
{ rt_dump_hooks_all(); cli_msg(0, ""); } ; CF_CLI(DUMP PROTOCOLS, text,, [[Dump protocol information]])
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { cmd_dump_file(this_cli, $3, "protocols", protos_dump_all); } ;
{ protos_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP FILTER ALL, text,, [[Dump all filters in linearized form]])
CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]]) { cmd_dump_file(this_cli, $4, "filter bytecode", filters_dump_all); } ;
{ filters_dump_all(); cli_msg(0, ""); } ;
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]]) CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
{ cmd_eval(f_linearize($2, 1)); } ; { cmd_eval(f_linearize($2, 1)); } ;

View File

@ -52,8 +52,8 @@ static void if_recalc_preferred(struct iface *i);
static void ifa_delete_locked(struct ifa *a); static void ifa_delete_locked(struct ifa *a);
static void ifa_dump_locked(struct ifa *); static void ifa_dump_locked(struct dump_request *, struct ifa *);
static void if_dump_locked(struct iface *); static void if_dump_locked(struct dump_request *, struct iface *);
struct iface * struct iface *
if_walk_first(void) if_walk_first(void)
@ -85,17 +85,17 @@ if_walk_done(void)
* This function dumps contents of an &ifa to the debug output. * This function dumps contents of an &ifa to the debug output.
*/ */
void void
ifa_dump(struct ifa *a) ifa_dump(struct dump_request *dreq, struct ifa *a)
{ {
IFACE_LOCK; IFACE_LOCK;
ifa_dump_locked(a); ifa_dump_locked(dreq, a);
IFACE_UNLOCK; IFACE_UNLOCK;
} }
static void static void
ifa_dump_locked(struct ifa *a) ifa_dump_locked(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_PRIMARY) ? " PRIMARY" : "",
(a->flags & IA_SECONDARY) ? " SEC" : "", (a->flags & IA_SECONDARY) ? " SEC" : "",
(a->flags & IA_HOST) ? " HOST" : "", (a->flags & IA_HOST) ? " HOST" : "",
@ -110,43 +110,43 @@ ifa_dump_locked(struct ifa *a)
* network interface to the debug output. * network interface to the debug output.
*/ */
void void
if_dump(struct iface *i) if_dump(struct dump_request *dreq, struct iface *i)
{ {
IFACE_LOCK; IFACE_LOCK;
if_dump_locked(i); if_dump_locked(dreq, i);
IFACE_UNLOCK; IFACE_UNLOCK;
} }
static void static void
if_dump_locked(struct iface *i) if_dump_locked(struct dump_request *dreq, struct iface *i)
{ {
struct ifa *a; struct ifa *a;
debug("IF%d: %s", i->index, i->name); RDUMP("IF%d: %s", i->index, i->name);
if (i->flags & IF_SHUTDOWN) if (i->flags & IF_SHUTDOWN)
debug(" SHUTDOWN"); RDUMP(" SHUTDOWN");
if (i->flags & IF_UP) if (i->flags & IF_UP)
debug(" UP"); RDUMP(" UP");
else else
debug(" DOWN"); RDUMP(" DOWN");
if (i->flags & IF_ADMIN_UP) if (i->flags & IF_ADMIN_UP)
debug(" LINK-UP"); RDUMP(" LINK-UP");
if (i->flags & IF_MULTIACCESS) if (i->flags & IF_MULTIACCESS)
debug(" MA"); RDUMP(" MA");
if (i->flags & IF_BROADCAST) if (i->flags & IF_BROADCAST)
debug(" BC"); RDUMP(" BC");
if (i->flags & IF_MULTICAST) if (i->flags & IF_MULTICAST)
debug(" MC"); RDUMP(" MC");
if (i->flags & IF_LOOPBACK) if (i->flags & IF_LOOPBACK)
debug(" LOOP"); RDUMP(" LOOP");
if (i->flags & IF_IGNORE) if (i->flags & IF_IGNORE)
debug(" IGN"); RDUMP(" IGN");
if (i->flags & IF_TMP_DOWN) if (i->flags & IF_TMP_DOWN)
debug(" TDOWN"); RDUMP(" TDOWN");
debug(" MTU=%d\n", i->mtu); RDUMP(" MTU=%d\n", i->mtu);
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
{ {
ifa_dump_locked(a); ifa_dump_locked(dreq, a);
ASSERT(!!(a->flags & IA_PRIMARY) == ASSERT(!!(a->flags & IA_PRIMARY) ==
((a == i->addr4) || (a == i->addr6) || (a == i->llv6))); ((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
} }
@ -159,13 +159,13 @@ if_dump_locked(struct iface *i)
* interfaces to the debug output. * interfaces to the debug output.
*/ */
void void
if_dump_all(void) if_dump_all(struct dump_request *dreq)
{ {
debug("Known network interfaces:\n"); RDUMP("Known network interfaces:\n");
IFACE_WALK(i) IFACE_WALK(i)
if_dump(i); if_dump_locked(dreq, i);
rcu_read_lock(); rcu_read_lock();
debug("Router ID: %08x\n", atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id); RDUMP("Router ID: %08x\n", atomic_load_explicit(&global_runtime, memory_order_relaxed)->router_id);
rcu_read_unlock(); rcu_read_unlock();
} }

View File

@ -107,9 +107,9 @@ struct iface {
#define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6) #define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
void if_init(void); void if_init(void);
void if_dump(struct iface *); void if_dump(struct dump_request *dreq, struct iface *);
void if_dump_all(void); void if_dump_all(struct dump_request *);
void ifa_dump(struct ifa *); void ifa_dump(struct dump_request *dreq, struct ifa *);
void if_show(void); void if_show(void);
void if_show_summary(void); void if_show_summary(void);
struct iface *if_update(struct iface *); struct iface *if_update(struct iface *);
@ -168,7 +168,7 @@ typedef struct neighbor {
neighbor *neigh_find(struct proto *p, ip_addr a, struct iface *ifa, uint flags); neighbor *neigh_find(struct proto *p, ip_addr a, struct iface *ifa, uint flags);
void neigh_dump_all(void); void neigh_dump_all(struct dump_request *);
void neigh_if_up(struct iface *); void neigh_if_up(struct iface *);
void neigh_if_down(struct iface *); void neigh_if_down(struct iface *);
void neigh_if_link(struct iface *); void neigh_if_link(struct iface *);

View File

@ -107,14 +107,14 @@ olock_free(resource *r)
} }
static void static void
olock_dump(resource *r, unsigned indent UNUSED) olock_dump(struct dump_request *dreq, resource *r)
{ {
struct object_lock *l = (struct object_lock *) r; struct object_lock *l = (struct object_lock *) r;
static char *olock_states[] = { "free", "locked", "waiting", "event" }; 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)) if (!EMPTY_LIST(l->waiters))
debug(" [wanted]\n"); RDUMP(" [wanted]\n");
} }
static struct resclass olock_class = { static struct resclass olock_class = {

View File

@ -302,17 +302,17 @@ bad:
* This functions dumps the contents of a given neighbor entry to debug output. * This functions dumps the contents of a given neighbor entry to debug output.
*/ */
static void static 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->iface ? n->iface->name : "[]",
n->ifreq ? n->ifreq->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) if (n->flags & NEF_STICKY)
debug(" STICKY"); RDUMP(" STICKY");
if (n->flags & NEF_ONLINK) if (n->flags & NEF_ONLINK)
debug(" ONLINK"); RDUMP(" ONLINK");
debug("\n"); RDUMP("\n");
} }
/** /**
@ -321,18 +321,18 @@ neigh_dump(neighbor *n)
* This function dumps the contents of the neighbor cache to debug output. * This function dumps the contents of the neighbor cache to debug output.
*/ */
void void
neigh_dump_all(void) neigh_dump_all(struct dump_request *dreq)
{ {
IFACE_LOCK; IFACE_LOCK;
neighbor *n; neighbor *n;
int i; int i;
debug("Known neighbors:\n"); RDUMP("Known neighbors:\n");
for(i=0; i<NEIGH_HASH_SIZE; i++) for(i=0; i<NEIGH_HASH_SIZE; i++)
WALK_LIST(n, neigh_hash_table[i]) WALK_LIST(n, neigh_hash_table[i])
neigh_dump(n); neigh_dump(dreq, n);
debug("\n"); RDUMP("\n");
IFACE_UNLOCK; IFACE_UNLOCK;
} }

View File

@ -2053,14 +2053,14 @@ channel_graceful_restart_unlock(struct channel *c)
* the internals. * the internals.
*/ */
void void
protos_dump_all(void) protos_dump_all(struct dump_request *dreq)
{ {
debug("Protocols:\n"); RDUMP("Protocols:\n");
WALK_TLIST(proto, p, &global_proto_list) PROTO_LOCKED_FROM_MAIN(p) WALK_TLIST(proto, p, &global_proto_list) PROTO_LOCKED_FROM_MAIN(p)
{ {
#define DPF(x) (p->x ? " " #x : "") #define DPF(x) (p->x ? " " #x : "")
debug(" protocol %s (%p) state %s with %d active channels flags: %s%s%s\n", RDUMP(" protocol %s (%p) state %s with %d active channels flags: %s%s%s\n",
p->name, p, p_states[p->proto_state], p->active_channels, p->name, p, p_states[p->proto_state], p->active_channels,
DPF(disabled), DPF(do_stop), DPF(reconfiguring)); DPF(disabled), DPF(do_stop), DPF(reconfiguring));
#undef DPF #undef DPF
@ -2068,23 +2068,24 @@ protos_dump_all(void)
struct channel *c; struct channel *c;
WALK_LIST(c, p->channels) WALK_LIST(c, p->channels)
{ {
debug("\tTABLE %s\n", c->table->name); RDUMP("\tTABLE %s\n", c->table->name);
if (c->in_filter) 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) if (c->out_filter)
debug("\tOutput filter: %s\n", filter_name(c->out_filter)); RDUMP("\tOutput filter: %s\n", filter_name(c->out_filter));
debug("\tChannel state: %s/%s/%s\n", c_states[c->channel_state], RDUMP("\tChannel state: %s/%s/%s\n", c_states[c->channel_state],
c->in_req.hook ? rt_import_state_name(rt_import_get_state(c->in_req.hook)) : "-", c->in_req.hook ? rt_import_state_name(rt_import_get_state(c->in_req.hook)) : "-",
rt_export_state_name(rt_export_get_state(&c->out_req))); rt_export_state_name(rt_export_get_state(&c->out_req)));
} }
debug("\tSOURCES\n"); RDUMP("\tSOURCES\n");
rt_dump_sources(&p->sources); if (p->proto_state != PS_DOWN_XX)
rt_dump_sources(dreq, &p->sources);
if (p->proto->dump && if (p->proto->dump &&
(p->proto_state != PS_DOWN_XX) && (p->proto_state != PS_DOWN_XX) &&
(p->proto_state != PS_FLUSH)) (p->proto_state != PS_FLUSH))
p->proto->dump(p); p->proto->dump(p, dreq);
} }
} }

View File

@ -63,7 +63,7 @@ struct protocol {
void (*postconfig)(struct proto_config *); /* After configuring each instance */ void (*postconfig)(struct proto_config *); /* After configuring each instance */
struct proto * (*init)(struct proto_config *); /* Create new instance */ struct proto * (*init)(struct proto_config *); /* Create new instance */
int (*reconfigure)(struct proto *, struct proto_config *); /* Try to reconfigure instance, returns success */ 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 (*start)(struct proto *); /* Start the instance */
int (*shutdown)(struct proto *); /* Stop the instance */ int (*shutdown)(struct proto *); /* Stop the instance */
void (*cleanup)(struct proto *); /* Cleanup the instance right before tearing it all down */ void (*cleanup)(struct proto *); /* Cleanup the instance right before tearing it all down */
@ -78,7 +78,7 @@ void proto_build(struct protocol *); /* Called from protocol to register itself
void protos_preconfig(struct config *); void protos_preconfig(struct config *);
void protos_commit(struct config *new, struct config *old, int type); void protos_commit(struct config *new, struct config *old, int type);
struct proto * proto_spawn(struct proto_config *cf, uint disabled); 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_UNKNOWN 0 /* Attribute not recognized */
#define GA_NAME 1 /* Result = name */ #define GA_NAME 1 /* Result = name */

View File

@ -809,11 +809,11 @@ rte *rt_export_merged(struct channel *c, const struct rt_export_feed *feed, linp
void rt_refresh_begin(struct rt_import_request *); void rt_refresh_begin(struct rt_import_request *);
void rt_refresh_end(struct rt_import_request *); void rt_refresh_end(struct rt_import_request *);
void rt_schedule_prune(struct rtable_private *t); void rt_schedule_prune(struct rtable_private *t);
void rte_dump(struct rte_storage *); void rte_dump(struct dump_request *, struct rte_storage *);
void rt_dump(rtable *); void rt_dump(struct dump_request *, rtable *);
void rt_dump_all(void); void rt_dump_all(struct dump_request *);
void rt_dump_hooks(rtable *); void rt_dump_hooks(struct dump_request *, rtable *);
void rt_dump_hooks_all(void); void rt_dump_hooks_all(struct dump_request *);
int rt_reload_channel(struct channel *c); int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c); void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all); void rt_prune_sync(rtable *t, int all);

View File

@ -390,18 +390,18 @@ rt_prune_sources(void *data)
} }
void void
rt_dump_sources(struct rte_owner *o) rt_dump_sources(struct dump_request *dreq, struct rte_owner *o)
{ {
debug("\t%s: hord=%u, uc=%u, cnt=%u prune=%p, stop=%p\n", RDUMP("\t%s: hord=%u, uc=%u, cnt=%u prune=%p, stop=%p\n",
o->name, o->hash.order, o->uc, o->hash.count, o->prune, o->stop); o->name, o->hash.order, o->uc, o->hash.count, o->prune, o->stop);
debug("\tget_route_info=%p, better=%p, mergable=%p, igp_metric=%p, recalculate=%p", RDUMP("\tget_route_info=%p, better=%p, mergable=%p, igp_metric=%p, recalculate=%p",
o->class->get_route_info, o->class->rte_better, o->class->rte_mergable, o->class->get_route_info, o->class->rte_better, o->class->rte_mergable,
o->class->rte_igp_metric, o->rte_recalculate); o->class->rte_igp_metric, o->rte_recalculate);
int splitting = 0; int splitting = 0;
HASH_WALK(o->hash, next, src) HASH_WALK(o->hash, next, src)
{ {
debug("%c%c%uL %uG %luU", RDUMP("%c%c%uL %uG %luU",
(splitting % 8) ? ',' : '\n', (splitting % 8) ? ',' : '\n',
(splitting % 8) ? ' ' : '\t', (splitting % 8) ? ' ' : '\t',
src->private_id, src->global_id, src->private_id, src->global_id,
@ -410,7 +410,7 @@ rt_dump_sources(struct rte_owner *o)
splitting++; splitting++;
} }
HASH_WALK_END; HASH_WALK_END;
debug("\n"); RDUMP("\n");
} }
static struct rte_owner_class default_rte_owner_class; static struct rte_owner_class default_rte_owner_class;
@ -653,10 +653,10 @@ ea_class_ref_free(resource *r)
} }
static void static void
ea_class_ref_dump(resource *r, unsigned indent UNUSED) ea_class_ref_dump(struct dump_request *dreq, resource *r)
{ {
SKIP_BACK_DECLARE(struct ea_class_ref, ref, r, r); SKIP_BACK_DECLARE(struct ea_class_ref, ref, r, r);
debug("name \"%s\", type=%d\n", ref->class->name, ref->class->type); RDUMP("name \"%s\", type=%d\n", ref->class->name, ref->class->type);
} }
static struct resclass ea_class_ref_class = { static struct resclass ea_class_ref_class = {
@ -1348,27 +1348,27 @@ ea_show(struct cli *c, const eattr *e)
} }
static void static void
nexthop_dump(const struct adata *ad) nexthop_dump(struct dump_request *dreq, const struct adata *ad)
{ {
struct nexthop_adata *nhad = (struct nexthop_adata *) ad; struct nexthop_adata *nhad = (struct nexthop_adata *) ad;
debug(":"); RDUMP(":");
if (!NEXTHOP_IS_REACHABLE(nhad)) if (!NEXTHOP_IS_REACHABLE(nhad))
{ {
const char *name = rta_dest_name(nhad->dest); const char *name = rta_dest_name(nhad->dest);
if (name) if (name)
debug(" %s", name); RDUMP(" %s", name);
else else
debug(" D%d", nhad->dest); RDUMP(" D%d", nhad->dest);
} }
else NEXTHOP_WALK(nh, nhad) else NEXTHOP_WALK(nh, nhad)
{ {
if (ipa_nonzero(nh->gw)) debug(" ->%I", nh->gw); if (ipa_nonzero(nh->gw)) RDUMP(" ->%I", nh->gw);
if (nh->labels) debug(" L %d", nh->label[0]); if (nh->labels) RDUMP(" L %d", nh->label[0]);
for (int i=1; i<nh->labels; i++) for (int i=1; i<nh->labels; i++)
debug("/%d", nh->label[i]); RDUMP("/%d", nh->label[i]);
debug(" [%s]", nh->iface ? nh->iface->name : "???"); RDUMP(" [%s]", nh->iface ? nh->iface->name : "???");
} }
} }
@ -1380,19 +1380,19 @@ nexthop_dump(const struct adata *ad)
* the debug output. * the debug output.
*/ */
void void
ea_dump(ea_list *e) ea_dump(struct dump_request *dreq, ea_list *e)
{ {
int i; int i;
if (!e) if (!e)
{ {
debug("NONE"); RDUMP("NONE");
return; return;
} }
while (e) while (e)
{ {
struct ea_storage *s = e->stored ? ea_get_storage(e) : NULL; struct ea_storage *s = e->stored ? ea_get_storage(e) : NULL;
debug("[%c%c] overlay=%d uc=%d h=%08x", RDUMP("[%c%c] overlay=%d uc=%d h=%08x",
(e->flags & EALF_SORTED) ? 'S' : 's', (e->flags & EALF_SORTED) ? 'S' : 's',
(e->flags & EALF_BISECT) ? 'B' : 'b', (e->flags & EALF_BISECT) ? 'B' : 'b',
e->stored, e->stored,
@ -1403,34 +1403,34 @@ ea_dump(ea_list *e)
eattr *a = &e->attrs[i]; eattr *a = &e->attrs[i];
struct ea_class *clp = (a->id < ea_class_max) ? ea_class_global[a->id] : NULL; struct ea_class *clp = (a->id < ea_class_max) ? ea_class_global[a->id] : NULL;
if (clp) if (clp)
debug(" %s", clp->name); RDUMP(" %s", clp->name);
else else
debug(" 0x%x", a->id); RDUMP(" 0x%x", a->id);
debug(".%02x", a->flags); RDUMP(".%02x", a->flags);
debug("=%c", RDUMP("=%c",
"?iO?IRP???S??pE?" "?iO?IRP???S??pE?"
"??L???N?????????" "??L???N?????????"
"?o???r??????????" [a->type]); "?o???r??????????" [a->type]);
if (a->originated) if (a->originated)
debug("o"); RDUMP("o");
if (a->undef) if (a->undef)
debug(":undef"); RDUMP(":undef");
else if (a->type & EAF_EMBEDDED) else if (a->type & EAF_EMBEDDED)
debug(":%08x", a->u.data); RDUMP(":%08x", a->u.data);
else if (a->id == ea_gen_nexthop.id) else if (a->id == ea_gen_nexthop.id)
nexthop_dump(a->u.ptr); nexthop_dump(dreq, a->u.ptr);
else else
{ {
int j, len = a->u.ptr->length; int j, len = a->u.ptr->length;
debug("[%d]:", len); RDUMP("[%d]:", len);
for(j=0; j<len; j++) for(j=0; j<len; j++)
debug("%02x", a->u.ptr->data[j]); RDUMP("%02x", a->u.ptr->data[j]);
} }
debug(" "); RDUMP(" ");
} }
if (e = e->next) if (e = e->next)
debug(" | "); RDUMP(" | ");
} }
} }
@ -1681,20 +1681,20 @@ ea_free_deferred(struct deferred_call *dc)
* to the debug output. * to the debug output.
*/ */
void void
ea_dump_all(void) ea_dump_all(struct dump_request *dreq)
{ {
debug("Route attribute cache (%d entries, order %d):\n", RDUMP("Route attribute cache (%d entries, order %d):\n",
atomic_load_explicit(&rta_hash_table.count, memory_order_relaxed), atomic_load_explicit(&rta_hash_table.count, memory_order_relaxed),
atomic_load_explicit(&rta_hash_table.cur, memory_order_relaxed)->order); atomic_load_explicit(&rta_hash_table.cur, memory_order_relaxed)->order);
SPINHASH_WALK(rta_hash_table, RTAH, a) SPINHASH_WALK(rta_hash_table, RTAH, a)
{ {
debug("%p ", a); RDUMP("%p ", a);
ea_dump(a->l); ea_dump(dreq, a->l);
debug("\n"); RDUMP("\n");
} }
SPINHASH_WALK_END; SPINHASH_WALK_END;
debug("\n"); RDUMP("\n");
} }
void void

View File

@ -2749,15 +2749,15 @@ rt_refresh_trace(struct rtable_private *tab, struct rt_import_hook *ih, const ch
* This functions dumps contents of a &rte to debug output. * This functions dumps contents of a &rte to debug output.
*/ */
void void
rte_dump(struct rte_storage *e) rte_dump(struct dump_request *dreq, struct rte_storage *e)
{ {
debug("(%u) %-1N", NET_TO_INDEX(e->rte.net)->index, e->rte.net); RDUMP("(%u) %-1N", NET_TO_INDEX(e->rte.net)->index, e->rte.net);
debug("ID=%d ", e->rte.id); RDUMP("ID=%d ", e->rte.id);
debug("SENDER=%s ", e->rte.sender->req->name); RDUMP("SENDER=%s ", e->rte.sender->req->name);
debug("PF=%02x ", e->rte.pflags); RDUMP("PF=%02x ", e->rte.pflags);
debug("SRC=%uG ", e->rte.src->global_id); RDUMP("SRC=%uG ", e->rte.src->global_id);
ea_dump(e->rte.attrs); ea_dump(dreq, e->rte.attrs);
debug("\n"); RDUMP("\n");
} }
/** /**
@ -2767,20 +2767,20 @@ rte_dump(struct rte_storage *e)
* This function dumps contents of a given routing table to debug output. * This function dumps contents of a given routing table to debug output.
*/ */
void void
rt_dump(rtable *tab) rt_dump(struct dump_request *dreq, rtable *tab)
{ {
RT_READ(tab, tp); RT_READ(tab, tp);
/* Looking at priv.deleted is technically unsafe but we don't care */ /* Looking at priv.deleted is technically unsafe but we don't care */
debug("Dump of routing table <%s>%s\n", tab->name, OBSREF_GET(tab->priv.deleted) ? " (deleted)" : ""); RDUMP("Dump of routing table <%s>%s\n", tab->name, OBSREF_GET(tab->priv.deleted) ? " (deleted)" : "");
u32 bs = atomic_load_explicit(&tp->t->routes_block_size, memory_order_relaxed); u32 bs = atomic_load_explicit(&tp->t->routes_block_size, memory_order_relaxed);
net *routes = atomic_load_explicit(&tp->t->routes, memory_order_relaxed); net *routes = atomic_load_explicit(&tp->t->routes, memory_order_relaxed);
for (u32 i = 0; i < bs; i++) for (u32 i = 0; i < bs; i++)
NET_READ_WALK_ROUTES(tp, &routes[i], ep, e) NET_READ_WALK_ROUTES(tp, &routes[i], ep, e)
rte_dump(e); rte_dump(dreq, e);
debug("\n"); RDUMP("\n");
} }
/** /**
@ -2789,35 +2789,35 @@ rt_dump(rtable *tab)
* This function dumps contents of all routing tables to debug output. * This function dumps contents of all routing tables to debug output.
*/ */
void void
rt_dump_all(void) rt_dump_all(struct dump_request *dreq)
{ {
rtable *t; rtable *t;
node *n; node *n;
WALK_LIST2(t, n, routing_tables, n) WALK_LIST2(t, n, routing_tables, n)
rt_dump(t); rt_dump(dreq, t);
WALK_LIST2(t, n, deleted_routing_tables, n) WALK_LIST2(t, n, deleted_routing_tables, n)
rt_dump(t); rt_dump(dreq, t);
} }
void void
rt_dump_hooks(rtable *tp) rt_dump_hooks(struct dump_request *dreq, rtable *tp)
{ {
RT_LOCKED(tp, tab) RT_LOCKED(tp, tab)
{ {
debug("Dump of hooks in routing table <%s>%s\n", tab->name, OBSREF_GET(tab->deleted) ? " (deleted)" : ""); RDUMP("Dump of hooks in routing table <%s>%s\n", tab->name, OBSREF_GET(tab->deleted) ? " (deleted)" : "");
debug(" nhu_state=%u use_count=%d rt_count=%u\n", RDUMP(" nhu_state=%u use_count=%d rt_count=%u\n",
tab->nhu_state, tab->use_count, tab->rt_count); tab->nhu_state, tab->use_count, tab->rt_count);
debug(" last_rt_change=%t gc_time=%t gc_counter=%d prune_state=%u\n", RDUMP(" last_rt_change=%t gc_time=%t gc_counter=%d prune_state=%u\n",
tab->last_rt_change, tab->gc_time, tab->gc_counter, tab->prune_state); tab->last_rt_change, tab->gc_time, tab->gc_counter, tab->prune_state);
struct rt_import_hook *ih; struct rt_import_hook *ih;
WALK_LIST(ih, tab->imports) WALK_LIST(ih, tab->imports)
{ {
ih->req->dump_req(ih->req); ih->req->dump_req(ih->req);
debug(" Import hook %p requested by %p: pref=%u" RDUMP(" Import hook %p requested by %p: pref=%u"
" last_state_change=%t import_state=%u stopped=%p\n", " last_state_change=%t import_state=%u stopped=%p\n",
ih, ih->req, ih->stats.pref, ih, ih->req, ih->stats.pref,
ih->last_state_change, ih->import_state, ih->stopped); ih->last_state_change, ih->import_state, ih->stopped);
@ -2829,30 +2829,30 @@ rt_dump_hooks(rtable *tp)
{ {
SKIP_BACK_DECLARE(struct rt_export_hook, eh, recipient, r); SKIP_BACK_DECLARE(struct rt_export_hook, eh, recipient, r);
eh->req->dump_req(eh->req); eh->req->dump_req(eh->req);
debug(" Export hook %p requested by %p:" RDUMP(" Export hook %p requested by %p:"
" refeed_pending=%u last_state_change=%t export_state=%u\n", " refeed_pending=%u last_state_change=%t export_state=%u\n",
eh, eh->req, eh->refeed_pending, eh->last_state_change, eh, eh->req, eh->refeed_pending, eh->last_state_change,
atomic_load_explicit(&eh->export_state, memory_order_relaxed)); atomic_load_explicit(&eh->export_state, memory_order_relaxed));
} }
#endif #endif
debug("\n"); RDUMP("\n");
} }
} }
void void
rt_dump_hooks_all(void) rt_dump_hooks_all(struct dump_request *dreq)
{ {
rtable *t; rtable *t;
node *n; node *n;
debug("Dump of all table hooks\n"); RDUMP("Dump of all table hooks\n");
WALK_LIST2(t, n, routing_tables, n) WALK_LIST2(t, n, routing_tables, n)
rt_dump_hooks(t); rt_dump_hooks(dreq, t);
WALK_LIST2(t, n, deleted_routing_tables, n) WALK_LIST2(t, n, deleted_routing_tables, n)
rt_dump_hooks(t); rt_dump_hooks(dreq, t);
} }
static inline void static inline void
@ -3209,11 +3209,11 @@ rt_free(resource *_r)
} }
static void static void
rt_res_dump(resource *_r, unsigned indent UNUSED) rt_res_dump(struct dump_request *dreq, resource *_r)
{ {
SKIP_BACK_DECLARE(struct rtable_private, r, r, _r); SKIP_BACK_DECLARE(struct rtable_private, r, r, _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); r->name, net_label[r->addr_type], r->rt_count, r->use_count);
#if 0 #if 0

View File

@ -2103,82 +2103,82 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
*/ */
static void 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->router_id, s->seqno, s->metric,
s->expires ? s->expires - current_time() : 0); s->expires ? s->expires - current_time() : 0);
} }
static void 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->neigh->addr, r->neigh->ifa->ifname, r->seqno, r->advert_metric, r->metric,
r->router_id, r->expires ? r->expires - current_time() : 0); r->router_id, r->expires ? r->expires - current_time() : 0);
} }
static void 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_source *s;
struct babel_route *r; 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) WALK_LIST(s,e->sources)
{ debug(" "); babel_dump_source(s); } { RDUMP(" "); babel_dump_source(dreq, s); }
WALK_LIST(r,e->routes) WALK_LIST(r,e->routes)
{ {
debug(" "); RDUMP(" ");
if (r == e->selected) debug("*"); if (r == e->selected) RDUMP("*");
babel_dump_route(r); babel_dump_route(dreq, r);
} }
} }
static void 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->addr, n->txcost, n->hello_map, n->next_hello_seqno,
n->hello_expiry ? n->hello_expiry - current_time() : 0, n->hello_expiry ? n->hello_expiry - current_time() : 0,
n->ihu_expiry ? n->ihu_expiry - current_time() : 0); n->ihu_expiry ? n->ihu_expiry - current_time() : 0);
} }
static void static void
babel_dump_iface(struct babel_iface *ifa) babel_dump_iface(struct dump_request *dreq, struct babel_iface *ifa)
{ {
struct babel_neighbor *n; 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->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno,
ifa->cf->hello_interval, ifa->cf->update_interval); 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) WALK_LIST(n, ifa->neigh_list)
{ debug(" "); babel_dump_neighbor(n); } { RDUMP(" "); babel_dump_neighbor(dreq, n); }
} }
static void 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_proto *p = (struct babel_proto *) P;
struct babel_iface *ifa; 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) WALK_LIST(ifa, p->interfaces)
babel_dump_iface(ifa); babel_dump_iface(dreq, ifa);
FIB_WALK(&p->ip4_rtable, struct babel_entry, e) FIB_WALK(&p->ip4_rtable, struct babel_entry, e)
{ {
babel_dump_entry(e); babel_dump_entry(dreq, e);
} }
FIB_WALK_END; FIB_WALK_END;
FIB_WALK(&p->ip6_rtable, struct babel_entry, e) FIB_WALK(&p->ip6_rtable, struct babel_entry, e)
{ {
babel_dump_entry(e); babel_dump_entry(dreq, e);
} }
FIB_WALK_END; FIB_WALK_END;
} }

View File

@ -929,11 +929,11 @@ bfd_request_free(resource *r)
} }
static void static void
bfd_request_dump(resource *r, unsigned indent UNUSED) bfd_request_dump(struct dump_request *dreq, resource *r)
{ {
struct bfd_request *req = (struct bfd_request *) 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 = { static struct resclass bfd_request_class = {

View File

@ -236,7 +236,7 @@ static void
bmp_tx_resource_free(resource *r UNUSED) {} bmp_tx_resource_free(resource *r UNUSED) {}
static void static void
bmp_tx_resource_dump(resource *r UNUSED, uint indent UNUSED) {} bmp_tx_resource_dump(struct dump_request *dreq UNUSED, resource *r UNUSED) {}
static struct resmem static struct resmem
bmp_tx_resource_memsize(resource *r) bmp_tx_resource_memsize(resource *r)

View File

@ -334,32 +334,31 @@ ospf_start(struct proto *P)
} }
static void 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_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa; struct ospf_iface *ifa;
struct ospf_neighbor *n; 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) WALK_LIST(ifa, p->iface_list)
{ {
OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname); RDUMP("Interface: %s\n", ifa->ifname);
OSPF_TRACE(D_EVENTS, "state: %u", ifa->state); RDUMP("state: %u\n", ifa->state);
OSPF_TRACE(D_EVENTS, "DR: %R", ifa->drid); RDUMP("DR: %R\n", ifa->drid);
OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid); RDUMP("BDR: %R\n", ifa->bdrid);
WALK_LIST(n, ifa->neigh_list) 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_top_dump(p->gr, p);
OSPF_TRACE(D_EVENTS, "LSA graph dump finished"); RDUMP("LSA graph dump finished");
*/ */
neigh_dump_all();
} }
static struct proto * static struct proto *

View File

@ -1351,7 +1351,7 @@ rip_show_neighbors(struct proto *P, const char *iff)
} }
static void 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_proto *p = (struct rip_proto *) P;
struct rip_iface *ifa; struct rip_iface *ifa;
@ -1360,12 +1360,12 @@ rip_dump(struct proto *P)
i = 0; i = 0;
FIB_WALK(&p->rtable, struct rip_entry, en) 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)", i++, en->n.addr, en->next_hop, en->iface ? en->iface->name : "(null)",
en->valid, en->metric, current_time() - en->changed); en->valid, en->metric, current_time() - en->changed);
for (struct rip_rte *e = en->routes; e; e = e->next) 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()); e->next_hop, e->metric, e->expires - current_time());
} }
FIB_WALK_END; FIB_WALK_END;
@ -1373,7 +1373,7 @@ rip_dump(struct proto *P)
i = 0; i = 0;
WALK_LIST(ifa, p->iface_list) 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, i++, ifa->iface->name, ifa->sk ? ifa->sk->daddr : IPA_NONE,
ifa->up, ifa->tx_active); ifa->up, ifa->tx_active);
} }

View File

@ -606,27 +606,27 @@ static_cleanup(struct proto *P)
} }
static void 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->dest == RTD_UNICAST)
if (r->iface && ipa_zero(r->via)) if (r->iface && ipa_zero(r->via))
debug("dev %s\n", r->iface->name); RDUMP("dev %s\n", r->iface->name);
else else
debug("via %I%J\n", r->via, r->iface); RDUMP("via %I%J\n", r->via, r->iface);
else else
debug("rtd %d\n", r->dest); RDUMP("rtd %d\n", r->dest);
} }
static void 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_config *c = (void *) P->cf;
struct static_route *r; struct static_route *r;
debug("Static routes:\n"); RDUMP("Static routes:\n");
WALK_LIST(r, c->routes) 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 ) #define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )

View File

@ -431,6 +431,30 @@ page_cleanup(void *_ UNUSED)
} }
#endif #endif
void
page_dump(struct dump_request *dreq)
{
#ifdef HAVE_MMAP
RDUMP("Hot pages:\n");
struct free_page *fptop = PAGE_STACK_GET;
for (struct free_page *fp = fptop; fp; fp = atomic_load_explicit(&fp->next, memory_order_relaxed))
RDUMP(" %p\n", fp);
PAGE_STACK_PUT(fptop);
RDUMP("Cold pages:\n");
LOCK_DOMAIN(resource, empty_pages_domain);
for (struct empty_pages *ep = empty_pages; ep; ep = ep->next)
{
RDUMP(" %p (index)\n", ep);
for (uint i=0; i<ep->pos; i++)
RDUMP(" %p\n", ep->pages[i]);
}
UNLOCK_DOMAIN(resource, empty_pages_domain);
#endif
}
void void
resource_sys_init(void) resource_sys_init(void)
{ {

View File

@ -21,6 +21,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/un.h> #include <sys/un.h>
#include <poll.h> #include <poll.h>
@ -43,6 +44,7 @@
#include "lib/timer.h" #include "lib/timer.h"
#include "lib/string.h" #include "lib/string.h"
#include "nest/iface.h" #include "nest/iface.h"
#include "nest/cli.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "sysdep/unix/unix.h" #include "sysdep/unix/unix.h"
@ -90,11 +92,11 @@ rf_free(resource *r)
} }
static void static void
rf_dump(resource *r, unsigned indent UNUSED) rf_dump(struct dump_request *dreq, resource *r)
{ {
struct rfile *a = (struct rfile *) r; struct rfile *a = (struct rfile *) r;
debug("(fd %d)\n", a->fd); RDUMP("(fd %d)\n", a->fd);
} }
static struct resclass rf_class = { static struct resclass rf_class = {
@ -285,6 +287,147 @@ rf_writev(struct rfile *r, struct iovec *iov, int iov_count)
} }
} }
/*
* 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 * Time clock
@ -1069,12 +1212,12 @@ sk_reallocate(sock *s)
} }
static void static void
sk_dump(resource *r, unsigned indent UNUSED) sk_dump(struct dump_request *dreq, resource *r)
{ {
sock *s = (sock *) r; sock *s = (sock *) r;
static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "SSH>", "SSH", "DEL!" }; 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], sk_type_names[s->type],
s->data, s->data,
s->saddr, s->saddr,
@ -2253,19 +2396,21 @@ sk_err(sock *s, int revents)
} }
void void
sk_dump_all(void) sk_dump_all(struct dump_request *dreq)
{ {
node *n; node *n;
sock *s; sock *s;
debug("Open sockets:\n"); RDUMP("Open sockets:\n");
dreq->indent += 3;
WALK_LIST(n, main_birdloop.sock_list) WALK_LIST(n, main_birdloop.sock_list)
{ {
s = SKIP_BACK(sock, n, n); s = SKIP_BACK(sock, n, n);
debug("%p ", s); RDUMP("%p ", s);
sk_dump(&s->r, 3); sk_dump(dreq, &s->r);
} }
debug("\n"); dreq->indent -= 3;
RDUMP("\n");
} }
@ -2345,16 +2490,16 @@ io_close_event(void)
} }
void void
io_log_dump(void) io_log_dump(struct dump_request *dreq)
{ {
int i; int i;
log(L_DEBUG "Event log:"); RDUMP("Event log:\n");
for (i = 0; i < EVENT_LOG_LENGTH; i++) for (i = 0; i < EVENT_LOG_LENGTH; i++)
{ {
struct event_log_entry *en = event_log + (event_log_pos + i) % EVENT_LOG_LENGTH; struct event_log_entry *en = event_log + (event_log_pos + i) % EVENT_LOG_LENGTH;
if (en->hook) 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\n", en->hook, en->data,
(int) ((last_io_time - en->timestamp) TO_MS), (int) (en->duration TO_MS)); (int) ((last_io_time - en->timestamp) TO_MS), (int) (en->duration TO_MS));
} }
} }

View File

@ -49,21 +49,38 @@
* Debugging * 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);
ea_dump_all(dreq);
rt_dump_all(dreq);
protos_dump_all(dreq);
debug("\n");
}
void void
async_dump(void) async_dump(void)
{ {
debug("INTERNAL STATE DUMP\n\n"); struct dump_request *dr = dump_to_file_init(0);
dr->report = async_dump_report;
rdump(&root_pool, 0); dump_to_file_run(dr, "bird.dump", "async dump", async_dump_run);
sk_dump_all();
// XXXX tm_dump_all();
if_dump_all();
neigh_dump_all();
ea_dump_all();
rt_dump_all();
protos_dump_all();
debug("\n");
} }
/* /*

View File

@ -20,6 +20,7 @@ struct pool;
struct iface; struct iface;
struct birdsock; struct birdsock;
struct rfile; struct rfile;
struct cli;
struct config; struct config;
/* main.c */ /* main.c */
@ -113,7 +114,7 @@ extern volatile sig_atomic_t async_shutdown_flag;
void io_init(void); void io_init(void);
void io_loop(void); void io_loop(void);
void io_log_dump(void); void io_log_dump(struct dump_request *);
int sk_open_unix(struct birdsock *s, struct birdloop *, const char *name); int sk_open_unix(struct birdsock *s, struct birdloop *, const char *name);
enum rf_mode { enum rf_mode {
@ -133,6 +134,11 @@ extern struct rfile rf_stderr;
void test_old_bird(const char *path); void test_old_bird(const char *path);
ip_addr resolve_hostname(const char *host, int type, const char **err_msg); 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 */ /* krt.c bits */
void krt_io_init(void); void krt_io_init(void);