Commit 61dae32b authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

Nest: Per-channel debug flags

The patch add support for per-channel debug flags, currently just
'states', 'routes', and 'filters'. Flag 'states' is used for channel
state changes, remaining two for routes passed through the channel.
The per-protocol debug flags 'routes'/'filters' still enable reporting
of routes for all channels, to keep existing behavior.

The patch causes minor changes in some log messages.
parent 8cc5bb09
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -32,8 +32,9 @@ struct config {
  struct iface_patt *router_id_from;	/* Configured list of router ID iface patterns */

  u32 router_id;			/* Our Router ID */
  unsigned proto_default_debug;		/* Default protocol debug mask */
  unsigned proto_default_mrtdump;	/* Default protocol mrtdump mask */
  u32 proto_default_debug;		/* Default protocol debug mask */
  u32 proto_default_mrtdump;		/* Default protocol mrtdump mask */
  u32 channel_default_debug;		/* Default channel debug mask */
  struct timeformat tf_route;		/* Time format for 'show route' */
  struct timeformat tf_proto;		/* Time format for 'show protocol' */
  struct timeformat tf_log;		/* Time format for the logfile */
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ CF_DECLS
  const char *t;
  struct rtable_config *r;
  struct channel_config *cc;
  struct channel *c;
  struct f_inst *x;
  struct {
    struct f_inst *begin, *end;
+37 −30
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OF
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
@@ -123,7 +123,8 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
%type <cl> limit_spec
%type <net> r_args_for_val
%type <net_ptr> r_args_for
%type <t> r_args_channel
%type <t> channel_sym
%type <c> channel_arg

CF_GRAMMAR

@@ -247,7 +248,7 @@ channel_start: net_type
  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
};

channel_item:
channel_item_:
   TABLE rtable {
     if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
       cf_error("Incompatible table type");
@@ -262,6 +263,12 @@ channel_item:
 | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
 ;

/* To avoid grammar collision in Pipe protocol */
channel_item:
   channel_item_
 | DEBUG debug_mask { this_channel->debug = $2; }
 ;

channel_opts:
   /* empty */
 | channel_opts channel_item ';'
@@ -310,6 +317,7 @@ conf: debug_default ;

debug_default:
   DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
 | DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; }
 | DEBUG COMMANDS expr { new_config->cli_debug = $3; }
 ;

@@ -604,26 +612,14 @@ r_args:
       rt_show_add_table($$, t->table);
     $$->tables_defined_by = RSD_TDB_ALL;
   }
 | r_args IMPORT TABLE CF_SYM_KNOWN '.' r_args_channel {
     cf_assert_symbol($4, SYM_PROTO);
     $$ = $1;
     struct proto_config *cf = $4->proto;
     if (!cf->proto) cf_error("%s is not a protocol", $4->name);
     struct channel *c = proto_find_channel_by_name(cf->proto, $6);
     if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
     if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
     rt_show_add_table($$, c->in_table);
 | r_args IMPORT TABLE channel_arg {
     if (!$4->in_table) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name);
     rt_show_add_table($$, $4->in_table);
     $$->tables_defined_by = RSD_TDB_DIRECT;
   }
 | r_args EXPORT TABLE CF_SYM_KNOWN '.' r_args_channel {
     cf_assert_symbol($4, SYM_PROTO);
     $$ = $1;
     struct proto_config *cf = $4->proto;
     if (!cf->proto) cf_error("%s is not a protocol", $4->name);
     struct channel *c = proto_find_channel_by_name(cf->proto, $6);
     if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
     if (!c->out_table) cf_error("No export table in channel %s.%s", $4->name, $6);
     rt_show_add_table($$, c->out_table);
 | r_args EXPORT TABLE channel_arg {
     if (!$4->out_table) cf_error("No export table in channel %s.%s", $4->proto->name, $4->name);
     rt_show_add_table($$, $4->out_table);
     $$->tables_defined_by = RSD_TDB_DIRECT;
   }
 | r_args FILTER filter {
@@ -658,15 +654,11 @@ r_args:
     $$->export_protocol = c->proto;
     $$->tables_defined_by = RSD_TDB_INDIRECT;
   }
 | r_args export_mode CF_SYM_KNOWN '.' r_args_channel {
     cf_assert_symbol($3, SYM_PROTO);
     struct proto_config *c = (struct proto_config *) $3->proto;
 | r_args export_mode channel_arg {
     $$ = $1;
     if ($$->export_mode) cf_error("Export specified twice");
     if (!c->proto) cf_error("%s is not a protocol", $3->name);
     $$->export_mode = $2;
     $$->export_channel = proto_find_channel_by_name(c->proto, $5);
     if (!$$->export_channel) cf_error("Export channel not found");
     $$->export_channel = $3;
     $$->tables_defined_by = RSD_TDB_INDIRECT;
   }
 | r_args PROTOCOL CF_SYM_KNOWN {
@@ -735,7 +727,7 @@ export_mode:
 ;

/* This is ugly hack */
r_args_channel:
channel_sym:
   IPV4		{ $$ = "ipv4"; }
 | IPV4_MC	{ $$ = "ipv4-mc"; }
 | IPV4_MPLS	{ $$ = "ipv4-mpls"; }
@@ -758,6 +750,16 @@ r_args_channel:
 | SEC		{ $$ = "sec"; }
 ;

channel_arg:
   CF_SYM_KNOWN '.' channel_sym {
     cf_assert_symbol($1, SYM_PROTO);
     struct proto *p =  $1->proto->proto;
     if (!p) cf_error("%s is not a protocol", $1->name);
     $$ = proto_find_channel_by_name(p, $3);
     if (!$$) cf_error("Channel %s.%s not found", $1->name, $3);
   }
 ;

CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
{ cmd_show_symbols($3); } ;
@@ -832,8 +834,13 @@ CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protoc
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;

CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
CF_CLI(DEBUG, debug_args, (<protocol> | <channel> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
{ /* Done in debug_args */  };

debug_args:
   proto_patt debug_mask { proto_apply_cmd($1, proto_cmd_debug, 1, $2);  }
 | channel_arg debug_mask { channel_cmd_debug($1, $2); }
 ;

CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|messages [, ...] }), [[Control protocol debugging via MRTdump format]])
+40 −9
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ list proto_list;
static list protocol_list;
struct protocol *class_to_protocol[PROTOCOL__MAX];

#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
#define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); })
#define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); })

static timer *proto_shutdown_timer;
static timer *gr_wait_timer;
@@ -42,6 +43,7 @@ static u32 graceful_restart_locks;

static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" };
static char *e_states[] = { "DOWN", "FEEDING", "READY" };

extern struct protocol proto_unix_iface;

@@ -58,6 +60,15 @@ static inline int proto_is_done(struct proto *p)
static inline int channel_is_active(struct channel *c)
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }

static inline void
channel_log_state_change(struct channel *c)
{
  if (c->export_state)
    CD(c, "State changed to %s/%s", c_states[c->channel_state], e_states[c->export_state]);
  else
    CD(c, "State changed to %s", c_states[c->channel_state]);
}

static void
proto_log_state_change(struct proto *p)
{
@@ -159,6 +170,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
  c->net_type = cf->net_type;
  c->ra_mode = cf->ra_mode;
  c->preference = cf->preference;
  c->debug = cf->debug;
  c->merge_limit = cf->merge_limit;
  c->in_keep_filtered = cf->in_keep_filtered;

@@ -172,17 +184,17 @@ proto_add_channel(struct proto *p, struct channel_config *cf)

  add_tail(&p->channels, &c->n);

  PD(p, "Channel %s connected to table %s", c->name, c->table->name);
  CD(c, "Connected to table %s", c->table->name);

  return c;
}

void
proto_remove_channel(struct proto *p, struct channel *c)
proto_remove_channel(struct proto *p UNUSED, struct channel *c)
{
  ASSERT(c->channel_state == CS_DOWN);

  PD(p, "Channel %s removed", c->name);
  CD(c, "Removed", c->name);

  rem_node(&c->n);
  mb_free(c);
@@ -273,7 +285,7 @@ channel_feed_loop(void *ptr)

  // DBG("Feeding protocol %s finished\n", p->name);
  c->export_state = ES_READY;
  // proto_log_state_change(p);
  channel_log_state_change(c);

  if (c->proto->feed_end)
    c->proto->feed_end(c);
@@ -498,7 +510,8 @@ channel_set_state(struct channel *c, uint state)
  default:
    ASSERT(0);
  }
  // XXXX proto_log_state_change(c);

  channel_log_state_change(c);
}

