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

@ -73,6 +73,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
$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()
@ -241,7 +241,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
@ -434,13 +434,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()[[))
@ -681,22 +681,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 */
@ -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->results = results;
#ifdef LOCAL_DEBUG
f_dump_line(out, 0);
#endif
return out;
}

View File

@ -181,11 +181,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

@ -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 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++]);
@ -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)
debug(" ALL");
RDUMP(" ALL");
else if (f == FILTER_REJECT)
debug(" NONE");
RDUMP(" NONE");
else if (f == FILTER_UNDEF)
debug(" UNDEF");
RDUMP(" UNDEF");
else if (f->sym) {
ASSERT(f->sym->filter == f);
debug(" named filter %s", f->sym->name);
RDUMP(" named filter %s", f->sym->name);
} else {
debug("\n");
f_dump_line(f->root, 2);
RDUMP("\n");
f_dump_line(dreq, f->root, 2);
}
}
void filters_dump_all(void)
void filters_dump_all(struct dump_request *dreq)
{
struct symbol *sym;
WALK_LIST(sym, OBSREF_GET(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]);
channel_filter_dump(c->in_filter);
debug(" EXPORT", c->name, net_label[c->net_type]);
channel_filter_dump(c->out_filter);
debug("\n");
RDUMP(" Channel %s (%s) IMPORT", c->name, net_label[c->net_type]);
channel_filter_dump(dreq, c->in_filter);
RDUMP(" EXPORT", c->name, net_label[c->net_type]);
channel_filter_dump(dreq, c->out_filter);
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_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

@ -310,4 +310,15 @@ static inline u32 u64_hash(u64 v)
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

View File

@ -173,11 +173,11 @@ ev_postpone(event *e)
}
static void
ev_dump(resource *r, unsigned indent UNUSED)
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,
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_free(resource *);
static void lp_dump(resource *, unsigned);
static void lp_dump(struct dump_request *, resource *);
static resource *lp_lookup(resource *, unsigned long);
static struct resmem lp_memsize(resource *r);
@ -278,30 +278,27 @@ lp_free(resource *r)
}
static void
lp_dump(resource *r, unsigned indent)
lp_dump(struct dump_request *dreq, resource *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++)
;
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);
int chunks = 0, large = 0;
bsprintf(x, "%%%dschunk %%p\n", indent + 2);
for (c=m->first; c; c=c->next)
debug(x, "", c);
RDUMP("\n%*schunks:\n", dreq->indent+3, "");
for (struct lp_chunk *c = m->first; c; c = c->next)
{
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);
for (c=m->first_large; c; c=c->next)
debug(x, "", c);
RDUMP("%*slarge:\n", dreq->indent+3, "");
for (struct lp_chunk *c = m->first_large; c; c = c->next)
{
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

View File

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

View File

@ -42,7 +42,7 @@ struct resclass {
char *name; /* Resource class name */
unsigned size; /* Standard size of single resource */
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) */
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 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 */
void rlookup(unsigned long); /* Look up address (only for debugging) */
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_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
@ -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);
void ea_dump(ea_list *);
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 */
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;
}
void ea_dump(ea_list *);
void ea_dump_all(void);
void ea_dump(struct dump_request *, ea_list *);
void ea_dump_all(struct dump_request *);
void ea_show_list(struct cli *, ea_list *);
#endif

View File

@ -41,7 +41,7 @@
#endif
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 struct resmem slab_memsize(resource *r);
@ -393,27 +393,38 @@ slab_free(resource *r)
}
static void
slab_dump(resource *r, unsigned indent UNUSED)
slab_dump(struct dump_request *dreq, resource *r)
{
slab *s = (slab *) r;
int ec=0, pc=0, fc=0;
WALK_TLIST(sl_head, h, &s->empty_heads)
ec++;
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);
RDUMP("(%d objs per %d bytes in page)\n",
s->objs_per_slab, s->obj_size);
char x[16];
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);
RDUMP("%*sempty:\n", dreq->indent+3, "");
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

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_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

