]> git.proxmox.com Git - mirror_frr.git/blob - vtysh/vtysh_config.c
Merge remote-tracking branch 'origin/master' into EIGRP
[mirror_frr.git] / vtysh / vtysh_config.c
1 /* Configuration generator.
2 Copyright (C) 2000 Kunihiro Ishiguro
3
4 This file is part of GNU Zebra.
5
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-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 #include "vtysh/vtysh_user.h"
29
30 DEFINE_MGROUP(MVTYSH, "vtysh")
31 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
32 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
33
34 vector configvec;
35
36 struct 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
51 struct list *config_top;
52
53 static int
54 line_cmp (char *c1, char *c2)
55 {
56 return strcmp (c1, c2);
57 }
58
59 static void
60 line_del (char *line)
61 {
62 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
63 }
64
65 static struct config *
66 config_new (void)
67 {
68 struct config *config;
69 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
70 return config;
71 }
72
73 static int
74 config_cmp (struct config *c1, struct config *c2)
75 {
76 return strcmp (c1->name, c2->name);
77 }
78
79 static void
80 config_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
88 static struct config *
89 config_get (int index, const char *line)
90 {
91 struct config *config;
92 struct config *config_loop;
93 struct list *master;
94 struct listnode *node, *nnode;
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
108 for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
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
127 void
128 config_add_line (struct list *config, const char *line)
129 {
130 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
131 }
132
133 static void
134 config_add_line_uniq (struct list *config, const char *line)
135 {
136 struct listnode *node, *nnode;
137 char *pnt;
138
139 for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
140 {
141 if (strcmp (pnt, line) == 0)
142 return;
143 }
144 listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
145 }
146
147 void
148 vtysh_config_parse_line (const char *line)
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 {
165 /* Suppress exclamation points ! and commented lines. The !s are generated
166 * dynamically in vtysh_config_dump() */
167 case '!':
168 case '#':
169 break;
170 case ' ':
171 /* Store line to current configuration. */
172 if (config)
173 {
174 if (strncmp (line, " link-params", strlen (" link-params")) == 0)
175 {
176 config_add_line (config->line, line);
177 config->index = LINK_PARAMS_NODE;
178 }
179 else if (config->index == LINK_PARAMS_NODE &&
180 strncmp (line, " exit-link-params", strlen (" exit")) == 0)
181 {
182 config_add_line (config->line, line);
183 config->index = INTERFACE_NODE;
184 }
185 else if (config->index == RMAP_NODE ||
186 config->index == INTERFACE_NODE ||
187 config->index == NS_NODE ||
188 config->index == VTY_NODE)
189 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);
199 else if (strncmp (line, "logical-router", strlen ("ns")) == 0)
200 config = config_get (NS_NODE, line);
201 else if (strncmp (line, "vrf", strlen ("vrf")) == 0)
202 config = config_get (VRF_NODE, line);
203 else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
204 config = config_get (ZEBRA_NODE, line);
205 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
206 config = config_get (RIP_NODE, line);
207 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
208 config = config_get (RIPNG_NODE, line);
209 else if (strncmp (line, "router eigrp", strlen ("router eigrp")) == 0)
210 config = config_get (EIGRP_NODE, line);
211 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
212 config = config_get (OSPF_NODE, line);
213 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
214 config = config_get (OSPF6_NODE, line);
215 else if (strncmp (line, "mpls ldp", strlen ("mpls ldp")) == 0)
216 config = config_get (LDP_NODE, line);
217 else if (strncmp (line, "l2vpn", strlen ("l2vpn")) == 0)
218 config = config_get (LDP_L2VPN_NODE, line);
219 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
220 config = config_get (BGP_NODE, line);
221 else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
222 config = config_get (ISIS_NODE, line);
223 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
224 config = config_get (RMAP_NODE, line);
225 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
226 config = config_get (ACCESS_NODE, line);
227 else if (strncmp (line, "ipv6 access-list",
228 strlen ("ipv6 access-list")) == 0)
229 config = config_get (ACCESS_IPV6_NODE, line);
230 else if (strncmp (line, "ip prefix-list",
231 strlen ("ip prefix-list")) == 0)
232 config = config_get (PREFIX_NODE, line);
233 else if (strncmp (line, "ipv6 prefix-list",
234 strlen ("ipv6 prefix-list")) == 0)
235 config = config_get (PREFIX_IPV6_NODE, line);
236 else if (strncmp (line, "ip as-path access-list",
237 strlen ("ip as-path access-list")) == 0)
238 config = config_get (AS_LIST_NODE, line);
239 else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0 ||
240 strncmp (line, "ip extcommunity-list", strlen ("ip extcommunity-list")) == 0)
241 config = config_get (COMMUNITY_LIST_NODE, line);
242 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
243 config = config_get (IP_NODE, line);
244 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
245 config = config_get (IP_NODE, line);
246 else if (strncmp (line, "key", strlen ("key")) == 0)
247 config = config_get (KEYCHAIN_NODE, line);
248 else if (strncmp (line, "line", strlen ("line")) == 0)
249 config = config_get (VTY_NODE, line);
250 else if ( (strncmp (line, "ipv6 forwarding",
251 strlen ("ipv6 forwarding")) == 0)
252 || (strncmp (line, "ip forwarding",
253 strlen ("ip forwarding")) == 0) )
254 config = config_get (FORWARDING_NODE, line);
255 else if (strncmp (line, "service", strlen ("service")) == 0)
256 config = config_get (SERVICE_NODE, line);
257 else if (strncmp (line, "debug vrf", strlen ("debug vrf")) == 0)
258 config = config_get (VRF_DEBUG_NODE, line);
259 else if (strncmp (line, "debug", strlen ("debug")) == 0)
260 config = config_get (DEBUG_NODE, line);
261 else if (strncmp (line, "password", strlen ("password")) == 0
262 || strncmp (line, "enable password",
263 strlen ("enable password")) == 0)
264 config = config_get (AAA_NODE, line);
265 else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
266 config = config_get (PROTOCOL_NODE, line);
267 else if (strncmp (line, "ipv6 protocol", strlen ("ipv6 protocol")) == 0)
268 config = config_get (PROTOCOL_NODE, line);
269 else if (strncmp (line, "ip nht", strlen ("ip nht")) == 0)
270 config = config_get (PROTOCOL_NODE, line);
271 else if (strncmp (line, "ipv6 nht", strlen ("ipv6 nht")) == 0)
272 config = config_get (PROTOCOL_NODE, line);
273 else if (strncmp (line, "mpls", strlen ("mpls")) == 0)
274 config = config_get (MPLS_NODE, line);
275 else
276 {
277 if (strncmp (line, "log", strlen ("log")) == 0
278 || strncmp (line, "hostname", strlen ("hostname")) == 0
279 )
280 config_add_line_uniq (config_top, line);
281 else
282 config_add_line (config_top, line);
283 config = NULL;
284 }
285 break;
286 }
287 }
288
289 /* Macro to check delimiter is needed between each configuration line
290 * or not. */
291 #define NO_DELIMITER(I) \
292 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
293 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
294 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
295 || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
296 || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
297
298 /* Display configuration to file pointer. */
299 void
300 vtysh_config_dump (FILE *fp)
301 {
302 struct listnode *node, *nnode;
303 struct listnode *mnode, *mnnode;
304 struct config *config;
305 struct list *master;
306 char *line;
307 unsigned int i;
308
309 for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
310 {
311 fprintf (fp, "%s\n", line);
312 fflush (fp);
313 }
314 fprintf (fp, "!\n");
315 fflush (fp);
316
317 for (i = 0; i < vector_active (configvec); i++)
318 if ((master = vector_slot (configvec, i)) != NULL)
319 {
320 for (ALL_LIST_ELEMENTS (master, node, nnode, config))
321 {
322 /* Don't print empty sections for interface/vrf. Route maps on the
323 * other hand could have a legitimate empty section at the end.
324 */
325 if ((config->index == INTERFACE_NODE || (config->index == VRF_NODE))
326 && list_isempty (config->line))
327 continue;
328
329 fprintf (fp, "%s\n", config->name);
330 fflush (fp);
331
332 for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
333 {
334 fprintf (fp, "%s\n", line);
335 fflush (fp);
336 }
337 if (! NO_DELIMITER (i))
338 {
339 fprintf (fp, "!\n");
340 fflush (fp);
341 }
342 }
343 if (NO_DELIMITER (i))
344 {
345 fprintf (fp, "!\n");
346 fflush (fp);
347 }
348 }
349
350 for (i = 0; i < vector_active (configvec); i++)
351 if ((master = vector_slot (configvec, i)) != NULL)
352 {
353 list_delete (master);
354 vector_slot (configvec, i) = NULL;
355 }
356 list_delete_all_node (config_top);
357 }
358
359 /* Read up configuration file from file_name. */
360 static int
361 vtysh_read_file (FILE *confp)
362 {
363 struct vty *vty;
364 int ret;
365
366 vty = vty_new ();
367 vty->fd = 0; /* stdout */
368 vty->type = VTY_TERM;
369 vty->node = CONFIG_NODE;
370
371 vtysh_execute_no_pager ("enable");
372 vtysh_execute_no_pager ("configure terminal");
373
374 /* Execute configuration file. */
375 ret = vtysh_config_from_file (vty, confp);
376
377 vtysh_execute_no_pager ("end");
378 vtysh_execute_no_pager ("disable");
379
380 vty_close (vty);
381
382 return (ret);
383 }
384
385 /* Read up configuration file from config_default_dir. */
386 int
387 vtysh_read_config (const char *config_default_dir)
388 {
389 FILE *confp = NULL;
390 int ret;
391
392 confp = fopen (config_default_dir, "r");
393 if (confp == NULL)
394 {
395 fprintf (stderr, "%% Can't open configuration file %s due to '%s'.\n",
396 config_default_dir, safe_strerror (errno));
397 return (CMD_ERR_NO_FILE);
398 }
399
400 ret = vtysh_read_file (confp);
401 fclose (confp);
402
403 return (ret);
404 }
405
406 /* We don't write vtysh specific into file from vtysh. vtysh.conf should
407 * be edited by hand. So, we handle only "write terminal" case here and
408 * integrate vtysh specific conf with conf from daemons.
409 */
410 void
411 vtysh_config_write ()
412 {
413 char line[81];
414 extern struct host host;
415
416 if (host.name)
417 {
418 sprintf (line, "hostname %s", host.name);
419 vtysh_config_parse_line(line);
420 }
421 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
422 vtysh_config_parse_line ("no service integrated-vtysh-config");
423 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
424 vtysh_config_parse_line ("service integrated-vtysh-config");
425
426 user_config_write ();
427 }
428
429 void
430 vtysh_config_init ()
431 {
432 config_top = list_new ();
433 config_top->del = (void (*) (void *))line_del;
434 configvec = vector_init (1);
435 }