/**
@@ -516,6 +529,8 @@ channel_request_feeding(struct channel *c)
{
  ASSERT(c->channel_state == CS_UP);

  CD(c, "Feeding requested");

  /* Do nothing if we are still waiting for feeding */
  if (c->export_state == ES_DOWN)
    return;
@@ -534,7 +549,7 @@ channel_request_feeding(struct channel *c)
  c->refeed_count = 0;

  channel_schedule_feed(c, 0);	/* Sets ES_FEEDING */
  // proto_log_state_change(c);
  channel_log_state_change(c);
}

static inline int
@@ -549,6 +564,8 @@ channel_request_reload(struct channel *c)
  ASSERT(c->channel_state == CS_UP);
  ASSERT(channel_reloadable(c));

  CD(c, "Reload requested");

  c->proto->reload_routes(c);

  /*
@@ -594,6 +611,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
  cf->net_type = net_type;
  cf->ra_mode = RA_OPTIMAL;
  cf->preference = proto->protocol->preference;
  cf->debug = new_config->channel_default_debug;

  add_tail(&proto->channels, &cf->n);

@@ -663,6 +681,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
  // c->ra_mode = cf->ra_mode;
  c->merge_limit = cf->merge_limit;
  c->preference = cf->preference;
  c->debug = cf->debug;
  c->in_keep_filtered = cf->in_keep_filtered;

  channel_verify_limits(c);
@@ -676,7 +695,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)

  /* If the channel is not open, it has no routes and we cannot reload it anyways */
  if (c->channel_state != CS_UP)
    return 1;
    goto done;

  if (reconfigure_type == RECONFIG_SOFT)
  {
@@ -686,7 +705,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
    if (export_changed)
      log(L_INFO "Channel %s.%s changed export", c->proto->name, c->name);

    return 1;
    goto done;
  }

  /* Route reload may be not supported */