@ -60,19 +60,19 @@ tm_free(resource *r)
}
static void
tm_dump(resource *r, unsigned indent UNUSED)
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("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
debug("inactive)\n");
RDUMP("inactive)\n");
}

View File

@ -932,28 +932,27 @@ 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, 0); 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]])
{ ea_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP ROUTES,,, [[Dump routes]])
{ rt_dump_all(); cli_msg(0, ""); } ;
CF_CLI(DUMP TABLES,,, [[Dump table connections]])
{ rt_dump_hooks_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", ea_dump_all); } ;
CF_CLI(DUMP ROUTES, text,, [[Dump routes]])
{ cmd_dump_file(this_cli, $3, "routing tables", rt_dump_all); } ;
CF_CLI(DUMP TABLES, text,, [[Dump table connections]])
{ cmd_dump_file(this_cli, $3, "table connections", rt_dump_hooks_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

@ -52,8 +52,8 @@ static void if_recalc_preferred(struct iface *i);
static void ifa_delete_locked(struct ifa *a);
static void ifa_dump_locked(struct ifa *);
static void if_dump_locked(struct iface *);
static void ifa_dump_locked(struct dump_request *, struct ifa *);
static void if_dump_locked(struct dump_request *, struct iface *);
struct iface *
if_walk_first(void)
@ -85,17 +85,17 @@ if_walk_done(void)
* 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)
{
IFACE_LOCK;
ifa_dump_locked(a);
ifa_dump_locked(dreq, a);
IFACE_UNLOCK;
}
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_SECONDARY) ? " SEC" : "",
(a->flags & IA_HOST) ? " HOST" : "",
@ -110,43 +110,43 @@ ifa_dump_locked(struct ifa *a)
* network interface to the debug output.
*/
void
if_dump(struct iface *i)
if_dump(struct dump_request *dreq, struct iface *i)
{
IFACE_LOCK;
if_dump_locked(i);
if_dump_locked(dreq, i);
IFACE_UNLOCK;
}
static void
if_dump_locked(struct iface *i)
if_dump_locked(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_locked(a);
ifa_dump_locked(dreq, a);
ASSERT(!!(a->flags & IA_PRIMARY) ==
((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
}
@ -159,13 +159,13 @@ if_dump_locked(struct iface *i)
* interfaces to the debug output.
*/
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)
if_dump(i);
if_dump_locked(dreq, i);
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();
}

View File

@ -107,9 +107,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 *);
@ -168,7 +168,7 @@ typedef struct neighbor {
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_down(struct iface *);
void neigh_if_link(struct iface *);

View File

@ -107,14 +107,14 @@ olock_free(resource *r)
}
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;
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

@ -302,17 +302,17 @@ bad:
* This functions dumps the contents of a given neighbor entry to debug output.
*/
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->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");
}
/**
@ -321,18 +321,18 @@ 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)
{
IFACE_LOCK;
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");
IFACE_UNLOCK;
}

View File

@ -2053,14 +2053,14 @@ 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");
WALK_TLIST(proto, p, &global_proto_list) PROTO_LOCKED_FROM_MAIN(p)
{
#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,
DPF(disabled), DPF(do_stop), DPF(reconfiguring));
#undef DPF
@ -2068,23 +2068,24 @@ protos_dump_all(void)
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));
debug("\tChannel state: %s/%s/%s\n", c_states[c->channel_state],
RDUMP("\tOutput filter: %s\n", filter_name(c->out_filter));
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)) : "-",
rt_export_state_name(rt_export_get_state(&c->out_req)));
}
debug("\tSOURCES\n");
rt_dump_sources(&p->sources);
RDUMP("\tSOURCES\n");
if (p->proto_state != PS_DOWN_XX)
rt_dump_sources(dreq, &p->sources);
if (p->proto->dump &&
(p->proto_state != PS_DOWN_XX) &&
(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 */
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 *); /* 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_commit(struct config *new, struct config *old, 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

@ -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_end(struct rt_import_request *);
void rt_schedule_prune(struct rtable_private *t);
void rte_dump(struct rte_storage *);
void rt_dump(rtable *);
void rt_dump_all(void);
void rt_dump_hooks(rtable *);
void rt_dump_hooks_all(void);
void rte_dump(struct dump_request *, struct rte_storage *);
void rt_dump(struct dump_request *, rtable *);
void rt_dump_all(struct dump_request *);
void rt_dump_hooks(struct dump_request *, rtable *);
void rt_dump_hooks_all(struct dump_request *);
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);

View File

@ -390,18 +390,18 @@ rt_prune_sources(void *data)
}
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);
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->rte_igp_metric, o->rte_recalculate);
int splitting = 0;
HASH_WALK(o->hash, next, src)
{
debug("%c%c%uL %uG %luU",
RDUMP("%c%c%uL %uG %luU",
(splitting % 8) ? ',' : '\n',
(splitting % 8) ? ' ' : '\t',
src->private_id, src->global_id,
@ -410,7 +410,7 @@ rt_dump_sources(struct rte_owner *o)
splitting++;
}
HASH_WALK_END;
debug("\n");
RDUMP("\n");
}
static struct rte_owner_class default_rte_owner_class;
@ -653,10 +653,10 @@ ea_class_ref_free(resource *r)
}
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);
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 = {
@ -1348,27 +1348,27 @@ ea_show(struct cli *c, const eattr *e)
}
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;
debug(":");
RDUMP(":");
if (!NEXTHOP_IS_REACHABLE(nhad))
{
const char *name = rta_dest_name(nhad->dest);
if (name)
debug(" %s", name);
RDUMP(" %s", name);
else
debug(" D%d", nhad->dest);
RDUMP(" D%d", nhad->dest);
}
else NEXTHOP_WALK(nh, nhad)
{
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 : "???");
}
}
@ -1380,19 +1380,19 @@ nexthop_dump(const struct adata *ad)
* 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)
{
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_BISECT) ? 'B' : 'b',
e->stored,
@ -1403,34 +1403,34 @@ ea_dump(ea_list *e)
eattr *a = &e->attrs[i];
struct ea_class *clp = (a->id < ea_class_max) ? ea_class_global[a->id] : NULL;
if (clp)
debug(" %s", clp->name);
RDUMP(" %s", clp->name);
else
debug(" 0x%x", a->id);
RDUMP(" 0x%x", a->id);
debug(".%02x", a->flags);
debug("=%c",
RDUMP(".%02x", a->flags);
RDUMP("=%c",
"?iO?IRP???S??pE?"
"??L???N?????????"
"?o???r??????????" [a->type]);
if (a->originated)
debug("o");
RDUMP("o");
if (a->undef)
debug(":undef");
RDUMP(":undef");
else if (a->type & EAF_EMBEDDED)
debug(":%08x", a->u.data);
RDUMP(":%08x", a->u.data);
else if (a->id == ea_gen_nexthop.id)
nexthop_dump(a->u.ptr);
nexthop_dump(dreq, a->u.ptr);
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]);
}
debug(" ");
RDUMP(" ");
}
if (e = e->next)
debug(" | ");
RDUMP(" | ");
}
}
@ -1681,20 +1681,20 @@ ea_free_deferred(struct deferred_call *dc)
* to the debug output.
*/
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.cur, memory_order_relaxed)->order);
SPINHASH_WALK(rta_hash_table, RTAH, a)
{
debug("%p ", a);
ea_dump(a->l);
debug("\n");
RDUMP("%p ", a);
ea_dump(dreq, a->l);
RDUMP("\n");
}
SPINHASH_WALK_END;
debug("\n");
RDUMP("\n");
}
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.
*/
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);
debug("ID=%d ", e->rte.id);
debug("SENDER=%s ", e->rte.sender->req->name);
debug("PF=%02x ", e->rte.pflags);
debug("SRC=%uG ", e->rte.src->global_id);
ea_dump(e->rte.attrs);
debug("\n");
RDUMP("(%u) %-1N", NET_TO_INDEX(e->rte.net)->index, e->rte.net);
RDUMP("ID=%d ", e->rte.id);
RDUMP("SENDER=%s ", e->rte.sender->req->name);
RDUMP("PF=%02x ", e->rte.pflags);
RDUMP("SRC=%uG ", e->rte.src->global_id);
ea_dump(dreq, e->rte.attrs);
RDUMP("\n");
}
/**
@ -2767,20 +2767,20 @@ rte_dump(struct rte_storage *e)
* This function dumps contents of a given routing table to debug output.
*/
void
rt_dump(rtable *tab)
rt_dump(struct dump_request *dreq, rtable *tab)
{
RT_READ(tab, tp);
/* 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);
net *routes = atomic_load_explicit(&tp->t->routes, memory_order_relaxed);
for (u32 i = 0; i < bs; i++)
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.
*/
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);
WALK_LIST2(t, n, deleted_routing_tables, n)
rt_dump(t);
rt_dump(dreq, t);
}
void
rt_dump_hooks(rtable *tp)
rt_dump_hooks(struct dump_request *dreq, rtable *tp)
{
RT_LOCKED(tp, tab)
{
debug("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("Dump of hooks in routing table <%s>%s\n", tab->name, OBSREF_GET(tab->deleted) ? " (deleted)" : "");
RDUMP(" nhu_state=%u use_count=%d rt_count=%u\n",
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);
struct rt_import_hook *ih;
WALK_LIST(ih, tab->imports)
{
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",
ih, ih->req, ih->stats.pref,
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);
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",
eh, eh->req, eh->refeed_pending, eh->last_state_change,
atomic_load_explicit(&eh->export_state, memory_order_relaxed));
}
#endif
debug("\n");
RDUMP("\n");
}
}
void
rt_dump_hooks_all(void)
rt_dump_hooks_all(struct dump_request *dreq)
{
rtable *t;
node *n;
debug("Dump of all table hooks\n");
RDUMP("Dump of all table hooks\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)
rt_dump_hooks(t);
rt_dump_hooks(dreq, t);
}
static inline void
@ -3209,11 +3209,11 @@ rt_free(resource *_r)
}
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);
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);
#if 0

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

