frr/vtysh/vtysh_config.c

451 lines
13 KiB
C
Raw Normal View History

2002-12-13 21:15:29 +01:00
/* Configuration generator.
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 GNU Zebra; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <zebra.h>
#include "command.h"
#include "linklist.h"
#include "memory.h"
#include "vtysh/vtysh.h"
#include "vtysh/vtysh_user.h"
2002-12-13 21:15:29 +01: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;
struct config
{
/* Configuration node name. */
char *name;
/* Configuration string line. */
struct list *line;
/* Configuration can be nest. */
struct config *config;
/* Index of this config. */
u_int32_t index;
};
struct list *config_top;
static int
2002-12-13 21:15:29 +01:00
line_cmp (char *c1, char *c2)
{
return strcmp (c1, c2);
}
static void
2002-12-13 21:15:29 +01:00
line_del (char *line)
{
XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
}
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 int
2002-12-13 21:15:29 +01:00
config_cmp (struct config *c1, struct config *c2)
{
return strcmp (c1->name, c2->name);
}
static void
2002-12-13 21:15:29 +01:00
config_del (struct config* config)
{
list_delete (config->line);
if (config->name)
XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
XFREE (MTYPE_VTYSH_CONFIG, config);
}
static struct config *
2004-10-07 23:40:25 +02:00
config_get (int index, const char *line)
2002-12-13 21:15:29 +01:00
{
struct config *config;
struct config *config_loop;
struct list *master;
struct listnode *node, *nnode;
2002-12-13 21:15:29 +01:00
config = config_loop = NULL;
master = vector_lookup_ensure (configvec, index);
if (! master)
{
master = list_new ();
master->del = (void (*) (void *))config_del;
master->cmp = (int (*)(void *, void *)) config_cmp;
vector_set_index (configvec, index, master);
}
for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
2002-12-13 21:15:29 +01:00
{
if (strcmp (config_loop->name, line) == 0)
config = config_loop;
}
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;
listnode_add (master, config);
}
return config;
}
void
2004-10-07 23:40:25 +02:00
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));
}
static void
2004-10-07 23:40:25 +02:00
config_add_line_uniq (struct list *config, const char *line)
2002-12-13 21:15:29 +01:00
{
struct listnode *node, *nnode;
2002-12-13 21:15:29 +01:00
char *pnt;
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));
}
void
2004-10-07 23:40:25 +02:00
vtysh_config_parse_line (const char *line)
2002-12-13 21:15:29 +01:00
{
char c;
static struct config *config = NULL;
if (! line)
return;
c = line[0];
if (c == '\0')
return;
/* printf ("[%s]\n", line); */
switch (c)
{
Display the BGP ipv4 unicast configuration under "address-family ipv4 unicast". Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com> Ticket: CM-6739 Before router bgp 10 bgp router-id 10.1.1.1 bgp log-neighbor-changes no bgp default ipv4-unicast network 9.9.9.9/32 neighbor 10.1.1.2 remote-as 10 neighbor 10.1.1.2 shutdown neighbor 10.1.1.2 update-source lo neighbor 10.1.1.2 advertisement-interval 1 neighbor 10.1.1.2 timers connect 10 neighbor 10.1.1.2 activate neighbor 10.1.1.2 next-hop-self neighbor 10.1.1.2 route-map BAR in neighbor 10.1.1.2 route-map FOO out neighbor 20.1.2.2 remote-as 20 neighbor 20.1.2.2 shutdown neighbor 20.1.2.2 advertisement-interval 1 neighbor 20.1.2.2 timers connect 10 neighbor 20.1.2.2 activate neighbor 20.1.2.2 route-map HAA in neighbor 20.1.2.2 route-map BOO out ! address-family ipv6 network 2001:1:1:1::/64 exit-address-family ! After ! router bgp 10 bgp router-id 10.1.1.1 bgp log-neighbor-changes no bgp default ipv4-unicast no bgp network import-check neighbor 10.1.1.2 remote-as 10 neighbor 10.1.1.2 shutdown neighbor 10.1.1.2 update-source lo neighbor 10.1.1.2 advertisement-interval 1 neighbor 10.1.1.2 timers connect 10 neighbor 20.1.2.2 remote-as 20 neighbor 20.1.2.2 shutdown neighbor 20.1.2.2 advertisement-interval 1 neighbor 20.1.2.2 timers connect 10 ! address-family ipv4 unicast network 9.9.9.9/32 neighbor 10.1.1.2 activate neighbor 10.1.1.2 next-hop-self neighbor 10.1.1.2 route-map BAR in neighbor 10.1.1.2 route-map FOO out neighbor 20.1.2.2 activate neighbor 20.1.2.2 route-map HAA in neighbor 20.1.2.2 route-map BOO out exit-address-family ! address-family ipv6 unicast network 2001:1:1:1::/64 exit-address-family !
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)
{
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
if (strncmp (line, " address-family vpnv4",
strlen (" address-family vpnv4")) == 0)
config = config_get (BGP_VPNV4_NODE, line);
else if (strncmp (line, " address-family vpn6",
strlen (" address-family vpn6")) == 0)
config = config_get (BGP_VPNV6_NODE, line);
else if (strncmp (line, " address-family encapv6",
strlen (" address-family encapv6")) == 0)
config = config_get (BGP_ENCAPV6_NODE, line);
else if (strncmp (line, " address-family encap",
strlen (" address-family encap")) == 0)
config = config_get (BGP_ENCAP_NODE, line);
else if (strncmp (line, " address-family ipv4 multicast",
strlen (" address-family ipv4 multicast")) == 0)
config = config_get (BGP_IPV4M_NODE, line);
else if (strncmp (line, " address-family ipv6",
strlen (" address-family ipv6")) == 0)
config = config_get (BGP_IPV6_NODE, line);
else if (strncmp (line, " vnc defaults",
strlen (" vnc defaults")) == 0)
config = config_get (BGP_VNC_DEFAULTS_NODE, line);
else if (strncmp (line, " vnc nve-group",
strlen (" vnc nve-group")) == 0)
config = config_get (BGP_VNC_NVE_GROUP_NODE, line);
else if (strncmp (line, " vnc l2-group",
strlen (" vnc l2-group")) == 0)
config = config_get (BGP_VNC_L2_GROUP_NODE, line);
else if (config->index == RMAP_NODE ||
config->index == INTERFACE_NODE ||
config->index == NS_NODE ||
config->index == VTY_NODE)
2002-12-13 21:15:29 +01:00
config_add_line_uniq (config->line, line);
else
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);
else if (strncmp (line, "logical-router", strlen ("ns")) == 0)
config = config_get (NS_NODE, line);
else if (strncmp (line, "vrf", strlen ("vrf")) == 0)
config = config_get (VRF_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);
else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
config = config_get (RIPNG_NODE, line);
2002-12-13 21:15:29 +01:00
else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
config = config_get (OSPF_NODE, line);
else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
config = config_get (OSPF6_NODE, line);
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);
else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
2003-12-23 11:39:08 +01:00
config = config_get (ISIS_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);
else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
config = config_get (ACCESS_NODE, line);
else if (strncmp (line, "ipv6 access-list",
strlen ("ipv6 access-list")) == 0)
config = config_get (ACCESS_IPV6_NODE, line);
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);
else if (strncmp (line, "ipv6 prefix-list",
strlen ("ipv6 prefix-list")) == 0)
config = config_get (PREFIX_IPV6_NODE, line);
else if (strncmp (line, "ip as-path access-list",
strlen ("ip as-path access-list")) == 0)
2002-12-13 21:15:29 +01:00
config = config_get (AS_LIST_NODE, line);
else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0 ||
strncmp (line, "ip extcommunity-list", strlen ("ip extcommunity-list")) == 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);
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);
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);
else if (strncmp (line, "service", strlen ("service")) == 0)
config = config_get (SERVICE_NODE, line);
else if (strncmp (line, "debug vrf", strlen ("debug vrf")) == 0)
config = config_get (VRF_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);
else if (strncmp (line, "password", strlen ("password")) == 0
|| strncmp (line, "enable password",
strlen ("enable password")) == 0)
config = config_get (AAA_NODE, line);
else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
config = config_get (PROTOCOL_NODE, line);
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);
else if (strncmp (line, "mpls", strlen ("mpls")) == 0)
config = config_get (MPLS_NODE, line);
2002-12-13 21:15:29 +01:00
else
{
if (strncmp (line, "log", strlen ("log")) == 0
|| strncmp (line, "hostname", strlen ("hostname")) == 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;
}
break;
}
}
/* Macro to check delimiter is needed between each configuration line
* or not. */
2002-12-13 21:15:29 +01:00
#define NO_DELIMITER(I) \
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
(I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
|| (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
|| (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
2002-12-13 21:15:29 +01:00
/* Display configuration to file pointer. */
2002-12-13 21:15:29 +01:00
void
vtysh_config_dump (FILE *fp)
{
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
2002-12-13 21:15:29 +01:00
struct config *config;
struct list *master;
char *line;
2004-10-07 23:40:25 +02:00
unsigned int i;
2002-12-13 21:15:29 +01:00
for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
2002-12-13 21:15:29 +01:00
{
fprintf (fp, "%s\n", line);
fflush (fp);
}
fprintf (fp, "!\n");
fflush (fp);
for (i = 0; i < vector_active (configvec); i++)
2002-12-13 21:15:29 +01:00
if ((master = vector_slot (configvec, i)) != NULL)
{
for (ALL_LIST_ELEMENTS (master, node, nnode, config))
{
/* Don't print empty sections for interface/vrf. Route maps on the
* other hand could have a legitimate empty section at the end.
*/
if ((config->index == INTERFACE_NODE || (config->index == VRF_NODE))
&& list_isempty (config->line))
continue;
2002-12-13 21:15:29 +01:00
fprintf (fp, "%s\n", config->name);
fflush (fp);
2002-12-13 21:15:29 +01:00
for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
2002-12-13 21:15:29 +01:00
{
fprintf (fp, "%s\n", line);
fflush (fp);
}
if (! NO_DELIMITER (i))
{
fprintf (fp, "!\n");
fflush (fp);
}
}
if (NO_DELIMITER (i))
{
fprintf (fp, "!\n");
fflush (fp);
}
}
for (i = 0; i < vector_active (configvec); i++)
2002-12-13 21:15:29 +01:00
if ((master = vector_slot (configvec, i)) != NULL)
{
list_delete (master);
vector_slot (configvec, i) = NULL;
}
list_delete_all_node (config_top);
}
/* Read up configuration file from file_name. */
static int
2002-12-13 21:15:29 +01:00
vtysh_read_file (FILE *confp)
{
struct vty *vty;
int ret;
2002-12-13 21:15:29 +01:00
vty = vty_new ();
vty->fd = 0; /* stdout */
vty->type = VTY_TERM;
vty->node = CONFIG_NODE;
vtysh_execute_no_pager ("enable");
vtysh_execute_no_pager ("configure terminal");
/* Execute configuration file. */
ret = vtysh_config_from_file (vty, confp);
2002-12-13 21:15:29 +01:00
vtysh_execute_no_pager ("end");
vtysh_execute_no_pager ("disable");
vty_close (vty);
return (ret);
2002-12-13 21:15:29 +01:00
}
/* Read up configuration file from config_default_dir. */
int
vtysh_read_config (const char *config_default_dir)
2002-12-13 21:15:29 +01:00
{
FILE *confp = NULL;
int ret;
2002-12-13 21:15:29 +01:00
host_config_set (config_default_dir);
confp = fopen (config_default_dir, "r");
if (confp == NULL)
{
fprintf (stderr, "%% Can't open configuration file %s due to '%s'.\n",
config_default_dir, safe_strerror (errno));
return (CMD_ERR_NO_FILE);
}
ret = vtysh_read_file (confp);
2002-12-13 21:15:29 +01:00
fclose (confp);
return (ret);
2002-12-13 21:15:29 +01: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.
*/
2002-12-13 21:15:29 +01:00
void
vtysh_config_write ()
2002-12-13 21:15:29 +01:00
{
2004-10-07 23:40:25 +02:00
char line[81];
2002-12-13 21:15:29 +01:00
extern struct host host;
if (host.name)
{
sprintf (line, "hostname %s", host.name);
vtysh_config_parse_line(line);
}
if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
vtysh_config_parse_line ("no service integrated-vtysh-config");
if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
vtysh_config_parse_line ("service integrated-vtysh-config");
user_config_write ();
2002-12-13 21:15:29 +01:00
}
void
vtysh_config_init ()
{
config_top = list_new ();
config_top->del = (void (*) (void *))line_del;
configvec = vector_init (1);
}