@@ -702,6 +721,8 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
  if (export_changed)
    channel_request_feeding(c);

done:
  CD(c, "Reconfigured");
  return 1;
}

@@ -1862,6 +1883,16 @@ channel_show_info(struct channel *c)
    channel_show_stats(c);
}

void
channel_cmd_debug(struct channel *c, uint mask)
{
  if (cli_access_restricted())
    return;

  c->debug = mask;
  cli_msg(0, "");
}

void
proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
{
+3 −0
Original line number Diff line number Diff line
@@ -281,6 +281,7 @@ void channel_graceful_restart_unlock(struct channel *c);

void channel_show_limit(struct channel_limit *l, const char *dsc);
void channel_show_info(struct channel *c);
void channel_cmd_debug(struct channel *c, uint mask);

void proto_cmd_show(struct proto *, uintptr_t, int);
void proto_cmd_disable(struct proto *, uintptr_t, int);
@@ -496,6 +497,7 @@ struct channel_config {
  u8 net_type;				/* Routing table network type (NET_*), 0 for undefined */
  u8 ra_mode;				/* Mode of received route advertisements (RA_*) */
  u16 preference;			/* Default route preference */
  u32 debug;				/* Debugging flags (D_*) */
  u8 merge_limit;			/* Maximal number of nexthops for RA_MERGED */
  u8 in_keep_filtered;			/* Routes rejected in import filter are kept */
};
@@ -524,6 +526,7 @@ struct channel {
  u8 net_type;				/* Routing table network type (NET_*), 0 for undefined */
  u8 ra_mode;				/* Mode of received route advertisements (RA_*) */
  u16 preference;			/* Default route preference */
  u32 debug;				/* Debugging flags (D_*) */
  u8 merge_limit;			/* Maximal number of nexthops for RA_MERGED */
  u8 in_keep_filtered;			/* Routes rejected in import filter are kept */
  u8 disabled;
Loading