]> git.proxmox.com Git - mirror_frr.git/blame_incremental - vtysh/vtysh_config.c
redhat: Add fabricd to RPM package
[mirror_frr.git] / vtysh / vtysh_config.c
... / ...
CommitLineData
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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
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
30DEFINE_MGROUP(MVTYSH, "vtysh")
31DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
33
34vector configvec;
35
36struct config {
37 /* Configuration node name. */
38 char *name;
39
40 /* Configuration string line. */
41 struct list *line;
42
43 /* Configuration can be nest. */
44 struct config *config;
45
46 /* Index of this config. */
47 uint32_t index;
48};
49
50struct list *config_top;
51
52static int line_cmp(char *c1, char *c2)
53{
54 return strcmp(c1, c2);
55}
56
57static void line_del(char *line)
58{
59 XFREE(MTYPE_VTYSH_CONFIG_LINE, line);
60}
61
62static struct config *config_new(void)
63{
64 struct config *config;
65 config = XCALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config));
66 return config;
67}
68
69static int config_cmp(struct config *c1, struct config *c2)
70{
71 return strcmp(c1->name, c2->name);
72}
73
74static void config_del(struct config *config)
75{
76 list_delete_and_null(&config->line);
77 if (config->name)
78 XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
79 XFREE(MTYPE_VTYSH_CONFIG, config);
80}
81
82static struct config *config_get(int index, const char *line)
83{
84 struct config *config;
85 struct config *config_loop;
86 struct list *master;
87 struct listnode *node, *nnode;
88
89 config = config_loop = NULL;
90
91 master = vector_lookup_ensure(configvec, index);
92
93 if (!master) {
94 master = list_new();
95 master->del = (void (*)(void *))config_del;
96 master->cmp = (int (*)(void *, void *))config_cmp;
97 vector_set_index(configvec, index, master);
98 }
99
100 for (ALL_LIST_ELEMENTS(master, node, nnode, config_loop)) {
101 if (strcmp(config_loop->name, line) == 0)
102 config = config_loop;
103 }
104
105 if (!config) {
106 config = config_new();
107 config->line = list_new();
108 config->line->del = (void (*)(void *))line_del;
109 config->line->cmp = (int (*)(void *, void *))line_cmp;
110 config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
111 config->index = index;
112 listnode_add(master, config);
113 }
114 return config;
115}
116
117void config_add_line(struct list *config, const char *line)
118{
119 listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
120}
121
122static void config_add_line_uniq(struct list *config, const char *line)
123{
124 struct listnode *node, *nnode;
125 char *pnt;
126
127 for (ALL_LIST_ELEMENTS(config, node, nnode, pnt)) {
128 if (strcmp(pnt, line) == 0)
129 return;
130 }
131 listnode_add_sort(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
132}
133
134/*
135 * I want to explicitly move this command to the end of the line
136 */
137static void config_add_line_end(struct list *config, const char *line)
138{
139 struct listnode *node;
140 void *item = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
141
142 listnode_add(config, item);
143 node = listnode_lookup(config, item);
144 if (node)
145 listnode_move_to_tail(config, node);
146}
147
148void vtysh_config_parse_line(void *arg, 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 /* Suppress exclamation points ! and commented lines. The !s are
165 * 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 if (strncmp(line, " link-params",
174 strlen(" link-params"))
175 == 0) {
176 config_add_line(config->line, line);
177 config->index = LINK_PARAMS_NODE;
178 } else if (strncmp(line, " ip multicast boundary",
179 strlen(" ip multicast boundary"))
180 == 0) {
181 config_add_line_end(config->line, line);
182 } else if (strncmp(line, " ip igmp query-interval",
183 strlen(" ip igmp query-interval")) == 0) {
184 config_add_line_end(config->line, line);
185 } else if (config->index == LINK_PARAMS_NODE
186 && strncmp(line, " exit-link-params",
187 strlen(" exit"))
188 == 0) {
189 config_add_line(config->line, line);
190 config->index = INTERFACE_NODE;
191 } else if (config->index == VRF_NODE
192 && strncmp(line, " exit-vrf",
193 strlen(" exit-vrf"))
194 == 0) {
195 config_add_line(config->line, line);
196 config->index = CONFIG_NODE;
197 } else if (config->index == RMAP_NODE
198 || config->index == INTERFACE_NODE
199 || config->index == LOGICALROUTER_NODE
200 || config->index == VTY_NODE
201 || config->index == VRF_NODE)
202 config_add_line_uniq(config->line, line);
203 else
204 config_add_line(config->line, line);
205 } else
206 config_add_line(config_top, line);
207 break;
208 default:
209 if (strncmp(line, "interface", strlen("interface")) == 0)
210 config = config_get(INTERFACE_NODE, line);
211 else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
212 config = config_get(PW_NODE, line);
213 else if (strncmp(line, "logical-router", strlen("logical-router")) == 0)
214 config = config_get(LOGICALROUTER_NODE, line);
215 else if (strncmp(line, "vrf", strlen("vrf")) == 0)
216 config = config_get(VRF_NODE, line);
217 else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
218 == 0)
219 config = config_get(NH_GROUP_NODE, line);
220 else if (strncmp(line, "router-id", strlen("router-id")) == 0)
221 config = config_get(ZEBRA_NODE, line);
222 else if (strncmp(line, "router rip", strlen("router rip")) == 0)
223 config = config_get(RIP_NODE, line);
224 else if (strncmp(line, "router ripng", strlen("router ripng"))
225 == 0)
226 config = config_get(RIPNG_NODE, line);
227 else if (strncmp(line, "router eigrp", strlen("router eigrp"))
228 == 0)
229 config = config_get(EIGRP_NODE, line);
230 else if (strncmp(line, "router babel", strlen("router babel"))
231 == 0)
232 config = config_get(BABEL_NODE, line);
233 else if (strncmp(line, "router ospf", strlen("router ospf"))
234 == 0)
235 config = config_get(OSPF_NODE, line);
236 else if (strncmp(line, "router ospf6", strlen("router ospf6"))
237 == 0)
238 config = config_get(OSPF6_NODE, line);
239 else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
240 config = config_get(LDP_NODE, line);
241 else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
242 config = config_get(LDP_L2VPN_NODE, line);
243 else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
244 config = config_get(BGP_NODE, line);
245 else if (strncmp(line, "router isis", strlen("router isis"))
246 == 0)
247 config = config_get(ISIS_NODE, line);
248 else if (strncmp(line, "route-map", strlen("route-map")) == 0)
249 config = config_get(RMAP_NODE, line);
250 else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
251 config = config_get(PBRMAP_NODE, line);
252 else if (strncmp(line, "access-list", strlen("access-list"))
253 == 0)
254 config = config_get(ACCESS_NODE, line);
255 else if (strncmp(line, "ipv6 access-list",
256 strlen("ipv6 access-list"))
257 == 0)
258 config = config_get(ACCESS_IPV6_NODE, line);
259 else if (strncmp(line, "mac access-list",
260 strlen("mac access-list"))
261 == 0)
262 config = config_get(ACCESS_MAC_NODE, line);
263 else if (strncmp(line, "ip prefix-list",
264 strlen("ip prefix-list"))
265 == 0)
266 config = config_get(PREFIX_NODE, line);
267 else if (strncmp(line, "ipv6 prefix-list",
268 strlen("ipv6 prefix-list"))
269 == 0)
270 config = config_get(PREFIX_IPV6_NODE, line);
271 else if (strncmp(line, "ip as-path access-list",
272 strlen("ip as-path access-list"))
273 == 0)
274 config = config_get(AS_LIST_NODE, line);
275 else if (strncmp(line, "ip community-list",
276 strlen("ip community-list"))
277 == 0
278 || strncmp(line, "ip extcommunity-list",
279 strlen("ip extcommunity-list"))
280 == 0
281 || strncmp(line, "ip large-community-list",
282 strlen("ip large-community-list"))
283 == 0)
284 config = config_get(COMMUNITY_LIST_NODE, line);
285 else if (strncmp(line, "ip route", strlen("ip route")) == 0)
286 config = config_get(IP_NODE, line);
287 else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
288 config = config_get(IP_NODE, line);
289 else if (strncmp(line, "key", strlen("key")) == 0)
290 config = config_get(KEYCHAIN_NODE, line);
291 else if (strncmp(line, "line", strlen("line")) == 0)
292 config = config_get(VTY_NODE, line);
293 else if ((strncmp(line, "ipv6 forwarding",
294 strlen("ipv6 forwarding"))
295 == 0)
296 || (strncmp(line, "ip forwarding",
297 strlen("ip forwarding"))
298 == 0))
299 config = config_get(FORWARDING_NODE, line);
300 else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
301 config = config_get(VRF_DEBUG_NODE, line);
302 else if (strncmp(line, "debug", strlen("debug")) == 0)
303 config = config_get(DEBUG_NODE, line);
304 else if (strncmp(line, "password", strlen("password")) == 0
305 || strncmp(line, "enable password",
306 strlen("enable password"))
307 == 0)
308 config = config_get(AAA_NODE, line);
309 else if (strncmp(line, "ip protocol", strlen("ip protocol"))
310 == 0)
311 config = config_get(PROTOCOL_NODE, line);
312 else if (strncmp(line, "ipv6 protocol", strlen("ipv6 protocol"))
313 == 0)
314 config = config_get(PROTOCOL_NODE, line);
315 else if (strncmp(line, "ip nht", strlen("ip nht")) == 0)
316 config = config_get(PROTOCOL_NODE, line);
317 else if (strncmp(line, "ipv6 nht", strlen("ipv6 nht")) == 0)
318 config = config_get(PROTOCOL_NODE, line);
319 else if (strncmp(line, "mpls", strlen("mpls")) == 0)
320 config = config_get(MPLS_NODE, line);
321 else if (strncmp(line, "bfd", strlen("bfd")) == 0)
322 config = config_get(BFD_NODE, line);
323 else {
324 if (strncmp(line, "log", strlen("log")) == 0
325 || strncmp(line, "hostname", strlen("hostname"))
326 == 0
327 || strncmp(line, "frr", strlen("frr")) == 0
328 || strncmp(line, "agentx", strlen("agentx")) == 0
329 || strncmp(line, "no log", strlen("no log")) == 0)
330 config_add_line_uniq(config_top, line);
331 else
332 config_add_line(config_top, line);
333 config = NULL;
334 }
335 break;
336 }
337}
338
339/* Macro to check delimiter is needed between each configuration line
340 * or not. */
341#define NO_DELIMITER(I) \
342 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
343 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
344 || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
345 || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
346 || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
347 || (I) == MPLS_NODE)
348
349/* Display configuration to file pointer. */
350void vtysh_config_dump(void)
351{
352 struct listnode *node, *nnode;
353 struct listnode *mnode, *mnnode;
354 struct config *config;
355 struct list *master;
356 char *line;
357 unsigned int i;
358
359 for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
360 vty_out(vty, "%s\n", line);
361
362 vty_out(vty, "!\n");
363
364 for (i = 0; i < vector_active(configvec); i++)
365 if ((master = vector_slot(configvec, i)) != NULL) {
366 for (ALL_LIST_ELEMENTS(master, node, nnode, config)) {
367 /* Don't print empty sections for interface.
368 * Route maps on the
369 * other hand could have a legitimate empty
370 * section at the end.
371 * VRF is handled in the backend, we could have
372 * "configured" VRFs with static routes which
373 * are not under the VRF node.
374 */
375 if (config->index == INTERFACE_NODE
376 && list_isempty(config->line))
377 continue;
378
379 vty_out(vty, "%s\n", config->name);
380
381 for (ALL_LIST_ELEMENTS(config->line, mnode,
382 mnnode, line))
383 vty_out(vty, "%s\n", line);
384 if (!NO_DELIMITER(i))
385 vty_out(vty, "!\n");
386 }
387 if (NO_DELIMITER(i))
388 vty_out(vty, "!\n");
389 }
390
391 for (i = 0; i < vector_active(configvec); i++)
392 if ((master = vector_slot(configvec, i)) != NULL) {
393 list_delete_and_null(&master);
394 vector_slot(configvec, i) = NULL;
395 }
396 list_delete_all_node(config_top);
397}
398
399/* Read up configuration file from file_name. */
400static int vtysh_read_file(FILE *confp)
401{
402 struct vty *vty;
403 int ret;
404
405 vty = vty_new();
406 vty->wfd = STDERR_FILENO;
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
413 /* Execute configuration file. */
414 ret = vtysh_config_from_file(vty, confp);
415
416 vtysh_execute_no_pager("end");
417 vtysh_execute_no_pager("disable");
418
419 vty_close(vty);
420
421 return (ret);
422}
423
424/* Read up configuration file from config_default_dir. */
425int vtysh_read_config(const char *config_default_dir)
426{
427 FILE *confp = NULL;
428 int ret;
429
430 confp = fopen(config_default_dir, "r");
431 if (confp == NULL) {
432 fprintf(stderr,
433 "%% Can't open configuration file %s due to '%s'.\n",
434 config_default_dir, safe_strerror(errno));
435 return (CMD_ERR_NO_FILE);
436 }
437
438 ret = vtysh_read_file(confp);
439 fclose(confp);
440
441 return (ret);
442}
443
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 */
448void vtysh_config_write()
449{
450 char line[81];
451
452 if (cmd_hostname_get()) {
453 sprintf(line, "hostname %s", cmd_hostname_get());
454 vtysh_config_parse_line(NULL, line);
455 }
456
457 if (cmd_domainname_get()) {
458 sprintf(line, "domainname %s", cmd_domainname_get());
459 vtysh_config_parse_line(NULL, line);
460 }
461 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
462 vtysh_config_parse_line(NULL,
463 "no service integrated-vtysh-config");
464 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
465 vtysh_config_parse_line(NULL,
466 "service integrated-vtysh-config");
467
468 user_config_write();
469}
470
471void vtysh_config_init()
472{
473 config_top = list_new();
474 config_top->del = (void (*)(void *))line_del;
475 configvec = vector_init(1);
476}