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