0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

CLI fix for long-lived sessions during high loads

When there is a continuos stream of CLI commands, cli_get_command()
always returns 1 (there is a new command). Anyway, the socket receive
buffer was reset only when there was no command at all, leading to a
strange behavior: after a while, the CLI receive buffer came to its end,
then read() was called with zero size buffer, it returned 0 which was
interpreted as EOF.

Fixing this by:
* resetting the buffer any time CLI RX gets to EOL
* explicitly refusing to pipeline

In future, we may implement CLI pipelining, yet to make it conveniently,
a push-parser may come handy instead of the current implementation.
This commit is contained in:
Maria Matejka 2022-07-11 13:53:09 +02:00
parent beb5f78ada
commit 8691151dbd
5 changed files with 35 additions and 18 deletions

View File

@ -75,3 +75,4 @@ Reply codes of BIRD command-line interface
9000 Command too long 9000 Command too long
9001 Parse error 9001 Parse error
9002 Invalid symbol type 9002 Invalid symbol type
9003 Pipelining not supported

View File

@ -293,13 +293,20 @@ cli_event(void *data)
c->cont(c); c->cont(c);
else else
{ {
err = cli_get_command(c); switch (cli_get_command(c))
if (!err) {
return; case CGC_OK:
if (err < 0) cli_command(c);
cli_printf(c, 9000, "Command too long"); break;
else case CGC_INCOMPLETE:
cli_command(c); return;
case CGC_TOO_LONG:
cli_printf(c, 9000, "Command too long");
break;
case CGC_TRAILING:
cli_printf(c, 9003, "Pipelining not supported");
break;
}
} }
cli_write_trigger(c); cli_write_trigger(c);

View File

@ -29,7 +29,7 @@ typedef struct cli {
node n; /* Node in list of all log hooks */ node n; /* Node in list of all log hooks */
pool *pool; pool *pool;
void *priv; /* Private to sysdep layer */ void *priv; /* Private to sysdep layer */
byte *rx_buf, *rx_pos, *rx_aux; /* sysdep */ byte *rx_buf, *rx_pos; /* sysdep */
struct cli_out *tx_buf, *tx_pos, *tx_write; struct cli_out *tx_buf, *tx_pos, *tx_write;
event *event; event *event;
void (*cont)(struct cli *c); void (*cont)(struct cli *c);
@ -81,6 +81,13 @@ static inline int cli_access_restricted(void)
/* Functions provided by sysdep layer */ /* Functions provided by sysdep layer */
void cli_write_trigger(cli *); void cli_write_trigger(cli *);
int cli_get_command(cli *); enum cli_get_command_result {
CGC_OK,
CGC_INCOMPLETE,
CGC_TOO_LONG,
CGC_TRAILING,
};
enum cli_get_command_result cli_get_command(cli *);
#endif #endif

View File

@ -430,11 +430,11 @@ cli_tx(sock *s)
cli_write(s->data); cli_write(s->data);
} }
int enum cli_get_command_result
cli_get_command(cli *c) cli_get_command(cli *c)
{ {
sock *s = c->priv; sock *s = c->priv;
byte *t = c->rx_aux ? : s->rbuf; byte *t = s->rbuf;
byte *tend = s->rpos; byte *tend = s->rpos;
byte *d = c->rx_pos; byte *d = c->rx_pos;
byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2; byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
@ -445,18 +445,21 @@ cli_get_command(cli *c)
t++; t++;
else if (*t == '\n') else if (*t == '\n')
{ {
t++; if (++t < tend)
return CGC_TRAILING;
s->rpos = s->rbuf;
c->rx_pos = c->rx_buf; c->rx_pos = c->rx_buf;
c->rx_aux = t;
*d = 0; *d = 0;
return (d < dend) ? 1 : -1; return (d < dend) ? CGC_OK : CGC_TOO_LONG;
} }
else if (d < dend) else if (d < dend)
*d++ = *t++; *d++ = *t++;
} }
c->rx_aux = s->rpos = s->rbuf;
s->rpos = s->rbuf;
c->rx_pos = d; c->rx_pos = d;
return 0; return CGC_INCOMPLETE;
} }
static int static int
@ -493,7 +496,6 @@ cli_connect(sock *s, uint size UNUSED)
s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */ s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
s->fast_rx = 1; s->fast_rx = 1;
c->rx_pos = c->rx_buf; c->rx_pos = c->rx_buf;
c->rx_aux = NULL;
rmove(s, c->pool); rmove(s, c->pool);
return 1; return 1;
} }

View File

@ -549,6 +549,6 @@ int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return
void sysdep_shutdown_done(void) {} void sysdep_shutdown_done(void) {}
#include "nest/cli.h" #include "nest/cli.h"
int cli_get_command(cli *c UNUSED) { return 0; } enum cli_get_command_result cli_get_command(cli *c UNUSED) { return CGC_OK; }
void cli_write_trigger(cli *c UNUSED) {} void cli_write_trigger(cli *c UNUSED) {}
cli *cmd_reconfig_stored_cli; cli *cmd_reconfig_stored_cli;