]>
git.proxmox.com Git - mirror_frr.git/blob - vtysh/vtysh_config.c
1 /* Configuration generator.
2 * Copyright (C) 2000 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
27 #include "vtysh/vtysh.h"
28 #include "vtysh/vtysh_user.h"
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")
37 /* Configuration node name. */
40 /* Configuration string line. */
43 /* Configuration can be nest. */
44 struct config
*config
;
46 /* Index of this config. */
50 struct list
*config_top
;
52 static int line_cmp(char *c1
, char *c2
)
54 return strcmp(c1
, c2
);
57 static void line_del(char *line
)
59 XFREE(MTYPE_VTYSH_CONFIG_LINE
, line
);
62 static struct config
*config_new(void)
64 struct config
*config
;
65 config
= XCALLOC(MTYPE_VTYSH_CONFIG
, sizeof(struct config
));
69 static int config_cmp(struct config
*c1
, struct config
*c2
)
71 return strcmp(c1
->name
, c2
->name
);
74 static void config_del(struct config
*config
)
76 list_delete_and_null(&config
->line
);
78 XFREE(MTYPE_VTYSH_CONFIG_LINE
, config
->name
);
79 XFREE(MTYPE_VTYSH_CONFIG
, config
);
82 static struct config
*config_get(int index
, const char *line
)
84 struct config
*config
;
85 struct config
*config_loop
;
87 struct listnode
*node
, *nnode
;
89 config
= config_loop
= NULL
;
91 master
= vector_lookup_ensure(configvec
, index
);
95 master
->del
= (void (*)(void *))config_del
;
96 master
->cmp
= (int (*)(void *, void *))config_cmp
;
97 vector_set_index(configvec
, index
, master
);
100 for (ALL_LIST_ELEMENTS(master
, node
, nnode
, config_loop
)) {
101 if (strcmp(config_loop
->name
, line
) == 0)
102 config
= config_loop
;
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
);
117 void config_add_line(struct list
*config
, const char *line
)
119 listnode_add(config
, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE
, line
));
122 static void config_add_line_uniq(struct list
*config
, const char *line
)
124 struct listnode
*node
, *nnode
;
127 for (ALL_LIST_ELEMENTS(config
, node
, nnode
, pnt
)) {
128 if (strcmp(pnt
, line
) == 0)
131 listnode_add_sort(config
, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE
, line
));
135 * I want to explicitly move this command to the end of the line
137 static void config_add_line_end(struct list
*config
, const char *line
)
139 struct listnode
*node
;
140 void *item
= XSTRDUP(MTYPE_VTYSH_CONFIG_LINE
, line
);
142 listnode_add(config
, item
);
143 node
= listnode_lookup(config
, item
);
145 listnode_move_to_tail(config
, node
);
148 void vtysh_config_parse_line(void *arg
, const char *line
)
151 static struct config
*config
= NULL
;
161 /* printf ("[%s]\n", line); */
164 /* Suppress exclamation points ! and commented lines. The !s are
166 * dynamically in vtysh_config_dump() */
171 /* Store line to current configuration. */
173 if (strncmp(line
, " link-params",
174 strlen(" link-params"))
176 config_add_line(config
->line
, line
);
177 config
->index
= LINK_PARAMS_NODE
;
178 } else if (strncmp(line
,
179 " ip multicast boundary",
180 strlen(" ip multicast boundary")) == 0) {
181 config_add_line_end(config
->line
, line
);
182 } else if (config
->index
== LINK_PARAMS_NODE
183 && strncmp(line
, " exit-link-params",
186 config_add_line(config
->line
, line
);
187 config
->index
= INTERFACE_NODE
;
188 } else if (config
->index
== RMAP_NODE
189 || config
->index
== INTERFACE_NODE
190 || config
->index
== LOGICALROUTER_NODE
191 || config
->index
== VTY_NODE
192 || config
->index
== VRF_NODE
)
193 config_add_line_uniq(config
->line
, line
);
195 config_add_line(config
->line
, line
);
197 config_add_line(config_top
, line
);
200 if (strncmp(line
, "interface", strlen("interface")) == 0)
201 config
= config_get(INTERFACE_NODE
, line
);
202 else if (strncmp(line
, "pseudowire", strlen("pseudowire")) == 0)
203 config
= config_get(PW_NODE
, line
);
204 else if (strncmp(line
, "logical-router", strlen("ns")) == 0)
205 config
= config_get(LOGICALROUTER_NODE
, line
);
206 else if (strncmp(line
, "vrf", strlen("vrf")) == 0)
207 config
= config_get(VRF_NODE
, line
);
208 else if (strncmp(line
, "router-id", strlen("router-id")) == 0)
209 config
= config_get(ZEBRA_NODE
, line
);
210 else if (strncmp(line
, "router rip", strlen("router rip")) == 0)
211 config
= config_get(RIP_NODE
, line
);
212 else if (strncmp(line
, "router ripng", strlen("router ripng"))
214 config
= config_get(RIPNG_NODE
, line
);
215 else if (strncmp(line
, "router eigrp", strlen("router eigrp"))
217 config
= config_get(EIGRP_NODE
, line
);
218 else if (strncmp(line
, "router babel", strlen("router babel"))
220 config
= config_get(BABEL_NODE
, line
);
221 else if (strncmp(line
, "router ospf", strlen("router ospf"))
223 config
= config_get(OSPF_NODE
, line
);
224 else if (strncmp(line
, "router ospf6", strlen("router ospf6"))
226 config
= config_get(OSPF6_NODE
, line
);
227 else if (strncmp(line
, "mpls ldp", strlen("mpls ldp")) == 0)
228 config
= config_get(LDP_NODE
, line
);
229 else if (strncmp(line
, "l2vpn", strlen("l2vpn")) == 0)
230 config
= config_get(LDP_L2VPN_NODE
, line
);
231 else if (strncmp(line
, "router bgp", strlen("router bgp")) == 0)
232 config
= config_get(BGP_NODE
, line
);
233 else if (strncmp(line
, "router isis", strlen("router isis"))
235 config
= config_get(ISIS_NODE
, line
);
236 else if (strncmp(line
, "route-map", strlen("route-map")) == 0)
237 config
= config_get(RMAP_NODE
, line
);
238 else if (strncmp(line
, "access-list", strlen("access-list"))
240 config
= config_get(ACCESS_NODE
, line
);
241 else if (strncmp(line
, "ipv6 access-list",
242 strlen("ipv6 access-list"))
244 config
= config_get(ACCESS_IPV6_NODE
, line
);
245 else if (strncmp(line
, "mac access-list",
246 strlen("mac access-list"))
248 config
= config_get(ACCESS_MAC_NODE
, line
);
249 else if (strncmp(line
, "ip prefix-list",
250 strlen("ip prefix-list"))
252 config
= config_get(PREFIX_NODE
, line
);
253 else if (strncmp(line
, "ipv6 prefix-list",
254 strlen("ipv6 prefix-list"))
256 config
= config_get(PREFIX_IPV6_NODE
, line
);
257 else if (strncmp(line
, "ip as-path access-list",
258 strlen("ip as-path access-list"))
260 config
= config_get(AS_LIST_NODE
, line
);
261 else if (strncmp(line
, "ip community-list",
262 strlen("ip community-list"))
264 || strncmp(line
, "ip extcommunity-list",
265 strlen("ip extcommunity-list"))
267 || strncmp(line
, "ip large-community-list",
268 strlen("ip large-community-list"))
270 config
= config_get(COMMUNITY_LIST_NODE
, line
);
271 else if (strncmp(line
, "ip route", strlen("ip route")) == 0)
272 config
= config_get(IP_NODE
, line
);
273 else if (strncmp(line
, "ipv6 route", strlen("ipv6 route")) == 0)
274 config
= config_get(IP_NODE
, line
);
275 else if (strncmp(line
, "key", strlen("key")) == 0)
276 config
= config_get(KEYCHAIN_NODE
, line
);
277 else if (strncmp(line
, "line", strlen("line")) == 0)
278 config
= config_get(VTY_NODE
, line
);
279 else if ((strncmp(line
, "ipv6 forwarding",
280 strlen("ipv6 forwarding"))
282 || (strncmp(line
, "ip forwarding",
283 strlen("ip forwarding"))
285 config
= config_get(FORWARDING_NODE
, line
);
286 else if (strncmp(line
, "service", strlen("service")) == 0)
287 config
= config_get(SERVICE_NODE
, line
);
288 else if (strncmp(line
, "debug vrf", strlen("debug vrf")) == 0)
289 config
= config_get(VRF_DEBUG_NODE
, line
);
290 else if (strncmp(line
, "debug", strlen("debug")) == 0)
291 config
= config_get(DEBUG_NODE
, line
);
292 else if (strncmp(line
, "password", strlen("password")) == 0
293 || strncmp(line
, "enable password",
294 strlen("enable password"))
296 config
= config_get(AAA_NODE
, line
);
297 else if (strncmp(line
, "ip protocol", strlen("ip protocol"))
299 config
= config_get(PROTOCOL_NODE
, line
);
300 else if (strncmp(line
, "ipv6 protocol", strlen("ipv6 protocol"))
302 config
= config_get(PROTOCOL_NODE
, line
);
303 else if (strncmp(line
, "ip nht", strlen("ip nht")) == 0)
304 config
= config_get(PROTOCOL_NODE
, line
);
305 else if (strncmp(line
, "ipv6 nht", strlen("ipv6 nht")) == 0)
306 config
= config_get(PROTOCOL_NODE
, line
);
307 else if (strncmp(line
, "mpls", strlen("mpls")) == 0)
308 config
= config_get(MPLS_NODE
, line
);
310 if (strncmp(line
, "log", strlen("log")) == 0
311 || strncmp(line
, "hostname", strlen("hostname"))
313 || strncmp(line
, "frr", strlen("frr")) == 0
314 || strncmp(line
, "agentx", strlen("agentx")) == 0
315 || strncmp(line
, "no log", strlen("no log")) == 0)
316 config_add_line_uniq(config_top
, line
);
318 config_add_line(config_top
, line
);
325 /* Macro to check delimiter is needed between each configuration line
327 #define NO_DELIMITER(I) \
328 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
329 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
330 || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
331 || (I) == PREFIX_IPV6_NODE || (I) == SERVICE_NODE \
332 || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
333 || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
335 /* Display configuration to file pointer. */
336 void vtysh_config_dump(FILE *fp
)
338 struct listnode
*node
, *nnode
;
339 struct listnode
*mnode
, *mnnode
;
340 struct config
*config
;
345 for (ALL_LIST_ELEMENTS(config_top
, node
, nnode
, line
)) {
346 fprintf(fp
, "%s\n", line
);
352 for (i
= 0; i
< vector_active(configvec
); i
++)
353 if ((master
= vector_slot(configvec
, i
)) != NULL
) {
354 for (ALL_LIST_ELEMENTS(master
, node
, nnode
, config
)) {
355 /* Don't print empty sections for interface.
357 * other hand could have a legitimate empty
358 * section at the end.
359 * VRF is handled in the backend, we could have
360 * "configured" VRFs with static routes which
361 * are not under the VRF node.
363 if (config
->index
== INTERFACE_NODE
364 && list_isempty(config
->line
))
367 fprintf(fp
, "%s\n", config
->name
);
370 for (ALL_LIST_ELEMENTS(config
->line
, mnode
,
372 fprintf(fp
, "%s\n", line
);
375 if (!NO_DELIMITER(i
)) {
380 if (NO_DELIMITER(i
)) {
386 for (i
= 0; i
< vector_active(configvec
); i
++)
387 if ((master
= vector_slot(configvec
, i
)) != NULL
) {
388 list_delete_and_null(&master
);
389 vector_slot(configvec
, i
) = NULL
;
391 list_delete_all_node(config_top
);
394 /* Read up configuration file from file_name. */
395 static int vtysh_read_file(FILE *confp
)
401 vty
->fd
= 0; /* stdout */
402 vty
->type
= VTY_TERM
;
403 vty
->node
= CONFIG_NODE
;
405 vtysh_execute_no_pager("enable");
406 vtysh_execute_no_pager("configure terminal");
408 /* Execute configuration file. */
409 ret
= vtysh_config_from_file(vty
, confp
);
411 vtysh_execute_no_pager("end");
412 vtysh_execute_no_pager("disable");
419 /* Read up configuration file from config_default_dir. */
420 int vtysh_read_config(const char *config_default_dir
)
425 confp
= fopen(config_default_dir
, "r");
428 "%% Can't open configuration file %s due to '%s'.\n",
429 config_default_dir
, safe_strerror(errno
));
430 return (CMD_ERR_NO_FILE
);
433 ret
= vtysh_read_file(confp
);
439 /* We don't write vtysh specific into file from vtysh. vtysh.conf should
440 * be edited by hand. So, we handle only "write terminal" case here and
441 * integrate vtysh specific conf with conf from daemons.
443 void vtysh_config_write()
447 if (cmd_hostname_get()) {
448 sprintf(line
, "hostname %s", cmd_hostname_get());
449 vtysh_config_parse_line(NULL
, line
);
452 if (cmd_domainname_get()) {
453 sprintf(line
, "domainname %s", cmd_domainname_get());
454 vtysh_config_parse_line(NULL
, line
);
456 if (vtysh_write_integrated
== WRITE_INTEGRATED_NO
)
457 vtysh_config_parse_line(NULL
,
458 "no service integrated-vtysh-config");
459 if (vtysh_write_integrated
== WRITE_INTEGRATED_YES
)
460 vtysh_config_parse_line(NULL
,
461 "service integrated-vtysh-config");
466 void vtysh_config_init()
468 config_top
= list_new();
469 config_top
->del
= (void (*)(void *))line_del
;
470 configvec
= vector_init(1);