blob: c80c42a4fb2f1bb27d1963ebee95ba14a50350b4 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
28
29vector configvec;
30
hassoe7168df2004-10-03 20:11:32 +000031extern int vtysh_writeconfig_integrated;
32
paul718e3742002-12-13 20:15:29 +000033struct config
34{
35 /* Configuration node name. */
36 char *name;
37
38 /* Configuration string line. */
39 struct list *line;
40
41 /* Configuration can be nest. */
42 struct config *config;
43
44 /* Index of this config. */
45 u_int32_t index;
46};
47
48struct list *config_top;
hasso95e735b2004-08-26 13:08:30 +000049
David Lampartera9eb9062015-03-04 07:07:01 +010050static int
paul718e3742002-12-13 20:15:29 +000051line_cmp (char *c1, char *c2)
52{
53 return strcmp (c1, c2);
54}
55
David Lampartera9eb9062015-03-04 07:07:01 +010056static void
paul718e3742002-12-13 20:15:29 +000057line_del (char *line)
58{
59 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
60}
61
David Lampartera9eb9062015-03-04 07:07:01 +010062static struct config *
paul718e3742002-12-13 20:15:29 +000063config_new ()
64{
65 struct config *config;
66 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
67 return config;
68}
69
David Lampartera9eb9062015-03-04 07:07:01 +010070static int
paul718e3742002-12-13 20:15:29 +000071config_cmp (struct config *c1, struct config *c2)
72{
73 return strcmp (c1->name, c2->name);
74}
75
David Lampartera9eb9062015-03-04 07:07:01 +010076static void
paul718e3742002-12-13 20:15:29 +000077config_del (struct config* config)
78{
79 list_delete (config->line);
80 if (config->name)
81 XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
82 XFREE (MTYPE_VTYSH_CONFIG, config);
83}
84
David Lampartera9eb9062015-03-04 07:07:01 +010085static struct config *
hassodda09522004-10-07 21:40:25 +000086config_get (int index, const char *line)
paul718e3742002-12-13 20:15:29 +000087{
88 struct config *config;
89 struct config *config_loop;
90 struct list *master;
paul1eb8ef22005-04-07 07:30:20 +000091 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +000092
93 config = config_loop = NULL;
94
95 master = vector_lookup_ensure (configvec, index);
96
97 if (! master)
98 {
99 master = list_new ();
100 master->del = (void (*) (void *))config_del;
101 master->cmp = (int (*)(void *, void *)) config_cmp;
102 vector_set_index (configvec, index, master);
103 }
104
paul1eb8ef22005-04-07 07:30:20 +0000105 for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
paul718e3742002-12-13 20:15:29 +0000106 {
107 if (strcmp (config_loop->name, line) == 0)
108 config = config_loop;
109 }
110
111 if (! config)
112 {
113 config = config_new ();
114 config->line = list_new ();
115 config->line->del = (void (*) (void *))line_del;
116 config->line->cmp = (int (*)(void *, void *)) line_cmp;
117 config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
118 config->index = index;
119 listnode_add (master, config);
120 }
121 return config;
122}
123
David Lampartera9eb9062015-03-04 07:07:01 +0100124static void
hassodda09522004-10-07 21:40:25 +0000125config_add_line (struct list *config, const char *line)
paul718e3742002-12-13 20:15:29 +0000126{
127 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
128}
129
David Lampartera9eb9062015-03-04 07:07:01 +0100130static void
hassodda09522004-10-07 21:40:25 +0000131config_add_line_uniq (struct list *config, const char *line)
paul718e3742002-12-13 20:15:29 +0000132{
paul1eb8ef22005-04-07 07:30:20 +0000133 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000134 char *pnt;
135
paul1eb8ef22005-04-07 07:30:20 +0000136 for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
paul718e3742002-12-13 20:15:29 +0000137 {
138 if (strcmp (pnt, line) == 0)
139 return;
140 }
141 listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
142}
143
David Lampartera9eb9062015-03-04 07:07:01 +0100144static void
hassodda09522004-10-07 21:40:25 +0000145vtysh_config_parse_line (const char *line)
paul718e3742002-12-13 20:15:29 +0000146{
147 char c;
148 static struct config *config = NULL;
149
150 if (! line)
151 return;
152
153 c = line[0];
154
155 if (c == '\0')
156 return;
157
158 /* printf ("[%s]\n", line); */
159
160 switch (c)
161 {
162 case '!':
163 case '#':
164 break;
165 case ' ':
166 /* Store line to current configuration. */
167 if (config)
168 {
Olivier Dugeonac10d302016-04-19 18:33:42 +0200169 if (strncmp (line, " address-family vpnv4",
hasso95e735b2004-08-26 13:08:30 +0000170 strlen (" address-family vpnv4")) == 0)
paul718e3742002-12-13 20:15:29 +0000171 config = config_get (BGP_VPNV4_NODE, line);
Lou Berger13c378d2016-01-12 13:41:56 -0500172 else if (strncmp (line, " address-family vpn6",
173 strlen (" address-family vpn6")) == 0)
174 config = config_get (BGP_VPNV6_NODE, line);
Lou Bergera3fda882016-01-12 13:42:04 -0500175 else if (strncmp (line, " address-family encapv6",
176 strlen (" address-family encapv6")) == 0)
177 config = config_get (BGP_ENCAPV6_NODE, line);
178 else if (strncmp (line, " address-family encap",
179 strlen (" address-family encap")) == 0)
180 config = config_get (BGP_ENCAP_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000181 else if (strncmp (line, " address-family ipv4 multicast",
182 strlen (" address-family ipv4 multicast")) == 0)
paul718e3742002-12-13 20:15:29 +0000183 config = config_get (BGP_IPV4M_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000184 else if (strncmp (line, " address-family ipv6",
185 strlen (" address-family ipv6")) == 0)
paul718e3742002-12-13 20:15:29 +0000186 config = config_get (BGP_IPV6_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000187 else if (config->index == RMAP_NODE ||
hassoe7168df2004-10-03 20:11:32 +0000188 config->index == VTY_NODE)
paul718e3742002-12-13 20:15:29 +0000189 config_add_line_uniq (config->line, line);
190 else
191 config_add_line (config->line, line);
192 }
193 else
194 config_add_line (config_top, line);
195 break;
196 default:
197 if (strncmp (line, "interface", strlen ("interface")) == 0)
198 config = config_get (INTERFACE_NODE, line);
hassodfbb9122004-12-22 11:53:09 +0000199 else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
200 config = config_get (ZEBRA_NODE, line);
paul718e3742002-12-13 20:15:29 +0000201 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
202 config = config_get (RIP_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000203 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
hassob094d262004-08-25 12:22:00 +0000204 config = config_get (RIPNG_NODE, line);
paul718e3742002-12-13 20:15:29 +0000205 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
hassob094d262004-08-25 12:22:00 +0000206 config = config_get (OSPF_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000207 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
hassob094d262004-08-25 12:22:00 +0000208 config = config_get (OSPF6_NODE, line);
paul718e3742002-12-13 20:15:29 +0000209 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
210 config = config_get (BGP_NODE, line);
paul13b8baa2004-01-15 01:00:49 +0000211 else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
hassoc25e4582003-12-23 10:39:08 +0000212 config = config_get (ISIS_NODE, line);
hassodfbb9122004-12-22 11:53:09 +0000213 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
paul718e3742002-12-13 20:15:29 +0000214 config = config_get (BGP_NODE, line);
215 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
216 config = config_get (RMAP_NODE, line);
217 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
218 config = config_get (ACCESS_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000219 else if (strncmp (line, "ipv6 access-list",
220 strlen ("ipv6 access-list")) == 0)
hassob094d262004-08-25 12:22:00 +0000221 config = config_get (ACCESS_IPV6_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000222 else if (strncmp (line, "ip prefix-list",
223 strlen ("ip prefix-list")) == 0)
paul718e3742002-12-13 20:15:29 +0000224 config = config_get (PREFIX_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000225 else if (strncmp (line, "ipv6 prefix-list",
226 strlen ("ipv6 prefix-list")) == 0)
hassob094d262004-08-25 12:22:00 +0000227 config = config_get (PREFIX_IPV6_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000228 else if (strncmp (line, "ip as-path access-list",
229 strlen ("ip as-path access-list")) == 0)
paul718e3742002-12-13 20:15:29 +0000230 config = config_get (AS_LIST_NODE, line);
hasso95e735b2004-08-26 13:08:30 +0000231 else if (strncmp (line, "ip community-list",
232 strlen ("ip community-list")) == 0)
paul718e3742002-12-13 20:15:29 +0000233 config = config_get (COMMUNITY_LIST_NODE, line);
234 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
235 config = config_get (IP_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000236 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
237 config = config_get (IP_NODE, line);
paul718e3742002-12-13 20:15:29 +0000238 else if (strncmp (line, "key", strlen ("key")) == 0)
239 config = config_get (KEYCHAIN_NODE, line);
hassoe7168df2004-10-03 20:11:32 +0000240 else if (strncmp (line, "line", strlen ("line")) == 0)
241 config = config_get (VTY_NODE, line);
242 else if ( (strncmp (line, "ipv6 forwarding",
243 strlen ("ipv6 forwarding")) == 0)
244 || (strncmp (line, "ip forwarding",
245 strlen ("ip forwarding")) == 0) )
246 config = config_get (FORWARDING_NODE, line);
247 else if (strncmp (line, "service", strlen ("service")) == 0)
248 config = config_get (SERVICE_NODE, line);
hassodfbb9122004-12-22 11:53:09 +0000249 else if (strncmp (line, "debug", strlen ("debug")) == 0)
250 config = config_get (DEBUG_NODE, line);
hasso060d4382005-03-09 12:41:14 +0000251 else if (strncmp (line, "password", strlen ("password")) == 0
252 || strncmp (line, "enable password",
253 strlen ("enable password")) == 0)
254 config = config_get (AAA_NODE, line);
Chris Caputo6e79f8b2009-06-23 05:55:57 +0000255 else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
256 config = config_get (PROTOCOL_NODE, line);
paul718e3742002-12-13 20:15:29 +0000257 else
258 {
259 if (strncmp (line, "log", strlen ("log")) == 0
260 || strncmp (line, "hostname", strlen ("hostname")) == 0
hassoe7168df2004-10-03 20:11:32 +0000261 )
paul718e3742002-12-13 20:15:29 +0000262 config_add_line_uniq (config_top, line);
263 else
264 config_add_line (config_top, line);
265 config = NULL;
266 }
267 break;
268 }
269}
270
271void
272vtysh_config_parse (char *line)
273{
274 char *begin;
275 char *pnt;
276
277 begin = pnt = line;
278
279 while (*pnt != '\0')
280 {
281 if (*pnt == '\n')
282 {
283 *pnt++ = '\0';
284 vtysh_config_parse_line (begin);
285 begin = pnt;
286 }
287 else
288 {
289 pnt++;
290 }
291 }
292}
293
294/* Macro to check delimiter is needed between each configuration line
hasso95e735b2004-08-26 13:08:30 +0000295 * or not. */
paul718e3742002-12-13 20:15:29 +0000296#define NO_DELIMITER(I) \
297 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
paul97e1c4d2003-03-28 02:25:23 +0000298 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
hassoe7168df2004-10-03 20:11:32 +0000299 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
hasso060d4382005-03-09 12:41:14 +0000300 || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
301 || (I) == AAA_NODE)
paul718e3742002-12-13 20:15:29 +0000302
hasso95e735b2004-08-26 13:08:30 +0000303/* Display configuration to file pointer. */
paul718e3742002-12-13 20:15:29 +0000304void
305vtysh_config_dump (FILE *fp)
306{
paul1eb8ef22005-04-07 07:30:20 +0000307 struct listnode *node, *nnode;
308 struct listnode *mnode, *mnnode;
paul718e3742002-12-13 20:15:29 +0000309 struct config *config;
310 struct list *master;
311 char *line;
hassodda09522004-10-07 21:40:25 +0000312 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000313
paul1eb8ef22005-04-07 07:30:20 +0000314 for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
paul718e3742002-12-13 20:15:29 +0000315 {
316 fprintf (fp, "%s\n", line);
317 fflush (fp);
318 }
319 fprintf (fp, "!\n");
320 fflush (fp);
321
paul55468c82005-03-14 20:19:01 +0000322 for (i = 0; i < vector_active (configvec); i++)
paul718e3742002-12-13 20:15:29 +0000323 if ((master = vector_slot (configvec, i)) != NULL)
324 {
paul1eb8ef22005-04-07 07:30:20 +0000325 for (ALL_LIST_ELEMENTS (master, node, nnode, config))
paul718e3742002-12-13 20:15:29 +0000326 {
327 fprintf (fp, "%s\n", config->name);
hassob094d262004-08-25 12:22:00 +0000328 fflush (fp);
paul718e3742002-12-13 20:15:29 +0000329
paul1eb8ef22005-04-07 07:30:20 +0000330 for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
paul718e3742002-12-13 20:15:29 +0000331 {
332 fprintf (fp, "%s\n", line);
333 fflush (fp);
334 }
335 if (! NO_DELIMITER (i))
336 {
337 fprintf (fp, "!\n");
338 fflush (fp);
339 }
340 }
341 if (NO_DELIMITER (i))
342 {
343 fprintf (fp, "!\n");
344 fflush (fp);
345 }
346 }
347
paul55468c82005-03-14 20:19:01 +0000348 for (i = 0; i < vector_active (configvec); i++)
paul718e3742002-12-13 20:15:29 +0000349 if ((master = vector_slot (configvec, i)) != NULL)
350 {
351 list_delete (master);
352 vector_slot (configvec, i) = NULL;
353 }
354 list_delete_all_node (config_top);
355}
356
357/* Read up configuration file from file_name. */
358static void
359vtysh_read_file (FILE *confp)
360{
361 int ret;
362 struct vty *vty;
363
364 vty = vty_new ();
365 vty->fd = 0; /* stdout */
366 vty->type = VTY_TERM;
367 vty->node = CONFIG_NODE;
368
369 vtysh_execute_no_pager ("enable");
370 vtysh_execute_no_pager ("configure terminal");
371
hasso95e735b2004-08-26 13:08:30 +0000372 /* Execute configuration file. */
paul718e3742002-12-13 20:15:29 +0000373 ret = vtysh_config_from_file (vty, confp);
374
375 vtysh_execute_no_pager ("end");
376 vtysh_execute_no_pager ("disable");
377
378 vty_close (vty);
379
380 if (ret != CMD_SUCCESS)
381 {
382 switch (ret)
383 {
384 case CMD_ERR_AMBIGUOUS:
385 fprintf (stderr, "Ambiguous command.\n");
386 break;
387 case CMD_ERR_NO_MATCH:
388 fprintf (stderr, "There is no such command.\n");
389 break;
390 }
391 fprintf (stderr, "Error occured during reading below line.\n%s\n",
392 vty->buf);
393 exit (1);
394 }
395}
396
hassoe7168df2004-10-03 20:11:32 +0000397/* Read up configuration file from config_default_dir. */
398int
399vtysh_read_config (char *config_default_dir)
paul718e3742002-12-13 20:15:29 +0000400{
paul718e3742002-12-13 20:15:29 +0000401 FILE *confp = NULL;
paul718e3742002-12-13 20:15:29 +0000402
hassoe7168df2004-10-03 20:11:32 +0000403 confp = fopen (config_default_dir, "r");
404 if (confp == NULL)
405 return (1);
hasso67e29ab2004-08-26 22:21:31 +0000406
paul718e3742002-12-13 20:15:29 +0000407 vtysh_read_file (confp);
paul718e3742002-12-13 20:15:29 +0000408 fclose (confp);
hassoe7168df2004-10-03 20:11:32 +0000409 host_config_set (config_default_dir);
paul718e3742002-12-13 20:15:29 +0000410
hassoe7168df2004-10-03 20:11:32 +0000411 return (0);
paul718e3742002-12-13 20:15:29 +0000412}
413
hassoe7168df2004-10-03 20:11:32 +0000414/* We don't write vtysh specific into file from vtysh. vtysh.conf should
415 * be edited by hand. So, we handle only "write terminal" case here and
416 * integrate vtysh specific conf with conf from daemons.
417 */
paul718e3742002-12-13 20:15:29 +0000418void
hassoe7168df2004-10-03 20:11:32 +0000419vtysh_config_write ()
paul718e3742002-12-13 20:15:29 +0000420{
hassodda09522004-10-07 21:40:25 +0000421 char line[81];
paul718e3742002-12-13 20:15:29 +0000422 extern struct host host;
423
424 if (host.name)
hassoe7168df2004-10-03 20:11:32 +0000425 {
426 sprintf (line, "hostname %s", host.name);
427 vtysh_config_parse_line(line);
428 }
429 if (vtysh_writeconfig_integrated)
430 vtysh_config_parse_line ("service integrated-vtysh-config");
paul718e3742002-12-13 20:15:29 +0000431}
432
433void
434vtysh_config_init ()
435{
436 config_top = list_new ();
437 config_top->del = (void (*) (void *))line_del;
438 configvec = vector_init (1);
439}