]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
bgpd: add L3/L2VPN Virtual Network Control feature
[mirror_frr.git] / vtysh / vtysh_config.c
CommitLineData
718e3744 1/* Configuration generator.
2 Copyright (C) 2000 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "command.h"
24#include "linklist.h"
25#include "memory.h"
26
27#include "vtysh/vtysh.h"
88177fe3 28#include "vtysh/vtysh_user.h"
718e3744 29
4a1ab8e4
DL
30DEFINE_MGROUP(MVTYSH, "vtysh")
31DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
33
718e3744 34vector configvec;
35
e7168df4 36extern int vtysh_writeconfig_integrated;
37
718e3744 38struct config
39{
40 /* Configuration node name. */
41 char *name;
42
43 /* Configuration string line. */
44 struct list *line;
45
46 /* Configuration can be nest. */
47 struct config *config;
48
49 /* Index of this config. */
50 u_int32_t index;
51};
52
53struct list *config_top;
95e735b5 54
4201dd11 55static int
718e3744 56line_cmp (char *c1, char *c2)
57{
58 return strcmp (c1, c2);
59}
60
4201dd11 61static void
718e3744 62line_del (char *line)
63{
64 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
65}
66
4201dd11 67static struct config *
35dece84 68config_new (void)
718e3744 69{
70 struct config *config;
71 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
72 return config;
73}
74
4201dd11 75static int
718e3744 76config_cmp (struct config *c1, struct config *c2)
77{
78 return strcmp (c1->name, c2->name);
79}
80
4201dd11 81static void
718e3744 82config_del (struct config* config)
83{
84 list_delete (config->line);
85 if (config->name)
86 XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
87 XFREE (MTYPE_VTYSH_CONFIG, config);
88}
89
4201dd11 90static struct config *
dda09522 91config_get (int index, const char *line)
718e3744 92{
93 struct config *config;
94 struct config *config_loop;
95 struct list *master;
1eb8ef25 96 struct listnode *node, *nnode;
718e3744 97
98 config = config_loop = NULL;
99
100 master = vector_lookup_ensure (configvec, index);
101
102 if (! master)
103 {
104 master = list_new ();
105 master->del = (void (*) (void *))config_del;
106 master->cmp = (int (*)(void *, void *)) config_cmp;
107 vector_set_index (configvec, index, master);
108 }
109
1eb8ef25 110 for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
718e3744 111 {
112 if (strcmp (config_loop->name, line) == 0)
113 config = config_loop;
114 }
115
116 if (! config)
117 {
118 config = config_new ();
119 config->line = list_new ();
120 config->line->del = (void (*) (void *))line_del;
121 config->line->cmp = (int (*)(void *, void *)) line_cmp;
122 config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
123 config->index = index;
124 listnode_add (master, config);
125 }
126 return config;
127}
128
129void
dda09522 130config_add_line (struct list *config, const char *line)
718e3744 131{
132 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
133}
134
4201dd11 135static void
dda09522 136config_add_line_uniq (struct list *config, const char *line)
718e3744 137{
1eb8ef25 138 struct listnode *node, *nnode;
718e3744 139 char *pnt;
140
1eb8ef25 141 for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
718e3744 142 {
143 if (strcmp (pnt, line) == 0)
144 return;
145 }
146 listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
147}
148
4201dd11 149static void
dda09522 150vtysh_config_parse_line (const char *line)
718e3744 151{
152 char c;
153 static struct config *config = NULL;
154
155 if (! line)
156 return;
157
158 c = line[0];
159
160 if (c == '\0')
161 return;
162
163 /* printf ("[%s]\n", line); */
164
165 switch (c)
166 {
0b960b4d
DW
167 /* Suppress exclamation points ! and commented lines. The !s are generated
168 * dynamically in vtysh_config_dump() */
718e3744 169 case '!':
170 case '#':
171 break;
172 case ' ':
173 /* Store line to current configuration. */
174 if (config)
175 {
65efcfce
LB
176 if (strncmp (line, " address-family vpnv4",
177 strlen (" address-family vpnv4")) == 0)
178 config = config_get (BGP_VPNV4_NODE, line);
179 else if (strncmp (line, " address-family vpn6",
180 strlen (" address-family vpn6")) == 0)
181 config = config_get (BGP_VPNV6_NODE, line);
182 else if (strncmp (line, " address-family encapv6",
183 strlen (" address-family encapv6")) == 0)
184 config = config_get (BGP_ENCAPV6_NODE, line);
185 else if (strncmp (line, " address-family encap",
186 strlen (" address-family encap")) == 0)
187 config = config_get (BGP_ENCAP_NODE, line);
188 else if (strncmp (line, " address-family ipv4 multicast",
189 strlen (" address-family ipv4 multicast")) == 0)
190 config = config_get (BGP_IPV4M_NODE, line);
191 else if (strncmp (line, " address-family ipv6",
192 strlen (" address-family ipv6")) == 0)
193 config = config_get (BGP_IPV6_NODE, line);
194 else if (strncmp (line, " vnc defaults",
195 strlen (" vnc defaults")) == 0)
196 config = config_get (BGP_VNC_DEFAULTS_NODE, line);
197 else if (strncmp (line, " vnc nve-group",
198 strlen (" vnc nve-group")) == 0)
199 config = config_get (BGP_VNC_NVE_GROUP_NODE, line);
200 else if (strncmp (line, " vnc l2-group",
201 strlen (" vnc l2-group")) == 0)
202 config = config_get (BGP_VNC_L2_GROUP_NODE, line);
203 else if (config->index == RMAP_NODE ||
e7168df4 204 config->index == INTERFACE_NODE ||
13460c44 205 config->index == NS_NODE ||
e7168df4 206 config->index == VTY_NODE)
718e3744 207 config_add_line_uniq (config->line, line);
208 else
209 config_add_line (config->line, line);
210 }
211 else
212 config_add_line (config_top, line);
213 break;
214 default:
215 if (strncmp (line, "interface", strlen ("interface")) == 0)
216 config = config_get (INTERFACE_NODE, line);
c253dcb5 217 else if (strncmp (line, "logical-router", strlen ("ns")) == 0)
13460c44 218 config = config_get (NS_NODE, line);
e9d94ea7
DS
219 else if (strncmp (line, "vrf", strlen ("vrf")) == 0)
220 config = config_get (VRF_NODE, line);
dfbb9124 221 else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
222 config = config_get (ZEBRA_NODE, line);
718e3744 223 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
224 config = config_get (RIP_NODE, line);
97e1c4dc 225 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
b094d260 226 config = config_get (RIPNG_NODE, line);
718e3744 227 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
b094d260 228 config = config_get (OSPF_NODE, line);
97e1c4dc 229 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
b094d260 230 config = config_get (OSPF6_NODE, line);
4fcbf6e2
RW
231 else if (strncmp (line, "mpls ldp", strlen ("mpls ldp")) == 0)
232 config = config_get (LDP_NODE, line);
233 else if (strncmp (line, "l2vpn", strlen ("l2vpn")) == 0)
234 config = config_get (LDP_L2VPN_NODE, line);
718e3744 235 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
236 config = config_get (BGP_NODE, line);
13b8baad 237 else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
c25e458a 238 config = config_get (ISIS_NODE, line);
718e3744 239 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
240 config = config_get (RMAP_NODE, line);
241 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
242 config = config_get (ACCESS_NODE, line);
95e735b5 243 else if (strncmp (line, "ipv6 access-list",
244 strlen ("ipv6 access-list")) == 0)
b094d260 245 config = config_get (ACCESS_IPV6_NODE, line);
95e735b5 246 else if (strncmp (line, "ip prefix-list",
247 strlen ("ip prefix-list")) == 0)
718e3744 248 config = config_get (PREFIX_NODE, line);
95e735b5 249 else if (strncmp (line, "ipv6 prefix-list",
250 strlen ("ipv6 prefix-list")) == 0)
b094d260 251 config = config_get (PREFIX_IPV6_NODE, line);
95e735b5 252 else if (strncmp (line, "ip as-path access-list",
253 strlen ("ip as-path access-list")) == 0)
718e3744 254 config = config_get (AS_LIST_NODE, line);
eb2674af
DW
255 else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0 ||
256 strncmp (line, "ip extcommunity-list", strlen ("ip extcommunity-list")) == 0)
718e3744 257 config = config_get (COMMUNITY_LIST_NODE, line);
258 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
259 config = config_get (IP_NODE, line);
97e1c4dc 260 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
261 config = config_get (IP_NODE, line);
718e3744 262 else if (strncmp (line, "key", strlen ("key")) == 0)
263 config = config_get (KEYCHAIN_NODE, line);
e7168df4 264 else if (strncmp (line, "line", strlen ("line")) == 0)
265 config = config_get (VTY_NODE, line);
266 else if ( (strncmp (line, "ipv6 forwarding",
267 strlen ("ipv6 forwarding")) == 0)
268 || (strncmp (line, "ip forwarding",
269 strlen ("ip forwarding")) == 0) )
270 config = config_get (FORWARDING_NODE, line);
271 else if (strncmp (line, "service", strlen ("service")) == 0)
272 config = config_get (SERVICE_NODE, line);
19dc275e
DS
273 else if (strncmp (line, "debug vrf", strlen ("debug vrf")) == 0)
274 config = config_get (VRF_DEBUG_NODE, line);
dfbb9124 275 else if (strncmp (line, "debug", strlen ("debug")) == 0)
276 config = config_get (DEBUG_NODE, line);
060d438c 277 else if (strncmp (line, "password", strlen ("password")) == 0
278 || strncmp (line, "enable password",
279 strlen ("enable password")) == 0)
280 config = config_get (AAA_NODE, line);
6e79f8bb
CC
281 else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
282 config = config_get (PROTOCOL_NODE, line);
80b55c57 283 else if (strncmp (line, "ipv6 protocol", strlen ("ipv6 protocol")) == 0)
284 config = config_get (PROTOCOL_NODE, line);
285 else if (strncmp (line, "ip nht", strlen ("ip nht")) == 0)
286 config = config_get (PROTOCOL_NODE, line);
287 else if (strncmp (line, "ipv6 nht", strlen ("ipv6 nht")) == 0)
288 config = config_get (PROTOCOL_NODE, line);
7758e3f3 289 else if (strncmp (line, "mpls", strlen ("mpls")) == 0)
290 config = config_get (MPLS_NODE, line);
718e3744 291 else
292 {
293 if (strncmp (line, "log", strlen ("log")) == 0
294 || strncmp (line, "hostname", strlen ("hostname")) == 0
e7168df4 295 )
718e3744 296 config_add_line_uniq (config_top, line);
297 else
298 config_add_line (config_top, line);
299 config = NULL;
300 }
301 break;
302 }
303}
304
305void
306vtysh_config_parse (char *line)
307{
308 char *begin;
309 char *pnt;
310
311 begin = pnt = line;
312
313 while (*pnt != '\0')
314 {
315 if (*pnt == '\n')
316 {
317 *pnt++ = '\0';
318 vtysh_config_parse_line (begin);
319 begin = pnt;
320 }
321 else
322 {
323 pnt++;
324 }
325 }
326}
327
328/* Macro to check delimiter is needed between each configuration line
95e735b5 329 * or not. */
718e3744 330#define NO_DELIMITER(I) \
331 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
97e1c4dc 332 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
e7168df4 333 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
060d438c 334 || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
7758e3f3 335 || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
718e3744 336
95e735b5 337/* Display configuration to file pointer. */
718e3744 338void
339vtysh_config_dump (FILE *fp)
340{
1eb8ef25 341 struct listnode *node, *nnode;
342 struct listnode *mnode, *mnnode;
718e3744 343 struct config *config;
344 struct list *master;
345 char *line;
dda09522 346 unsigned int i;
718e3744 347
1eb8ef25 348 for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
718e3744 349 {
350 fprintf (fp, "%s\n", line);
351 fflush (fp);
352 }
353 fprintf (fp, "!\n");
354 fflush (fp);
355
55468c86 356 for (i = 0; i < vector_active (configvec); i++)
718e3744 357 if ((master = vector_slot (configvec, i)) != NULL)
358 {
1eb8ef25 359 for (ALL_LIST_ELEMENTS (master, node, nnode, config))
5be7afc8
DD
360 {
361 /* Don't print empty sections for interface/vrf. Route maps on the
362 * other hand could have a legitimate empty section at the end.
363 */
364 if ((config->index == INTERFACE_NODE || (config->index == VRF_NODE))
365 && list_isempty (config->line))
366 continue;
367
718e3744 368 fprintf (fp, "%s\n", config->name);
b094d260 369 fflush (fp);
718e3744 370
1eb8ef25 371 for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
718e3744 372 {
373 fprintf (fp, "%s\n", line);
374 fflush (fp);
375 }
376 if (! NO_DELIMITER (i))
377 {
378 fprintf (fp, "!\n");
379 fflush (fp);
380 }
381 }
382 if (NO_DELIMITER (i))
383 {
384 fprintf (fp, "!\n");
385 fflush (fp);
386 }
387 }
388
55468c86 389 for (i = 0; i < vector_active (configvec); i++)
718e3744 390 if ((master = vector_slot (configvec, i)) != NULL)
391 {
392 list_delete (master);
393 vector_slot (configvec, i) = NULL;
394 }
395 list_delete_all_node (config_top);
396}
397
398/* Read up configuration file from file_name. */
3221dca8 399static int
718e3744 400vtysh_read_file (FILE *confp)
401{
718e3744 402 struct vty *vty;
3221dca8 403 int ret;
718e3744 404
405 vty = vty_new ();
406 vty->fd = 0; /* stdout */
407 vty->type = VTY_TERM;
408 vty->node = CONFIG_NODE;
409
410 vtysh_execute_no_pager ("enable");
411 vtysh_execute_no_pager ("configure terminal");
412
95e735b5 413 /* Execute configuration file. */
3221dca8 414 ret = vtysh_config_from_file (vty, confp);
718e3744 415
416 vtysh_execute_no_pager ("end");
417 vtysh_execute_no_pager ("disable");
418
419 vty_close (vty);
3221dca8
DS
420
421 return (ret);
718e3744 422}
423
e7168df4 424/* Read up configuration file from config_default_dir. */
425int
c0e8c16f 426vtysh_read_config (const char *config_default_dir)
718e3744 427{
718e3744 428 FILE *confp = NULL;
3221dca8 429 int ret;
718e3744 430
e4421165 431 host_config_set (config_default_dir);
e7168df4 432 confp = fopen (config_default_dir, "r");
433 if (confp == NULL)
1db63918
DS
434 {
435 fprintf (stderr, "%% Can't open configuration file %s due to '%s'.\n",
436 config_default_dir, safe_strerror (errno));
437 return (CMD_ERR_NO_FILE);
438 }
67e29abc 439
3221dca8 440 ret = vtysh_read_file (confp);
718e3744 441 fclose (confp);
442
3221dca8 443 return (ret);
718e3744 444}
445
e7168df4 446/* We don't write vtysh specific into file from vtysh. vtysh.conf should
447 * be edited by hand. So, we handle only "write terminal" case here and
448 * integrate vtysh specific conf with conf from daemons.
449 */
718e3744 450void
e7168df4 451vtysh_config_write ()
718e3744 452{
dda09522 453 char line[81];
718e3744 454 extern struct host host;
455
456 if (host.name)
e7168df4 457 {
458 sprintf (line, "hostname %s", host.name);
459 vtysh_config_parse_line(line);
460 }
f013eacd
DD
461 if (!vtysh_writeconfig_integrated)
462 vtysh_config_parse_line ("no service integrated-vtysh-config");
a7222276
DS
463
464 user_config_write ();
718e3744 465}
466
467void
468vtysh_config_init ()
469{
470 config_top = list_new ();
471 config_top->del = (void (*) (void *))line_del;
472 configvec = vector_init (1);
473}