2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
/*
|
2016-09-22 01:55:29 +02:00
|
|
|
* CLI backend interface.
|
|
|
|
*
|
|
|
|
* --
|
|
|
|
* Copyright (C) 2016 Cumulus Networks, Inc.
|
|
|
|
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
|
|
|
|
* Copyright (C) 2013 by Open Source Routing.
|
|
|
|
* Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
*/
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
2018-05-11 21:32:06 +02:00
|
|
|
#include <lib/version.h>
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2018-05-11 21:32:06 +02:00
|
|
|
#include "command.h"
|
|
|
|
#include "frrstr.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
2017-05-06 06:40:17 +02:00
|
|
|
#include "log_vty.h"
|
2023-03-07 20:22:48 +01:00
|
|
|
#include "frrevent.h"
|
2003-06-15 03:28:29 +02:00
|
|
|
#include "vector.h"
|
2016-09-20 01:46:51 +02:00
|
|
|
#include "linklist.h"
|
2003-06-15 03:28:29 +02:00
|
|
|
#include "vty.h"
|
2005-04-25 18:26:42 +02:00
|
|
|
#include "workqueue.h"
|
2016-02-03 15:00:25 +01:00
|
|
|
#include "vrf.h"
|
2016-09-20 01:46:51 +02:00
|
|
|
#include "command_match.h"
|
2016-11-18 16:24:47 +01:00
|
|
|
#include "command_graph.h"
|
2016-09-26 17:30:30 +02:00
|
|
|
#include "qobj.h"
|
2017-03-09 19:00:19 +01:00
|
|
|
#include "defaults.h"
|
2017-08-23 16:18:49 +02:00
|
|
|
#include "libfrr.h"
|
2017-09-04 00:50:35 +02:00
|
|
|
#include "jhash.h"
|
2018-05-13 02:09:08 +02:00
|
|
|
#include "hook.h"
|
2018-06-14 15:13:18 +02:00
|
|
|
#include "lib_errors.h"
|
2023-04-26 23:50:46 +02:00
|
|
|
#include "mgmt_be_client.h"
|
|
|
|
#include "mgmt_fe_client.h"
|
2017-12-07 20:31:48 +01:00
|
|
|
#include "northbound_cli.h"
|
2020-04-17 15:35:15 +02:00
|
|
|
#include "network.h"
|
2022-10-07 13:51:17 +02:00
|
|
|
#include "routemap.h"
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2020-11-29 03:51:42 +01:00
|
|
|
#include "frrscript.h"
|
|
|
|
|
2019-06-21 08:25:42 +02:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, HOST, "Host config");
|
2016-11-19 11:57:08 +01:00
|
|
|
DEFINE_MTYPE(LIB, COMPLETION, "Completion item");
|
2015-05-29 05:48:31 +02:00
|
|
|
|
2018-04-20 20:34:46 +02:00
|
|
|
#define item(x) \
|
|
|
|
{ \
|
|
|
|
x, #x \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clang-format off */
|
|
|
|
const struct message tokennames[] = {
|
|
|
|
item(WORD_TKN),
|
|
|
|
item(VARIABLE_TKN),
|
|
|
|
item(RANGE_TKN),
|
|
|
|
item(IPV4_TKN),
|
|
|
|
item(IPV4_PREFIX_TKN),
|
|
|
|
item(IPV6_TKN),
|
|
|
|
item(IPV6_PREFIX_TKN),
|
|
|
|
item(MAC_TKN),
|
|
|
|
item(MAC_PREFIX_TKN),
|
2022-11-02 18:17:21 +01:00
|
|
|
item(ASNUM_TKN),
|
2018-04-20 20:34:46 +02:00
|
|
|
item(FORK_TKN),
|
|
|
|
item(JOIN_TKN),
|
|
|
|
item(START_TKN),
|
|
|
|
item(END_TKN),
|
2021-08-26 11:43:08 +02:00
|
|
|
item(NEG_ONLY_TKN),
|
2018-04-20 20:34:46 +02:00
|
|
|
{0},
|
|
|
|
};
|
|
|
|
/* clang-format on */
|
2017-07-25 23:28:19 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Command vector which includes some level of command lists. Normally
|
|
|
|
each daemon maintains each own cmdvec. */
|
2005-09-05 13:54:13 +02:00
|
|
|
vector cmdvec = NULL;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Host information structure. */
|
|
|
|
struct host host;
|
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
/* for vtysh, put together CLI trees only when switching into node */
|
|
|
|
static bool defer_cli_tree;
|
|
|
|
|
2017-08-21 23:56:06 +02:00
|
|
|
/*
|
|
|
|
* Returns host.name if any, otherwise
|
|
|
|
* it returns the system hostname.
|
|
|
|
*/
|
2017-08-29 01:52:29 +02:00
|
|
|
const char *cmd_hostname_get(void)
|
2017-08-21 23:56:06 +02:00
|
|
|
{
|
|
|
|
return host.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns unix domainname
|
|
|
|
*/
|
2017-08-29 01:52:29 +02:00
|
|
|
const char *cmd_domainname_get(void)
|
2017-08-21 23:56:06 +02:00
|
|
|
{
|
|
|
|
return host.domainname;
|
|
|
|
}
|
|
|
|
|
2022-01-22 14:15:42 +01:00
|
|
|
const char *cmd_system_get(void)
|
|
|
|
{
|
|
|
|
return host.system;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *cmd_release_get(void)
|
|
|
|
{
|
|
|
|
return host.release;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *cmd_version_get(void)
|
|
|
|
{
|
|
|
|
return host.version;
|
|
|
|
}
|
|
|
|
|
2022-07-01 22:24:52 +02:00
|
|
|
bool cmd_allow_reserved_ranges_get(void)
|
|
|
|
{
|
|
|
|
return host.allow_reserved_ranges;
|
|
|
|
}
|
|
|
|
|
bgpd: Add BGP Software Version Capability
Implement: https://datatracker.ietf.org/doc/html/draft-abraitis-bgp-version-capability
Tested with GoBGP:
```
% ./gobgp neighbor 192.168.10.124
BGP neighbor is 192.168.10.124, remote AS 65001
BGP version 4, remote router ID 200.200.200.202
BGP state = ESTABLISHED, up for 00:01:49
BGP OutQ = 0, Flops = 0
Hold time is 3, keepalive interval is 1 seconds
Configured hold time is 90, keepalive interval is 30 seconds
Neighbor capabilities:
multiprotocol:
ipv4-unicast: advertised and received
ipv6-unicast: advertised
route-refresh: advertised and received
extended-nexthop: advertised
Local: nlri: ipv4-unicast, nexthop: ipv6
UnknownCapability(6): received
UnknownCapability(9): received
graceful-restart: advertised and received
Local: restart time 10 sec
ipv6-unicast
ipv4-unicast
Remote: restart time 120 sec, notification flag set
ipv4-unicast, forward flag set
4-octet-as: advertised and received
add-path: received
Remote:
ipv4-unicast: receive
enhanced-route-refresh: received
long-lived-graceful-restart: advertised and received
Local:
ipv6-unicast, restart time 10 sec
ipv4-unicast, restart time 20 sec
Remote:
ipv4-unicast, restart time 0 sec, forward flag set
fqdn: advertised and received
Local:
name: donatas-pc, domain:
Remote:
name: spine1-debian-11, domain:
software-version: advertised and received
Local:
GoBGP/3.10.0
Remote:
FRRouting/8.5-dev-MyOwnFRRVersion-gdc92f44a45-dirt
cisco-route-refresh: received
Message statistics:
```
FRR side:
```
root@spine1-debian-11:~# vtysh -c 'show bgp neighbor 192.168.10.17 json' | \
> jq '."192.168.10.17".neighborCapabilities.softwareVersion.receivedSoftwareVersion'
"GoBGP/3.10.0"
root@spine1-debian-11:~#
```
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
2023-02-25 08:00:23 +01:00
|
|
|
const char *cmd_software_version_get(void)
|
|
|
|
{
|
|
|
|
return FRR_FULL_NAME "/" FRR_VERSION;
|
|
|
|
}
|
|
|
|
|
2018-09-09 00:03:19 +02:00
|
|
|
static int root_on_exit(struct vty *vty);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Standard command node structures. */
|
2008-12-01 20:10:34 +01:00
|
|
|
static struct cmd_node auth_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "auth",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = AUTH_NODE,
|
|
|
|
.prompt = "Password: ",
|
2002-12-13 21:15:29 +01:00
|
|
|
};
|
|
|
|
|
2008-12-01 20:10:34 +01:00
|
|
|
static struct cmd_node view_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "view",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = VIEW_NODE,
|
|
|
|
.prompt = "%s> ",
|
2018-09-09 00:03:19 +02:00
|
|
|
.node_exit = root_on_exit,
|
2002-12-13 21:15:29 +01:00
|
|
|
};
|
|
|
|
|
2008-12-01 20:10:34 +01:00
|
|
|
static struct cmd_node auth_enable_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "auth enable",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = AUTH_ENABLE_NODE,
|
|
|
|
.prompt = "Password: ",
|
2002-12-13 21:15:29 +01:00
|
|
|
};
|
|
|
|
|
2008-12-01 20:10:34 +01:00
|
|
|
static struct cmd_node enable_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "enable",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = ENABLE_NODE,
|
|
|
|
.prompt = "%s# ",
|
2018-09-09 00:03:19 +02:00
|
|
|
.node_exit = root_on_exit,
|
2002-12-13 21:15:29 +01:00
|
|
|
};
|
|
|
|
|
2018-09-08 22:31:43 +02:00
|
|
|
static int config_write_host(struct vty *vty);
|
2018-09-08 21:46:23 +02:00
|
|
|
static struct cmd_node config_node = {
|
2018-09-09 00:15:50 +02:00
|
|
|
.name = "config",
|
2018-09-08 21:46:23 +02:00
|
|
|
.node = CONFIG_NODE,
|
2018-09-08 23:15:09 +02:00
|
|
|
.parent_node = ENABLE_NODE,
|
2018-09-08 21:46:23 +02:00
|
|
|
.prompt = "%s(config)# ",
|
2018-09-08 22:31:43 +02:00
|
|
|
.config_write = config_write_host,
|
2018-09-09 00:03:19 +02:00
|
|
|
.node_exit = vty_config_node_exit,
|
2018-09-08 21:46:23 +02:00
|
|
|
};
|
2004-10-19 22:40:08 +02:00
|
|
|
|
2005-01-14 18:09:38 +01:00
|
|
|
/* This is called from main when a daemon is invoked with -v or --version. */
|
2004-10-19 22:40:08 +02:00
|
|
|
void print_version(const char *progname)
|
|
|
|
{
|
2016-12-14 19:30:44 +01:00
|
|
|
printf("%s version %s\n", progname, FRR_VERSION);
|
|
|
|
printf("%s\n", FRR_COPYRIGHT);
|
2020-06-17 18:48:34 +02:00
|
|
|
#ifdef ENABLE_VERSION_BUILD_CONFIG
|
2016-12-14 19:30:44 +01:00
|
|
|
printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
|
2020-06-17 18:48:34 +02:00
|
|
|
#endif
|
2004-10-19 22:40:08 +02:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
char *argv_concat(struct cmd_token **argv, int argc, int shift)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2018-06-20 18:25:28 +02:00
|
|
|
int cnt = MAX(argc - shift, 0);
|
|
|
|
const char *argstr[cnt + 1];
|
|
|
|
|
|
|
|
if (!cnt)
|
|
|
|
return NULL;
|
2018-05-11 21:32:06 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < cnt; i++)
|
|
|
|
argstr[i] = argv[i + shift]->arg;
|
|
|
|
|
|
|
|
return frrstr_join(argstr, cnt, " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
vector cmd_make_strvec(const char *string)
|
|
|
|
{
|
|
|
|
if (!string)
|
2005-01-28 21:28:35 +01:00
|
|
|
return NULL;
|
2018-05-11 21:32:06 +02:00
|
|
|
|
|
|
|
const char *copy = string;
|
|
|
|
|
|
|
|
/* skip leading whitespace */
|
2019-08-06 16:54:52 +02:00
|
|
|
while (isspace((unsigned char)*copy) && *copy != '\0')
|
2018-05-11 21:32:06 +02:00
|
|
|
copy++;
|
|
|
|
|
|
|
|
/* if the entire string was whitespace or a comment, return */
|
|
|
|
if (*copy == '\0' || *copy == '!' || *copy == '#')
|
|
|
|
return NULL;
|
|
|
|
|
2018-05-25 22:31:07 +02:00
|
|
|
vector result = frrstr_split_vec(copy, "\n\r\t ");
|
2018-05-11 21:32:06 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < vector_active(result); i++) {
|
|
|
|
if (strlen(vector_slot(result, i)) == 0) {
|
|
|
|
XFREE(MTYPE_TMP, vector_slot(result, i));
|
2018-05-29 23:38:18 +02:00
|
|
|
vector_unset(result, i);
|
2018-05-11 21:32:06 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2018-05-29 23:38:18 +02:00
|
|
|
|
|
|
|
vector_compact(result);
|
|
|
|
|
2018-05-11 21:32:06 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cmd_free_strvec(vector v)
|
|
|
|
{
|
|
|
|
frrstr_strvec_free(v);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-10-20 22:31:24 +02:00
|
|
|
/**
|
|
|
|
* Convenience function for accessing argv data.
|
|
|
|
*
|
|
|
|
* @param argc
|
|
|
|
* @param argv
|
|
|
|
* @param text definition snippet of the desired token
|
|
|
|
* @param index the starting index, and where to store the
|
|
|
|
* index of the found token if it exists
|
|
|
|
* @return 1 if found, 0 otherwise
|
|
|
|
*/
|
|
|
|
int argv_find(struct cmd_token **argv, int argc, const char *text, int *index)
|
|
|
|
{
|
|
|
|
int found = 0;
|
|
|
|
for (int i = *index; i < argc && found == 0; i++)
|
|
|
|
if ((found = strmatch(text, argv[i]->text)))
|
|
|
|
*index = i;
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2019-05-14 22:19:07 +02:00
|
|
|
static unsigned int cmd_hash_key(const void *p)
|
2016-06-16 17:03:11 +02:00
|
|
|
{
|
2017-09-04 00:50:35 +02:00
|
|
|
int size = sizeof(p);
|
|
|
|
|
|
|
|
return jhash(p, size, 0);
|
2016-06-16 17:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-10-17 21:27:12 +02:00
|
|
|
static bool cmd_hash_cmp(const void *a, const void *b)
|
2016-06-16 17:03:11 +02:00
|
|
|
{
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Install top node of command vector. */
|
2018-09-08 22:31:43 +02:00
|
|
|
void install_node(struct cmd_node *node)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-06-23 16:58:16 +02:00
|
|
|
#define CMD_HASH_STR_SIZE 256
|
|
|
|
char hash_name[CMD_HASH_STR_SIZE];
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
vector_set_index(cmdvec, node->node, node);
|
2016-09-20 01:46:51 +02:00
|
|
|
node->cmdgraph = graph_new();
|
2016-09-30 21:33:11 +02:00
|
|
|
node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
|
|
|
|
// add start node
|
2022-10-04 13:30:04 +02:00
|
|
|
struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
|
2016-11-18 16:24:47 +01:00
|
|
|
graph_new_node(node->cmdgraph, token,
|
|
|
|
(void (*)(void *)) & cmd_token_del);
|
2021-06-23 16:58:16 +02:00
|
|
|
|
|
|
|
snprintf(hash_name, sizeof(hash_name), "Command Hash: %s", node->name);
|
|
|
|
node->cmd_hash =
|
|
|
|
hash_create_size(16, cmd_hash_key, cmd_hash_cmp, hash_name);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return prompt character of specified node. */
|
|
|
|
const char *cmd_prompt(enum node_type node)
|
|
|
|
{
|
|
|
|
struct cmd_node *cnode;
|
|
|
|
|
|
|
|
cnode = vector_slot(cmdvec, node);
|
|
|
|
return cnode->prompt;
|
|
|
|
}
|
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
void cmd_defer_tree(bool val)
|
|
|
|
{
|
|
|
|
defer_cli_tree = val;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Install a command into a node. */
|
2020-07-21 08:28:04 +02:00
|
|
|
void _install_element(enum node_type ntype, const struct cmd_element *cmd)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct cmd_node *cnode;
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2005-09-05 13:54:13 +02:00
|
|
|
/* cmd_init hasn't been called */
|
|
|
|
if (!cmdvec) {
|
2016-06-16 17:03:11 +02:00
|
|
|
fprintf(stderr, "%s called before cmd_init, breakage likely\n",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-29 06:43:04 +02:00
|
|
|
|
2017-08-23 17:06:24 +02:00
|
|
|
cnode = vector_lookup(cmdvec, ntype);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
if (cnode == NULL) {
|
2002-12-13 21:15:29 +01:00
|
|
|
fprintf(stderr,
|
2017-08-23 17:06:24 +02:00
|
|
|
"%s[%s]:\n"
|
2018-09-09 00:15:50 +02:00
|
|
|
"\tnode %d does not exist.\n"
|
2017-08-23 17:06:24 +02:00
|
|
|
"\tplease call install_node() before install_element()\n",
|
2018-09-09 00:15:50 +02:00
|
|
|
cmd->name, cmd->string, ntype);
|
2016-09-20 01:46:51 +02:00
|
|
|
exit(EXIT_FAILURE);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2016-10-29 06:43:04 +02:00
|
|
|
|
2019-11-14 23:27:29 +01:00
|
|
|
if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) {
|
2016-10-29 06:43:04 +02:00
|
|
|
fprintf(stderr,
|
2017-08-23 17:06:24 +02:00
|
|
|
"%s[%s]:\n"
|
|
|
|
"\tnode %d (%s) already has this command installed.\n"
|
|
|
|
"\tduplicate install_element call?\n",
|
2018-09-09 00:15:50 +02:00
|
|
|
cmd->name, cmd->string, ntype, cnode->name);
|
2016-10-07 20:41:41 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-10-29 06:43:04 +02:00
|
|
|
|
*: remove the checking returned value for hash_get()
Firstly, *keep no change* for `hash_get()` with NULL
`alloc_func`.
Only focus on cases with non-NULL `alloc_func` of
`hash_get()`.
Since `hash_get()` with non-NULL `alloc_func` parameter
shall not fail, just ignore the returned value of it.
The returned value must not be NULL.
So in this case, remove the unnecessary checking NULL
or not for the returned value and add `void` in front
of it.
Importantly, also *keep no change* for the two cases with
non-NULL `alloc_func` -
1) Use `assert(<returned_data> == <searching_data>)` to
ensure it is a created node, not a found node.
Refer to `isis_vertex_queue_insert()` of isisd, there
are many examples of this case in isid.
2) Use `<returned_data> != <searching_data>` to judge it
is a found node, then free <searching_data>.
Refer to `aspath_intern()` of bgpd, there are many
examples of this case in bgpd.
Here, <returned_data> is the returned value from `hash_get()`,
and <searching_data> is the data, which is to be put into
hash table.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-04-21 08:37:12 +02:00
|
|
|
(void)hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern);
|
2016-10-29 06:43:04 +02:00
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
if (cnode->graph_built || !defer_cli_tree) {
|
|
|
|
struct graph *graph = graph_new();
|
|
|
|
struct cmd_token *token =
|
2022-10-04 13:30:04 +02:00
|
|
|
cmd_token_new(START_TKN, 0, NULL, NULL);
|
2021-10-18 11:51:09 +02:00
|
|
|
graph_new_node(graph, token,
|
|
|
|
(void (*)(void *)) & cmd_token_del);
|
|
|
|
|
|
|
|
cmd_graph_parse(graph, cmd);
|
|
|
|
cmd_graph_names(graph);
|
|
|
|
cmd_graph_merge(cnode->cmdgraph, graph, +1);
|
|
|
|
graph_delete_graph(graph);
|
|
|
|
|
|
|
|
cnode->graph_built = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector_set(cnode->cmd_vector, (void *)cmd);
|
|
|
|
|
|
|
|
if (ntype == VIEW_NODE)
|
|
|
|
_install_element(ENABLE_NODE, cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
|
|
|
|
{
|
|
|
|
struct cmd_node *cnode = arg;
|
|
|
|
const struct cmd_element *cmd = hb->data;
|
2016-12-16 23:27:39 +01:00
|
|
|
struct graph *graph = graph_new();
|
2022-10-04 13:30:04 +02:00
|
|
|
struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
|
2021-10-18 11:51:09 +02:00
|
|
|
|
2016-11-18 16:24:47 +01:00
|
|
|
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
|
2016-12-16 23:27:39 +01:00
|
|
|
|
2016-11-18 16:24:47 +01:00
|
|
|
cmd_graph_parse(graph, cmd);
|
2017-03-22 06:56:17 +01:00
|
|
|
cmd_graph_names(graph);
|
2016-11-18 16:24:47 +01:00
|
|
|
cmd_graph_merge(cnode->cmdgraph, graph, +1);
|
2016-12-16 23:27:39 +01:00
|
|
|
graph_delete_graph(graph);
|
2021-10-18 11:51:09 +02:00
|
|
|
}
|
2016-12-16 23:27:39 +01:00
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
void cmd_finalize_node(struct cmd_node *cnode)
|
|
|
|
{
|
|
|
|
if (cnode->graph_built)
|
|
|
|
return;
|
2016-03-11 20:27:12 +01:00
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
hash_iterate(cnode->cmd_hash, cmd_finalize_iter, cnode);
|
|
|
|
cnode->graph_built = true;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-11-14 23:27:29 +01:00
|
|
|
void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
|
2016-12-16 23:27:39 +01:00
|
|
|
{
|
|
|
|
struct cmd_node *cnode;
|
|
|
|
|
|
|
|
/* cmd_init hasn't been called */
|
|
|
|
if (!cmdvec) {
|
|
|
|
fprintf(stderr, "%s called before cmd_init, breakage likely\n",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-23 17:06:24 +02:00
|
|
|
cnode = vector_lookup(cmdvec, ntype);
|
2016-12-16 23:27:39 +01:00
|
|
|
|
|
|
|
if (cnode == NULL) {
|
|
|
|
fprintf(stderr,
|
2017-08-23 17:06:24 +02:00
|
|
|
"%s[%s]:\n"
|
2018-09-09 00:15:50 +02:00
|
|
|
"\tnode %d does not exist.\n"
|
2017-08-23 17:06:24 +02:00
|
|
|
"\tplease call install_node() before uninstall_element()\n",
|
2018-09-09 00:15:50 +02:00
|
|
|
cmd->name, cmd->string, ntype);
|
2016-12-16 23:27:39 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2019-11-14 23:27:29 +01:00
|
|
|
if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) {
|
2016-12-16 23:27:39 +01:00
|
|
|
fprintf(stderr,
|
2017-08-23 17:06:24 +02:00
|
|
|
"%s[%s]:\n"
|
|
|
|
"\tnode %d (%s) does not have this command installed.\n"
|
|
|
|
"\tduplicate uninstall_element call?\n",
|
2018-09-09 00:15:50 +02:00
|
|
|
cmd->name, cmd->string, ntype, cnode->name);
|
2016-12-16 23:27:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-14 23:27:29 +01:00
|
|
|
vector_unset_value(cnode->cmd_vector, (void *)cmd);
|
2016-12-16 23:27:39 +01:00
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
if (cnode->graph_built) {
|
|
|
|
struct graph *graph = graph_new();
|
|
|
|
struct cmd_token *token =
|
2022-10-04 13:30:04 +02:00
|
|
|
cmd_token_new(START_TKN, 0, NULL, NULL);
|
2021-10-18 11:51:09 +02:00
|
|
|
graph_new_node(graph, token,
|
|
|
|
(void (*)(void *)) & cmd_token_del);
|
|
|
|
|
|
|
|
cmd_graph_parse(graph, cmd);
|
|
|
|
cmd_graph_names(graph);
|
|
|
|
cmd_graph_merge(cnode->cmdgraph, graph, -1);
|
|
|
|
graph_delete_graph(graph);
|
|
|
|
}
|
2016-12-16 23:27:39 +01:00
|
|
|
|
|
|
|
if (ntype == VIEW_NODE)
|
|
|
|
uninstall_element(ENABLE_NODE, cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-21 10:54:58 +01:00
|
|
|
static const unsigned char itoa64[] =
|
2002-12-13 21:15:29 +01:00
|
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
|
|
static void to64(char *s, long v, int n)
|
|
|
|
{
|
2016-09-20 01:46:51 +02:00
|
|
|
while (--n >= 0) {
|
2002-12-13 21:15:29 +01:00
|
|
|
*s++ = itoa64[v & 0x3f];
|
|
|
|
v >>= 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
static char *zencrypt(const char *passwd)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
char salt[6];
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
gettimeofday(&tv, 0);
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2020-04-17 15:35:15 +02:00
|
|
|
to64(&salt[0], frr_weak_random(), 3);
|
2002-12-13 21:15:29 +01:00
|
|
|
to64(&salt[3], tv.tv_usec, 3);
|
|
|
|
salt[5] = '\0';
|
|
|
|
|
|
|
|
return crypt(passwd, salt);
|
|
|
|
}
|
|
|
|
|
2017-05-06 06:40:17 +02:00
|
|
|
static bool full_cli;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* This function write configuration of this host. */
|
|
|
|
static int config_write_host(struct vty *vty)
|
|
|
|
{
|
2022-04-21 20:13:01 +02:00
|
|
|
const char *name;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-04-21 20:13:01 +02:00
|
|
|
name = cmd_hostname_get();
|
|
|
|
if (name && name[0] != '\0')
|
|
|
|
vty_out(vty, "hostname %s\n", name);
|
|
|
|
|
|
|
|
name = cmd_domainname_get();
|
|
|
|
if (name && name[0] != '\0')
|
|
|
|
vty_out(vty, "domainname %s\n", name);
|
2018-02-07 23:46:04 +01:00
|
|
|
|
2022-07-01 22:24:52 +02:00
|
|
|
if (cmd_allow_reserved_ranges_get())
|
|
|
|
vty_out(vty, "allow-reserved-ranges\n");
|
|
|
|
|
2017-08-04 22:39:56 +02:00
|
|
|
/* The following are all configuration commands that are not sent to
|
2018-04-29 20:35:39 +02:00
|
|
|
* watchfrr. For instance watchfrr is hardcoded to log to syslog so
|
|
|
|
* we would always display 'log syslog informational' in the config
|
|
|
|
* which would cause other daemons to then switch to syslog when they
|
|
|
|
* parse frr.conf.
|
|
|
|
*/
|
2017-05-06 06:40:17 +02:00
|
|
|
if (full_cli) {
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.encrypt) {
|
|
|
|
if (host.password_encrypt)
|
2018-04-29 20:35:39 +02:00
|
|
|
vty_out(vty, "password 8 %s\n",
|
|
|
|
host.password_encrypt);
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.enable_encrypt)
|
|
|
|
vty_out(vty, "enable password 8 %s\n",
|
|
|
|
host.enable_encrypt);
|
|
|
|
} else {
|
|
|
|
if (host.password)
|
|
|
|
vty_out(vty, "password %s\n", host.password);
|
|
|
|
if (host.enable)
|
2018-04-29 20:35:39 +02:00
|
|
|
vty_out(vty, "enable password %s\n",
|
|
|
|
host.enable);
|
2017-08-04 22:39:56 +02:00
|
|
|
}
|
2017-05-06 06:40:17 +02:00
|
|
|
log_config_write(vty);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-13 20:38:09 +02:00
|
|
|
/* print disable always, but enable only if default is flipped
|
|
|
|
* => prep for future removal of compile-time knob
|
|
|
|
*/
|
|
|
|
if (!cputime_enabled)
|
|
|
|
vty_out(vty, "no service cputime-stats\n");
|
|
|
|
#ifdef EXCLUDE_CPU_TIME
|
|
|
|
else
|
|
|
|
vty_out(vty, "service cputime-stats\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!cputime_threshold)
|
|
|
|
vty_out(vty, "no service cputime-warning\n");
|
|
|
|
#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
|
|
|
|
else /* again, always print non-default */
|
|
|
|
#else
|
|
|
|
else if (cputime_threshold != 5000000)
|
|
|
|
#endif
|
|
|
|
vty_out(vty, "service cputime-warning %lu\n",
|
2022-12-28 09:33:09 +01:00
|
|
|
cputime_threshold / 1000);
|
2021-04-13 20:38:09 +02:00
|
|
|
|
|
|
|
if (!walltime_threshold)
|
|
|
|
vty_out(vty, "no service walltime-warning\n");
|
|
|
|
#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
|
|
|
|
else /* again, always print non-default */
|
|
|
|
#else
|
|
|
|
else if (walltime_threshold != 5000000)
|
|
|
|
#endif
|
|
|
|
vty_out(vty, "service walltime-warning %lu\n",
|
2022-12-28 09:33:09 +01:00
|
|
|
walltime_threshold / 1000);
|
2021-04-13 20:38:09 +02:00
|
|
|
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.advanced)
|
|
|
|
vty_out(vty, "service advanced-vty\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.encrypt)
|
|
|
|
vty_out(vty, "service password-encryption\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.lines >= 0)
|
2018-04-29 20:35:39 +02:00
|
|
|
vty_out(vty, "service terminal-length %d\n",
|
|
|
|
host.lines);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-04 22:39:56 +02:00
|
|
|
if (host.motdfile)
|
|
|
|
vty_out(vty, "banner motd file %s\n", host.motdfile);
|
2019-10-22 17:06:03 +02:00
|
|
|
else if (host.motd
|
|
|
|
&& strncmp(host.motd, FRR_DEFAULT_MOTD,
|
|
|
|
strlen(host.motd)))
|
|
|
|
vty_out(vty, "banner motd line %s\n", host.motd);
|
2017-08-04 22:39:56 +02:00
|
|
|
else if (!host.motd)
|
|
|
|
vty_out(vty, "no banner motd\n");
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-23 16:18:49 +02:00
|
|
|
if (debug_memstats_at_exit)
|
|
|
|
vty_out(vty, "!\ndebug memstats-at-exit\n");
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
/* Utility function for getting command graph. */
|
|
|
|
static struct graph *cmd_node_graph(vector v, enum node_type ntype)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-20 01:46:51 +02:00
|
|
|
struct cmd_node *cnode = vector_slot(v, ntype);
|
2021-10-18 11:51:09 +02:00
|
|
|
|
|
|
|
cmd_finalize_node(cnode);
|
2016-09-20 01:46:51 +02:00
|
|
|
return cnode->cmdgraph;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
static int cmd_try_do_shortcut(enum node_type node, char *first_word)
|
|
|
|
{
|
|
|
|
if (first_word != NULL && node != AUTH_NODE && node != VIEW_NODE
|
|
|
|
&& node != AUTH_ENABLE_NODE && 0 == strcmp("do", first_word))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
/**
|
|
|
|
* Compare function for cmd_token.
|
|
|
|
* Used with qsort to sort command completions.
|
|
|
|
*/
|
|
|
|
static int compare_completions(const void *fst, const void *snd)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2018-09-17 18:22:59 +02:00
|
|
|
const struct cmd_token *first = *(const struct cmd_token * const *)fst,
|
|
|
|
*secnd = *(const struct cmd_token * const *)snd;
|
2016-09-20 01:46:51 +02:00
|
|
|
return strcmp(first->text, secnd->text);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
/**
|
|
|
|
* Takes a list of completions returned by command_complete,
|
|
|
|
* dedeuplicates them based on both text and description,
|
2016-10-06 03:15:48 +02:00
|
|
|
* sorts them, and returns them as a vector.
|
|
|
|
*
|
|
|
|
* @param completions linked list of cmd_token
|
|
|
|
* @return deduplicated and sorted vector with
|
2016-09-20 01:46:51 +02:00
|
|
|
*/
|
|
|
|
vector completions_to_vec(struct list *completions)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-20 01:46:51 +02:00
|
|
|
vector comps = vector_init(VECTOR_MIN_SIZE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
struct listnode *ln;
|
2016-10-06 03:15:48 +02:00
|
|
|
struct cmd_token *token, *cr = NULL;
|
2016-09-20 01:46:51 +02:00
|
|
|
unsigned int i, exists;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(completions, ln, token)) {
|
2016-10-06 03:15:48 +02:00
|
|
|
if (token->type == END_TKN && (cr = token))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// linear search for token in completions vector
|
|
|
|
exists = 0;
|
|
|
|
for (i = 0; i < vector_active(comps) && !exists; i++) {
|
|
|
|
struct cmd_token *curr = vector_slot(comps, i);
|
2017-01-19 18:07:39 +01:00
|
|
|
#ifdef VTYSH_DEBUG
|
2016-09-20 01:46:51 +02:00
|
|
|
exists = !strcmp(curr->text, token->text)
|
|
|
|
&& !strcmp(curr->desc, token->desc);
|
2017-01-19 18:07:39 +01:00
|
|
|
#else
|
|
|
|
exists = !strcmp(curr->text, token->text);
|
|
|
|
#endif /* VTYSH_DEBUG */
|
2013-09-30 14:27:51 +02:00
|
|
|
}
|
2005-03-14 18:41:45 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
if (!exists)
|
2016-11-12 02:06:32 +01:00
|
|
|
vector_set(comps, token);
|
2016-09-20 01:46:51 +02:00
|
|
|
}
|
2013-09-30 14:27:51 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// sort completions
|
|
|
|
qsort(comps->index, vector_active(comps), sizeof(void *),
|
|
|
|
&compare_completions);
|
2013-09-30 14:27:51 +02:00
|
|
|
|
2016-10-29 06:43:04 +02:00
|
|
|
// make <cr> the first element, if it is present
|
2016-10-06 03:15:48 +02:00
|
|
|
if (cr) {
|
|
|
|
vector_set_index(comps, vector_active(comps), NULL);
|
|
|
|
memmove(comps->index + 1, comps->index,
|
|
|
|
(comps->alloced - 1) * sizeof(void *));
|
2016-11-12 02:06:32 +01:00
|
|
|
vector_set_index(comps, 0, cr);
|
2016-10-06 03:15:48 +02:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return comps;
|
2013-09-30 14:27:51 +02:00
|
|
|
}
|
2016-09-20 01:46:51 +02:00
|
|
|
/**
|
|
|
|
* Generates a vector of cmd_token representing possible completions
|
|
|
|
* on the current input.
|
|
|
|
*
|
|
|
|
* @param vline the vectorized input line
|
|
|
|
* @param vty the vty with the node to match on
|
|
|
|
* @param status pointer to matcher status code
|
2016-10-29 06:43:04 +02:00
|
|
|
* @return vector of struct cmd_token * with possible completions
|
2016-09-20 01:46:51 +02:00
|
|
|
*/
|
|
|
|
static vector cmd_complete_command_real(vector vline, struct vty *vty,
|
|
|
|
int *status)
|
2013-09-30 14:27:51 +02:00
|
|
|
{
|
2016-09-20 01:46:51 +02:00
|
|
|
struct list *completions;
|
|
|
|
struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
|
2013-09-30 14:27:51 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
enum matcher_rv rv = command_complete(cmdgraph, vline, &completions);
|
2013-09-30 14:27:51 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
if (MATCHER_ERROR(rv)) {
|
2016-11-12 02:06:32 +01:00
|
|
|
*status = CMD_ERR_NO_MATCH;
|
2016-09-20 01:46:51 +02:00
|
|
|
return NULL;
|
2002-12-13 22:20:42 +01:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
vector comps = completions_to_vec(completions);
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&completions);
|
2002-12-13 22:20:42 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// set status code appropriately
|
|
|
|
switch (vector_active(comps)) {
|
|
|
|
case 0:
|
|
|
|
*status = CMD_ERR_NO_MATCH;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*status = CMD_COMPLETE_FULL_MATCH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*status = CMD_COMPLETE_LIST_MATCH;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return comps;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
vector cmd_describe_command(vector vline, struct vty *vty, int *status)
|
|
|
|
{
|
|
|
|
vector ret;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
|
|
|
|
enum node_type onode;
|
2017-12-07 20:31:48 +01:00
|
|
|
int orig_xpath_index;
|
2016-09-20 01:46:51 +02:00
|
|
|
vector shifted_vline;
|
|
|
|
unsigned int index;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
onode = vty->node;
|
2017-12-07 20:31:48 +01:00
|
|
|
orig_xpath_index = vty->xpath_index;
|
2016-09-20 01:46:51 +02:00
|
|
|
vty->node = ENABLE_NODE;
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index = 0;
|
2016-09-20 01:46:51 +02:00
|
|
|
/* We can try it on enable node, cos' the vty is authenticated
|
|
|
|
*/
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
shifted_vline = vector_init(vector_count(vline));
|
|
|
|
/* use memcpy? */
|
|
|
|
for (index = 1; index < vector_active(vline); index++) {
|
|
|
|
vector_set_index(shifted_vline, index - 1,
|
|
|
|
vector_lookup(vline, index));
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
ret = cmd_complete_command_real(shifted_vline, vty, status);
|
|
|
|
|
|
|
|
vector_free(shifted_vline);
|
|
|
|
vty->node = onode;
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index = orig_xpath_index;
|
2016-09-20 01:46:51 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return cmd_complete_command_real(vline, vty, status);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
static struct list *varhandlers = NULL;
|
|
|
|
|
|
|
|
void cmd_variable_complete(struct cmd_token *token, const char *arg,
|
|
|
|
vector comps)
|
|
|
|
{
|
|
|
|
struct listnode *ln;
|
|
|
|
const struct cmd_variable_handler *cvh;
|
|
|
|
size_t i, argsz;
|
|
|
|
vector tmpcomps;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
tmpcomps = arg ? vector_init(VECTOR_MIN_SIZE) : comps;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(varhandlers, ln, cvh)) {
|
|
|
|
if (cvh->tokenname && strcmp(cvh->tokenname, token->text))
|
|
|
|
continue;
|
2017-07-22 14:52:33 +02:00
|
|
|
if (cvh->varname && (!token->varname
|
|
|
|
|| strcmp(cvh->varname, token->varname)))
|
2016-11-19 11:57:08 +01:00
|
|
|
continue;
|
|
|
|
cvh->completions(tmpcomps, token);
|
|
|
|
break;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
if (!arg)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
argsz = strlen(arg);
|
|
|
|
for (i = vector_active(tmpcomps); i; i--) {
|
|
|
|
char *item = vector_slot(tmpcomps, i - 1);
|
|
|
|
if (strlen(item) >= argsz && !strncmp(item, arg, argsz))
|
|
|
|
vector_set(comps, item);
|
|
|
|
else
|
|
|
|
XFREE(MTYPE_COMPLETION, item);
|
|
|
|
}
|
|
|
|
vector_free(tmpcomps);
|
|
|
|
}
|
|
|
|
|
2017-07-12 20:40:18 +02:00
|
|
|
#define AUTOCOMP_INDENT 5
|
|
|
|
|
2017-07-14 13:18:14 +02:00
|
|
|
char *cmd_variable_comp2str(vector comps, unsigned short cols)
|
2017-07-12 20:40:18 +02:00
|
|
|
{
|
|
|
|
size_t bsz = 16;
|
|
|
|
char *buf = XCALLOC(MTYPE_TMP, bsz);
|
|
|
|
int lc = AUTOCOMP_INDENT;
|
|
|
|
size_t cs = AUTOCOMP_INDENT;
|
|
|
|
size_t itemlen;
|
|
|
|
snprintf(buf, bsz, "%*s", AUTOCOMP_INDENT, "");
|
|
|
|
for (size_t j = 0; j < vector_active(comps); j++) {
|
|
|
|
char *item = vector_slot(comps, j);
|
|
|
|
itemlen = strlen(item);
|
|
|
|
|
2017-07-14 13:18:14 +02:00
|
|
|
if (cs + itemlen + AUTOCOMP_INDENT + 3 >= bsz)
|
2017-07-12 20:40:18 +02:00
|
|
|
buf = XREALLOC(MTYPE_TMP, buf, (bsz *= 2));
|
|
|
|
|
|
|
|
if (lc + itemlen + 1 >= cols) {
|
2017-07-14 13:18:14 +02:00
|
|
|
cs += snprintf(&buf[cs], bsz - cs, "\n%*s",
|
|
|
|
AUTOCOMP_INDENT, "");
|
2017-07-12 20:40:18 +02:00
|
|
|
lc = AUTOCOMP_INDENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t written = snprintf(&buf[cs], bsz - cs, "%s ", item);
|
|
|
|
lc += written;
|
|
|
|
cs += written;
|
|
|
|
XFREE(MTYPE_COMPLETION, item);
|
|
|
|
vector_set_index(comps, j, NULL);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
|
|
|
|
{
|
|
|
|
if (!varhandlers)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (; cvh->completions; cvh++)
|
|
|
|
listnode_add(varhandlers, (void *)cvh);
|
|
|
|
}
|
|
|
|
|
2017-05-10 16:38:48 +02:00
|
|
|
DEFUN_HIDDEN (autocomplete,
|
|
|
|
autocomplete_cmd,
|
|
|
|
"autocomplete TYPE TEXT VARNAME",
|
|
|
|
"Autocompletion handler (internal, for vtysh)\n"
|
|
|
|
"cmd_token->type\n"
|
|
|
|
"cmd_token->text\n"
|
|
|
|
"cmd_token->varname\n")
|
|
|
|
{
|
|
|
|
struct cmd_token tok;
|
|
|
|
vector comps = vector_init(32);
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
memset(&tok, 0, sizeof(tok));
|
|
|
|
tok.type = atoi(argv[1]->arg);
|
|
|
|
tok.text = argv[2]->arg;
|
|
|
|
tok.varname = argv[3]->arg;
|
|
|
|
if (!strcmp(tok.varname, "-"))
|
|
|
|
tok.varname = NULL;
|
|
|
|
|
|
|
|
cmd_variable_complete(&tok, NULL, comps);
|
|
|
|
|
|
|
|
for (i = 0; i < vector_active(comps); i++) {
|
|
|
|
char *text = vector_slot(comps, i);
|
|
|
|
vty_out(vty, "%s\n", text);
|
|
|
|
XFREE(MTYPE_COMPLETION, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
vector_free(comps);
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-10-29 06:43:04 +02:00
|
|
|
/**
|
|
|
|
* Generate possible tab-completions for the given input. This function only
|
|
|
|
* returns results that would result in a valid command if used as Readline
|
|
|
|
* completions (as is the case in vtysh). For instance, if the passed vline ends
|
|
|
|
* with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
|
|
|
|
*
|
|
|
|
* @param vline vectorized input line
|
|
|
|
* @param vty the vty
|
|
|
|
* @param status location to store matcher status code in
|
|
|
|
* @return set of valid strings for use with Readline as tab-completions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char **cmd_complete_command(vector vline, struct vty *vty, int *status)
|
2002-12-13 22:20:42 +01:00
|
|
|
{
|
2016-10-04 01:21:11 +02:00
|
|
|
char **ret = NULL;
|
|
|
|
int original_node = vty->node;
|
|
|
|
vector input_line = vector_init(vector_count(vline));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// if the first token is 'do' we'll want to execute the command in the
|
|
|
|
// enable node
|
|
|
|
int do_shortcut = cmd_try_do_shortcut(vty->node, vector_slot(vline, 0));
|
|
|
|
vty->node = do_shortcut ? ENABLE_NODE : original_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// construct the input line we'll be matching on
|
|
|
|
unsigned int offset = (do_shortcut) ? 1 : 0;
|
|
|
|
for (unsigned index = 0; index + offset < vector_active(vline); index++)
|
2016-12-18 06:14:55 +01:00
|
|
|
vector_set_index(input_line, index,
|
|
|
|
vector_lookup(vline, index + offset));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// get token completions -- this is a copying operation
|
2016-11-29 13:42:06 +01:00
|
|
|
vector comps = NULL, initial_comps;
|
2016-10-29 06:43:04 +02:00
|
|
|
initial_comps = cmd_complete_command_real(input_line, vty, status);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
if (!MATCHER_ERROR(*status)) {
|
2016-10-31 04:34:27 +01:00
|
|
|
assert(initial_comps);
|
|
|
|
// filter out everything that is not suitable for a
|
|
|
|
// tab-completion
|
|
|
|
comps = vector_init(VECTOR_MIN_SIZE);
|
|
|
|
for (unsigned int i = 0; i < vector_active(initial_comps);
|
|
|
|
i++) {
|
|
|
|
struct cmd_token *token = vector_slot(initial_comps, i);
|
|
|
|
if (token->type == WORD_TKN)
|
2016-11-19 11:57:08 +01:00
|
|
|
vector_set(comps, XSTRDUP(MTYPE_COMPLETION,
|
|
|
|
token->text));
|
|
|
|
else if (IS_VARYING_TOKEN(token->type)) {
|
|
|
|
const char *ref = vector_lookup(
|
|
|
|
vline, vector_active(vline) - 1);
|
|
|
|
cmd_variable_complete(token, ref, comps);
|
2016-10-31 04:34:27 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-10-31 04:34:27 +01:00
|
|
|
vector_free(initial_comps);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-15 23:53:02 +01:00
|
|
|
// since we filtered results, we need to re-set status code
|
|
|
|
switch (vector_active(comps)) {
|
|
|
|
case 0:
|
|
|
|
*status = CMD_ERR_NO_MATCH;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*status = CMD_COMPLETE_FULL_MATCH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*status = CMD_COMPLETE_LIST_MATCH;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// copy completions text into an array of char*
|
2016-11-12 02:06:32 +01:00
|
|
|
ret = XMALLOC(MTYPE_TMP,
|
|
|
|
(vector_active(comps) + 1) * sizeof(char *));
|
2016-10-04 01:21:11 +02:00
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < vector_active(comps); i++) {
|
2016-11-19 11:57:08 +01:00
|
|
|
ret[i] = vector_slot(comps, i);
|
2016-10-04 01:21:11 +02:00
|
|
|
}
|
2016-10-29 06:43:04 +02:00
|
|
|
// set the last element to NULL, because this array is used in
|
|
|
|
// a Readline completion_generator function which expects NULL
|
|
|
|
// as a sentinel value
|
2016-10-04 01:21:11 +02:00
|
|
|
ret[i] = NULL;
|
|
|
|
vector_free(comps);
|
|
|
|
comps = NULL;
|
2017-02-08 15:14:23 +01:00
|
|
|
} else if (initial_comps)
|
|
|
|
vector_free(initial_comps);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// comps should always be null here
|
|
|
|
assert(!comps);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// free the adjusted input line
|
|
|
|
vector_free(input_line);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-04 01:21:11 +02:00
|
|
|
// reset vty->node to its original value
|
|
|
|
vty->node = original_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return ret;
|
2016-01-12 19:41:46 +01:00
|
|
|
}
|
2002-12-13 22:20:42 +01:00
|
|
|
|
|
|
|
/* return parent node */
|
|
|
|
/* MUST eventually converge on CONFIG_NODE */
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
enum node_type node_parent(enum node_type node)
|
2002-12-13 22:20:42 +01:00
|
|
|
{
|
2021-08-18 12:14:27 +02:00
|
|
|
struct cmd_node *cnode;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
This patch adds Yon's CLI 'walk back up tree' patch. Following are email
describing original patch and a shorter email describing changes to an
updated patch, the one which is applied:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
From havanna_moon@gmx.net Sat Jan 18 01:13:11 2003
Date: Sat, 11 Jan 2003 23:36:51 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: zebra@zebra.org
Subject: [zebra 17218] Re: [PATCH] CLI extensions.
Hi,
[redacted]
> I prefer the IOS way for the node "up walking".
This patch should walk the tree upwards:
bgpd(config)# router bgp 1
bgpd(config-router)# address-family ipv4 multicast
bgpd(config-router-af)# access-list 1 remark hola que tal
bgpd(config)#
I cant test all combinations, so I cant rule out some bugs. I'd love to
get (long and explicit) bug reports.
[redacted]
2003-01-18 02:16:20 +01:00
|
|
|
assert(node > CONFIG_NODE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-18 12:14:27 +02:00
|
|
|
cnode = vector_lookup(cmdvec, node);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-18 12:14:27 +02:00
|
|
|
return cnode->parent_node;
|
2002-12-13 22:20:42 +01:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Execute command by argument vline vector. */
|
2019-02-11 19:01:32 +01:00
|
|
|
static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
|
2016-09-20 01:46:51 +02:00
|
|
|
struct vty *vty,
|
2021-04-08 13:35:09 +02:00
|
|
|
const struct cmd_element **cmd,
|
|
|
|
unsigned int up_level)
|
2016-09-20 01:46:51 +02:00
|
|
|
{
|
|
|
|
struct list *argv_list;
|
|
|
|
enum matcher_rv status;
|
2016-11-12 02:06:32 +01:00
|
|
|
const struct cmd_element *matched_element = NULL;
|
2021-04-08 13:35:09 +02:00
|
|
|
unsigned int i;
|
|
|
|
int xpath_index = vty->xpath_index;
|
|
|
|
int node = vty->node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-08 13:35:09 +02:00
|
|
|
/* only happens for legacy split config file load; need to check for
|
|
|
|
* a match before calling node_exit handlers below
|
|
|
|
*/
|
|
|
|
for (i = 0; i < up_level; i++) {
|
2021-11-06 21:10:41 +01:00
|
|
|
struct cmd_node *cnode;
|
|
|
|
|
2021-04-08 13:35:09 +02:00
|
|
|
if (node <= CONFIG_NODE)
|
|
|
|
return CMD_NO_LEVEL_UP;
|
|
|
|
|
2021-11-06 21:10:41 +01:00
|
|
|
cnode = vector_slot(cmdvec, node);
|
2021-04-08 13:35:09 +02:00
|
|
|
node = node_parent(node);
|
|
|
|
|
2021-11-06 21:10:41 +01:00
|
|
|
if (xpath_index > 0 && !cnode->no_xpath)
|
2021-04-08 13:35:09 +02:00
|
|
|
xpath_index--;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
|
2016-10-01 22:05:10 +02:00
|
|
|
status = command_match(cmdgraph, vline, &argv_list, &matched_element);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-01 22:05:10 +02:00
|
|
|
if (cmd)
|
|
|
|
*cmd = matched_element;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// if matcher error, return corresponding CMD_ERR
|
|
|
|
if (MATCHER_ERROR(status)) {
|
2017-02-08 15:14:23 +01:00
|
|
|
if (argv_list)
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&argv_list);
|
2016-09-20 01:46:51 +02:00
|
|
|
switch (status) {
|
|
|
|
case MATCHER_INCOMPLETE:
|
|
|
|
return CMD_ERR_INCOMPLETE;
|
|
|
|
case MATCHER_AMBIGUOUS:
|
|
|
|
return CMD_ERR_AMBIGUOUS;
|
2023-01-30 16:06:29 +01:00
|
|
|
case MATCHER_NO_MATCH:
|
|
|
|
case MATCHER_OK:
|
2016-09-20 01:46:51 +02:00
|
|
|
return CMD_ERR_NO_MATCH;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-08 13:35:09 +02:00
|
|
|
for (i = 0; i < up_level; i++)
|
|
|
|
cmd_exit(vty);
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// build argv array from argv list
|
|
|
|
struct cmd_token **argv = XMALLOC(
|
|
|
|
MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
|
|
|
|
struct listnode *ln;
|
|
|
|
struct cmd_token *token;
|
2021-04-08 13:35:09 +02:00
|
|
|
|
|
|
|
i = 0;
|
2016-09-20 01:46:51 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
|
|
|
|
argv[i++] = token;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
int argc = argv_list->count;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
int ret;
|
2016-10-01 22:05:10 +02:00
|
|
|
if (matched_element->daemon)
|
2016-09-20 01:46:51 +02:00
|
|
|
ret = CMD_SUCCESS_DAEMON;
|
lib, ripd: rework API for converted CLI commands
When editing the candidate configuration, the northbound must ensure
that either all changes made by a command are accepted or none are.
This is done to prevent inconsistent states where only parts of a
command are applied in the event any error happens.
The previous API for converted commands, the nb_cli_cfg_change()
function, required callers to pass an array containing all changes
that needed to be applied in the candidate configuration. The
problem with this API is that it was very inconvenient for complex
commands, which change different configuration options depending
on several factors. This required users to manipulate the array
of configuration changes using low-level primitives, making it
complicated to implement some commands.
To solve this problem, introduce a new API based on the two following
functions:
- nb_cli_enqueue_change()
- nb_cli_apply_changes()
The first function is used to enqueue configuration changes, one
at time. Then the nb_cli_apply_changes() function is used to apply
all the enqueued configuration changes.
To implement this, a static-sized array was allocated in the "vty"
structure, along with a counter of enqueued changes. This eliminates
the need to declare an array of configuration changes in every
converted CLI command, simplifying things quite considerably.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2018-11-26 18:30:14 +01:00
|
|
|
else {
|
2019-05-28 00:48:13 +02:00
|
|
|
if (vty->config) {
|
|
|
|
/* Clear array of enqueued configuration changes. */
|
|
|
|
vty->num_cfg_changes = 0;
|
|
|
|
memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
|
|
|
|
|
2019-09-06 00:43:27 +02:00
|
|
|
/* Regenerate candidate configuration if necessary. */
|
|
|
|
if (frr_get_cli_mode() == FRR_CLI_CLASSIC
|
|
|
|
&& running_config->version
|
|
|
|
> vty->candidate_config->version)
|
2019-05-28 00:48:13 +02:00
|
|
|
nb_config_replace(vty->candidate_config,
|
|
|
|
running_config, true);
|
lib: introduce configuration back-off timer for YANG-modeled commands
When using the default CLI mode, the northbound layer needs to create
a separate transaction to process each YANG-modeled command since
they are supposed to be applied immediately (there's no candidate
configuration nor the "commit" command like in the transactional
CLI). The problem is that configuration transactions have an overhead
associated to them, in big part because of the use of some heavy
libyang functions like `lyd_validate()` and `lyd_diff()`. As of
now this overhead is substantial and doesn't scale well when large
numbers of transactions need to be performed in sequence.
As an example, loading 50k prefix-lists using a single transaction
takes about 2 seconds on a modern CPU. Loading the same 50k
prefix-lists using 50k transactions can take more than an hour
to complete (which is unacceptable by any standard). To fix this
problem, some heavy optimization work needs to be done on libyang and
on the FRR northbound itself too (e.g. perform partial configuration
diffs whenever possible). This, however, should be a long term
effort since these optimizations shouldn't be trivial to implement
and we're far from having the performance numbers we need.
In the meanwhile, this commit introduces a simple but efficient
workaround to alleviate the issue. In short, a new back-off timer
was introduced in the CLI to monitor and detect when too many
YANG-modeled commands are being received at the same time. When
a certain threshold is reached (100 YANG-modeled commands within
one second), the northbound starts to group all subsequent commands
into a single large transaction, which allows them to be processed
much faster (e.g. seconds and not hours). It's essentially a
protection mechanism that creates dynamically-sized transactions
when necessary to prevent performance issues from happening. This
mechanism is enabled both when parsing configuration files and when
reading commands from a terminal.
The downside of this optimization is that, if several YANG-modeled
commands are grouped into the same transaction and at least one of
them fails, the whole transaction is rejected. This is undesirable
since users don't expect transactional behavior when that's not
enabled explicitly. To minimize this issue, the CLI will log all
commands that were rejected whenever that happens, to make the
user aware of what happened and have enough information to fix
the problem. Commands that fail due to parsing errors or CLI-level
validations in general are rejected separately.
Again, this proposed workaround is intended to be temporary. The
goal is to provided a quick fix to issues like #6658 while we work
on better long-term solutions.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2020-07-02 19:43:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform pending commit (if any) before executing
|
|
|
|
* non-YANG command.
|
|
|
|
*/
|
2022-10-04 13:30:04 +02:00
|
|
|
if (!(matched_element->attr & CMD_ATTR_YANG))
|
2021-05-28 21:16:18 +02:00
|
|
|
(void)nb_cli_pending_commit_check(vty);
|
2019-05-28 00:48:13 +02:00
|
|
|
}
|
lib, ripd: rework API for converted CLI commands
When editing the candidate configuration, the northbound must ensure
that either all changes made by a command are accepted or none are.
This is done to prevent inconsistent states where only parts of a
command are applied in the event any error happens.
The previous API for converted commands, the nb_cli_cfg_change()
function, required callers to pass an array containing all changes
that needed to be applied in the candidate configuration. The
problem with this API is that it was very inconvenient for complex
commands, which change different configuration options depending
on several factors. This required users to manipulate the array
of configuration changes using low-level primitives, making it
complicated to implement some commands.
To solve this problem, introduce a new API based on the two following
functions:
- nb_cli_enqueue_change()
- nb_cli_apply_changes()
The first function is used to enqueue configuration changes, one
at time. Then the nb_cli_apply_changes() function is used to apply
all the enqueued configuration changes.
To implement this, a static-sized array was allocated in the "vty"
structure, along with a counter of enqueued changes. This eliminates
the need to declare an array of configuration changes in every
converted CLI command, simplifying things quite considerably.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2018-11-26 18:30:14 +01:00
|
|
|
|
2016-10-01 22:05:10 +02:00
|
|
|
ret = matched_element->func(matched_element, vty, argc, argv);
|
lib, ripd: rework API for converted CLI commands
When editing the candidate configuration, the northbound must ensure
that either all changes made by a command are accepted or none are.
This is done to prevent inconsistent states where only parts of a
command are applied in the event any error happens.
The previous API for converted commands, the nb_cli_cfg_change()
function, required callers to pass an array containing all changes
that needed to be applied in the candidate configuration. The
problem with this API is that it was very inconvenient for complex
commands, which change different configuration options depending
on several factors. This required users to manipulate the array
of configuration changes using low-level primitives, making it
complicated to implement some commands.
To solve this problem, introduce a new API based on the two following
functions:
- nb_cli_enqueue_change()
- nb_cli_apply_changes()
The first function is used to enqueue configuration changes, one
at time. Then the nb_cli_apply_changes() function is used to apply
all the enqueued configuration changes.
To implement this, a static-sized array was allocated in the "vty"
structure, along with a counter of enqueued changes. This eliminates
the need to declare an array of configuration changes in every
converted CLI command, simplifying things quite considerably.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2018-11-26 18:30:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
// delete list and cmd_token's in it
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&argv_list);
|
2016-11-12 02:06:32 +01:00
|
|
|
XFREE(MTYPE_TMP, argv);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return ret;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2013-09-30 14:27:51 +02:00
|
|
|
/**
|
|
|
|
* Execute a given command, handling things like "do ..." and checking
|
|
|
|
* whether the given command might apply at a parent node if doesn't
|
|
|
|
* apply for the current node.
|
|
|
|
*
|
|
|
|
* @param vline Command line input, vector of char* where each element is
|
|
|
|
* one input token.
|
|
|
|
* @param vty The vty context in which the command should be executed.
|
|
|
|
* @param cmd Pointer where the struct cmd_element of the matched command
|
|
|
|
* will be stored, if any. May be set to NULL if this info is
|
|
|
|
* not needed.
|
|
|
|
* @param vtysh If set != 0, don't lookup the command at parent nodes.
|
|
|
|
* @return The status of the command that has been executed or an error code
|
|
|
|
* as to why no command could be executed.
|
|
|
|
*/
|
2016-11-12 02:06:32 +01:00
|
|
|
int cmd_execute_command(vector vline, struct vty *vty,
|
|
|
|
const struct cmd_element **cmd, int vtysh)
|
|
|
|
{
|
2016-06-23 17:14:06 +02:00
|
|
|
int ret, saved_ret = 0;
|
This patch adds Yon's CLI 'walk back up tree' patch. Following are email
describing original patch and a shorter email describing changes to an
updated patch, the one which is applied:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
From havanna_moon@gmx.net Sat Jan 18 01:13:11 2003
Date: Sat, 11 Jan 2003 23:36:51 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: zebra@zebra.org
Subject: [zebra 17218] Re: [PATCH] CLI extensions.
Hi,
[redacted]
> I prefer the IOS way for the node "up walking".
This patch should walk the tree upwards:
bgpd(config)# router bgp 1
bgpd(config-router)# address-family ipv4 multicast
bgpd(config-router-af)# access-list 1 remark hola que tal
bgpd(config)#
I cant test all combinations, so I cant rule out some bugs. I'd love to
get (long and explicit) bug reports.
[redacted]
2003-01-18 02:16:20 +01:00
|
|
|
enum node_type onode, try_node;
|
2017-12-07 20:31:48 +01:00
|
|
|
int orig_xpath_index;
|
Finish off merge off CLI extensions, see below for description. Merge should
be off:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
2003-01-18 01:39:19 +01:00
|
|
|
|
This patch adds Yon's CLI 'walk back up tree' patch. Following are email
describing original patch and a shorter email describing changes to an
updated patch, the one which is applied:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
From havanna_moon@gmx.net Sat Jan 18 01:13:11 2003
Date: Sat, 11 Jan 2003 23:36:51 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: zebra@zebra.org
Subject: [zebra 17218] Re: [PATCH] CLI extensions.
Hi,
[redacted]
> I prefer the IOS way for the node "up walking".
This patch should walk the tree upwards:
bgpd(config)# router bgp 1
bgpd(config-router)# address-family ipv4 multicast
bgpd(config-router-af)# access-list 1 remark hola que tal
bgpd(config)#
I cant test all combinations, so I cant rule out some bugs. I'd love to
get (long and explicit) bug reports.
[redacted]
2003-01-18 02:16:20 +01:00
|
|
|
onode = try_node = vty->node;
|
2017-12-07 20:31:48 +01:00
|
|
|
orig_xpath_index = vty->xpath_index;
|
2002-12-13 22:20:42 +01:00
|
|
|
|
2016-11-12 02:06:32 +01:00
|
|
|
if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
|
2002-12-13 22:20:42 +01:00
|
|
|
vector shifted_vline;
|
2004-10-05 23:01:23 +02:00
|
|
|
unsigned int index;
|
2002-12-13 22:20:42 +01:00
|
|
|
|
|
|
|
vty->node = ENABLE_NODE;
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index = 0;
|
2002-12-13 22:20:42 +01:00
|
|
|
/* We can try it on enable node, cos' the vty is authenticated
|
|
|
|
*/
|
|
|
|
|
|
|
|
shifted_vline = vector_init(vector_count(vline));
|
|
|
|
/* use memcpy? */
|
2016-09-20 01:46:51 +02:00
|
|
|
for (index = 1; index < vector_active(vline); index++)
|
2016-06-23 17:14:06 +02:00
|
|
|
vector_set_index(shifted_vline, index - 1,
|
|
|
|
vector_lookup(vline, index));
|
2002-12-13 22:20:42 +01:00
|
|
|
|
2013-09-30 14:27:51 +02:00
|
|
|
ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
|
2021-04-08 13:35:09 +02:00
|
|
|
vty, cmd, 0);
|
2002-12-13 22:20:42 +01:00
|
|
|
|
|
|
|
vector_free(shifted_vline);
|
|
|
|
vty->node = onode;
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index = orig_xpath_index;
|
2002-12-13 22:20:42 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-30 14:27:51 +02:00
|
|
|
saved_ret = ret =
|
2021-04-08 13:35:09 +02:00
|
|
|
cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
|
2002-12-13 22:20:42 +01:00
|
|
|
|
2005-01-17 00:31:54 +01:00
|
|
|
if (vtysh)
|
|
|
|
return saved_ret;
|
|
|
|
|
2017-08-10 19:13:36 +02:00
|
|
|
if (ret != CMD_SUCCESS && ret != CMD_WARNING
|
2019-09-30 17:57:10 +02:00
|
|
|
&& ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
|
2017-08-10 19:13:36 +02:00
|
|
|
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
|
2016-06-23 17:14:06 +02:00
|
|
|
/* This assumes all nodes above CONFIG_NODE are childs of
|
|
|
|
* CONFIG_NODE */
|
|
|
|
while (vty->node > CONFIG_NODE) {
|
2021-11-06 21:10:41 +01:00
|
|
|
struct cmd_node *cnode = vector_slot(cmdvec, try_node);
|
|
|
|
|
2016-06-23 17:14:06 +02:00
|
|
|
try_node = node_parent(try_node);
|
|
|
|
vty->node = try_node;
|
2021-11-06 21:10:41 +01:00
|
|
|
if (vty->xpath_index > 0 && !cnode->no_xpath)
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index--;
|
2021-11-06 21:10:41 +01:00
|
|
|
|
2016-06-23 17:14:06 +02:00
|
|
|
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
|
2021-04-08 13:35:09 +02:00
|
|
|
vty, cmd, 0);
|
2017-08-10 19:13:36 +02:00
|
|
|
if (ret == CMD_SUCCESS || ret == CMD_WARNING
|
2019-09-30 17:57:10 +02:00
|
|
|
|| ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE
|
2017-08-10 19:13:36 +02:00
|
|
|
|| ret == CMD_NOT_MY_INSTANCE
|
|
|
|
|| ret == CMD_WARNING_CONFIG_FAILED)
|
2016-06-23 17:14:06 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/* no command succeeded, reset the vty to the original node */
|
|
|
|
vty->node = onode;
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index = orig_xpath_index;
|
2002-12-13 22:20:42 +01:00
|
|
|
}
|
2016-06-23 17:14:06 +02:00
|
|
|
|
|
|
|
/* return command status for original node */
|
This patch adds Yon's CLI 'walk back up tree' patch. Following are email
describing original patch and a shorter email describing changes to an
updated patch, the one which is applied:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
From havanna_moon@gmx.net Sat Jan 18 01:13:11 2003
Date: Sat, 11 Jan 2003 23:36:51 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: zebra@zebra.org
Subject: [zebra 17218] Re: [PATCH] CLI extensions.
Hi,
[redacted]
> I prefer the IOS way for the node "up walking".
This patch should walk the tree upwards:
bgpd(config)# router bgp 1
bgpd(config-router)# address-family ipv4 multicast
bgpd(config-router-af)# access-list 1 remark hola que tal
bgpd(config)#
I cant test all combinations, so I cant rule out some bugs. I'd love to
get (long and explicit) bug reports.
[redacted]
2003-01-18 02:16:20 +01:00
|
|
|
return saved_ret;
|
2002-12-13 22:20:42 +01:00
|
|
|
}
|
|
|
|
|
2013-09-30 14:27:51 +02:00
|
|
|
/**
|
|
|
|
* Execute a given command, matching it strictly against the current node.
|
|
|
|
* This mode is used when reading config files.
|
|
|
|
*
|
|
|
|
* @param vline Command line input, vector of char* where each element is
|
|
|
|
* one input token.
|
|
|
|
* @param vty The vty context in which the command should be executed.
|
|
|
|
* @param cmd Pointer where the struct cmd_element* of the matched command
|
|
|
|
* will be stored, if any. May be set to NULL if this info is
|
|
|
|
* not needed.
|
|
|
|
* @return The status of the command that has been executed or an error code
|
|
|
|
* as to why no command could be executed.
|
|
|
|
*/
|
2005-03-14 18:41:45 +01:00
|
|
|
int cmd_execute_command_strict(vector vline, struct vty *vty,
|
2016-11-12 02:06:32 +01:00
|
|
|
const struct cmd_element **cmd)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2021-04-08 13:35:09 +02:00
|
|
|
return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-05-13 02:09:08 +02:00
|
|
|
/*
|
|
|
|
* Hook for preprocessing command string before executing.
|
|
|
|
*
|
|
|
|
* All subscribers are called with the raw command string that is to be
|
|
|
|
* executed. If any changes are to be made, a new string should be allocated
|
|
|
|
* with MTYPE_TMP and *cmd_out updated to point to this new string. The caller
|
|
|
|
* is then responsible for freeing this string.
|
|
|
|
*
|
|
|
|
* All processing functions must be mutually exclusive in their action, i.e. if
|
|
|
|
* one subscriber decides to modify the command, all others must not modify it
|
|
|
|
* when called. Feeding the output of one processing command into a subsequent
|
|
|
|
* one is not supported.
|
|
|
|
*
|
|
|
|
* This hook is intentionally internal to the command processing system.
|
|
|
|
*
|
|
|
|
* cmd_in
|
|
|
|
* The raw command string.
|
|
|
|
*
|
|
|
|
* cmd_out
|
|
|
|
* The result of any processing.
|
|
|
|
*/
|
|
|
|
DECLARE_HOOK(cmd_execute,
|
2018-05-25 22:31:07 +02:00
|
|
|
(struct vty *vty, const char *cmd_in, char **cmd_out),
|
2018-05-13 02:09:08 +02:00
|
|
|
(vty, cmd_in, cmd_out));
|
2018-05-25 22:31:07 +02:00
|
|
|
DEFINE_HOOK(cmd_execute, (struct vty *vty, const char *cmd_in, char **cmd_out),
|
2018-05-13 02:09:08 +02:00
|
|
|
(vty, cmd_in, cmd_out));
|
|
|
|
|
|
|
|
/* Hook executed after a CLI command. */
|
2018-05-25 22:31:07 +02:00
|
|
|
DECLARE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
|
2018-05-13 02:09:08 +02:00
|
|
|
(vty, cmd_exec));
|
2018-05-25 22:31:07 +02:00
|
|
|
DEFINE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
|
2018-05-13 02:09:08 +02:00
|
|
|
(vty, cmd_exec));
|
|
|
|
|
2018-05-13 02:14:22 +02:00
|
|
|
/*
|
|
|
|
* cmd_execute hook subscriber to handle `|` actions.
|
|
|
|
*/
|
|
|
|
static int handle_pipe_action(struct vty *vty, const char *cmd_in,
|
|
|
|
char **cmd_out)
|
|
|
|
{
|
|
|
|
/* look for `|` */
|
2018-06-11 20:14:59 +02:00
|
|
|
char *orig, *working, *token, *u;
|
2018-05-13 02:14:22 +02:00
|
|
|
char *pipe = strstr(cmd_in, "| ");
|
2020-09-21 15:00:33 +02:00
|
|
|
int ret = 0;
|
2018-05-13 02:14:22 +02:00
|
|
|
|
|
|
|
if (!pipe)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* duplicate string for processing purposes, not including pipe */
|
|
|
|
orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
|
|
|
|
|
|
|
|
/* retrieve action */
|
|
|
|
token = strsep(&working, " ");
|
2018-09-08 20:16:59 +02:00
|
|
|
assert(token);
|
2018-05-13 02:14:22 +02:00
|
|
|
|
|
|
|
/* match result to known actions */
|
|
|
|
if (strmatch(token, "include")) {
|
|
|
|
/* the remaining text should be a regexp */
|
|
|
|
char *regexp = working;
|
2018-05-29 19:13:51 +02:00
|
|
|
|
|
|
|
if (!regexp) {
|
|
|
|
vty_out(vty, "%% Need a regexp to filter with\n");
|
2020-09-21 15:00:33 +02:00
|
|
|
ret = 1;
|
2018-05-29 19:13:51 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2018-05-13 02:14:22 +02:00
|
|
|
bool succ = vty_set_include(vty, regexp);
|
2018-05-25 22:31:07 +02:00
|
|
|
|
2018-05-13 02:14:22 +02:00
|
|
|
if (!succ) {
|
2018-05-29 19:13:51 +02:00
|
|
|
vty_out(vty, "%% Bad regexp '%s'\n", regexp);
|
2020-09-21 15:00:33 +02:00
|
|
|
ret = 1;
|
2018-05-13 02:14:22 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
2018-05-15 00:13:03 +02:00
|
|
|
*cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
|
2018-06-11 20:14:59 +02:00
|
|
|
u = *cmd_out;
|
|
|
|
strsep(&u, "|");
|
2018-05-13 02:14:22 +02:00
|
|
|
} else {
|
2018-05-29 19:13:51 +02:00
|
|
|
vty_out(vty, "%% Unknown action '%s'\n", token);
|
2020-09-21 15:00:33 +02:00
|
|
|
ret = 1;
|
2018-05-13 02:14:22 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
XFREE(MTYPE_TMP, orig);
|
2020-09-21 15:00:33 +02:00
|
|
|
return ret;
|
2018-05-13 02:14:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
|
|
|
|
{
|
2018-06-06 21:09:44 +02:00
|
|
|
if (vty->filter)
|
2018-05-13 02:14:22 +02:00
|
|
|
vty_set_include(vty, NULL);
|
2018-06-06 21:09:44 +02:00
|
|
|
|
2018-05-13 02:14:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-13 02:09:08 +02:00
|
|
|
int cmd_execute(struct vty *vty, const char *cmd,
|
|
|
|
const struct cmd_element **matched, int vtysh)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *cmd_out = NULL;
|
2020-09-21 15:00:33 +02:00
|
|
|
const char *cmd_exec = NULL;
|
2018-05-13 02:09:08 +02:00
|
|
|
vector vline;
|
|
|
|
|
2020-09-21 15:00:33 +02:00
|
|
|
ret = hook_call(cmd_execute, vty, cmd, &cmd_out);
|
|
|
|
if (ret) {
|
|
|
|
ret = CMD_WARNING;
|
|
|
|
goto free;
|
|
|
|
}
|
|
|
|
|
2018-05-13 02:09:08 +02:00
|
|
|
cmd_exec = cmd_out ? (const char *)cmd_out : cmd;
|
|
|
|
|
|
|
|
vline = cmd_make_strvec(cmd_exec);
|
|
|
|
|
|
|
|
if (vline) {
|
|
|
|
ret = cmd_execute_command(vline, vty, matched, vtysh);
|
|
|
|
cmd_free_strvec(vline);
|
|
|
|
} else {
|
|
|
|
ret = CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-09-21 15:00:33 +02:00
|
|
|
free:
|
2018-05-13 02:09:08 +02:00
|
|
|
hook_call(cmd_execute_done, vty, cmd_exec);
|
|
|
|
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_TMP, cmd_out);
|
2018-05-13 02:09:08 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-28 22:17:36 +02:00
|
|
|
/**
|
|
|
|
* Parse one line of config, walking up the parse tree attempting to find a
|
|
|
|
* match
|
|
|
|
*
|
|
|
|
* @param vty The vty context in which the command should be executed.
|
|
|
|
* @param cmd Pointer where the struct cmd_element* of the match command
|
|
|
|
* will be stored, if any. May be set to NULL if this info is
|
|
|
|
* not needed.
|
|
|
|
* @param use_daemon Boolean to control whether or not we match on
|
|
|
|
* CMD_SUCCESS_DAEMON
|
|
|
|
* or not.
|
|
|
|
* @return The status of the command that has been executed or an error code
|
|
|
|
* as to why no command could be executed.
|
|
|
|
*/
|
2016-11-12 02:06:32 +01:00
|
|
|
int command_config_read_one_line(struct vty *vty,
|
2018-10-11 15:43:32 +02:00
|
|
|
const struct cmd_element **cmd,
|
|
|
|
uint32_t line_num, int use_daemon)
|
2015-09-28 22:17:36 +02:00
|
|
|
{
|
|
|
|
vector vline;
|
|
|
|
int ret;
|
2021-04-08 13:35:09 +02:00
|
|
|
unsigned up_level = 0;
|
2015-09-28 22:17:36 +02:00
|
|
|
|
|
|
|
vline = cmd_make_strvec(vty->buf);
|
|
|
|
|
|
|
|
/* In case of comment line */
|
|
|
|
if (vline == NULL)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
|
|
|
/* Execute configuration command : this is strict match */
|
|
|
|
ret = cmd_execute_command_strict(vline, vty, cmd);
|
|
|
|
|
2021-04-08 13:35:09 +02:00
|
|
|
/* The logic for trying parent nodes is in cmd_execute_command_real()
|
|
|
|
* since calling ->node_exit() correctly is a bit involved. This is
|
|
|
|
* also the only reason CMD_NO_LEVEL_UP exists.
|
|
|
|
*/
|
|
|
|
while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
|
|
|
|
&& !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
|
|
|
|
&& ret != CMD_SUCCESS && ret != CMD_WARNING
|
2019-09-30 17:57:10 +02:00
|
|
|
&& ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
|
2021-04-08 13:35:09 +02:00
|
|
|
&& ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
|
|
|
|
&& ret != CMD_NO_LEVEL_UP)
|
|
|
|
ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
|
|
|
|
++up_level);
|
|
|
|
|
|
|
|
if (ret == CMD_NO_LEVEL_UP)
|
|
|
|
ret = CMD_ERR_NO_MATCH;
|
2015-09-28 22:17:36 +02:00
|
|
|
|
2018-10-25 03:03:18 +02:00
|
|
|
if (ret != CMD_SUCCESS &&
|
|
|
|
ret != CMD_WARNING &&
|
|
|
|
ret != CMD_SUCCESS_DAEMON) {
|
2018-10-11 15:43:32 +02:00
|
|
|
struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve));
|
|
|
|
|
|
|
|
memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
|
|
|
|
ve->line_num = line_num;
|
2023-05-09 15:19:24 +02:00
|
|
|
ve->cmd_ret = ret;
|
2018-10-11 15:43:32 +02:00
|
|
|
if (!vty->error)
|
|
|
|
vty->error = list_new();
|
|
|
|
|
|
|
|
listnode_add(vty->error, ve);
|
|
|
|
}
|
2016-10-06 20:39:31 +02:00
|
|
|
|
2015-09-28 22:17:36 +02:00
|
|
|
cmd_free_strvec(vline);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-07-28 05:30:22 +02:00
|
|
|
/* Configuration make from file. */
|
2009-07-28 22:36:14 +02:00
|
|
|
int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2015-07-28 05:30:22 +02:00
|
|
|
int ret, error_ret = 0;
|
2009-07-28 22:36:14 +02:00
|
|
|
*line_num = 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
|
2018-10-11 15:43:32 +02:00
|
|
|
++(*line_num);
|
2009-07-28 22:36:14 +02:00
|
|
|
|
2023-05-03 06:41:19 +02:00
|
|
|
if (vty_log_commands) {
|
|
|
|
int len = strlen(vty->buf);
|
|
|
|
|
|
|
|
/* now log the command */
|
|
|
|
zlog_notice("config-from-file# %.*s", len ? len - 1 : 0,
|
|
|
|
vty->buf);
|
|
|
|
}
|
|
|
|
|
2018-10-11 15:43:32 +02:00
|
|
|
ret = command_config_read_one_line(vty, NULL, *line_num, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2015-07-28 05:30:22 +02:00
|
|
|
if (ret != CMD_SUCCESS && ret != CMD_WARNING
|
2016-09-20 01:46:51 +02:00
|
|
|
&& ret != CMD_ERR_NOTHING_TODO)
|
|
|
|
error_ret = ret;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2015-07-28 05:30:22 +02:00
|
|
|
|
|
|
|
if (error_ret) {
|
|
|
|
return error_ret;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2015-07-28 05:30:22 +02:00
|
|
|
/* Configuration from terminal */
|
2002-12-13 21:15:29 +01:00
|
|
|
DEFUN (config_terminal,
|
|
|
|
config_terminal_cmd,
|
2019-05-08 03:00:34 +02:00
|
|
|
"configure [terminal]",
|
2002-12-13 21:15:29 +01:00
|
|
|
"Configuration from vty interface\n"
|
|
|
|
"Configuration terminal\n")
|
|
|
|
{
|
2018-11-26 19:47:22 +01:00
|
|
|
return vty_config_enter(vty, false, false);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable command */
|
2016-09-20 01:46:51 +02:00
|
|
|
DEFUN (enable,
|
2002-12-13 21:15:29 +01:00
|
|
|
config_enable_cmd,
|
|
|
|
"enable",
|
|
|
|
"Turn on privileged mode command\n")
|
|
|
|
{
|
|
|
|
/* If enable password is NULL, change to ENABLE_NODE */
|
|
|
|
if ((host.enable == NULL && host.enable_encrypt == NULL)
|
|
|
|
|| vty->type == VTY_SHELL_SERV)
|
|
|
|
vty->node = ENABLE_NODE;
|
|
|
|
else
|
|
|
|
vty->node = AUTH_ENABLE_NODE;
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable command */
|
2016-09-20 01:46:51 +02:00
|
|
|
DEFUN (disable,
|
2002-12-13 21:15:29 +01:00
|
|
|
config_disable_cmd,
|
|
|
|
"disable",
|
|
|
|
"Turn off privileged mode command\n")
|
|
|
|
{
|
|
|
|
if (vty->node == ENABLE_NODE)
|
|
|
|
vty->node = VIEW_NODE;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Down vty node level. */
|
|
|
|
DEFUN (config_exit,
|
|
|
|
config_exit_cmd,
|
|
|
|
"exit",
|
|
|
|
"Exit current mode and down to previous mode\n")
|
2016-11-16 07:00:52 +01:00
|
|
|
{
|
|
|
|
cmd_exit(vty);
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-09-09 00:03:19 +02:00
|
|
|
static int root_on_exit(struct vty *vty)
|
|
|
|
{
|
|
|
|
if (vty_shell(vty))
|
|
|
|
exit(0);
|
|
|
|
else
|
|
|
|
vty->status = VTY_CLOSE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-16 07:00:52 +01:00
|
|
|
void cmd_exit(struct vty *vty)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2018-09-08 23:15:09 +02:00
|
|
|
struct cmd_node *cnode = vector_lookup(cmdvec, vty->node);
|
2017-12-07 20:31:48 +01:00
|
|
|
|
2018-09-09 00:03:19 +02:00
|
|
|
if (cnode->node_exit) {
|
|
|
|
if (!cnode->node_exit(vty))
|
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2018-09-09 00:03:19 +02:00
|
|
|
if (cnode->parent_node)
|
|
|
|
vty->node = cnode->parent_node;
|
2021-11-06 21:10:41 +01:00
|
|
|
if (vty->xpath_index > 0 && !cnode->no_xpath)
|
2017-12-07 20:31:48 +01:00
|
|
|
vty->xpath_index--;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-09-23 22:08:47 +02:00
|
|
|
/* ALIAS_FIXME */
|
|
|
|
DEFUN (config_quit,
|
|
|
|
config_quit_cmd,
|
|
|
|
"quit",
|
|
|
|
"Exit current mode and down to previous mode\n")
|
|
|
|
{
|
|
|
|
return config_exit(self, vty, argc, argv);
|
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* End of configuration. */
|
|
|
|
DEFUN (config_end,
|
|
|
|
config_end_cmd,
|
|
|
|
"end",
|
2017-10-21 02:16:57 +02:00
|
|
|
"End current mode and change to enable mode.\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-19 02:23:45 +01:00
|
|
|
if (vty->config) {
|
2018-11-26 19:47:22 +01:00
|
|
|
vty_config_exit(vty);
|
2002-12-13 21:15:29 +01:00
|
|
|
vty->node = ENABLE_NODE;
|
|
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Show version. */
|
|
|
|
DEFUN (show_version,
|
|
|
|
show_version_cmd,
|
|
|
|
"show version",
|
|
|
|
SHOW_STR
|
|
|
|
"Displays zebra version\n")
|
|
|
|
{
|
2022-01-22 14:15:42 +01:00
|
|
|
vty_out(vty, "%s %s (%s) on %s(%s).\n", FRR_FULL_NAME, FRR_VERSION,
|
|
|
|
cmd_hostname_get() ? cmd_hostname_get() : "", cmd_system_get(),
|
|
|
|
cmd_release_get());
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
|
2020-06-17 18:48:34 +02:00
|
|
|
#ifdef ENABLE_VERSION_BUILD_CONFIG
|
2017-07-13 19:20:20 +02:00
|
|
|
vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
|
2020-06-17 18:48:34 +02:00
|
|
|
#endif
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Help display function for all node. */
|
|
|
|
DEFUN (config_help,
|
|
|
|
config_help_cmd,
|
|
|
|
"help",
|
|
|
|
"Description of the interactive help system\n")
|
|
|
|
{
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
2017-07-13 19:20:20 +02:00
|
|
|
"Quagga VTY provides advanced help feature. When you need help,\n\
|
|
|
|
anytime at the command line please press '?'.\n\
|
|
|
|
\n\
|
|
|
|
If nothing matches, the help list will be empty and you must backup\n\
|
|
|
|
until entering a '?' shows the available options.\n\
|
|
|
|
Two styles of help are provided:\n\
|
|
|
|
1. Full help is available when you are ready to enter a\n\
|
|
|
|
command argument (e.g. 'show ?') and describes each possible\n\
|
|
|
|
argument.\n\
|
|
|
|
2. Partial help is provided when an abbreviated argument is entered\n\
|
|
|
|
and you want to know what arguments match the input\n\
|
|
|
|
(e.g. 'show me?'.)\n\n");
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-07 23:44:10 +02:00
|
|
|
static void permute(struct graph_node *start, struct vty *vty)
|
|
|
|
{
|
|
|
|
static struct list *position = NULL;
|
|
|
|
if (!position)
|
|
|
|
position = list_new();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-05 00:46:46 +02:00
|
|
|
struct cmd_token *stok = start->data;
|
|
|
|
struct graph_node *gnn;
|
|
|
|
struct listnode *ln;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-07 23:44:10 +02:00
|
|
|
// recursive dfs
|
|
|
|
listnode_add(position, start);
|
|
|
|
for (unsigned int i = 0; i < vector_active(start->to); i++) {
|
|
|
|
struct graph_node *gn = vector_slot(start->to, i);
|
|
|
|
struct cmd_token *tok = gn->data;
|
2022-10-04 13:30:04 +02:00
|
|
|
if (tok->attr & CMD_ATTR_HIDDEN)
|
2016-11-11 00:30:20 +01:00
|
|
|
continue;
|
|
|
|
else if (tok->type == END_TKN || gn == start) {
|
2016-10-07 23:44:10 +02:00
|
|
|
vty_out(vty, " ");
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
|
|
|
|
struct cmd_token *tt = gnn->data;
|
2016-12-16 22:30:36 +01:00
|
|
|
if (tt->type < SPECIAL_TKN)
|
2016-10-07 23:44:10 +02:00
|
|
|
vty_out(vty, " %s", tt->text);
|
|
|
|
}
|
|
|
|
if (gn == start)
|
|
|
|
vty_out(vty, "...");
|
2017-07-13 19:04:25 +02:00
|
|
|
vty_out(vty, "\n");
|
2016-10-07 23:44:10 +02:00
|
|
|
} else {
|
2017-05-05 00:46:46 +02:00
|
|
|
bool skip = false;
|
|
|
|
if (stok->type == FORK_TKN && tok->type != FORK_TKN)
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
|
2017-05-10 03:57:11 +02:00
|
|
|
if (gnn == gn) {
|
|
|
|
skip = true;
|
2017-05-05 00:46:46 +02:00
|
|
|
break;
|
2017-05-10 03:57:11 +02:00
|
|
|
}
|
2017-05-05 00:46:46 +02:00
|
|
|
if (!skip)
|
|
|
|
permute(gn, vty);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2017-05-05 00:46:46 +02:00
|
|
|
}
|
2016-10-07 23:44:10 +02:00
|
|
|
list_delete_node(position, listtail(position));
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-06-03 01:02:45 +02:00
|
|
|
static void print_cmd(struct vty *vty, const char *cmd)
|
|
|
|
{
|
|
|
|
int i, j, len = strlen(cmd);
|
2021-06-07 16:02:16 +02:00
|
|
|
char buf[len + 1];
|
2021-06-03 01:02:45 +02:00
|
|
|
bool skip = false;
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
/* skip varname */
|
|
|
|
if (cmd[i] == '$')
|
|
|
|
skip = true;
|
|
|
|
else if (strchr(" ()<>[]{}|", cmd[i]))
|
|
|
|
skip = false;
|
|
|
|
|
|
|
|
if (skip)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (isspace(cmd[i])) {
|
|
|
|
/* skip leading whitespace */
|
|
|
|
if (i == 0)
|
|
|
|
continue;
|
|
|
|
/* skip trailing whitespace */
|
|
|
|
if (i == len - 1)
|
|
|
|
continue;
|
|
|
|
/* skip all whitespace after opening brackets or pipe */
|
|
|
|
if (strchr("(<[{|", cmd[i - 1])) {
|
|
|
|
while (isspace(cmd[i + 1]))
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* skip repeated whitespace */
|
|
|
|
if (isspace(cmd[i + 1]))
|
|
|
|
continue;
|
|
|
|
/* skip whitespace before closing brackets or pipe */
|
|
|
|
if (strchr(")>]}|", cmd[i + 1]))
|
|
|
|
continue;
|
|
|
|
/* convert tabs to spaces */
|
|
|
|
if (cmd[i] == '\t') {
|
|
|
|
buf[j++] = ' ';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[j++] = cmd[i];
|
|
|
|
}
|
|
|
|
buf[j] = 0;
|
|
|
|
|
|
|
|
vty_out(vty, "%s\n", buf);
|
|
|
|
}
|
|
|
|
|
2016-11-16 07:00:52 +01:00
|
|
|
int cmd_list_cmds(struct vty *vty, int do_permute)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-10-07 23:44:10 +02:00
|
|
|
struct cmd_node *node = vector_slot(cmdvec, vty->node);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-10-18 11:51:09 +02:00
|
|
|
if (do_permute) {
|
|
|
|
cmd_finalize_node(node);
|
2016-10-07 23:44:10 +02:00
|
|
|
permute(vector_slot(node->cmdgraph->nodes, 0), vty);
|
2021-10-18 11:51:09 +02:00
|
|
|
} else {
|
2016-10-07 23:44:10 +02:00
|
|
|
/* loop over all commands at this node */
|
2019-11-14 23:27:29 +01:00
|
|
|
const struct cmd_element *element = NULL;
|
2016-10-07 23:44:10 +02:00
|
|
|
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
|
|
|
|
i++)
|
2022-10-04 13:30:04 +02:00
|
|
|
if ((element = vector_slot(node->cmd_vector, i)) &&
|
|
|
|
!(element->attr & CMD_ATTR_HIDDEN)) {
|
2021-06-03 01:02:45 +02:00
|
|
|
vty_out(vty, " ");
|
|
|
|
print_cmd(vty, element->string);
|
|
|
|
}
|
2016-10-07 23:44:10 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-11-16 07:00:52 +01:00
|
|
|
/* Help display function for all node. */
|
|
|
|
DEFUN (config_list,
|
|
|
|
config_list_cmd,
|
|
|
|
"list [permutations]",
|
|
|
|
"Print command list\n"
|
|
|
|
"Print all possible command permutations\n")
|
|
|
|
{
|
|
|
|
return cmd_list_cmds(vty, argc == 2);
|
|
|
|
}
|
|
|
|
|
2016-10-07 23:44:10 +02:00
|
|
|
DEFUN (show_commandtree,
|
|
|
|
show_commandtree_cmd,
|
|
|
|
"show commandtree [permutations]",
|
|
|
|
SHOW_STR
|
2017-03-03 16:54:10 +01:00
|
|
|
"Show command tree\n"
|
|
|
|
"Permutations that we are interested in\n")
|
2016-10-07 23:44:10 +02:00
|
|
|
{
|
2016-11-16 07:00:52 +01:00
|
|
|
return cmd_list_cmds(vty, argc == 3);
|
2016-10-07 23:44:10 +02:00
|
|
|
}
|
|
|
|
|
2018-04-20 20:34:46 +02:00
|
|
|
DEFUN_HIDDEN(show_cli_graph,
|
|
|
|
show_cli_graph_cmd,
|
|
|
|
"show cli graph",
|
|
|
|
SHOW_STR
|
|
|
|
"CLI reflection\n"
|
|
|
|
"Dump current command space as DOT graph\n")
|
|
|
|
{
|
|
|
|
struct cmd_node *cn = vector_slot(cmdvec, vty->node);
|
2021-10-18 11:51:09 +02:00
|
|
|
char *dot;
|
|
|
|
|
|
|
|
cmd_finalize_node(cn);
|
|
|
|
dot = cmd_graph_dump_dot(cn->cmdgraph);
|
2018-04-20 20:34:46 +02:00
|
|
|
|
|
|
|
vty_out(vty, "%s\n", dot);
|
|
|
|
XFREE(MTYPE_TMP, dot);
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-11-06 22:43:32 +01:00
|
|
|
static int vty_write_config(struct vty *vty)
|
2017-03-09 19:00:19 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
struct cmd_node *node;
|
|
|
|
|
2017-11-06 22:43:32 +01:00
|
|
|
if (host.noconfig)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
2019-10-06 06:16:47 +02:00
|
|
|
nb_cli_show_config_prepare(running_config, false);
|
|
|
|
|
2017-03-09 19:00:19 +01:00
|
|
|
if (vty->type == VTY_TERM) {
|
2017-07-13 19:20:20 +02:00
|
|
|
vty_out(vty, "\nCurrent configuration:\n");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "!\n");
|
2017-03-09 19:00:19 +01:00
|
|
|
}
|
|
|
|
|
2018-10-26 18:41:00 +02:00
|
|
|
if (strcmp(frr_defaults_version(), FRR_VER_SHORT))
|
|
|
|
vty_out(vty, "! loaded from %s\n", frr_defaults_version());
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
|
2018-10-26 18:41:00 +02:00
|
|
|
vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "!\n");
|
2017-03-09 19:00:19 +01:00
|
|
|
|
2019-09-17 02:51:11 +02:00
|
|
|
for (i = 0; i < vector_active(cmdvec); i++)
|
2018-09-08 22:31:43 +02:00
|
|
|
if ((node = vector_slot(cmdvec, i)) && node->config_write) {
|
|
|
|
if ((*node->config_write)(vty))
|
2019-09-17 02:51:11 +02:00
|
|
|
vty_out(vty, "!\n");
|
|
|
|
}
|
2017-03-09 19:00:19 +01:00
|
|
|
|
|
|
|
if (vty->type == VTY_TERM) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "end\n");
|
2017-03-09 19:00:19 +01:00
|
|
|
}
|
|
|
|
|
2017-11-06 22:43:32 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2016-09-23 23:34:33 +02:00
|
|
|
|
2017-11-06 22:43:32 +01:00
|
|
|
static int file_write_config(struct vty *vty)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-02-08 16:14:10 +01:00
|
|
|
int fd, dirfd;
|
|
|
|
char *config_file, *slash;
|
2002-12-13 21:15:29 +01:00
|
|
|
char *config_file_tmp = NULL;
|
|
|
|
char *config_file_sav = NULL;
|
2005-10-26 07:49:54 +02:00
|
|
|
int ret = CMD_WARNING;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct vty *file_vty;
|
2015-05-21 01:55:57 +02:00
|
|
|
struct stat conf_stat;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-09 14:42:47 +01:00
|
|
|
if (host.noconfig)
|
|
|
|
return CMD_SUCCESS;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check and see if we are operating under vtysh configuration */
|
|
|
|
if (host.config == NULL) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Can't save to configuration file, using vtysh.\n");
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Get filename. */
|
|
|
|
config_file = host.config;
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2017-02-08 16:14:10 +01:00
|
|
|
#ifndef O_DIRECTORY
|
|
|
|
#define O_DIRECTORY 0
|
|
|
|
#endif
|
|
|
|
slash = strrchr(config_file, '/');
|
|
|
|
if (slash) {
|
|
|
|
char *config_dir = XSTRDUP(MTYPE_TMP, config_file);
|
|
|
|
config_dir[slash - config_file] = '\0';
|
|
|
|
dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
|
|
|
|
XFREE(MTYPE_TMP, config_dir);
|
|
|
|
} else
|
|
|
|
dirfd = open(".", O_DIRECTORY | O_RDONLY);
|
|
|
|
/* if dirfd is invalid, directory sync fails, but we're still OK */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-06 23:05:20 +02:00
|
|
|
size_t config_file_sav_sz = strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1;
|
|
|
|
config_file_sav = XMALLOC(MTYPE_TMP, config_file_sav_sz);
|
|
|
|
strlcpy(config_file_sav, config_file, config_file_sav_sz);
|
|
|
|
strlcat(config_file_sav, CONF_BACKUP_EXT, config_file_sav_sz);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
|
2005-10-26 07:49:54 +02:00
|
|
|
config_file_tmp = XMALLOC(MTYPE_TMP, strlen(config_file) + 8);
|
2020-04-20 23:59:31 +02:00
|
|
|
snprintf(config_file_tmp, strlen(config_file) + 8, "%s.XXXXXX",
|
|
|
|
config_file);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Open file to configuration write. */
|
|
|
|
fd = mkstemp(config_file_tmp);
|
|
|
|
if (fd < 0) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Can't open configuration file %s.\n",
|
|
|
|
config_file_tmp);
|
2005-10-26 07:49:54 +02:00
|
|
|
goto finished;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-02-08 16:14:10 +01:00
|
|
|
if (fchmod(fd, CONFIGFILE_MASK) != 0) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Can't chmod configuration file %s: %s (%d).\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
config_file_tmp, safe_strerror(errno), errno);
|
2017-02-08 16:14:10 +01:00
|
|
|
goto finished;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Make vty for configuration file. */
|
|
|
|
file_vty = vty_new();
|
2013-05-30 16:31:49 +02:00
|
|
|
file_vty->wfd = fd;
|
2002-12-13 21:15:29 +01:00
|
|
|
file_vty->type = VTY_FILE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Config file header print. */
|
|
|
|
vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! ");
|
|
|
|
vty_time_print(file_vty, 1);
|
|
|
|
vty_out(file_vty, "!\n");
|
2017-03-09 19:00:19 +01:00
|
|
|
vty_write_config(file_vty);
|
2002-12-13 21:15:29 +01:00
|
|
|
vty_close(file_vty);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-21 01:55:57 +02:00
|
|
|
if (stat(config_file, &conf_stat) >= 0) {
|
|
|
|
if (unlink(config_file_sav) != 0)
|
2016-09-20 01:46:51 +02:00
|
|
|
if (errno != ENOENT) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Can't unlink backup configuration file %s.\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
config_file_sav);
|
2016-09-20 01:46:51 +02:00
|
|
|
goto finished;
|
|
|
|
}
|
2015-05-21 01:55:57 +02:00
|
|
|
if (link(config_file, config_file_sav) != 0) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Can't backup old configuration file %s.\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
config_file_sav);
|
2016-09-20 01:46:51 +02:00
|
|
|
goto finished;
|
|
|
|
}
|
2017-02-10 15:04:06 +01:00
|
|
|
if (dirfd >= 0)
|
|
|
|
fsync(dirfd);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-02-08 16:14:10 +01:00
|
|
|
if (rename(config_file_tmp, config_file) != 0) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Can't save configuration file %s.\n",
|
|
|
|
config_file);
|
2005-10-26 07:49:54 +02:00
|
|
|
goto finished;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-02-10 15:04:06 +01:00
|
|
|
if (dirfd >= 0)
|
|
|
|
fsync(dirfd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Configuration saved to %s\n", config_file);
|
2005-10-26 07:49:54 +02:00
|
|
|
ret = CMD_SUCCESS;
|
|
|
|
|
|
|
|
finished:
|
2017-02-08 16:14:10 +01:00
|
|
|
if (ret != CMD_SUCCESS)
|
|
|
|
unlink(config_file_tmp);
|
2017-02-10 15:04:06 +01:00
|
|
|
if (dirfd >= 0)
|
|
|
|
close(dirfd);
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_TMP, config_file_tmp);
|
|
|
|
XFREE(MTYPE_TMP, config_file_sav);
|
|
|
|
return ret;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-11-06 22:43:32 +01:00
|
|
|
/* Write current configuration into file. */
|
|
|
|
|
|
|
|
DEFUN (config_write,
|
|
|
|
config_write_cmd,
|
|
|
|
"write [<file|memory|terminal>]",
|
|
|
|
"Write running configuration to memory, network, or terminal\n"
|
|
|
|
"Write to configuration file\n"
|
|
|
|
"Write configuration currently in memory\n"
|
|
|
|
"Write configuration to terminal\n")
|
|
|
|
{
|
|
|
|
const int idx_type = 1;
|
|
|
|
|
|
|
|
// if command was 'write terminal' or 'write memory'
|
|
|
|
if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal"))) {
|
|
|
|
return vty_write_config(vty);
|
|
|
|
}
|
|
|
|
|
|
|
|
return file_write_config(vty);
|
|
|
|
}
|
|
|
|
|
2016-09-23 23:34:33 +02:00
|
|
|
/* ALIAS_FIXME for 'write <terminal|memory>' */
|
|
|
|
DEFUN (show_running_config,
|
|
|
|
show_running_config_cmd,
|
|
|
|
"show running-config",
|
|
|
|
SHOW_STR
|
2017-11-06 22:43:32 +01:00
|
|
|
"running configuration (same as write terminal)\n")
|
2016-09-23 23:34:33 +02:00
|
|
|
{
|
2017-11-06 22:43:32 +01:00
|
|
|
return vty_write_config(vty);
|
2016-09-23 23:34:33 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2016-09-23 23:34:33 +02:00
|
|
|
/* ALIAS_FIXME for 'write file' */
|
|
|
|
DEFUN (copy_runningconf_startupconf,
|
|
|
|
copy_runningconf_startupconf_cmd,
|
|
|
|
"copy running-config startup-config",
|
|
|
|
"Copy configuration\n"
|
|
|
|
"Copy running config to... \n"
|
2017-11-06 22:43:32 +01:00
|
|
|
"Copy running config to startup config (same as write file/memory)\n")
|
2016-09-23 23:34:33 +02:00
|
|
|
{
|
2017-11-06 22:43:32 +01:00
|
|
|
return file_write_config(vty);
|
2016-09-23 23:34:33 +02:00
|
|
|
}
|
|
|
|
/** -- **/
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Write startup configuration into the terminal. */
|
|
|
|
DEFUN (show_startup_config,
|
|
|
|
show_startup_config_cmd,
|
|
|
|
"show startup-config",
|
|
|
|
SHOW_STR
|
2016-09-20 01:46:51 +02:00
|
|
|
"Contents of startup configuration\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
FILE *confp;
|
|
|
|
|
2016-11-09 14:42:47 +01:00
|
|
|
if (host.noconfig)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
if (host.config == NULL)
|
|
|
|
return CMD_WARNING;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
confp = fopen(host.config, "r");
|
|
|
|
if (confp == NULL) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Can't open configuration file [%s] due to '%s'\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
host.config, safe_strerror(errno));
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_WARNING;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(buf, BUFSIZ, confp)) {
|
|
|
|
char *cp = buf;
|
|
|
|
|
|
|
|
while (*cp != '\r' && *cp != '\n' && *cp != '\0')
|
2016-09-20 01:46:51 +02:00
|
|
|
cp++;
|
2002-12-13 21:15:29 +01:00
|
|
|
*cp = '\0';
|
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n", buf);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(confp);
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-08-29 01:52:29 +02:00
|
|
|
int cmd_domainname_set(const char *domainname)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_HOST, host.domainname);
|
|
|
|
host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Hostname configuration */
|
2017-08-30 17:23:01 +02:00
|
|
|
DEFUN(config_domainname,
|
|
|
|
domainname_cmd,
|
|
|
|
"domainname WORD",
|
|
|
|
"Set system's domain name\n"
|
|
|
|
"This system's domain name\n")
|
2017-08-29 01:52:29 +02:00
|
|
|
{
|
|
|
|
struct cmd_token *word = argv[1];
|
|
|
|
|
2019-08-06 16:54:52 +02:00
|
|
|
if (!isalpha((unsigned char)word->arg[0])) {
|
2017-08-29 01:52:29 +02:00
|
|
|
vty_out(vty, "Please specify string starting with alphabet\n");
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd_domainname_set(word->arg);
|
|
|
|
}
|
|
|
|
|
2017-08-30 17:23:01 +02:00
|
|
|
DEFUN(config_no_domainname,
|
|
|
|
no_domainname_cmd,
|
|
|
|
"no domainname [DOMAINNAME]",
|
|
|
|
NO_STR
|
|
|
|
"Reset system's domain name\n"
|
|
|
|
"domain name of this router\n")
|
2017-08-29 01:52:29 +02:00
|
|
|
{
|
|
|
|
return cmd_domainname_set(NULL);
|
|
|
|
}
|
|
|
|
|
2017-01-26 21:57:46 +01:00
|
|
|
int cmd_hostname_set(const char *hostname)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_HOST, host.name);
|
|
|
|
host.name = hostname ? XSTRDUP(MTYPE_HOST, hostname) : NULL;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Hostname configuration */
|
2016-09-20 01:46:51 +02:00
|
|
|
DEFUN (config_hostname,
|
2002-12-13 21:15:29 +01:00
|
|
|
hostname_cmd,
|
|
|
|
"hostname WORD",
|
|
|
|
"Set system's network name\n"
|
|
|
|
"This system's network name\n")
|
|
|
|
{
|
2016-09-20 01:46:51 +02:00
|
|
|
struct cmd_token *word = argv[1];
|
|
|
|
|
2019-08-06 16:54:52 +02:00
|
|
|
if (!isalnum((unsigned char)word->arg[0])) {
|
2019-05-30 23:56:55 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Please specify string starting with alphabet or number\n");
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* With reference to RFC 1123 Section 2.1 */
|
|
|
|
if (strlen(word->arg) > HOSTNAME_LEN) {
|
|
|
|
vty_out(vty, "Hostname length should be less than %d chars\n",
|
|
|
|
HOSTNAME_LEN);
|
2017-07-13 21:56:08 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 21:57:46 +01:00
|
|
|
return cmd_hostname_set(word->arg);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
DEFUN (config_no_hostname,
|
2002-12-13 21:15:29 +01:00
|
|
|
no_hostname_cmd,
|
|
|
|
"no hostname [HOSTNAME]",
|
|
|
|
NO_STR
|
|
|
|
"Reset system's network name\n"
|
|
|
|
"Host name of this router\n")
|
|
|
|
{
|
2017-01-26 21:57:46 +01:00
|
|
|
return cmd_hostname_set(NULL);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* VTY interface password set. */
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (config_password,
|
|
|
|
password_cmd,
|
2016-10-04 20:47:17 +02:00
|
|
|
"password [(8-8)] WORD",
|
2018-05-11 02:54:30 +02:00
|
|
|
"Modify the terminal connection password\n"
|
2002-12-13 21:15:29 +01:00
|
|
|
"Specifies a HIDDEN password will follow\n"
|
2016-09-20 01:46:51 +02:00
|
|
|
"The password string\n")
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_8 = 1;
|
|
|
|
int idx_word = 2;
|
2016-09-20 01:46:51 +02:00
|
|
|
if (argc == 3) // '8' was specified
|
|
|
|
{
|
|
|
|
if (host.password)
|
|
|
|
XFREE(MTYPE_HOST, host.password);
|
|
|
|
host.password = NULL;
|
|
|
|
if (host.password_encrypt)
|
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
2016-09-23 22:17:29 +02:00
|
|
|
host.password_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
|
2016-09-20 01:46:51 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-08-06 16:54:52 +02:00
|
|
|
if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Please specify string starting with alphanumeric\n");
|
2017-07-13 21:56:08 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (host.password)
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password);
|
2002-12-13 21:15:29 +01:00
|
|
|
host.password = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (host.encrypt) {
|
|
|
|
if (host.password_encrypt)
|
2016-09-20 01:46:51 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
2016-09-23 22:17:29 +02:00
|
|
|
host.password_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
|
2002-12-13 21:15:29 +01:00
|
|
|
} else
|
2016-09-23 22:17:29 +02:00
|
|
|
host.password = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-05-11 02:54:30 +02:00
|
|
|
/* VTY interface password delete. */
|
|
|
|
DEFUN (no_config_password,
|
|
|
|
no_password_cmd,
|
|
|
|
"no password",
|
|
|
|
NO_STR
|
|
|
|
"Modify the terminal connection password\n")
|
|
|
|
{
|
|
|
|
bool warned = false;
|
|
|
|
|
|
|
|
if (host.password) {
|
2018-05-12 20:19:49 +02:00
|
|
|
if (!vty_shell_serv(vty)) {
|
2018-05-13 19:11:43 +02:00
|
|
|
vty_out(vty, NO_PASSWD_CMD_WARNING);
|
2018-05-12 20:19:49 +02:00
|
|
|
warned = true;
|
|
|
|
}
|
2018-05-11 02:54:30 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password);
|
|
|
|
}
|
|
|
|
host.password = NULL;
|
|
|
|
|
|
|
|
if (host.password_encrypt) {
|
2018-05-12 20:19:49 +02:00
|
|
|
if (!warned && !vty_shell_serv(vty))
|
2018-05-13 19:11:43 +02:00
|
|
|
vty_out(vty, NO_PASSWD_CMD_WARNING);
|
2018-05-11 02:54:30 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
|
|
|
}
|
|
|
|
host.password_encrypt = NULL;
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* VTY enable password set. */
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (config_enable_password,
|
|
|
|
enable_password_cmd,
|
2016-10-04 20:47:17 +02:00
|
|
|
"enable password [(8-8)] WORD",
|
2002-12-13 21:15:29 +01:00
|
|
|
"Modify enable password parameters\n"
|
|
|
|
"Assign the privileged level password\n"
|
|
|
|
"Specifies a HIDDEN password will follow\n"
|
|
|
|
"The HIDDEN 'enable' password string\n")
|
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_8 = 2;
|
|
|
|
int idx_word = 3;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Crypt type is specified. */
|
2016-09-20 01:46:51 +02:00
|
|
|
if (argc == 4) {
|
2016-09-23 22:17:29 +02:00
|
|
|
if (argv[idx_8]->arg[0] == '8') {
|
2016-09-20 01:46:51 +02:00
|
|
|
if (host.enable)
|
|
|
|
XFREE(MTYPE_HOST, host.enable);
|
|
|
|
host.enable = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
if (host.enable_encrypt)
|
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
2016-09-23 22:17:29 +02:00
|
|
|
host.enable_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-20 01:46:51 +02:00
|
|
|
return CMD_SUCCESS;
|
2002-12-13 21:15:29 +01:00
|
|
|
} else {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Unknown encryption type.\n");
|
2017-07-13 21:56:08 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-09-20 01:46:51 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-08-06 16:54:52 +02:00
|
|
|
if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Please specify string starting with alphanumeric\n");
|
2017-07-13 21:56:08 +02:00
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (host.enable)
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable);
|
2002-12-13 21:15:29 +01:00
|
|
|
host.enable = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Plain password input. */
|
|
|
|
if (host.encrypt) {
|
|
|
|
if (host.enable_encrypt)
|
2016-09-20 01:46:51 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
2016-09-23 22:17:29 +02:00
|
|
|
host.enable_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
|
2002-12-13 21:15:29 +01:00
|
|
|
} else
|
2016-09-23 22:17:29 +02:00
|
|
|
host.enable = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* VTY enable password delete. */
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (no_config_enable_password,
|
|
|
|
no_enable_password_cmd,
|
2002-12-13 21:15:29 +01:00
|
|
|
"no enable password",
|
|
|
|
NO_STR
|
|
|
|
"Modify enable password parameters\n"
|
|
|
|
"Assign the privileged level password\n")
|
|
|
|
{
|
2018-05-11 02:54:30 +02:00
|
|
|
bool warned = false;
|
|
|
|
|
|
|
|
if (host.enable) {
|
2018-05-12 20:19:49 +02:00
|
|
|
if (!vty_shell_serv(vty)) {
|
2018-05-13 19:11:43 +02:00
|
|
|
vty_out(vty, NO_PASSWD_CMD_WARNING);
|
2018-05-12 20:19:49 +02:00
|
|
|
warned = true;
|
|
|
|
}
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable);
|
2018-05-11 02:54:30 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
host.enable = NULL;
|
|
|
|
|
2018-05-11 02:54:30 +02:00
|
|
|
if (host.enable_encrypt) {
|
2018-05-12 20:19:49 +02:00
|
|
|
if (!warned && !vty_shell_serv(vty))
|
2018-05-13 19:11:43 +02:00
|
|
|
vty_out(vty, NO_PASSWD_CMD_WARNING);
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
2018-05-11 02:54:30 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
host.enable_encrypt = NULL;
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2016-09-20 01:46:51 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
DEFUN (service_password_encrypt,
|
|
|
|
service_password_encrypt_cmd,
|
|
|
|
"service password-encryption",
|
|
|
|
"Set up miscellaneous service\n"
|
|
|
|
"Enable encrypted passwords\n")
|
|
|
|
{
|
|
|
|
if (host.encrypt)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
|
|
|
host.encrypt = 1;
|
|
|
|
|
|
|
|
if (host.password) {
|
|
|
|
if (host.password_encrypt)
|
2016-09-20 01:46:51 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
2005-10-26 07:49:54 +02:00
|
|
|
host.password_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, zencrypt(host.password));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
if (host.enable) {
|
|
|
|
if (host.enable_encrypt)
|
2016-09-20 01:46:51 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
2005-10-26 07:49:54 +02:00
|
|
|
host.enable_encrypt =
|
|
|
|
XSTRDUP(MTYPE_HOST, zencrypt(host.enable));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN (no_service_password_encrypt,
|
|
|
|
no_service_password_encrypt_cmd,
|
|
|
|
"no service password-encryption",
|
|
|
|
NO_STR
|
|
|
|
"Set up miscellaneous service\n"
|
|
|
|
"Enable encrypted passwords\n")
|
|
|
|
{
|
|
|
|
if (!host.encrypt)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
|
|
|
|
host.encrypt = 0;
|
|
|
|
|
|
|
|
if (host.password_encrypt)
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
2002-12-13 21:15:29 +01:00
|
|
|
host.password_encrypt = NULL;
|
|
|
|
|
|
|
|
if (host.enable_encrypt)
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
2002-12-13 21:15:29 +01:00
|
|
|
host.enable_encrypt = NULL;
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (config_terminal_length,
|
|
|
|
config_terminal_length_cmd,
|
2016-09-20 01:46:51 +02:00
|
|
|
"terminal length (0-512)",
|
2002-12-13 21:15:29 +01:00
|
|
|
"Set terminal line parameters\n"
|
|
|
|
"Set number of lines on a screen\n"
|
|
|
|
"Number of lines on screen (0 for no pausing)\n")
|
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_number = 2;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-05-12 15:16:23 +02:00
|
|
|
vty->lines = atoi(argv[idx_number]->arg);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (config_terminal_no_length,
|
|
|
|
config_terminal_no_length_cmd,
|
2002-12-13 21:15:29 +01:00
|
|
|
"terminal no length",
|
|
|
|
"Set terminal line parameters\n"
|
|
|
|
NO_STR
|
|
|
|
"Set number of lines on a screen\n")
|
|
|
|
{
|
|
|
|
vty->lines = -1;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (service_terminal_length,
|
|
|
|
service_terminal_length_cmd,
|
2016-09-20 01:46:51 +02:00
|
|
|
"service terminal-length (0-512)",
|
2002-12-13 21:15:29 +01:00
|
|
|
"Set up miscellaneous service\n"
|
|
|
|
"System wide terminal length configuration\n"
|
|
|
|
"Number of lines of VTY (0 means no line control)\n")
|
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_number = 2;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2017-05-12 15:16:23 +02:00
|
|
|
host.lines = atoi(argv[idx_number]->arg);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-09-23 05:55:26 +02:00
|
|
|
DEFUN (no_service_terminal_length,
|
|
|
|
no_service_terminal_length_cmd,
|
2016-09-20 01:46:51 +02:00
|
|
|
"no service terminal-length [(0-512)]",
|
2002-12-13 21:15:29 +01:00
|
|
|
NO_STR
|
|
|
|
"Set up miscellaneous service\n"
|
|
|
|
"System wide terminal length configuration\n"
|
|
|
|
"Number of lines of VTY (0 means no line control)\n")
|
|
|
|
{
|
|
|
|
host.lines = -1;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2004-12-18 00:16:33 +01:00
|
|
|
DEFUN_HIDDEN (do_echo,
|
2016-09-20 01:46:51 +02:00
|
|
|
echo_cmd,
|
|
|
|
"echo MESSAGE...",
|
|
|
|
"Echo a message back to the vty\n"
|
|
|
|
"The message to echo\n")
|
2004-12-18 00:16:33 +01:00
|
|
|
{
|
|
|
|
char *message;
|
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%s\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
((message = argv_concat(argv, argc, 1)) ? message : ""));
|
2005-01-28 21:28:35 +01:00
|
|
|
if (message)
|
|
|
|
XFREE(MTYPE_TMP, message);
|
2004-12-18 00:16:33 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
DEFUN (config_logmsg,
|
|
|
|
config_logmsg_cmd,
|
2016-09-25 18:49:39 +02:00
|
|
|
"logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
"Send a message to enabled logging destinations\n"
|
|
|
|
LOG_LEVEL_DESC
|
|
|
|
"The message to send\n")
|
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_log_level = 1;
|
2016-09-30 02:16:31 +02:00
|
|
|
int idx_message = 2;
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
int level;
|
|
|
|
char *message;
|
|
|
|
|
2017-05-06 06:40:17 +02:00
|
|
|
level = log_level_match(argv[idx_log_level]->arg);
|
|
|
|
if (level == ZLOG_DISABLED)
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
return CMD_ERR_NO_MATCH;
|
|
|
|
|
2016-02-23 11:59:36 +01:00
|
|
|
zlog(level, "%s",
|
|
|
|
((message = argv_concat(argv, argc, idx_message)) ? message : ""));
|
2005-01-28 21:28:35 +01:00
|
|
|
if (message)
|
|
|
|
XFREE(MTYPE_TMP, message);
|
bgpd: add L3/L2VPN Virtual Network Control feature
This feature adds an L3 & L2 VPN application that makes use of the VPN
and Encap SAFIs. This code is currently used to support IETF NVO3 style
operation. In NVO3 terminology it provides the Network Virtualization
Authority (NVA) and the ability to import/export IP prefixes and MAC
addresses from Network Virtualization Edges (NVEs). The code supports
per-NVE tables.
The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2
(L2) forwarding information between NVAs and NVEs is referred to as the
Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For
general background on NVO3 and RFP concepts see [1]. For information on
Openflow see [2].
RFPs are integrated with BGP via the RF API contained in the new "rfapi"
BGP sub-directory. Currently, only a simple example RFP is included in
Quagga. Developers may use this example as a starting point to integrate
Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code
also supports the ability import/export of routing information between
VNC and customer edge routers (CEs) operating within a virtual
network. Import/export may take place between BGP views or to the
default zebera VRF.
BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN
information between NVAs. BGP based IP VPN support is defined in
RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659,
BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use
of both the Encapsulation Subsequent Address Family Identifier (SAFI)
and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation
Subsequent Address Family Identifier (SAFI) and the BGP Tunnel
Encapsulation Attribute, are supported. MAC address distribution does
not follow any standard BGB encoding, although it was inspired by the
early IETF EVPN concepts.
The feature is conditionally compiled and disabled by default.
Use the --enable-bgp-vnc configure option to enable.
The majority of this code was authored by G. Paul Ziemba
<paulz@labn.net>.
[1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req
[2] https://www.opennetworking.org/sdn-resources/technical-library
Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
|
|
|
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-08-23 16:18:49 +02:00
|
|
|
DEFUN (debug_memstats,
|
|
|
|
debug_memstats_cmd,
|
|
|
|
"[no] debug memstats-at-exit",
|
|
|
|
NO_STR
|
|
|
|
DEBUG_STR
|
|
|
|
"Print memory type statistics at exit\n")
|
|
|
|
{
|
|
|
|
debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-02-18 16:23:45 +01:00
|
|
|
int cmd_banner_motd_file(const char *file)
|
|
|
|
{
|
2016-07-23 01:50:51 +02:00
|
|
|
int success = CMD_SUCCESS;
|
|
|
|
char p[PATH_MAX];
|
|
|
|
char *rpath;
|
|
|
|
char *in;
|
2016-02-18 16:23:45 +01:00
|
|
|
|
2016-07-23 01:50:51 +02:00
|
|
|
rpath = realpath(file, p);
|
|
|
|
if (!rpath)
|
|
|
|
return CMD_ERR_NO_FILE;
|
|
|
|
in = strstr(rpath, SYSCONFDIR);
|
|
|
|
if (in == rpath) {
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_HOST, host.motdfile);
|
2016-07-23 01:50:51 +02:00
|
|
|
host.motdfile = XSTRDUP(MTYPE_HOST, file);
|
|
|
|
} else
|
2017-07-13 21:56:08 +02:00
|
|
|
success = CMD_WARNING_CONFIG_FAILED;
|
2016-07-23 01:50:51 +02:00
|
|
|
|
|
|
|
return success;
|
2016-02-18 16:23:45 +01:00
|
|
|
}
|
|
|
|
|
2019-10-22 17:06:03 +02:00
|
|
|
void cmd_banner_motd_line(const char *line)
|
|
|
|
{
|
2020-02-04 19:19:37 +01:00
|
|
|
XFREE(MTYPE_HOST, host.motd);
|
2019-10-22 17:06:03 +02:00
|
|
|
host.motd = XSTRDUP(MTYPE_HOST, line);
|
|
|
|
}
|
|
|
|
|
2005-03-08 11:43:43 +01:00
|
|
|
DEFUN (banner_motd_file,
|
|
|
|
banner_motd_file_cmd,
|
2016-03-01 03:20:14 +01:00
|
|
|
"banner motd file FILE",
|
2005-03-08 11:43:43 +01:00
|
|
|
"Set banner\n"
|
|
|
|
"Banner for motd\n"
|
|
|
|
"Banner from a file\n"
|
|
|
|
"Filename\n")
|
|
|
|
{
|
2016-09-23 22:17:29 +02:00
|
|
|
int idx_file = 3;
|
|
|
|
const char *filename = argv[idx_file]->arg;
|
2016-09-22 22:26:07 +02:00
|
|
|
int cmd = cmd_banner_motd_file(filename);
|
2016-07-23 01:50:51 +02:00
|
|
|
|
|
|
|
if (cmd == CMD_ERR_NO_FILE)
|
2022-02-27 02:38:29 +01:00
|
|
|
vty_out(vty, "%s does not exist\n", filename);
|
2017-07-13 21:56:08 +02:00
|
|
|
else if (cmd == CMD_WARNING_CONFIG_FAILED)
|
2022-02-27 02:38:29 +01:00
|
|
|
vty_out(vty, "%s must be in %s\n", filename, SYSCONFDIR);
|
2016-07-23 01:50:51 +02:00
|
|
|
|
|
|
|
return cmd;
|
2005-03-08 11:43:43 +01:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-10-22 17:06:03 +02:00
|
|
|
DEFUN (banner_motd_line,
|
|
|
|
banner_motd_line_cmd,
|
|
|
|
"banner motd line LINE...",
|
|
|
|
"Set banner\n"
|
|
|
|
"Banner for motd\n"
|
|
|
|
"Banner from an input\n"
|
|
|
|
"Text\n")
|
|
|
|
{
|
|
|
|
int idx = 0;
|
|
|
|
char *motd;
|
|
|
|
|
|
|
|
argv_find(argv, argc, "LINE", &idx);
|
|
|
|
motd = argv_concat(argv, argc, idx);
|
|
|
|
|
|
|
|
cmd_banner_motd_line(motd);
|
|
|
|
XFREE(MTYPE_TMP, motd);
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
DEFUN (banner_motd_default,
|
|
|
|
banner_motd_default_cmd,
|
|
|
|
"banner motd default",
|
|
|
|
"Set banner string\n"
|
|
|
|
"Strings for motd\n"
|
|
|
|
"Default string\n")
|
|
|
|
{
|
2019-10-22 17:06:03 +02:00
|
|
|
cmd_banner_motd_line(FRR_DEFAULT_MOTD);
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN (no_banner_motd,
|
|
|
|
no_banner_motd_cmd,
|
|
|
|
"no banner motd",
|
|
|
|
NO_STR
|
|
|
|
"Set banner string\n"
|
|
|
|
"Strings for motd\n")
|
|
|
|
{
|
|
|
|
host.motd = NULL;
|
2016-09-20 01:46:51 +02:00
|
|
|
if (host.motdfile)
|
2005-10-26 07:49:54 +02:00
|
|
|
XFREE(MTYPE_HOST, host.motdfile);
|
2005-03-08 11:43:43 +01:00
|
|
|
host.motdfile = NULL;
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-01 22:24:52 +02:00
|
|
|
DEFUN(allow_reserved_ranges, allow_reserved_ranges_cmd, "allow-reserved-ranges",
|
|
|
|
"Allow using IPv4 (Class E) reserved IP space\n")
|
|
|
|
{
|
|
|
|
host.allow_reserved_ranges = true;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN(no_allow_reserved_ranges, no_allow_reserved_ranges_cmd,
|
|
|
|
"no allow-reserved-ranges",
|
|
|
|
NO_STR "Allow using IPv4 (Class E) reserved IP space\n")
|
|
|
|
{
|
|
|
|
host.allow_reserved_ranges = false;
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-06-02 23:29:51 +02:00
|
|
|
int cmd_find_cmds(struct vty *vty, struct cmd_token **argv, int argc)
|
2017-07-25 23:28:19 +02:00
|
|
|
{
|
2017-07-25 20:20:55 +02:00
|
|
|
const struct cmd_node *node;
|
|
|
|
const struct cmd_element *cli;
|
|
|
|
vector clis;
|
2017-07-25 23:28:19 +02:00
|
|
|
|
2019-08-30 18:18:11 +02:00
|
|
|
regex_t exp = {};
|
|
|
|
|
2021-03-18 20:31:35 +01:00
|
|
|
char *pattern = argv_concat(argv, argc, 1);
|
2019-08-30 18:18:11 +02:00
|
|
|
int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
|
2021-03-18 20:31:35 +01:00
|
|
|
XFREE(MTYPE_TMP, pattern);
|
2019-08-30 18:18:11 +02:00
|
|
|
|
|
|
|
if (cr != 0) {
|
|
|
|
switch (cr) {
|
|
|
|
case REG_BADBR:
|
|
|
|
vty_out(vty, "%% Invalid {...} expression\n");
|
|
|
|
break;
|
|
|
|
case REG_BADRPT:
|
|
|
|
vty_out(vty, "%% Bad repetition operator\n");
|
|
|
|
break;
|
|
|
|
case REG_BADPAT:
|
|
|
|
vty_out(vty, "%% Regex syntax error\n");
|
|
|
|
break;
|
|
|
|
case REG_ECOLLATE:
|
|
|
|
vty_out(vty, "%% Invalid collating element\n");
|
|
|
|
break;
|
|
|
|
case REG_ECTYPE:
|
|
|
|
vty_out(vty, "%% Invalid character class name\n");
|
|
|
|
break;
|
|
|
|
case REG_EESCAPE:
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Regex ended with escape character (\\)\n");
|
|
|
|
break;
|
|
|
|
case REG_ESUBREG:
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Invalid number in \\digit construction\n");
|
|
|
|
break;
|
|
|
|
case REG_EBRACK:
|
|
|
|
vty_out(vty, "%% Unbalanced square brackets\n");
|
|
|
|
break;
|
|
|
|
case REG_EPAREN:
|
|
|
|
vty_out(vty, "%% Unbalanced parentheses\n");
|
|
|
|
break;
|
|
|
|
case REG_EBRACE:
|
|
|
|
vty_out(vty, "%% Unbalanced braces\n");
|
|
|
|
break;
|
|
|
|
case REG_ERANGE:
|
|
|
|
vty_out(vty,
|
|
|
|
"%% Invalid endpoint in range expression\n");
|
|
|
|
break;
|
|
|
|
case REG_ESPACE:
|
|
|
|
vty_out(vty, "%% Failed to compile (out of memory)\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-25 23:28:19 +02:00
|
|
|
for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
|
2017-07-25 20:20:55 +02:00
|
|
|
node = vector_slot(cmdvec, i);
|
2017-07-25 23:28:19 +02:00
|
|
|
if (!node)
|
|
|
|
continue;
|
2017-07-25 20:20:55 +02:00
|
|
|
clis = node->cmd_vector;
|
2017-07-25 23:28:19 +02:00
|
|
|
for (unsigned int j = 0; j < vector_active(clis); j++) {
|
2017-07-25 20:20:55 +02:00
|
|
|
cli = vector_slot(clis, j);
|
2019-08-30 18:18:11 +02:00
|
|
|
|
2021-06-03 01:02:45 +02:00
|
|
|
if (regexec(&exp, cli->string, 0, NULL, 0) == 0) {
|
|
|
|
vty_out(vty, " (%s) ", node->name);
|
|
|
|
print_cmd(vty, cli->string);
|
|
|
|
}
|
2017-07-25 23:28:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-30 18:18:11 +02:00
|
|
|
done:
|
|
|
|
regfree(&exp);
|
2017-07-25 23:28:19 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-06-02 23:29:51 +02:00
|
|
|
DEFUN(find,
|
|
|
|
find_cmd,
|
|
|
|
"find REGEX...",
|
|
|
|
"Find CLI command matching a regular expression\n"
|
|
|
|
"Search pattern (POSIX regex)\n")
|
|
|
|
{
|
|
|
|
return cmd_find_cmds(vty, argv, argc);
|
|
|
|
}
|
|
|
|
|
2020-11-30 23:01:03 +01:00
|
|
|
#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
|
2021-07-23 18:29:21 +02:00
|
|
|
DEFUN(script, script_cmd, "script SCRIPT FUNCTION",
|
|
|
|
"Test command - execute a function in a script\n"
|
|
|
|
"Script name (same as filename in /etc/frr/scripts/)\n"
|
|
|
|
"Function name (in the script)\n")
|
lib: start adding generic scripting stuff
Rather than let Luaisms propagate from the start, this is some generic
wrapper stuff that defines some semantics for interacting with scripts
that aren't specific to the underlying language.
The concept I have in mind for FRR's idea of a script is:
- has a name
- has some inputs, which have types
- has some outputs, which have types
I don't want to even say they have to be files; maybe we can embed
scripts in frr.conf, for example. Similarly the types of inputs and
outputs are probably going to end up being some language-specific setup.
For now, we will stick to this simple model, but the plan is to add full
object support (ie calling back into C).
This shouldn't be misconstrued as prepping for multilingual scripting
support, which is a bad idea for the following reasons:
- Each language would require different FFI methods, and specifically
different object encoders; a lot of code
- Languages have different capabilities that would have to be brought to
parity with each other; a lot of work
- Languages have *vastly* different performance characteristics; bad
impressions, lots of issues we can't do anything about
- Each language would need a dedicated maintainer for the above reasons;
pragmatically difficult
- Supporting multiple languages fractures the community and limits the
audience with which a given script can be shared
The only pro for multilingual support would be ease of use for users not
familiar with Lua but familiar with one of the other supported
languages. This is not enough to outweigh the cons.
In order to get rich scripting capabilities, we need to be able to pass
representations of internal objects to the scripts. For example, a
script that performs some computation based on information about a peer
needs access to some equivalent of `struct peer` for the peer in
question. To transfer these objects from C-space into Lua-space we need
to encode them onto the Lua stack. This patch adds a mapping from
arbitrary type names to the functions that encode objects of that type.
For example, the function that encodes `struct peer` into a Lua table
could be registered with:
bgp_peer_encoder_func(struct frrscript *fs, struct peer *peer)
{
// encode peer to Lua table, push to stack in fs->scriptinfo->L
}
frrscript_register_type_encoder("peer", bgp_peer_encoder_func);
Later on when calling a script that wants a peer, the plan is to be able
to specify the type name like so:
frrscript_call(script, "peer", peer);
Using C-style types for the type names would have been nice, it might be
possible to do this with preprocessor magic or possibly python
preprocessing later on.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
mergeme no stdlib
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
2020-11-29 01:02:39 +01:00
|
|
|
{
|
2020-11-29 03:51:42 +01:00
|
|
|
struct prefix p;
|
2021-01-19 15:29:50 +01:00
|
|
|
|
|
|
|
(void)str2prefix("1.2.3.4/24", &p);
|
2021-07-04 17:12:07 +02:00
|
|
|
struct frrscript *fs = frrscript_new(argv[1]->arg);
|
lib: start adding generic scripting stuff
Rather than let Luaisms propagate from the start, this is some generic
wrapper stuff that defines some semantics for interacting with scripts
that aren't specific to the underlying language.
The concept I have in mind for FRR's idea of a script is:
- has a name
- has some inputs, which have types
- has some outputs, which have types
I don't want to even say they have to be files; maybe we can embed
scripts in frr.conf, for example. Similarly the types of inputs and
outputs are probably going to end up being some language-specific setup.
For now, we will stick to this simple model, but the plan is to add full
object support (ie calling back into C).
This shouldn't be misconstrued as prepping for multilingual scripting
support, which is a bad idea for the following reasons:
- Each language would require different FFI methods, and specifically
different object encoders; a lot of code
- Languages have different capabilities that would have to be brought to
parity with each other; a lot of work
- Languages have *vastly* different performance characteristics; bad
impressions, lots of issues we can't do anything about
- Each language would need a dedicated maintainer for the above reasons;
pragmatically difficult
- Supporting multiple languages fractures the community and limits the
audience with which a given script can be shared
The only pro for multilingual support would be ease of use for users not
familiar with Lua but familiar with one of the other supported
languages. This is not enough to outweigh the cons.
In order to get rich scripting capabilities, we need to be able to pass
representations of internal objects to the scripts. For example, a
script that performs some computation based on information about a peer
needs access to some equivalent of `struct peer` for the peer in
question. To transfer these objects from C-space into Lua-space we need
to encode them onto the Lua stack. This patch adds a mapping from
arbitrary type names to the functions that encode objects of that type.
For example, the function that encodes `struct peer` into a Lua table
could be registered with:
bgp_peer_encoder_func(struct frrscript *fs, struct peer *peer)
{
// encode peer to Lua table, push to stack in fs->scriptinfo->L
}
frrscript_register_type_encoder("peer", bgp_peer_encoder_func);
Later on when calling a script that wants a peer, the plan is to be able
to specify the type name like so:
frrscript_call(script, "peer", peer);
Using C-style types for the type names would have been nice, it might be
possible to do this with preprocessor magic or possibly python
preprocessing later on.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
mergeme no stdlib
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
2020-11-29 01:02:39 +01:00
|
|
|
|
2021-07-18 00:25:15 +02:00
|
|
|
if (frrscript_load(fs, argv[2]->arg, NULL)) {
|
|
|
|
vty_out(vty,
|
2021-07-23 18:29:21 +02:00
|
|
|
"/etc/frr/scripts/%s.lua or function '%s' not found\n",
|
2021-07-18 00:25:15 +02:00
|
|
|
argv[1]->arg, argv[2]->arg);
|
2020-11-29 03:51:42 +01:00
|
|
|
}
|
lib: start adding generic scripting stuff
Rather than let Luaisms propagate from the start, this is some generic
wrapper stuff that defines some semantics for interacting with scripts
that aren't specific to the underlying language.
The concept I have in mind for FRR's idea of a script is:
- has a name
- has some inputs, which have types
- has some outputs, which have types
I don't want to even say they have to be files; maybe we can embed
scripts in frr.conf, for example. Similarly the types of inputs and
outputs are probably going to end up being some language-specific setup.
For now, we will stick to this simple model, but the plan is to add full
object support (ie calling back into C).
This shouldn't be misconstrued as prepping for multilingual scripting
support, which is a bad idea for the following reasons:
- Each language would require different FFI methods, and specifically
different object encoders; a lot of code
- Languages have different capabilities that would have to be brought to
parity with each other; a lot of work
- Languages have *vastly* different performance characteristics; bad
impressions, lots of issues we can't do anything about
- Each language would need a dedicated maintainer for the above reasons;
pragmatically difficult
- Supporting multiple languages fractures the community and limits the
audience with which a given script can be shared
The only pro for multilingual support would be ease of use for users not
familiar with Lua but familiar with one of the other supported
languages. This is not enough to outweigh the cons.
In order to get rich scripting capabilities, we need to be able to pass
representations of internal objects to the scripts. For example, a
script that performs some computation based on information about a peer
needs access to some equivalent of `struct peer` for the peer in
question. To transfer these objects from C-space into Lua-space we need
to encode them onto the Lua stack. This patch adds a mapping from
arbitrary type names to the functions that encode objects of that type.
For example, the function that encodes `struct peer` into a Lua table
could be registered with:
bgp_peer_encoder_func(struct frrscript *fs, struct peer *peer)
{
// encode peer to Lua table, push to stack in fs->scriptinfo->L
}
frrscript_register_type_encoder("peer", bgp_peer_encoder_func);
Later on when calling a script that wants a peer, the plan is to be able
to specify the type name like so:
frrscript_call(script, "peer", peer);
Using C-style types for the type names would have been nice, it might be
possible to do this with preprocessor magic or possibly python
preprocessing later on.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
mergeme no stdlib
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
2020-11-29 01:02:39 +01:00
|
|
|
|
2021-07-04 17:12:07 +02:00
|
|
|
int ret = frrscript_call(fs, argv[2]->arg, ("p", &p));
|
|
|
|
char buf[40];
|
|
|
|
prefix2str(&p, buf, sizeof(buf));
|
|
|
|
vty_out(vty, "p: %s\n", buf);
|
|
|
|
vty_out(vty, "Script result: %d\n", ret);
|
lib: start adding generic scripting stuff
Rather than let Luaisms propagate from the start, this is some generic
wrapper stuff that defines some semantics for interacting with scripts
that aren't specific to the underlying language.
The concept I have in mind for FRR's idea of a script is:
- has a name
- has some inputs, which have types
- has some outputs, which have types
I don't want to even say they have to be files; maybe we can embed
scripts in frr.conf, for example. Similarly the types of inputs and
outputs are probably going to end up being some language-specific setup.
For now, we will stick to this simple model, but the plan is to add full
object support (ie calling back into C).
This shouldn't be misconstrued as prepping for multilingual scripting
support, which is a bad idea for the following reasons:
- Each language would require different FFI methods, and specifically
different object encoders; a lot of code
- Languages have different capabilities that would have to be brought to
parity with each other; a lot of work
- Languages have *vastly* different performance characteristics; bad
impressions, lots of issues we can't do anything about
- Each language would need a dedicated maintainer for the above reasons;
pragmatically difficult
- Supporting multiple languages fractures the community and limits the
audience with which a given script can be shared
The only pro for multilingual support would be ease of use for users not
familiar with Lua but familiar with one of the other supported
languages. This is not enough to outweigh the cons.
In order to get rich scripting capabilities, we need to be able to pass
representations of internal objects to the scripts. For example, a
script that performs some computation based on information about a peer
needs access to some equivalent of `struct peer` for the peer in
question. To transfer these objects from C-space into Lua-space we need
to encode them onto the Lua stack. This patch adds a mapping from
arbitrary type names to the functions that encode objects of that type.
For example, the function that encodes `struct peer` into a Lua table
could be registered with:
bgp_peer_encoder_func(struct frrscript *fs, struct peer *peer)
{
// encode peer to Lua table, push to stack in fs->scriptinfo->L
}
frrscript_register_type_encoder("peer", bgp_peer_encoder_func);
Later on when calling a script that wants a peer, the plan is to be able
to specify the type name like so:
frrscript_call(script, "peer", peer);
Using C-style types for the type names would have been nice, it might be
possible to do this with preprocessor magic or possibly python
preprocessing later on.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
mergeme no stdlib
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
2020-11-29 01:02:39 +01:00
|
|
|
|
2021-07-08 11:51:14 +02:00
|
|
|
frrscript_delete(fs);
|
2021-07-07 19:32:30 +02:00
|
|
|
|
lib: start adding generic scripting stuff
Rather than let Luaisms propagate from the start, this is some generic
wrapper stuff that defines some semantics for interacting with scripts
that aren't specific to the underlying language.
The concept I have in mind for FRR's idea of a script is:
- has a name
- has some inputs, which have types
- has some outputs, which have types
I don't want to even say they have to be files; maybe we can embed
scripts in frr.conf, for example. Similarly the types of inputs and
outputs are probably going to end up being some language-specific setup.
For now, we will stick to this simple model, but the plan is to add full
object support (ie calling back into C).
This shouldn't be misconstrued as prepping for multilingual scripting
support, which is a bad idea for the following reasons:
- Each language would require different FFI methods, and specifically
different object encoders; a lot of code
- Languages have different capabilities that would have to be brought to
parity with each other; a lot of work
- Languages have *vastly* different performance characteristics; bad
impressions, lots of issues we can't do anything about
- Each language would need a dedicated maintainer for the above reasons;
pragmatically difficult
- Supporting multiple languages fractures the community and limits the
audience with which a given script can be shared
The only pro for multilingual support would be ease of use for users not
familiar with Lua but familiar with one of the other supported
languages. This is not enough to outweigh the cons.
In order to get rich scripting capabilities, we need to be able to pass
representations of internal objects to the scripts. For example, a
script that performs some computation based on information about a peer
needs access to some equivalent of `struct peer` for the peer in
question. To transfer these objects from C-space into Lua-space we need
to encode them onto the Lua stack. This patch adds a mapping from
arbitrary type names to the functions that encode objects of that type.
For example, the function that encodes `struct peer` into a Lua table
could be registered with:
bgp_peer_encoder_func(struct frrscript *fs, struct peer *peer)
{
// encode peer to Lua table, push to stack in fs->scriptinfo->L
}
frrscript_register_type_encoder("peer", bgp_peer_encoder_func);
Later on when calling a script that wants a peer, the plan is to be able
to specify the type name like so:
frrscript_call(script, "peer", peer);
Using C-style types for the type names would have been nice, it might be
possible to do this with preprocessor magic or possibly python
preprocessing later on.
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
mergeme no stdlib
Signed-off-by: Quentin Young <qlyoung@nvidia.com>
2020-11-29 01:02:39 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set config filename. Called from vty.c */
|
2015-05-20 03:29:15 +02:00
|
|
|
void host_config_set(const char *filename)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_HOST, host.config);
|
2005-10-26 07:49:54 +02:00
|
|
|
host.config = XSTRDUP(MTYPE_HOST, filename);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-05-03 19:59:41 +02:00
|
|
|
const char *host_config_get(void)
|
|
|
|
{
|
|
|
|
return host.config;
|
|
|
|
}
|
|
|
|
|
2022-10-07 13:51:17 +02:00
|
|
|
void cmd_show_lib_debugs(struct vty *vty)
|
|
|
|
{
|
|
|
|
route_map_show_debug(vty);
|
2023-04-26 23:50:46 +02:00
|
|
|
mgmt_debug_be_client_show_debug(vty);
|
|
|
|
mgmt_debug_fe_client_show_debug(vty);
|
2022-10-07 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
void install_default(enum node_type node)
|
|
|
|
{
|
2020-07-21 08:28:04 +02:00
|
|
|
_install_element(node, &config_exit_cmd);
|
|
|
|
_install_element(node, &config_quit_cmd);
|
|
|
|
_install_element(node, &config_end_cmd);
|
|
|
|
_install_element(node, &config_help_cmd);
|
|
|
|
_install_element(node, &config_list_cmd);
|
|
|
|
_install_element(node, &show_cli_graph_cmd);
|
|
|
|
_install_element(node, &find_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2020-07-21 08:28:04 +02:00
|
|
|
_install_element(node, &config_write_cmd);
|
|
|
|
_install_element(node, &show_running_config_cmd);
|
2017-05-10 16:38:48 +02:00
|
|
|
|
2020-07-21 08:28:04 +02:00
|
|
|
_install_element(node, &autocomplete_cmd);
|
2017-12-07 20:31:48 +01:00
|
|
|
|
|
|
|
nb_cli_install_default(node);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2016-11-09 14:42:47 +01:00
|
|
|
/* Initialize command interface. Install basic nodes and commands.
|
|
|
|
*
|
|
|
|
* terminal = 0 -- vtysh / no logging, no config control
|
|
|
|
* terminal = 1 -- normal daemon
|
2017-01-04 02:13:02 +01:00
|
|
|
* terminal = -1 -- watchfrr / no logging, but minimal config control */
|
2002-12-13 21:15:29 +01:00
|
|
|
void cmd_init(int terminal)
|
|
|
|
{
|
2017-08-21 23:56:06 +02:00
|
|
|
struct utsname names;
|
|
|
|
|
|
|
|
uname(&names);
|
2016-09-26 17:30:30 +02:00
|
|
|
qobj_init();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-13 02:14:22 +02:00
|
|
|
/* register command preprocessors */
|
|
|
|
hook_register(cmd_execute, handle_pipe_action);
|
|
|
|
hook_register(cmd_execute_done, handle_pipe_action_done);
|
|
|
|
|
2016-11-19 11:57:08 +01:00
|
|
|
varhandlers = list_new();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Allocate initial top vector of commands. */
|
|
|
|
cmdvec = vector_init(VECTOR_MIN_SIZE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Default host value settings. */
|
2017-08-21 23:56:06 +02:00
|
|
|
host.name = XSTRDUP(MTYPE_HOST, names.nodename);
|
2022-01-22 14:15:42 +01:00
|
|
|
host.system = XSTRDUP(MTYPE_HOST, names.sysname);
|
|
|
|
host.release = XSTRDUP(MTYPE_HOST, names.release);
|
|
|
|
host.version = XSTRDUP(MTYPE_HOST, names.version);
|
|
|
|
|
2017-08-21 23:56:06 +02:00
|
|
|
#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
|
2017-08-29 01:52:29 +02:00
|
|
|
if ((strcmp(names.domainname, "(none)") == 0))
|
|
|
|
host.domainname = NULL;
|
|
|
|
else
|
|
|
|
host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
|
2017-08-21 23:56:06 +02:00
|
|
|
#else
|
|
|
|
host.domainname = NULL;
|
|
|
|
#endif
|
2002-12-13 21:15:29 +01:00
|
|
|
host.password = NULL;
|
|
|
|
host.enable = NULL;
|
|
|
|
host.config = NULL;
|
2016-11-09 14:42:47 +01:00
|
|
|
host.noconfig = (terminal < 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
host.lines = -1;
|
2019-10-22 17:06:03 +02:00
|
|
|
cmd_banner_motd_line(FRR_DEFAULT_MOTD);
|
2005-03-08 11:43:43 +01:00
|
|
|
host.motdfile = NULL;
|
2022-07-01 22:24:52 +02:00
|
|
|
host.allow_reserved_ranges = false;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Install top nodes. */
|
2018-09-08 22:31:43 +02:00
|
|
|
install_node(&view_node);
|
|
|
|
install_node(&enable_node);
|
|
|
|
install_node(&auth_node);
|
|
|
|
install_node(&auth_enable_node);
|
|
|
|
install_node(&config_node);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Each node's basic commands. */
|
|
|
|
install_element(VIEW_NODE, &show_version_cmd);
|
2017-07-25 23:28:19 +02:00
|
|
|
install_element(ENABLE_NODE, &show_startup_config_cmd);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (terminal) {
|
2019-05-30 22:14:25 +02:00
|
|
|
install_element(ENABLE_NODE, &debug_memstats_cmd);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
install_element(VIEW_NODE, &config_list_cmd);
|
|
|
|
install_element(VIEW_NODE, &config_exit_cmd);
|
2016-09-23 23:34:33 +02:00
|
|
|
install_element(VIEW_NODE, &config_quit_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
install_element(VIEW_NODE, &config_help_cmd);
|
|
|
|
install_element(VIEW_NODE, &config_enable_cmd);
|
|
|
|
install_element(VIEW_NODE, &config_terminal_length_cmd);
|
|
|
|
install_element(VIEW_NODE, &config_terminal_no_length_cmd);
|
2016-01-12 19:41:48 +01:00
|
|
|
install_element(VIEW_NODE, &show_commandtree_cmd);
|
2004-12-18 00:16:33 +01:00
|
|
|
install_element(VIEW_NODE, &echo_cmd);
|
2017-05-10 16:38:48 +02:00
|
|
|
install_element(VIEW_NODE, &autocomplete_cmd);
|
2017-07-25 23:28:19 +02:00
|
|
|
install_element(VIEW_NODE, &find_cmd);
|
2020-11-30 23:01:03 +01:00
|
|
|
#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
|
2020-11-29 03:51:42 +01:00
|
|
|
install_element(VIEW_NODE, &script_cmd);
|
|
|
|
#endif
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-12 17:39:02 +02:00
|
|
|
install_element(ENABLE_NODE, &config_end_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
install_element(ENABLE_NODE, &config_disable_cmd);
|
|
|
|
install_element(ENABLE_NODE, &config_terminal_cmd);
|
2016-09-23 23:34:33 +02:00
|
|
|
install_element(ENABLE_NODE, ©_runningconf_startupconf_cmd);
|
2016-10-12 17:39:02 +02:00
|
|
|
install_element(ENABLE_NODE, &config_write_cmd);
|
|
|
|
install_element(ENABLE_NODE, &show_running_config_cmd);
|
2004-12-07 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* bgp_main.c: (main) The 2nd argument to openzlog has been removed.
* isis_main.c: (main) The 2nd argument to openzlog has been removed.
* ospf6_main.c: (main) The 2nd argument to openzlog has been removed.
Note that stdout logging will no longer be enabled by default when
not running as a daemon.
* ospf_main.c: (main) The 2nd argument to openzlog has been removed.
* rip_main.c: (main) The 2nd argument to openzlog has been removed.
* ripng_main.c: (main) The 2nd argument to openzlog has been removed.
* main.c: (main) The 2nd argument to openzlog has been removed.
So stdout logging will no longer be enabled by default.
* irdp_main.c: (irdp_finish) Reduce severity of shutdown message
from LOG_WARNING to LOG_INFO.
* vtysh.c: Make several functions static instead of global.
Added several commands to support destination-specific logging levels.
(vtysh_completion) This function is unused, so comment it out.
* basic.texi: Document new logging features. Separate basic config
commands from basic VTY commands.
* log.h: Replace struct zlog flags and maskpri fields with maxlvl
array to support individual logging levels for each destination.
Remove the 2nd argument to openzlog since the default logging config
should be standardized inside the library. Replaced the
zlog_set_flag and zlog_reset_flag functions with zlog_set_level.
And zlog_set_file now requires an additional log_level argument.
Declare zlog_proto_names for use inside command.c in the
"show logging" command. Added defines useful for command
construction.
* log.c: (vzlog) Decide where to send the message based on the
individual logging levels configured for each destination.
Remove support for ZLOG_STDERR since it was never actually used.
Support record-priority for terminal monitors.
(zlog_signal,zlog_backtrace_sigsafe) Support destination-specific
logging levels. Remove stderr support (was never used). Added
support for terminal monitor logging.
(_zlog_assert_failed) Increase message severity to LOG_EMERG.
(openzlog) Remove 2nd argument since default config should be
standardized in library. By default, terminal monitoring
is set to debug, and all other logging is disabled.
(zlog_set_flag,zlog_reset_flag) Removed.
(zlog_set_level) New function to replace zlog_set_flag and
zlog_reset_flag. Supports destination-specific logging levels.
(zlog_set_file,zlog_reset_file) Support file-specific logging level.
(zlog_rotate) Log an error message if fopen fails, and support
new file-specific logging level.
* command.h: Change DEFUN_CMD_FUNC_DECL and DEFUN_CMD_FUNC_TEXT so that
command functions will be static instead of global. Remove
declarations for config_exit and config_help. Define new macros
DEFUNSH_ATTR, DEFUNSH_HIDDEN, and DEFUNSH_DEPRECATED so we can
have deprecated commands in vtysh. Similarly, for completeness,
define macros ALIAS_SH, ALIAS_SH_HIDDEN, and ALIAS_SH_DEPRECATED.
Also, fix bug in ALIAS_ATTR macro (didn't matter because it
was never used).
* command.c: Make many functions static instead of global.
(facility_name,facility_match,level_match) New functions
to support enhanced destination-specific logging levels.
(config_write_host) Support new destination-specific logging levels.
(config_logmsg) Added new "logmsg" command to help test logging
system.
(show_logging) Added "show logging" command to show the current
configuration of the logging system.
(config_log_stdout_level) Support explicit stdout logging level.
(no_config_log_stdout) Now takes optional LEVEL arg.
(config_log_monitor,config_log_monitor_level,no_config_log_monitor)
New commands creating new "log monitor" commands to set terminal
monitoring log level.
(config_log_file_level) Support explicit file logging level.
(config_log_syslog_level) Support explicit syslog logging level.
(config_log_facility,no_config_log_facility) Implement new
"log facility" command.
(cmd_init) Add hooks for new commands: "show logging", "logmsg",
"log stdout <level>", "log monitor", "log monitor <level>",
"no log monitor", "log file <filename> <level>",
"no log file <filename> <level>", "log syslog <level>",
"log facility", and "no log facility".
* vty.h: Added a "level" argument to vty_log so it can support
"log record-priority". Declare new function vty_log_fixed for
use in signal handlers.
* vty.c: (vty_log,vty_log_out) Added a "level" argument to support
"log record-priority" for vty terminal monitors.
(vty_down_level) Use config_exit_cmd.func instead of calling
config_exit directly (since command functions will now be static
instead of global).
(vty_log_fixed) New function to send terminal monitor messages
from inside a signal handler.
2004-12-07 16:39:31 +01:00
|
|
|
install_element(ENABLE_NODE, &config_logmsg_cmd);
|
2017-07-25 23:28:19 +02:00
|
|
|
|
2004-10-03 22:11:32 +02:00
|
|
|
install_default(CONFIG_NODE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-11 16:51:58 +01:00
|
|
|
event_cmd_init();
|
2016-11-16 07:00:52 +01:00
|
|
|
workqueue_cmd_init();
|
2017-06-19 16:22:26 +02:00
|
|
|
hash_cmd_init();
|
2004-10-07 23:32:14 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-07 23:32:14 +02:00
|
|
|
install_element(CONFIG_NODE, &hostname_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_hostname_cmd);
|
2017-08-29 01:52:29 +02:00
|
|
|
install_element(CONFIG_NODE, &domainname_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_domainname_cmd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-09 14:42:47 +01:00
|
|
|
if (terminal > 0) {
|
2017-05-06 06:40:17 +02:00
|
|
|
full_cli = true;
|
|
|
|
|
2019-05-30 22:14:25 +02:00
|
|
|
install_element(CONFIG_NODE, &debug_memstats_cmd);
|
|
|
|
|
2004-10-03 22:11:32 +02:00
|
|
|
install_element(CONFIG_NODE, &password_cmd);
|
2018-05-11 02:54:30 +02:00
|
|
|
install_element(CONFIG_NODE, &no_password_cmd);
|
2004-10-03 22:11:32 +02:00
|
|
|
install_element(CONFIG_NODE, &enable_password_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_enable_password_cmd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
install_element(CONFIG_NODE, &service_password_encrypt_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
|
|
|
|
install_element(CONFIG_NODE, &banner_motd_default_cmd);
|
2005-03-08 11:43:43 +01:00
|
|
|
install_element(CONFIG_NODE, &banner_motd_file_cmd);
|
2019-10-22 17:06:03 +02:00
|
|
|
install_element(CONFIG_NODE, &banner_motd_line_cmd);
|
2002-12-13 21:15:29 +01:00
|
|
|
install_element(CONFIG_NODE, &no_banner_motd_cmd);
|
|
|
|
install_element(CONFIG_NODE, &service_terminal_length_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
|
2022-07-01 22:24:52 +02:00
|
|
|
install_element(CONFIG_NODE, &allow_reserved_ranges_cmd);
|
|
|
|
install_element(CONFIG_NODE, &no_allow_reserved_ranges_cmd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-06 06:40:17 +02:00
|
|
|
log_cmd_init();
|
2016-02-03 15:00:25 +01:00
|
|
|
vrf_install_commands();
|
This patch adds Yon's CLI 'walk back up tree' patch. Following are email
describing original patch and a shorter email describing changes to an
updated patch, the one which is applied:
From havanna_moon@gmx.net Sat Jan 18 00:37:13 2003
Date: Mon, 9 Dec 2002 05:32:58 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: "the list(tm) Zebra" <zebra@zebra.org>
Subject: [zebra 16671] [PATCH] CLI extensions.
Hi,
this patch adds 2 improvements to the CLI (lib/command.c):
#1) When in subconfig mode (router XXX, interface XXX, ...) commands that
fail for that node are tried on the main CONFIG_NODE. This is great for
configuring interfaces or changing the sub-config mode quickly, without
the need to type 'exit' between commands:
ospfd(config)# int eth1
ospfd(config-if)# ip ospf cost 9
ospfd(config-if)# ip ospf prio 101
ospfd(config-if)# router ospf
ospfd(config-router)# network 1.1.1.0/24 area 51
ospfd(config-router)# int eth2
ospfd(config-if)# ip ospf authentication message-digest
ospfd(config-if)# ^Z
ospfd#
Is this IOS-like or does IOS try to walk up the tree of config sub-modes
instead of directly trying the command on CONFIG_NODE?
CAVEATS: "?" and "TAB" don't work. IIRC IOS doesnt show that help
neither.
NON-CAVEATS: This wont break much, as config_from_file() already does
try a failed command on the parent node of the actual vty->node. If
changing the code to walk the node tree instead of directly trying
the command on the ENABLE_NODE the same semantics would be in use
and no future bugs could creep in.
#2) When in config or subconfig mode use the "do " prefix to execute
commans of the ENABLE_NODE. "?" and "TAB" work. The space after the
"do" is needed:
ospfd(config-router)# do<?>
% There is no matched command.
ospfd(config-router)# do <?>
clear Reset functions
configure Configuration from vty interface
copy Copy configuration
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
end End current mode and change to enable mode.
exit Exit current mode and down to previous mode
help Description of the interactive help system
list Print command list
no Negate a command or set its defaults
quit Exit current mode and down to previous mode
show Show running system information
terminal Set terminal line parameters
who Display who is on vty
write Write running configuration to memory, network, or terminal
ospfd(config-router)# do sho<TAB>
ospfd(config-router)# do show me<TAB>
ospfd(config-router)# do show memory r<TAB>
ospfd(config-router)# do show memory rip
RIP structure : 0
RIP route info : 0
RIP interface : 0
RIP peer : 0
RIP offset list : 0
RIP distance : 0
ospfd(config-router)# ^Z
ospfd#
CAVEATS: I don't have access to an IOS with this feature, so I implemented
it from the comments on this mailing list (in fact my personal motivation
was to implement feature #1, which I missed on zebra. But #2 sounded like
a nice one to have, and xemacs was already parked on command.c ...).
Is this IOS-like or are there differences?
I will happily change this patch to mimick IOS or the mailing-list
consensus on CLI-usability.
regards,
yon
From havanna_moon@gmx.net Sat Jan 18 01:13:11 2003
Date: Sat, 11 Jan 2003 23:36:51 +0100 (CET)
From: Yon Uriarte <havanna_moon@gmx.net>
To: zebra@zebra.org
Subject: [zebra 17218] Re: [PATCH] CLI extensions.
Hi,
[redacted]
> I prefer the IOS way for the node "up walking".
This patch should walk the tree upwards:
bgpd(config)# router bgp 1
bgpd(config-router)# address-family ipv4 multicast
bgpd(config-router-af)# access-list 1 remark hola que tal
bgpd(config)#
I cant test all combinations, so I cant rule out some bugs. I'd love to
get (long and explicit) bug reports.
[redacted]
2003-01-18 02:16:20 +01:00
|
|
|
}
|
2016-12-16 08:11:37 +01:00
|
|
|
|
|
|
|
#ifdef DEV_BUILD
|
|
|
|
grammar_sandbox_init();
|
|
|
|
#endif
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
|
2019-01-24 10:12:36 +01:00
|
|
|
void cmd_terminate(void)
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
{
|
|
|
|
struct cmd_node *cmd_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-29 19:13:51 +02:00
|
|
|
hook_unregister(cmd_execute, handle_pipe_action);
|
|
|
|
hook_unregister(cmd_execute_done, handle_pipe_action_done);
|
|
|
|
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
if (cmdvec) {
|
2016-09-20 01:46:51 +02:00
|
|
|
for (unsigned int i = 0; i < vector_active(cmdvec); i++)
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
if ((cmd_node = vector_slot(cmdvec, i)) != NULL) {
|
2016-09-20 01:46:51 +02:00
|
|
|
// deleting the graph delets the cmd_element as
|
|
|
|
// well
|
|
|
|
graph_delete_graph(cmd_node->cmdgraph);
|
|
|
|
vector_free(cmd_node->cmd_vector);
|
2023-03-21 13:54:21 +01:00
|
|
|
hash_clean_and_free(&cmd_node->cmd_hash, NULL);
|
2016-09-20 01:46:51 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
vector_free(cmdvec);
|
|
|
|
cmdvec = NULL;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_HOST, host.name);
|
2022-01-22 14:15:42 +01:00
|
|
|
XFREE(MTYPE_HOST, host.system);
|
|
|
|
XFREE(MTYPE_HOST, host.release);
|
|
|
|
XFREE(MTYPE_HOST, host.version);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_HOST, host.domainname);
|
|
|
|
XFREE(MTYPE_HOST, host.password);
|
|
|
|
XFREE(MTYPE_HOST, host.password_encrypt);
|
|
|
|
XFREE(MTYPE_HOST, host.enable);
|
|
|
|
XFREE(MTYPE_HOST, host.enable_encrypt);
|
|
|
|
XFREE(MTYPE_HOST, host.motdfile);
|
|
|
|
XFREE(MTYPE_HOST, host.config);
|
2019-10-22 17:06:03 +02:00
|
|
|
XFREE(MTYPE_HOST, host.motd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&varhandlers);
|
2016-11-01 21:57:53 +01:00
|
|
|
qobj_finish();
|
[bgpd] Stability fixes including bugs 397, 492
I've spent the last several weeks working on stability fixes to bgpd.
These patches fix all of the numerous crashes, assertion failures, memory
leaks and memory stomping I could find. Valgrind was used extensively.
Added new function bgp_exit() to help catch problems. If "debug bgp" is
configured and bgpd exits with status of 0, statistics on remaining
lib/memory.c allocations are printed to stderr. It is my hope that other
developers will use this to stay on top of memory issues.
Example questionable exit:
bgpd: memstats: Current memory utilization in module LIB:
bgpd: memstats: Link List : 6
bgpd: memstats: Link Node : 5
bgpd: memstats: Hash : 8
bgpd: memstats: Hash Bucket : 2
bgpd: memstats: Hash Index : 8
bgpd: memstats: Work queue : 3
bgpd: memstats: Work queue item : 2
bgpd: memstats: Work queue name string : 3
bgpd: memstats: Current memory utilization in module BGP:
bgpd: memstats: BGP instance : 1
bgpd: memstats: BGP peer : 1
bgpd: memstats: BGP peer hostname : 1
bgpd: memstats: BGP attribute : 1
bgpd: memstats: BGP extra attributes : 1
bgpd: memstats: BGP aspath : 1
bgpd: memstats: BGP aspath str : 1
bgpd: memstats: BGP table : 24
bgpd: memstats: BGP node : 1
bgpd: memstats: BGP route : 1
bgpd: memstats: BGP synchronise : 8
bgpd: memstats: BGP Process queue : 1
bgpd: memstats: BGP node clear queue : 1
bgpd: memstats: NOTE: If configuration exists, utilization may be expected.
Example clean exit:
bgpd: memstats: No remaining tracked memory utilization.
This patch fixes bug #397: "Invalid free in bgp_announce_check()".
This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c:
bgp_clear_route_node()".
My apologies for not separating out these changes into individual patches.
The complexity of doing so boggled what is left of my brain. I hope this
is all still useful to the community.
This code has been production tested, in non-route-server-client mode, on
a linux 32-bit box and a 64-bit box.
Release/reset functions, used by bgp_exit(), added to:
bgpd/bgp_attr.c,h
bgpd/bgp_community.c,h
bgpd/bgp_dump.c,h
bgpd/bgp_ecommunity.c,h
bgpd/bgp_filter.c,h
bgpd/bgp_nexthop.c,h
bgpd/bgp_route.c,h
lib/routemap.c,h
File by file analysis:
* bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released.
* bgpd/bgp_attr.c: #if removed uncalled cluster_dup().
* bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from
bgp_exit().
* bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and
also fix memory leak.
* bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees
allocations made as part of bgpd initialization and, to some extent,
configuration. If "debug bgp" is configured, memory stats are printed
as described above.
* bgpd/bgp_nexthop.c: zclient_new() already allocates stream for
ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so
zlookup is global so bgp_exit() can use it.
* bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route()
adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag.
* bgpd/bgp_route.h: Correct reference counter "lock" to be signed.
bgp_clear_route() now accepts a bgp_clear_route_type of either
BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT.
* bgpd/bgp_route.c:
- bgp_process_rsclient(): attr was being zero'ed and then
bgp_attr_extra_free() was being called with it, even though it was
never filled with valid data.
- bgp_process_rsclient(): Make sure rsclient->group is not NULL before
use.
- bgp_processq_del(): Add call to bgp_table_unlock().
- bgp_process(): Add call to bgp_table_lock().
- bgp_update_rsclient(): memset clearing of new_attr not needed since
declarationw with "= { 0 }" does it. memset was already commented
out.
- bgp_update_rsclient(): Fix screwed up misleading indentation.
- bgp_withdraw_rsclient(): Fix screwed up misleading indentation.
- bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also
free struct bgp_clear_node_queue used for work item.
- bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in
case peer is released by peer_unlock() call.
- bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use
struct bgp_clear_node_queue to supply data to worker. Add call to
bgp_table_lock().
- bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or
BGP_CLEAR_ROUTE_MY_RSCLIENT.
- bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL.
Bug 397 fixes:
- bgp_default_originate()
- bgp_announce_table()
* bgpd/bgp_table.h:
- struct bgp_table: Added reference count. Changed type of owner to be
"struct peer *" rather than "void *".
- struct bgp_node: Correct reference counter "lock" to be signed.
* bgpd/bgp_table.c:
- Added bgp_table reference counting.
- bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if
set.
- bgp_unlock_node(): Added assertion.
- bgp_node_get(): Added call to bgp_lock_node() to code path that it was
missing from.
* bgpd/bgp_vty.c:
- peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment
to owner. Handle failure gracefully.
- peer_rsclient_unset_vty(): Add call to bgp_clear_route() with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
* bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it.
* bgpd/bgpd.c:
- peer_lock(): Allow to be called when status is "Deleted".
- peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to
bgp_clear_route() call.
- peer_delete(): Common variable listnode pn. Fix bug in which rsclient
was only dealt with if not part of a peer group. Call
bgp_clear_route() for rsclient, if appropriate, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host.
- peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with
BGP_CLEAR_ROUTE_MY_RSCLIENT purpose.
- bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host.
- bgp_delete(): Delete peers before groups, rather than after. And then
rather than deleting rsclients, verify that there are none at this
point.
- bgp_unlock(): Add assertion.
- bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself.
* lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed
massive leak in install_element() in which cmd_make_descvec() was being
called more than once for the same cmd->strvec/string/doc.
* lib/log.c: Make closezlog() check fp before calling fclose().
* lib/memory.c: Catch when alloc count goes negative by using signed
counts. Correct #endif comment. Add log_memstats_stderr().
* lib/memory.h: Add log_memstats_stderr().
* lib/thread.c: thread->funcname was being accessed in thread_call() after
it had been freed. Rearranged things so that thread_call() frees
funcname. Also made it so thread_master_free() cleans up cpu_record.
* lib/vty.c,h: Use global command_cr. Add vty_terminate().
* lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
|
|
|
}
|