@ -929,11 +929,11 @@ bfd_request_free(resource *r)
}
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;
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

@ -236,7 +236,7 @@ static void
bmp_tx_resource_free(resource *r UNUSED) {}
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
bmp_tx_resource_memsize(resource *r)

View File

@ -334,32 +334,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

@ -1351,7 +1351,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;
@ -1360,12 +1360,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;
@ -1373,7 +1373,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

@ -606,27 +606,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

@ -431,6 +431,30 @@ page_cleanup(void *_ UNUSED)
}
#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
resource_sys_init(void)
{

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <poll.h>
@ -43,6 +44,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"
@ -90,11 +92,11 @@ rf_free(resource *r)
}
static void
rf_dump(resource *r, unsigned indent UNUSED)
rf_dump(struct dump_request *dreq, resource *r)
{
struct rfile *a = (struct rfile *) r;
debug("(fd %d)\n", a->fd);
RDUMP("(fd %d)\n", a->fd);
}
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
@ -1069,12 +1212,12 @@ sk_reallocate(sock *s)
}
static void
sk_dump(resource *r, unsigned indent UNUSED)
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,
@ -2253,19 +2396,21 @@ 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");
dreq->indent += 3;
WALK_LIST(n, main_birdloop.sock_list)
{
s = SKIP_BACK(sock, n, n);
debug("%p ", s);
sk_dump(&s->r, 3);
RDUMP("%p ", s);
sk_dump(dreq, &s->r);
}
debug("\n");
dreq->indent -= 3;
RDUMP("\n");
}
@ -2345,16 +2490,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:\n");
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\n", en->hook, en->data,
(int) ((last_io_time - en->timestamp) TO_MS), (int) (en->duration TO_MS));
}
}

View File

@ -49,21 +49,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);
ea_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, 0);
sk_dump_all();
// XXXX tm_dump_all();
if_dump_all();
neigh_dump_all();
ea_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

@ -20,6 +20,7 @@ struct pool;
struct iface;
struct birdsock;
struct rfile;
struct cli;
struct config;
/* main.c */
@ -113,7 +114,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, struct birdloop *, const char *name);
enum rf_mode {
@ -133,6 +134,11 @@ extern struct rfile rf_stderr;
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);