struct f_prefix px;
struct proto_spec ps;
struct channel_limit cl;
- struct timeformat *tf;
+ struct timeformat tf;
+ struct timeformat *tfp;
- mpls_label_stack *mls;
+ struct settle_config settle;
+ struct adata *ad;
const struct adata *bs;
struct aggr_item_node *ai;
}
static list cli_log_hooks;
static int cli_log_inited;
-void
-cli_set_log_echo(cli *c, uint mask, uint size)
-{
- if (c->ring_buf)
- {
- mb_free(c->ring_buf);
- c->ring_buf = c->ring_end = c->ring_read = c->ring_write = NULL;
- rem_node(&c->n);
- }
- c->log_mask = mask;
- if (mask && size)
- {
- c->ring_buf = mb_alloc(c->pool, size);
- c->ring_end = c->ring_buf + size;
- c->ring_read = c->ring_write = c->ring_buf;
- add_tail(&cli_log_hooks, &c->n);
- c->log_threshold = size / 8;
- }
- c->ring_overflow = 0;
-}
-
-void
-cli_echo(uint class, byte *msg)
-{
- unsigned len, free, i, l;
- cli *c;
- byte *m;
-
- if (!cli_log_inited || EMPTY_LIST(cli_log_hooks))
- return;
- len = strlen(msg) + 1;
- WALK_LIST(c, cli_log_hooks)
- {
- if (!(c->log_mask & (1 << class)))
- continue;
- if (c->ring_read <= c->ring_write)
- free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1);
- else
- free = c->ring_read - c->ring_write - 1;
- if ((len > free) ||
- (free < c->log_threshold && class < (unsigned) L_INFO[0]))
- {
- c->ring_overflow++;
- continue;
- }
- if (c->ring_read == c->ring_write)
- ev_schedule(c->event);
- m = msg;
- l = len;
- while (l)
- {
- if (c->ring_read <= c->ring_write)
- i = c->ring_end - c->ring_write;
- else
- i = c->ring_read - c->ring_write;
- if (i > l)
- i = l;
- memcpy(c->ring_write, m, i);
- m += i;
- l -= i;
- c->ring_write += i;
- if (c->ring_write == c->ring_end)
- c->ring_write = c->ring_buf;
- }
- }
-}
-
+ /* Set time format override for the current session */
+ void
+ cli_set_timeformat(cli *c, const struct timeformat tf)
+ {
+ size_t len1 = strlen(tf.fmt1) + 1;
+ size_t len2 = tf.fmt2 ? strlen(tf.fmt2) + 1 : 0;
+
+ if (len1 > TM_DATETIME_BUFFER_SIZE || len2 > TM_DATETIME_BUFFER_SIZE)
+ {
+ cli_msg(9003, "Format string too long");
+ return;
+ }
+
+ struct timeformat *old_tf = c->tf;
+ struct timeformat *new_tf = mb_allocz(c->pool, sizeof(struct timeformat));
+ new_tf->fmt1 = memcpy(mb_alloc(c->pool, len1), tf.fmt1, len1);
+ new_tf->fmt2 = tf.fmt2 ? memcpy(mb_alloc(c->pool, len2), tf.fmt2, len2) : NULL;
+ new_tf->limit = tf.limit;
+ c->tf = new_tf;
+
+ if (old_tf)
+ {
+ mb_free((void *) old_tf->fmt1);
+ mb_free((void *) old_tf->fmt2);
+ mb_free(old_tf);
+ }
+
+ cli_msg(0, "");
+ }
+
/* Hack for scheduled undo notification */
extern cli *cmd_reconfig_stored_cli;
#define _BIRD_CLI_H_
#include "lib/resource.h"
+#include "lib/lists.h"
#include "lib/event.h"
+ #include "lib/timer.h"
#include "lib/tlists.h"
#include "conf/conf.h"
struct cli_out *tx_buf, *tx_pos, *tx_write;
event *event;
void (*cont)(struct cli *c);
- void (*cleanup)(struct cli *c);
+ void (*cleanup)(struct cli *c); /* The CLI has closed prematurely */
void *rover; /* Private to continuation routine */
+ struct config *main_config; /* Main config currently in use */
int last_reply;
int restricted; /* CLI is restricted to read-only commands */
+ struct timeformat *tf; /* Time format override */
struct linpool *parser_pool; /* Pool used during parsing */
- struct linpool *show_pool; /* Pool used during route show */
- byte *ring_buf; /* Ring buffer for asynchronous messages */
- byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */
- uint ring_overflow; /* Counter of ring overflows */
uint log_mask; /* Mask of allowed message levels */
uint log_threshold; /* When free < log_threshold, store only important messages */
uint async_msg_size; /* Total size of async messages queued in tx_buf */
void cli_printf(cli *, int, char *, ...);
#define cli_msg(x...) cli_printf(this_cli, x)
-void cli_set_log_echo(cli *, uint mask, uint size);
+ void cli_set_timeformat(cli *c, const struct timeformat tf);
static inline void cli_separator(cli *c)
{ if (c->last_reply) cli_printf(c, -c->last_reply, ""); };
void
cmd_show_status(void)
{
- byte tim[TM_DATETIME_BUFFER_SIZE];
-
- struct timeformat *tf_base = this_cli->tf ?: &config->tf_base;
+ rcu_read_lock();
+ struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_acquire);
- struct timeformat *tf = &gr->tf_base;
++ struct timeformat *tf = this_cli->tf ?: &gr->tf_base;
+ byte tim[TM_DATETIME_BUFFER_SIZE];
cli_msg(-1000, "BIRD " BIRD_VERSION);
- tm_format_time(tim, tf_base, current_time());
- cli_msg(-1011, "Router ID is %R", config->router_id);
- cli_msg(-1011, "Hostname is %s", config->hostname);
+ tm_format_time(tim, tf, current_time());
+ cli_msg(-1011, "Router ID is %R", gr->router_id);
+ cli_msg(-1011, "Hostname is %s", gr->hostname);
cli_msg(-1011, "Current server time is %s", tim);
- tm_format_time(tim, tf_base, boot_time);
+ tm_format_time(tim, tf, boot_time);
cli_msg(-1011, "Last reboot on %s", tim);
- tm_format_time(tim, tf_base, config->load_time);
+ tm_format_time(tim, tf, gr->load_time);
cli_msg(-1011, "Last reconfiguration on %s", tim);
graceful_restart_show_status();
;
timeformat_spec:
- timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
- | timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
- | timeformat_which ISO SHORT { *$1 = TM_ISO_SHORT_S; }
- | timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
- | timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
- | timeformat_which ISO LONG { *$1 = TM_ISO_LONG_S; }
- | timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
- | timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
- ;
-
- timeformat_base:
- TIMEFORMAT timeformat_spec ';'
+ TEXT { $$ = (struct timeformat){$1, NULL, 0}; }
+ | TEXT expr TEXT { $$ = (struct timeformat){$1, $3, (s64) $2 S_}; }
+ | ISO SHORT { $$ = TM_ISO_SHORT_S; }
+ | ISO SHORT MS { $$ = TM_ISO_SHORT_MS; }
+ | ISO SHORT US { $$ = TM_ISO_SHORT_US; }
+ | ISO LONG { $$ = TM_ISO_LONG_S; }
+ | ISO LONG MS { $$ = TM_ISO_LONG_MS; }
+ | ISO LONG US { $$ = TM_ISO_LONG_US; }
;
-
/* Interface patterns */
iface_patt_node_init:
buf[0] = 0;
if (p->proto->get_status)
p->proto->get_status(p, buf);
- tm_format_time(tbuf, (this_cli->tf ?: &config->tf_proto), p->last_state_change);
+
+ rcu_read_lock();
- tm_format_time(tbuf, &atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_proto, p->last_state_change);
++ tm_format_time(tbuf, this_cli->tf ?: &atomic_load_explicit(&global_runtime, memory_order_acquire)->tf_proto, p->last_state_change);
+ rcu_read_unlock();
cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
p->name,
p->proto->name,
{
byte from[IPA_MAX_TEXT_LENGTH+8];
byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
- rta *a = e->attrs;
- int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0;
- void (*get_route_info)(struct rte *, byte *buf);
- struct nexthop *nh;
-
- tm_format_time(tm, (c->tf ?: &config->tf_route), e->lastmod);
- if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
- bsprintf(from, " from %I", a->from);
+ ea_list *a = e->attrs;
+ int sync_error = d->tab->kernel ? krt_get_sync_error(d->tab->kernel, e) : 0;
+ void (*get_route_info)(const rte *, byte *buf);
+ const eattr *nhea = net_type_match(e->net, NB_DEST) ?
+ ea_find(a, &ea_gen_nexthop) : NULL;
+ struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+ int dest = nhad ? (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest) : RTD_NONE;
+ int flowspec_valid = net_is_flow(e->net) ? rt_get_flowspec_valid(e) : FLOWSPEC_UNKNOWN;
+
- tm_format_time(tm, &d->tf_route, e->lastmod);
++ tm_format_time(tm, c->tf ?: &d->tf_route, e->lastmod);
+ ip_addr a_from = ea_get_ip(a, &ea_gen_from, IPA_NONE);
+ if (ipa_nonzero(a_from) && (!nhad || !ipa_equal(a_from, nhad->nh.gw)))
+ bsprintf(from, " from %I", a_from);
else
from[0] = 0;
byte dbuf[BFD_DIAG_BUFFER_SIZE];
byte tbuf[TM_DATETIME_BUFFER_SIZE];
- tm_format_time(tbuf, (this_cli->tf ?: &config->tf_proto), s->last_state_change);
+
+ rcu_read_lock();
+ struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
- tm_format_time(tbuf, &gr->tf_proto, s->last_state_change);
++ tm_format_time(tbuf, this_cli->tf ?: &gr->tf_proto, s->last_state_change);
+ rcu_read_unlock();
if (!details)
{
CF_DECLS
-CF_KEYWORDS(LOG, SYSLOG, NAME, STDERR, UDP, PORT, CLI)
-CF_KEYWORDS(ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG)
-CF_KEYWORDS(DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING, TIMEOUT, THREADS)
+CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT, UDP, PORT, CLI)
+CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING, STATUS)
+CF_KEYWORDS(PING, WAKEUP, SOCKETS, SCHEDULING, EVENTS, TIMERS, ALLOCATOR)
+CF_KEYWORDS(GRACEFUL, RESTART, FIXED)
-%type <i> log_mask log_mask_list log_cat cfg_timeout
+%type <i> log_mask log_mask_list log_cat cfg_timeout debug_unix latency_debug_mask latency_debug_flag latency_debug_list
%type <t> cfg_name
- %type <tf> timeformat_which
%type <t> syslog_name
CF_GRAMMAR