2002-12-13 21:15:29 +01:00
|
|
|
/* Configuration generator.
|
2017-05-13 10:25:29 +02:00
|
|
|
* Copyright (C) 2000 Kunihiro Ishiguro
|
|
|
|
*
|
|
|
|
* This file is part of GNU Zebra.
|
|
|
|
*
|
|
|
|
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "command.h"
|
|
|
|
#include "linklist.h"
|
|
|
|
#include "memory.h"
|
2019-08-02 17:45:13 +02:00
|
|
|
#include "typesafe.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include "vtysh/vtysh.h"
|
2015-07-26 00:55:47 +02:00
|
|
|
#include "vtysh/vtysh_user.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2015-05-29 05:48:31 +02:00
|
|
|
DEFINE_MGROUP(MVTYSH, "vtysh");
|
|
|
|
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration");
|
|
|
|
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line");
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
vector configvec;
|
|
|
|
|
2020-06-30 14:59:46 +02:00
|
|
|
PREDECL_LIST(config_master);
|
2020-07-28 16:58:47 +02:00
|
|
|
PREDECL_HASH(config_master_hash);
|
2019-08-02 17:45:13 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
struct config {
|
|
|
|
/* Configuration node name. */
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
/* Configuration string line. */
|
|
|
|
struct list *line;
|
|
|
|
|
|
|
|
/* Configuration can be nest. */
|
|
|
|
struct config *config;
|
|
|
|
|
|
|
|
/* Index of this config. */
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t index;
|
2019-08-02 17:45:13 +02:00
|
|
|
|
|
|
|
/* Node entry for the typed Red-black tree */
|
|
|
|
struct config_master_item rbt_item;
|
2020-07-28 16:58:47 +02:00
|
|
|
struct config_master_hash_item hash_item;
|
2002-12-13 21:15:29 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct list *config_top;
|
2004-08-26 15:08:30 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
static int line_cmp(char *c1, char *c2)
|
|
|
|
{
|
|
|
|
return strcmp(c1, c2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void line_del(char *line)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_VTYSH_CONFIG_LINE, line);
|
|
|
|
}
|
|
|
|
|
2015-03-04 07:07:01 +01:00
|
|
|
static struct config *config_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct config *config;
|
|
|
|
config = XCALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config));
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void config_del(struct config *config)
|
|
|
|
{
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete(&config->line);
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
|
2002-12-13 21:15:29 +01:00
|
|
|
XFREE(MTYPE_VTYSH_CONFIG, config);
|
|
|
|
}
|
|
|
|
|
2020-07-28 16:58:47 +02:00
|
|
|
static int config_cmp(const struct config *c1, const struct config *c2)
|
|
|
|
{
|
|
|
|
return strcmp(c1->name, c2->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t config_hash(const struct config *c)
|
|
|
|
{
|
|
|
|
return string_hash_make(c->name);
|
|
|
|
}
|
|
|
|
|
2020-06-30 14:59:46 +02:00
|
|
|
DECLARE_LIST(config_master, struct config, rbt_item);
|
2020-07-28 16:58:47 +02:00
|
|
|
DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp,
|
|
|
|
config_hash);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The config_master_head is a list for order of receipt
|
|
|
|
* The hash is for quick lookup under this NODE
|
|
|
|
*/
|
|
|
|
struct configuration {
|
|
|
|
struct config_master_head master;
|
|
|
|
struct config_master_hash_head hash_master;
|
|
|
|
};
|
2019-08-02 17:45:13 +02:00
|
|
|
|
2004-10-07 23:40:25 +02:00
|
|
|
static struct config *config_get(int index, const char *line)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-06-30 14:59:46 +02:00
|
|
|
struct config *config, *config_loop;
|
2020-07-28 16:58:47 +02:00
|
|
|
struct configuration *configuration;
|
|
|
|
struct config lookup;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-30 14:59:46 +02:00
|
|
|
config = config_loop = NULL;
|
|
|
|
|
2020-07-28 16:58:47 +02:00
|
|
|
configuration = vector_lookup_ensure(configvec, index);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-07-28 16:58:47 +02:00
|
|
|
if (!configuration) {
|
|
|
|
configuration = XMALLOC(MTYPE_VTYSH_CONFIG,
|
|
|
|
sizeof(struct configuration));
|
|
|
|
config_master_init(&configuration->master);
|
|
|
|
config_master_hash_init(&configuration->hash_master);
|
|
|
|
vector_set_index(configvec, index, configuration);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-07-28 16:58:47 +02:00
|
|
|
lookup.name = (char *)line;
|
|
|
|
config = config_master_hash_find(&configuration->hash_master, &lookup);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (!config) {
|
|
|
|
config = config_new();
|
|
|
|
config->line = list_new();
|
|
|
|
config->line->del = (void (*)(void *))line_del;
|
|
|
|
config->line->cmp = (int (*)(void *, void *))line_cmp;
|
|
|
|
config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
|
|
|
|
config->index = index;
|
2020-07-28 16:58:47 +02:00
|
|
|
config_master_add_tail(&configuration->master, config);
|
|
|
|
config_master_hash_add(&configuration->hash_master, config);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2004-10-07 23:40:25 +02:00
|
|
|
void config_add_line(struct list *config, const char *line)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
|
|
|
|
}
|
|
|
|
|
2004-10-07 23:40:25 +02:00
|
|
|
static void config_add_line_uniq(struct list *config, const char *line)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
struct listnode *node, *nnode;
|
2002-12-13 21:15:29 +01:00
|
|
|
char *pnt;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(config, node, nnode, pnt)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (strcmp(pnt, line) == 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
listnode_add_sort(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
|
|
|
|
}
|
|
|
|
|
2017-10-04 23:46:29 +02:00
|
|
|
/*
|
2018-10-23 23:20:01 +02:00
|
|
|
* Add a line that should only be shown once, and always show at the end of the
|
|
|
|
* config block.
|
|
|
|
*
|
|
|
|
* If the line already exists, it will be moved to the end of the block. If it
|
|
|
|
* does not exist, it will be added at the end of the block.
|
|
|
|
*
|
|
|
|
* Note that this only makes sense when there is just one such line that should
|
|
|
|
* show up at the very end of a config block. Furthermore, if the same block
|
|
|
|
* can show up from multiple daemons, all of them must make sure to print the
|
|
|
|
* line at the end of their config, otherwise the line will show at the end of
|
|
|
|
* the config for the last daemon that printed it.
|
|
|
|
*
|
|
|
|
* Here is a motivating example with the 'exit-vrf' command. Suppose we receive
|
|
|
|
* a config from Zebra like so:
|
|
|
|
*
|
|
|
|
* vrf BLUE
|
|
|
|
* ip route A
|
|
|
|
* ip route B
|
|
|
|
* exit-vrf
|
|
|
|
*
|
|
|
|
* Then suppose we later receive this config from PIM:
|
|
|
|
*
|
|
|
|
* vrf BLUE
|
|
|
|
* ip msdp mesh-group MyGroup member 1.2.3.4
|
|
|
|
* exit-vrf
|
|
|
|
*
|
|
|
|
* Then we will combine them into one config block like so:
|
|
|
|
*
|
|
|
|
* vrf BLUE
|
|
|
|
* ip route A
|
|
|
|
* ip route B
|
|
|
|
* ip msdp mesh-group MyGroup member 1.2.3.4
|
|
|
|
* exit-vrf
|
|
|
|
*
|
|
|
|
* Because PIM also sent us an 'exit-vrf', we noticed that we already had one
|
|
|
|
* under the 'vrf BLUE' config block and so we moved it to the end of the
|
|
|
|
* config block again. If PIM had neglected to send us 'exit-vrf', the result
|
|
|
|
* would be this:
|
|
|
|
*
|
|
|
|
* vrf BLUE
|
|
|
|
* ip route A
|
|
|
|
* ip route B
|
|
|
|
* exit-vrf
|
|
|
|
* ip msdp mesh-group MyGroup member 1.2.3.4
|
|
|
|
*
|
|
|
|
* Therefore, daemons that share config blocks must take care to consistently
|
|
|
|
* print the same block terminators.
|
|
|
|
*
|
|
|
|
* Ideally this would be solved by adding a string to struct config that is
|
|
|
|
* always printed at the end when dumping a config. However, this would only
|
|
|
|
* work when the user is using integrated config. In the non-integrated config
|
|
|
|
* case, daemons are responsible for writing their own config files, and so the
|
|
|
|
* must be able to print these blocks correctly independently of vtysh, which
|
|
|
|
* means they are the ones that need to handle printing the block terminators
|
|
|
|
* and VTYSH needs to be smart enough to combine them properly.
|
|
|
|
*
|
|
|
|
* ---
|
|
|
|
*
|
|
|
|
* config
|
|
|
|
* The config to add the line to
|
|
|
|
*
|
|
|
|
* line
|
|
|
|
* The line to add to the end of the config
|
2017-10-04 23:46:29 +02:00
|
|
|
*/
|
2018-10-23 23:20:01 +02:00
|
|
|
static void config_add_line_uniq_end(struct list *config, const char *line)
|
2017-10-04 23:46:29 +02:00
|
|
|
{
|
|
|
|
struct listnode *node;
|
2018-10-23 23:20:01 +02:00
|
|
|
char *pnt;
|
2017-10-04 23:46:29 +02:00
|
|
|
|
2018-10-23 23:20:01 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(config, node, pnt)) {
|
|
|
|
if (strcmp(pnt, line) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node)
|
|
|
|
config_add_line(config, line);
|
|
|
|
else
|
2017-10-04 23:46:29 +02:00
|
|
|
listnode_move_to_tail(config, node);
|
|
|
|
}
|
|
|
|
|
2017-05-10 16:38:48 +02:00
|
|
|
void vtysh_config_parse_line(void *arg, const char *line)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
char c;
|
|
|
|
static struct config *config = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (!line)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
c = line[0];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (c == '\0')
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
switch (c) {
|
2015-10-21 00:00:40 +02:00
|
|
|
/* Suppress exclamation points ! and commented lines. The !s are
|
|
|
|
* generated
|
|
|
|
* dynamically in vtysh_config_dump() */
|
2002-12-13 21:15:29 +01:00
|
|
|
case '!':
|
|
|
|
case '#':
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
/* Store line to current configuration. */
|
|
|
|
if (config) {
|
2016-11-12 09:43:15 +01:00
|
|
|
if (strncmp(line, " link-params",
|
|
|
|
strlen(" link-params"))
|
|
|
|
== 0) {
|
|
|
|
config_add_line(config->line, line);
|
|
|
|
config->index = LINK_PARAMS_NODE;
|
2017-10-04 23:46:29 +02:00
|
|
|
} else if (strncmp(line, " ip multicast boundary",
|
|
|
|
strlen(" ip multicast boundary"))
|
|
|
|
== 0) {
|
2018-10-23 23:20:01 +02:00
|
|
|
config_add_line_uniq_end(config->line, line);
|
2018-08-02 16:36:59 +02:00
|
|
|
} else if (strncmp(line, " ip igmp query-interval",
|
|
|
|
strlen(" ip igmp query-interval")) == 0) {
|
2018-10-23 23:20:01 +02:00
|
|
|
config_add_line_uniq_end(config->line, line);
|
2016-11-12 09:43:15 +01:00
|
|
|
} else if (config->index == LINK_PARAMS_NODE
|
2016-11-18 21:42:41 +01:00
|
|
|
&& strncmp(line, " exit-link-params",
|
|
|
|
strlen(" exit"))
|
|
|
|
== 0) {
|
2016-11-12 09:43:15 +01:00
|
|
|
config_add_line(config->line, line);
|
|
|
|
config->index = INTERFACE_NODE;
|
2018-04-11 17:23:23 +02:00
|
|
|
} else if (config->index == VRF_NODE
|
|
|
|
&& strncmp(line, " exit-vrf",
|
|
|
|
strlen(" exit-vrf"))
|
|
|
|
== 0) {
|
2018-10-23 23:20:01 +02:00
|
|
|
config_add_line_uniq_end(config->line, line);
|
2019-03-05 19:57:14 +01:00
|
|
|
} else if (!strncmp(line, " vrrp", strlen(" vrrp"))
|
|
|
|
|| !strncmp(line, " no vrrp",
|
|
|
|
strlen(" no vrrp"))) {
|
|
|
|
config_add_line(config->line, line);
|
2019-12-20 15:47:30 +01:00
|
|
|
} else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) {
|
|
|
|
config_add_line_uniq_end(config->line, line);
|
2016-11-12 09:43:15 +01:00
|
|
|
} else if (config->index == RMAP_NODE
|
2017-05-22 21:43:20 +02:00
|
|
|
|| config->index == INTERFACE_NODE
|
|
|
|
|| config->index == VTY_NODE
|
2019-07-13 21:37:02 +02:00
|
|
|
|| config->index == VRF_NODE
|
|
|
|
|| config->index == NH_GROUP_NODE)
|
2002-12-13 21:15:29 +01:00
|
|
|
config_add_line_uniq(config->line, line);
|
2020-07-14 21:37:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
config_add_line(config->line, line);
|
|
|
|
} else
|
|
|
|
config_add_line(config_top, line);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (strncmp(line, "interface", strlen("interface")) == 0)
|
|
|
|
config = config_get(INTERFACE_NODE, line);
|
2017-08-02 01:16:28 +02:00
|
|
|
else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
|
|
|
|
config = config_get(PW_NODE, line);
|
2016-02-02 13:34:29 +01:00
|
|
|
else if (strncmp(line, "vrf", strlen("vrf")) == 0)
|
|
|
|
config = config_get(VRF_NODE, line);
|
pbrd: Add PBR to FRR
This is an implementation of PBR for FRR.
This implemenation uses a combination of rules and
tables to determine how packets will flow.
PBR introduces a new concept of 'nexthop-groups' to
specify a group of nexthops that will be used for
ecmp. Nexthop-groups are specified on the cli via:
nexthop-group DONNA
nexthop 192.168.208.1
nexthop 192.168.209.1
nexthop 192.168.210.1
!
PBR sees the nexthop-group and installs these as a default
route with these nexthops starting at table 10000
robot# show pbr nexthop-groups
Nexthop-Group: DONNA Table: 10001 Valid: 1 Installed: 1
Valid: 1 nexthop 192.168.209.1
Valid: 1 nexthop 192.168.210.1
Valid: 1 nexthop 192.168.208.1
I have also introduced the ability to specify a table
in a 'show ip route table XXX' to see the specified tables.
robot# show ip route table 10001
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, P - PIM, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
F - PBR,
> - selected route, * - FIB route
F>* 0.0.0.0/0 [0/0] via 192.168.208.1, enp0s8, 00:14:25
* via 192.168.209.1, enp0s9, 00:14:25
* via 192.168.210.1, enp0s10, 00:14:25
PBR tracks PBR-MAPS via the pbr-map command:
!
pbr-map EVA seq 10
match src-ip 4.3.4.0/24
set nexthop-group DONNA
!
pbr-map EVA seq 20
match dst-ip 4.3.5.0/24
set nexthop-group DONNA
!
pbr-maps can have 'match src-ip <prefix>' and 'match dst-ip <prefix>'
to affect decisions about incoming packets. Additionally if you
only have one nexthop to use for a pbr-map you do not need
to setup a nexthop-group and can specify 'set nexthop XXXX'.
To apply the pbr-map to an incoming interface you do this:
interface enp0s10
pbr-policy EVA
!
When a pbr-map is applied to interfaces it can be installed
into the kernel as a rule:
[sharpd@robot frr1]$ ip rule show
0: from all lookup local
309: from 4.3.4.0/24 iif enp0s10 lookup 10001
319: from all to 4.3.5.0/24 iif enp0s10 lookup 10001
1000: from all lookup [l3mdev-table]
32766: from all lookup main
32767: from all lookup default
[sharpd@robot frr1]$ ip route show table 10001
default proto pbr metric 20
nexthop via 192.168.208.1 dev enp0s8 weight 1
nexthop via 192.168.209.1 dev enp0s9 weight 1
nexthop via 192.168.210.1 dev enp0s10 weight 1
The linux kernel now will use the rules and tables to properly
apply these policies.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
2018-01-23 19:11:36 +01:00
|
|
|
else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(NH_GROUP_NODE, line);
|
2004-12-22 12:53:09 +01:00
|
|
|
else if (strncmp(line, "router-id", strlen("router-id")) == 0)
|
|
|
|
config = config_get(ZEBRA_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "router rip", strlen("router rip")) == 0)
|
|
|
|
config = config_get(RIP_NODE, line);
|
2003-03-28 03:25:23 +01:00
|
|
|
else if (strncmp(line, "router ripng", strlen("router ripng"))
|
|
|
|
== 0)
|
2004-08-25 14:22:00 +02:00
|
|
|
config = config_get(RIPNG_NODE, line);
|
2017-03-11 01:19:42 +01:00
|
|
|
else if (strncmp(line, "router eigrp", strlen("router eigrp"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(EIGRP_NODE, line);
|
2017-05-14 05:38:14 +02:00
|
|
|
else if (strncmp(line, "router babel", strlen("router babel"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(BABEL_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "router ospf", strlen("router ospf"))
|
|
|
|
== 0)
|
2004-08-25 14:22:00 +02:00
|
|
|
config = config_get(OSPF_NODE, line);
|
2003-03-28 03:25:23 +01:00
|
|
|
else if (strncmp(line, "router ospf6", strlen("router ospf6"))
|
|
|
|
== 0)
|
2004-08-25 14:22:00 +02:00
|
|
|
config = config_get(OSPF6_NODE, line);
|
2016-08-02 00:47:15 +02:00
|
|
|
else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
|
|
|
|
config = config_get(LDP_NODE, line);
|
|
|
|
else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
|
|
|
|
config = config_get(LDP_L2VPN_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
|
|
|
|
config = config_get(BGP_NODE, line);
|
2004-01-15 02:00:49 +01:00
|
|
|
else if (strncmp(line, "router isis", strlen("router isis"))
|
|
|
|
== 0)
|
2003-12-23 11:39:08 +01:00
|
|
|
config = config_get(ISIS_NODE, line);
|
2018-03-22 15:01:15 +01:00
|
|
|
else if (strncmp(line, "router openfabric", strlen("router openfabric"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(OPENFABRIC_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "route-map", strlen("route-map")) == 0)
|
|
|
|
config = config_get(RMAP_NODE, line);
|
pbrd: Add PBR to FRR
This is an implementation of PBR for FRR.
This implemenation uses a combination of rules and
tables to determine how packets will flow.
PBR introduces a new concept of 'nexthop-groups' to
specify a group of nexthops that will be used for
ecmp. Nexthop-groups are specified on the cli via:
nexthop-group DONNA
nexthop 192.168.208.1
nexthop 192.168.209.1
nexthop 192.168.210.1
!
PBR sees the nexthop-group and installs these as a default
route with these nexthops starting at table 10000
robot# show pbr nexthop-groups
Nexthop-Group: DONNA Table: 10001 Valid: 1 Installed: 1
Valid: 1 nexthop 192.168.209.1
Valid: 1 nexthop 192.168.210.1
Valid: 1 nexthop 192.168.208.1
I have also introduced the ability to specify a table
in a 'show ip route table XXX' to see the specified tables.
robot# show ip route table 10001
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, P - PIM, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
F - PBR,
> - selected route, * - FIB route
F>* 0.0.0.0/0 [0/0] via 192.168.208.1, enp0s8, 00:14:25
* via 192.168.209.1, enp0s9, 00:14:25
* via 192.168.210.1, enp0s10, 00:14:25
PBR tracks PBR-MAPS via the pbr-map command:
!
pbr-map EVA seq 10
match src-ip 4.3.4.0/24
set nexthop-group DONNA
!
pbr-map EVA seq 20
match dst-ip 4.3.5.0/24
set nexthop-group DONNA
!
pbr-maps can have 'match src-ip <prefix>' and 'match dst-ip <prefix>'
to affect decisions about incoming packets. Additionally if you
only have one nexthop to use for a pbr-map you do not need
to setup a nexthop-group and can specify 'set nexthop XXXX'.
To apply the pbr-map to an incoming interface you do this:
interface enp0s10
pbr-policy EVA
!
When a pbr-map is applied to interfaces it can be installed
into the kernel as a rule:
[sharpd@robot frr1]$ ip rule show
0: from all lookup local
309: from 4.3.4.0/24 iif enp0s10 lookup 10001
319: from all to 4.3.5.0/24 iif enp0s10 lookup 10001
1000: from all lookup [l3mdev-table]
32766: from all lookup main
32767: from all lookup default
[sharpd@robot frr1]$ ip route show table 10001
default proto pbr metric 20
nexthop via 192.168.208.1 dev enp0s8 weight 1
nexthop via 192.168.209.1 dev enp0s9 weight 1
nexthop via 192.168.210.1 dev enp0s10 weight 1
The linux kernel now will use the rules and tables to properly
apply these policies.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
2018-01-23 19:11:36 +01:00
|
|
|
else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
|
|
|
|
config = config_get(PBRMAP_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "access-list", strlen("access-list"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(ACCESS_NODE, line);
|
2004-08-26 15:08:30 +02:00
|
|
|
else if (strncmp(line, "ipv6 access-list",
|
|
|
|
strlen("ipv6 access-list"))
|
|
|
|
== 0)
|
2004-08-25 14:22:00 +02:00
|
|
|
config = config_get(ACCESS_IPV6_NODE, line);
|
2017-06-21 10:02:46 +02:00
|
|
|
else if (strncmp(line, "mac access-list",
|
|
|
|
strlen("mac access-list"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(ACCESS_MAC_NODE, line);
|
2004-08-26 15:08:30 +02:00
|
|
|
else if (strncmp(line, "ip prefix-list",
|
|
|
|
strlen("ip prefix-list"))
|
|
|
|
== 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
config = config_get(PREFIX_NODE, line);
|
2004-08-26 15:08:30 +02:00
|
|
|
else if (strncmp(line, "ipv6 prefix-list",
|
|
|
|
strlen("ipv6 prefix-list"))
|
|
|
|
== 0)
|
2004-08-25 14:22:00 +02:00
|
|
|
config = config_get(PREFIX_IPV6_NODE, line);
|
2018-09-17 09:33:22 +02:00
|
|
|
else if (strncmp(line, "bgp as-path access-list",
|
|
|
|
strlen("bgp as-path access-list"))
|
2004-08-26 15:08:30 +02:00
|
|
|
== 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
config = config_get(AS_LIST_NODE, line);
|
2018-09-17 09:33:22 +02:00
|
|
|
else if (strncmp(line, "bgp community-list",
|
|
|
|
strlen("bgp community-list"))
|
2015-11-18 19:54:23 +01:00
|
|
|
== 0
|
2018-09-17 09:33:22 +02:00
|
|
|
|| strncmp(line, "bgp extcommunity-list",
|
|
|
|
strlen("bgp extcommunity-list"))
|
2017-08-28 20:35:15 +02:00
|
|
|
== 0
|
2018-09-17 09:33:22 +02:00
|
|
|
|| strncmp(line, "bgp large-community-list",
|
|
|
|
strlen("bgp large-community-list"))
|
2017-08-28 20:35:15 +02:00
|
|
|
== 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
config = config_get(COMMUNITY_LIST_NODE, line);
|
|
|
|
else if (strncmp(line, "ip route", strlen("ip route")) == 0)
|
|
|
|
config = config_get(IP_NODE, line);
|
2003-03-28 03:25:23 +01:00
|
|
|
else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
|
|
|
|
config = config_get(IP_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else if (strncmp(line, "key", strlen("key")) == 0)
|
|
|
|
config = config_get(KEYCHAIN_NODE, line);
|
2004-10-03 22:11:32 +02:00
|
|
|
else if (strncmp(line, "line", strlen("line")) == 0)
|
|
|
|
config = config_get(VTY_NODE, line);
|
|
|
|
else if ((strncmp(line, "ipv6 forwarding",
|
|
|
|
strlen("ipv6 forwarding"))
|
|
|
|
== 0)
|
|
|
|
|| (strncmp(line, "ip forwarding",
|
|
|
|
strlen("ip forwarding"))
|
|
|
|
== 0))
|
|
|
|
config = config_get(FORWARDING_NODE, line);
|
2016-02-03 15:00:25 +01:00
|
|
|
else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
|
|
|
|
config = config_get(VRF_DEBUG_NODE, line);
|
2017-12-07 20:31:48 +01:00
|
|
|
else if (strncmp(line, "debug northbound",
|
|
|
|
strlen("debug northbound"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(NORTHBOUND_DEBUG_NODE, line);
|
2019-05-10 00:34:52 +02:00
|
|
|
else if (strncmp(line, "debug route-map",
|
|
|
|
strlen("debug route-map"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(RMAP_DEBUG_NODE, line);
|
2019-05-23 12:23:02 +02:00
|
|
|
else if (strncmp(line, "debug resolver",
|
|
|
|
strlen("debug resolver")) == 0)
|
|
|
|
config = config_get(RESOLVER_DEBUG_NODE, line);
|
2004-12-22 12:53:09 +01:00
|
|
|
else if (strncmp(line, "debug", strlen("debug")) == 0)
|
|
|
|
config = config_get(DEBUG_NODE, line);
|
2005-03-09 13:41:14 +01:00
|
|
|
else if (strncmp(line, "password", strlen("password")) == 0
|
|
|
|
|| strncmp(line, "enable password",
|
|
|
|
strlen("enable password"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(AAA_NODE, line);
|
2009-06-23 07:55:57 +02:00
|
|
|
else if (strncmp(line, "ip protocol", strlen("ip protocol"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(PROTOCOL_NODE, line);
|
2015-10-21 07:21:39 +02:00
|
|
|
else if (strncmp(line, "ipv6 protocol", strlen("ipv6 protocol"))
|
|
|
|
== 0)
|
|
|
|
config = config_get(PROTOCOL_NODE, line);
|
|
|
|
else if (strncmp(line, "ip nht", strlen("ip nht")) == 0)
|
|
|
|
config = config_get(PROTOCOL_NODE, line);
|
|
|
|
else if (strncmp(line, "ipv6 nht", strlen("ipv6 nht")) == 0)
|
|
|
|
config = config_get(PROTOCOL_NODE, line);
|
2016-04-15 19:51:56 +02:00
|
|
|
else if (strncmp(line, "mpls", strlen("mpls")) == 0)
|
|
|
|
config = config_get(MPLS_NODE, line);
|
2018-06-27 18:26:06 +02:00
|
|
|
else if (strncmp(line, "bfd", strlen("bfd")) == 0)
|
|
|
|
config = config_get(BFD_NODE, line);
|
2002-12-13 21:15:29 +01:00
|
|
|
else {
|
|
|
|
if (strncmp(line, "log", strlen("log")) == 0
|
2020-10-01 21:19:31 +02:00
|
|
|
|| strncmp(line, "hostname", strlen("hostname")) == 0
|
|
|
|
|| strncmp(line, "domainname", strlen("domainname")) == 0
|
2017-03-09 19:00:19 +01:00
|
|
|
|| strncmp(line, "frr", strlen("frr")) == 0
|
2017-05-05 21:28:38 +02:00
|
|
|
|| strncmp(line, "agentx", strlen("agentx")) == 0
|
2019-09-18 13:19:55 +02:00
|
|
|
|| strncmp(line, "no log", strlen("no log")) == 0
|
|
|
|
|| strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
|
|
|
|
|| strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
config_add_line_uniq(config_top, line);
|
|
|
|
else
|
|
|
|
config_add_line(config_top, line);
|
|
|
|
config = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
break;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Macro to check delimiter is needed between each configuration line
|
2004-08-26 15:08:30 +02:00
|
|
|
* or not. */
|
2002-12-13 21:15:29 +01:00
|
|
|
#define NO_DELIMITER(I) \
|
|
|
|
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|
2003-03-28 03:25:23 +01:00
|
|
|
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
|
2017-06-21 10:02:46 +02:00
|
|
|
|| (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
|
2018-03-30 22:29:51 +02:00
|
|
|
|| (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
|
|
|
|
|| (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
|
2019-05-10 00:34:52 +02:00
|
|
|
|| (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \
|
2019-05-23 12:23:02 +02:00
|
|
|
|| (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE)
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2004-08-26 15:08:30 +02:00
|
|
|
/* Display configuration to file pointer. */
|
2018-05-25 22:31:07 +02:00
|
|
|
void vtysh_config_dump(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct listnode *mnode, *mnnode;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct config *config;
|
2020-07-28 16:58:47 +02:00
|
|
|
struct configuration *configuration;
|
2002-12-13 21:15:29 +01:00
|
|
|
char *line;
|
2004-10-07 23:40:25 +02:00
|
|
|
unsigned int i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-15 00:13:03 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
|
|
|
|
vty_out(vty, "%s\n", line);
|
|
|
|
|
|
|
|
vty_out(vty, "!\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-03-14 21:19:01 +01:00
|
|
|
for (i = 0; i < vector_active(configvec); i++)
|
2020-07-28 16:58:47 +02:00
|
|
|
if ((configuration = vector_slot(configvec, i)) != NULL) {
|
|
|
|
while ((config = config_master_pop(
|
|
|
|
&configuration->master))) {
|
|
|
|
config_master_hash_del(
|
|
|
|
&configuration->hash_master, config);
|
2017-12-05 05:05:15 +01:00
|
|
|
/* Don't print empty sections for interface.
|
2017-05-22 21:43:20 +02:00
|
|
|
* Route maps on the
|
|
|
|
* other hand could have a legitimate empty
|
|
|
|
* section at the end.
|
2017-12-05 05:05:15 +01:00
|
|
|
* VRF is handled in the backend, we could have
|
|
|
|
* "configured" VRFs with static routes which
|
|
|
|
* are not under the VRF node.
|
2017-05-22 21:43:20 +02:00
|
|
|
*/
|
2017-12-05 05:05:15 +01:00
|
|
|
if (config->index == INTERFACE_NODE
|
2020-11-30 16:44:10 +01:00
|
|
|
&& list_isempty(config->line)) {
|
|
|
|
config_del(config);
|
2017-05-22 21:43:20 +02:00
|
|
|
continue;
|
2020-11-30 16:44:10 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-15 00:13:03 +02:00
|
|
|
vty_out(vty, "%s\n", config->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-22 21:43:20 +02:00
|
|
|
for (ALL_LIST_ELEMENTS(config->line, mnode,
|
2018-05-15 00:13:03 +02:00
|
|
|
mnnode, line))
|
|
|
|
vty_out(vty, "%s\n", line);
|
|
|
|
if (!NO_DELIMITER(i))
|
|
|
|
vty_out(vty, "!\n");
|
2019-08-02 17:45:13 +02:00
|
|
|
|
|
|
|
config_del(config);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2018-05-15 00:13:03 +02:00
|
|
|
if (NO_DELIMITER(i))
|
|
|
|
vty_out(vty, "!\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2005-03-14 21:19:01 +01:00
|
|
|
for (i = 0; i < vector_active(configvec); i++)
|
2020-07-28 16:58:47 +02:00
|
|
|
if ((configuration = vector_slot(configvec, i)) != NULL) {
|
|
|
|
config_master_fini(&configuration->master);
|
|
|
|
config_master_hash_fini(&configuration->hash_master);
|
|
|
|
XFREE(MTYPE_VTYSH_CONFIG, configuration);
|
2017-05-22 21:43:20 +02:00
|
|
|
vector_slot(configvec, i) = NULL;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
list_delete_all_node(config_top);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read up configuration file from file_name. */
|
2020-12-15 20:45:23 +01:00
|
|
|
static int vtysh_read_file(FILE *confp, bool dry_run)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct vty *vty;
|
2016-03-09 13:25:02 +01:00
|
|
|
int ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
vty = vty_new();
|
2018-03-06 00:46:01 +01:00
|
|
|
vty->wfd = STDERR_FILENO;
|
2002-12-13 21:15:29 +01:00
|
|
|
vty->type = VTY_TERM;
|
|
|
|
vty->node = CONFIG_NODE;
|
|
|
|
|
|
|
|
vtysh_execute_no_pager("enable");
|
|
|
|
vtysh_execute_no_pager("configure terminal");
|
|
|
|
|
2020-12-15 20:45:23 +01:00
|
|
|
if (!dry_run)
|
|
|
|
vtysh_execute_no_pager("XFRR_start_configuration");
|
2020-10-30 19:10:55 +01:00
|
|
|
|
2004-08-26 15:08:30 +02:00
|
|
|
/* Execute configuration file. */
|
2016-03-09 13:25:02 +01:00
|
|
|
ret = vtysh_config_from_file(vty, confp);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2020-12-15 20:45:23 +01:00
|
|
|
if (!dry_run)
|
|
|
|
vtysh_execute_no_pager("XFRR_end_configuration");
|
2020-10-30 19:10:55 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
vtysh_execute_no_pager("end");
|
|
|
|
vtysh_execute_no_pager("disable");
|
|
|
|
|
|
|
|
vty_close(vty);
|
2016-03-09 13:25:02 +01:00
|
|
|
|
|
|
|
return (ret);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2004-10-03 22:11:32 +02:00
|
|
|
/* Read up configuration file from config_default_dir. */
|
2020-12-15 20:45:23 +01:00
|
|
|
int vtysh_read_config(const char *config_default_dir, bool dry_run)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
FILE *confp = NULL;
|
2016-03-09 13:25:02 +01:00
|
|
|
int ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-03 22:11:32 +02:00
|
|
|
confp = fopen(config_default_dir, "r");
|
|
|
|
if (confp == NULL) {
|
2016-04-06 15:34:33 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"%% Can't open configuration file %s due to '%s'.\n",
|
|
|
|
config_default_dir, safe_strerror(errno));
|
2020-02-09 13:21:56 +01:00
|
|
|
return CMD_ERR_NO_FILE;
|
2016-04-06 15:34:33 +02:00
|
|
|
}
|
2004-08-27 00:21:31 +02:00
|
|
|
|
2020-12-15 20:45:23 +01:00
|
|
|
ret = vtysh_read_file(confp, dry_run);
|
2002-12-13 21:15:29 +01:00
|
|
|
fclose(confp);
|
|
|
|
|
2016-03-09 13:25:02 +01:00
|
|
|
return (ret);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2004-10-03 22:11:32 +02:00
|
|
|
/* We don't write vtysh specific into file from vtysh. vtysh.conf should
|
|
|
|
* be edited by hand. So, we handle only "write terminal" case here and
|
|
|
|
* integrate vtysh specific conf with conf from daemons.
|
|
|
|
*/
|
2019-01-24 10:12:36 +01:00
|
|
|
void vtysh_config_write(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-05-30 23:56:55 +02:00
|
|
|
char line[512];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-29 01:52:29 +02:00
|
|
|
if (cmd_hostname_get()) {
|
2019-05-30 23:56:55 +02:00
|
|
|
snprintf(line, sizeof(line), "hostname %s", cmd_hostname_get());
|
2017-05-10 16:38:48 +02:00
|
|
|
vtysh_config_parse_line(NULL, line);
|
2004-10-03 22:11:32 +02:00
|
|
|
}
|
2018-02-07 23:46:04 +01:00
|
|
|
|
|
|
|
if (cmd_domainname_get()) {
|
2020-04-20 20:12:38 +02:00
|
|
|
snprintf(line, sizeof(line), "domainname %s",
|
|
|
|
cmd_domainname_get());
|
2018-02-07 23:46:04 +01:00
|
|
|
vtysh_config_parse_line(NULL, line);
|
|
|
|
}
|
2016-09-26 22:01:37 +02:00
|
|
|
if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
|
2017-05-10 16:38:48 +02:00
|
|
|
vtysh_config_parse_line(NULL,
|
|
|
|
"no service integrated-vtysh-config");
|
2016-09-26 22:01:37 +02:00
|
|
|
if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
|
2017-05-10 16:38:48 +02:00
|
|
|
vtysh_config_parse_line(NULL,
|
|
|
|
"service integrated-vtysh-config");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:29:18 +02:00
|
|
|
user_config_write();
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 10:12:36 +01:00
|
|
|
void vtysh_config_init(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
config_top = list_new();
|
|
|
|
config_top->del = (void (*)(void *))line_del;
|
|
|
|
configvec = vector_init(1);
|
|
|
|
}
|