]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
lib, zebra: Add ability to encode/decode resilient nhg's
[mirror_frr.git] / vtysh / vtysh_config.c
CommitLineData
718e3744 1/* Configuration generator.
896014f4
DL
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 */
718e3744 20
21#include <zebra.h>
22
23#include "command.h"
24#include "linklist.h"
25#include "memory.h"
a7982412 26#include "typesafe.h"
718e3744 27
28#include "vtysh/vtysh.h"
88177fe3 29#include "vtysh/vtysh_user.h"
718e3744 30
bf8d3d6a
DL
31DEFINE_MGROUP(MVTYSH, "vtysh");
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration");
33DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line");
4a1ab8e4 34
718e3744 35vector configvec;
36
703dc64c 37PREDECL_LIST(config_master);
ece0e6ef 38PREDECL_HASH(config_master_hash);
a7982412 39
d62a17ae 40struct config {
41 /* Configuration node name. */
42 char *name;
718e3744 43
d62a17ae 44 /* Configuration string line. */
45 struct list *line;
718e3744 46
4b639f99
IR
47 /* Configuration can be nested. */
48 struct config *parent;
49 vector nested;
50
51 /* Exit command. */
52 char *exit;
718e3744 53
d62a17ae 54 /* Index of this config. */
d7c0a89a 55 uint32_t index;
a7982412
JW
56
57 /* Node entry for the typed Red-black tree */
58 struct config_master_item rbt_item;
ece0e6ef 59 struct config_master_hash_item hash_item;
718e3744 60};
61
62struct list *config_top;
95e735b5 63
d62a17ae 64static int line_cmp(char *c1, char *c2)
718e3744 65{
d62a17ae 66 return strcmp(c1, c2);
718e3744 67}
68
d62a17ae 69static void line_del(char *line)
718e3744 70{
d62a17ae 71 XFREE(MTYPE_VTYSH_CONFIG_LINE, line);
718e3744 72}
73
d62a17ae 74static struct config *config_new(void)
718e3744 75{
d62a17ae 76 struct config *config;
77 config = XCALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config));
78 return config;
718e3744 79}
80
d62a17ae 81static void config_del(struct config *config)
718e3744 82{
4b639f99 83 vector_free(config->nested);
6a154c88 84 list_delete(&config->line);
4b639f99
IR
85 if (config->exit)
86 XFREE(MTYPE_VTYSH_CONFIG_LINE, config->exit);
0a22ddfb 87 XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
d62a17ae 88 XFREE(MTYPE_VTYSH_CONFIG, config);
718e3744 89}
90
ece0e6ef
DS
91static int config_cmp(const struct config *c1, const struct config *c2)
92{
93 return strcmp(c1->name, c2->name);
94}
95
96static uint32_t config_hash(const struct config *c)
97{
98 return string_hash_make(c->name);
99}
100
960b9a53 101DECLARE_LIST(config_master, struct config, rbt_item);
ece0e6ef 102DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp,
960b9a53 103 config_hash);
ece0e6ef
DS
104
105/*
106 * The config_master_head is a list for order of receipt
107 * The hash is for quick lookup under this NODE
108 */
109struct configuration {
110 struct config_master_head master;
111 struct config_master_hash_head hash_master;
112};
a7982412 113
4b639f99 114static struct config *config_get_vec(vector vec, int index, const char *line)
718e3744 115{
703dc64c 116 struct config *config, *config_loop;
ece0e6ef
DS
117 struct configuration *configuration;
118 struct config lookup;
d62a17ae 119
703dc64c
DS
120 config = config_loop = NULL;
121
4b639f99 122 configuration = vector_lookup_ensure(vec, index);
d62a17ae 123
ece0e6ef
DS
124 if (!configuration) {
125 configuration = XMALLOC(MTYPE_VTYSH_CONFIG,
126 sizeof(struct configuration));
127 config_master_init(&configuration->master);
128 config_master_hash_init(&configuration->hash_master);
4b639f99 129 vector_set_index(vec, index, configuration);
d62a17ae 130 }
131
ece0e6ef
DS
132 lookup.name = (char *)line;
133 config = config_master_hash_find(&configuration->hash_master, &lookup);
d62a17ae 134
135 if (!config) {
136 config = config_new();
137 config->line = list_new();
138 config->line->del = (void (*)(void *))line_del;
139 config->line->cmp = (int (*)(void *, void *))line_cmp;
140 config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
4b639f99 141 config->exit = NULL;
d62a17ae 142 config->index = index;
4b639f99 143 config->nested = vector_init(1);
ece0e6ef
DS
144 config_master_add_tail(&configuration->master, config);
145 config_master_hash_add(&configuration->hash_master, config);
d62a17ae 146 }
147 return config;
718e3744 148}
149
4b639f99
IR
150static struct config *config_get(int index, const char *line)
151{
152 return config_get_vec(configvec, index, line);
153}
154
155static struct config *config_get_nested(struct config *parent, int index,
156 const char *line)
157{
158 struct config *config;
159
160 config = config_get_vec(parent->nested, index, line);
161 config->parent = parent;
162
163 return config;
164}
165
d62a17ae 166void config_add_line(struct list *config, const char *line)
718e3744 167{
d62a17ae 168 listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
718e3744 169}
170
d62a17ae 171static void config_add_line_uniq(struct list *config, const char *line)
718e3744 172{
d62a17ae 173 struct listnode *node, *nnode;
174 char *pnt;
175
176 for (ALL_LIST_ELEMENTS(config, node, nnode, pnt)) {
177 if (strcmp(pnt, line) == 0)
178 return;
179 }
180 listnode_add_sort(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
718e3744 181}
182
a3c1db5e 183/*
e8be380a
QY
184 * Add a line that should only be shown once, and always show at the end of the
185 * config block.
186 *
187 * If the line already exists, it will be moved to the end of the block. If it
188 * does not exist, it will be added at the end of the block.
189 *
190 * Note that this only makes sense when there is just one such line that should
191 * show up at the very end of a config block. Furthermore, if the same block
192 * can show up from multiple daemons, all of them must make sure to print the
193 * line at the end of their config, otherwise the line will show at the end of
194 * the config for the last daemon that printed it.
195 *
196 * Here is a motivating example with the 'exit-vrf' command. Suppose we receive
197 * a config from Zebra like so:
198 *
199 * vrf BLUE
200 * ip route A
201 * ip route B
202 * exit-vrf
203 *
204 * Then suppose we later receive this config from PIM:
205 *
206 * vrf BLUE
207 * ip msdp mesh-group MyGroup member 1.2.3.4
208 * exit-vrf
209 *
210 * Then we will combine them into one config block like so:
211 *
212 * vrf BLUE
213 * ip route A
214 * ip route B
215 * ip msdp mesh-group MyGroup member 1.2.3.4
216 * exit-vrf
217 *
218 * Because PIM also sent us an 'exit-vrf', we noticed that we already had one
219 * under the 'vrf BLUE' config block and so we moved it to the end of the
220 * config block again. If PIM had neglected to send us 'exit-vrf', the result
221 * would be this:
222 *
223 * vrf BLUE
224 * ip route A
225 * ip route B
226 * exit-vrf
227 * ip msdp mesh-group MyGroup member 1.2.3.4
228 *
229 * Therefore, daemons that share config blocks must take care to consistently
230 * print the same block terminators.
231 *
232 * Ideally this would be solved by adding a string to struct config that is
233 * always printed at the end when dumping a config. However, this would only
234 * work when the user is using integrated config. In the non-integrated config
235 * case, daemons are responsible for writing their own config files, and so the
236 * must be able to print these blocks correctly independently of vtysh, which
237 * means they are the ones that need to handle printing the block terminators
238 * and VTYSH needs to be smart enough to combine them properly.
239 *
240 * ---
241 *
242 * config
243 * The config to add the line to
244 *
245 * line
246 * The line to add to the end of the config
a3c1db5e 247 */
e8be380a 248static void config_add_line_uniq_end(struct list *config, const char *line)
a3c1db5e
DS
249{
250 struct listnode *node;
e8be380a 251 char *pnt;
a3c1db5e 252
e8be380a
QY
253 for (ALL_LIST_ELEMENTS_RO(config, node, pnt)) {
254 if (strcmp(pnt, line) == 0)
255 break;
256 }
257
258 if (!node)
259 config_add_line(config, line);
260 else
a3c1db5e
DS
261 listnode_move_to_tail(config, node);
262}
263
d62a17ae 264void vtysh_config_parse_line(void *arg, const char *line)
718e3744 265{
d62a17ae 266 char c;
267 static struct config *config = NULL;
268
269 if (!line)
270 return;
271
272 c = line[0];
273
274 if (c == '\0')
275 return;
276
d62a17ae 277 switch (c) {
278 /* Suppress exclamation points ! and commented lines. The !s are
279 * generated
280 * dynamically in vtysh_config_dump() */
281 case '!':
282 case '#':
283 break;
284 case ' ':
285 /* Store line to current configuration. */
286 if (config) {
4b639f99
IR
287 if (config->index == KEYCHAIN_NODE
288 && strncmp(line, " key", strlen(" key")) == 0) {
289 config = config_get_nested(
290 config, KEYCHAIN_KEY_NODE, line);
291 } else if (config->index == KEYCHAIN_KEY_NODE) {
292 if (strncmp(line, " exit", strlen(" exit"))
293 == 0) {
294 config_add_line_uniq_end(config->line,
295 line);
296 config = config->parent;
297 } else {
298 config_add_line_uniq(config->line,
299 line);
300 }
301 } else if (strncmp(line, " link-params",
302 strlen(" link-params"))
303 == 0) {
d62a17ae 304 config_add_line(config->line, line);
305 config->index = LINK_PARAMS_NODE;
996c9314
LB
306 } else if (strncmp(line, " ip multicast boundary",
307 strlen(" ip multicast boundary"))
308 == 0) {
e8be380a 309 config_add_line_uniq_end(config->line, line);
61a7a236 310 } else if (strncmp(line, " ip igmp query-interval",
4b639f99
IR
311 strlen(" ip igmp query-interval"))
312 == 0) {
e8be380a 313 config_add_line_uniq_end(config->line, line);
d62a17ae 314 } else if (config->index == LINK_PARAMS_NODE
07679ad9
IR
315 && strncmp(line, " exit-link-params",
316 strlen(" exit"))
d62a17ae 317 == 0) {
318 config_add_line(config->line, line);
319 config->index = INTERFACE_NODE;
18ca2e1f
QY
320 } else if (!strncmp(line, " vrrp", strlen(" vrrp"))
321 || !strncmp(line, " no vrrp",
322 strlen(" no vrrp"))) {
323 config_add_line(config->line, line);
4b639f99
IR
324 } else if (!strncmp(line, " ip mroute",
325 strlen(" ip mroute"))) {
c552f61e 326 config_add_line_uniq_end(config->line, line);
d62a17ae 327 } else if (config->index == RMAP_NODE
328 || config->index == INTERFACE_NODE
d62a17ae 329 || config->index == VTY_NODE
3741c4ba 330 || config->index == NH_GROUP_NODE)
d62a17ae 331 config_add_line_uniq(config->line, line);
1d4cfa5d 332 else
d62a17ae 333 config_add_line(config->line, line);
334 } else
335 config_add_line(config_top, line);
336 break;
337 default:
07679ad9
IR
338 if (strncmp(line, "exit", strlen("exit")) == 0) {
339 if (config)
4b639f99
IR
340 config->exit =
341 XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
07679ad9 342 } else if (strncmp(line, "interface", strlen("interface")) == 0)
d62a17ae 343 config = config_get(INTERFACE_NODE, line);
2dd0d726
RW
344 else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
345 config = config_get(PW_NODE, line);
d62a17ae 346 else if (strncmp(line, "vrf", strlen("vrf")) == 0)
347 config = config_get(VRF_NODE, line);
e5c83d9b
DS
348 else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
349 == 0)
350 config = config_get(NH_GROUP_NODE, line);
d62a17ae 351 else if (strncmp(line, "router-id", strlen("router-id")) == 0)
352 config = config_get(ZEBRA_NODE, line);
353 else if (strncmp(line, "router rip", strlen("router rip")) == 0)
354 config = config_get(RIP_NODE, line);
355 else if (strncmp(line, "router ripng", strlen("router ripng"))
356 == 0)
357 config = config_get(RIPNG_NODE, line);
358 else if (strncmp(line, "router eigrp", strlen("router eigrp"))
359 == 0)
360 config = config_get(EIGRP_NODE, line);
361 else if (strncmp(line, "router babel", strlen("router babel"))
362 == 0)
363 config = config_get(BABEL_NODE, line);
364 else if (strncmp(line, "router ospf", strlen("router ospf"))
365 == 0)
366 config = config_get(OSPF_NODE, line);
367 else if (strncmp(line, "router ospf6", strlen("router ospf6"))
368 == 0)
369 config = config_get(OSPF6_NODE, line);
370 else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
371 config = config_get(LDP_NODE, line);
372 else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
373 config = config_get(LDP_L2VPN_NODE, line);
374 else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
375 config = config_get(BGP_NODE, line);
376 else if (strncmp(line, "router isis", strlen("router isis"))
377 == 0)
378 config = config_get(ISIS_NODE, line);
770ccdf8
CF
379 else if (strncmp(line, "router openfabric", strlen("router openfabric"))
380 == 0)
381 config = config_get(OPENFABRIC_NODE, line);
d62a17ae 382 else if (strncmp(line, "route-map", strlen("route-map")) == 0)
383 config = config_get(RMAP_NODE, line);
38133c4a
IR
384 else if (strncmp(line, "no route-map", strlen("no route-map"))
385 == 0)
386 config = config_get(RMAP_NODE, line);
e5c83d9b
DS
387 else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
388 config = config_get(PBRMAP_NODE, line);
d62a17ae 389 else if (strncmp(line, "access-list", strlen("access-list"))
390 == 0)
391 config = config_get(ACCESS_NODE, line);
392 else if (strncmp(line, "ipv6 access-list",
393 strlen("ipv6 access-list"))
394 == 0)
395 config = config_get(ACCESS_IPV6_NODE, line);
d37ba549
MK
396 else if (strncmp(line, "mac access-list",
397 strlen("mac access-list"))
398 == 0)
399 config = config_get(ACCESS_MAC_NODE, line);
d62a17ae 400 else if (strncmp(line, "ip prefix-list",
401 strlen("ip prefix-list"))
402 == 0)
403 config = config_get(PREFIX_NODE, line);
404 else if (strncmp(line, "ipv6 prefix-list",
405 strlen("ipv6 prefix-list"))
406 == 0)
407 config = config_get(PREFIX_IPV6_NODE, line);
7336e101
SP
408 else if (strncmp(line, "bgp as-path access-list",
409 strlen("bgp as-path access-list"))
d62a17ae 410 == 0)
411 config = config_get(AS_LIST_NODE, line);
7336e101
SP
412 else if (strncmp(line, "bgp community-list",
413 strlen("bgp community-list"))
d62a17ae 414 == 0
7336e101
SP
415 || strncmp(line, "bgp extcommunity-list",
416 strlen("bgp extcommunity-list"))
996c9314 417 == 0
7336e101
SP
418 || strncmp(line, "bgp large-community-list",
419 strlen("bgp large-community-list"))
996c9314 420 == 0)
d62a17ae 421 config = config_get(COMMUNITY_LIST_NODE, line);
ed0e57e3
DA
422 else if (strncmp(line, "bgp community alias",
423 strlen("bgp community alias")) == 0)
424 config = config_get(COMMUNITY_ALIAS_NODE, line);
d62a17ae 425 else if (strncmp(line, "ip route", strlen("ip route")) == 0)
426 config = config_get(IP_NODE, line);
427 else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
428 config = config_get(IP_NODE, line);
429 else if (strncmp(line, "key", strlen("key")) == 0)
430 config = config_get(KEYCHAIN_NODE, line);
431 else if (strncmp(line, "line", strlen("line")) == 0)
432 config = config_get(VTY_NODE, line);
433 else if ((strncmp(line, "ipv6 forwarding",
434 strlen("ipv6 forwarding"))
435 == 0)
436 || (strncmp(line, "ip forwarding",
437 strlen("ip forwarding"))
438 == 0))
439 config = config_get(FORWARDING_NODE, line);
d62a17ae 440 else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
441 config = config_get(VRF_DEBUG_NODE, line);
1c2facd1
RW
442 else if (strncmp(line, "debug northbound",
443 strlen("debug northbound"))
444 == 0)
445 config = config_get(NORTHBOUND_DEBUG_NODE, line);
e3ab8170
AD
446 else if (strncmp(line, "debug route-map",
447 strlen("debug route-map"))
448 == 0)
449 config = config_get(RMAP_DEBUG_NODE, line);
fe9e7b71
DL
450 else if (strncmp(line, "debug resolver",
451 strlen("debug resolver")) == 0)
452 config = config_get(RESOLVER_DEBUG_NODE, line);
d62a17ae 453 else if (strncmp(line, "debug", strlen("debug")) == 0)
454 config = config_get(DEBUG_NODE, line);
455 else if (strncmp(line, "password", strlen("password")) == 0
456 || strncmp(line, "enable password",
457 strlen("enable password"))
458 == 0)
459 config = config_get(AAA_NODE, line);
460 else if (strncmp(line, "ip protocol", strlen("ip protocol"))
461 == 0)
462 config = config_get(PROTOCOL_NODE, line);
463 else if (strncmp(line, "ipv6 protocol", strlen("ipv6 protocol"))
464 == 0)
465 config = config_get(PROTOCOL_NODE, line);
466 else if (strncmp(line, "ip nht", strlen("ip nht")) == 0)
467 config = config_get(PROTOCOL_NODE, line);
468 else if (strncmp(line, "ipv6 nht", strlen("ipv6 nht")) == 0)
469 config = config_get(PROTOCOL_NODE, line);
470 else if (strncmp(line, "mpls", strlen("mpls")) == 0)
471 config = config_get(MPLS_NODE, line);
6c0a7c09
HS
472 else if (strncmp(line, "segment-routing",
473 strlen("segment-routing"))
474 == 0)
475 config = config_get(SEGMENT_ROUTING_NODE, line);
c2f29cf3
RZ
476 else if (strncmp(line, "bfd", strlen("bfd")) == 0)
477 config = config_get(BFD_NODE, line);
eebb8260
IR
478 else if (strncmp(line, "rpki", strlen("rpki")) == 0)
479 config = config_get(RPKI_NODE, line);
d62a17ae 480 else {
ac156aec
DA
481 if (strncmp(line, "log", strlen("log")) == 0 ||
482 strncmp(line, "hostname", strlen("hostname")) ==
483 0 ||
484 strncmp(line, "domainname", strlen("domainname")) ==
485 0 ||
ac67c0e4
DA
486 strncmp(line, "allow-reserved-ranges",
487 strlen("allow-reserved-ranges")) == 0 ||
ac156aec
DA
488 strncmp(line, "frr", strlen("frr")) == 0 ||
489 strncmp(line, "agentx", strlen("agentx")) == 0 ||
490 strncmp(line, "no log", strlen("no log")) == 0 ||
491 strncmp(line, "no ip prefix-list",
492 strlen("no ip prefix-list")) == 0 ||
493 strncmp(line, "no ipv6 prefix-list",
54b7d471 494 strlen("no ipv6 prefix-list")) == 0 ||
f531fae8
DS
495 strncmp(line, "service ", strlen("service ")) ==
496 0 ||
54b7d471 497 strncmp(line, "no service cputime-stats",
17c149ff
DS
498 strlen("no service cputime-stats")) == 0 ||
499 strncmp(line, "service cputime-warning",
500 strlen("service cputime-warning")) == 0)
d62a17ae 501 config_add_line_uniq(config_top, line);
502 else
503 config_add_line(config_top, line);
504 config = NULL;
505 }
506 break;
718e3744 507 }
718e3744 508}
509
718e3744 510/* Macro to check delimiter is needed between each configuration line
95e735b5 511 * or not. */
d62a17ae 512#define NO_DELIMITER(I) \
513 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
514 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
ed0e57e3
DA
515 || (I) == COMMUNITY_ALIAS_NODE || (I) == ACCESS_IPV6_NODE \
516 || (I) == ACCESS_MAC_NODE || (I) == PREFIX_IPV6_NODE \
517 || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
518 || (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \
519 || (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \
4b639f99 520 || (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE)
718e3744 521
4b639f99 522static void configvec_dump(vector vec, bool nested)
718e3744 523{
d62a17ae 524 struct listnode *mnode, *mnnode;
525 struct config *config;
ece0e6ef 526 struct configuration *configuration;
d62a17ae 527 char *line;
528 unsigned int i;
529
4b639f99
IR
530 for (i = 0; i < vector_active(vec); i++)
531 if ((configuration = vector_slot(vec, i)) != NULL) {
ece0e6ef
DS
532 while ((config = config_master_pop(
533 &configuration->master))) {
534 config_master_hash_del(
535 &configuration->hash_master, config);
1d72e48a 536 /* Don't print empty sections for interface.
d62a17ae 537 * Route maps on the
538 * other hand could have a legitimate empty
539 * section at the end.
1d72e48a 540 * VRF is handled in the backend, we could have
541 * "configured" VRFs with static routes which
542 * are not under the VRF node.
d62a17ae 543 */
1d72e48a 544 if (config->index == INTERFACE_NODE
07679ad9
IR
545 && (listcount(config->line) == 1)
546 && (line = listnode_head(config->line))
547 && strmatch(line, "exit")) {
40ab4111 548 config_del(config);
d62a17ae 549 continue;
40ab4111 550 }
d62a17ae 551
2cddf2ff 552 vty_out(vty, "%s\n", config->name);
d62a17ae 553
554 for (ALL_LIST_ELEMENTS(config->line, mnode,
2cddf2ff
QY
555 mnnode, line))
556 vty_out(vty, "%s\n", line);
4b639f99
IR
557
558 configvec_dump(config->nested, true);
559
560 if (config->exit)
561 vty_out(vty, "%s\n", config->exit);
562
2cddf2ff
QY
563 if (!NO_DELIMITER(i))
564 vty_out(vty, "!\n");
a7982412
JW
565
566 config_del(config);
d62a17ae 567 }
ece0e6ef
DS
568 config_master_fini(&configuration->master);
569 config_master_hash_fini(&configuration->hash_master);
570 XFREE(MTYPE_VTYSH_CONFIG, configuration);
4b639f99
IR
571 vector_slot(vec, i) = NULL;
572 if (!nested && NO_DELIMITER(i))
573 vty_out(vty, "!\n");
d62a17ae 574 }
4b639f99
IR
575}
576
577void vtysh_config_dump(void)
578{
579 struct listnode *node, *nnode;
580 char *line;
581
582 for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
583 vty_out(vty, "%s\n", line);
584
d62a17ae 585 list_delete_all_node(config_top);
4b639f99
IR
586
587 vty_out(vty, "!\n");
588
589 configvec_dump(configvec, false);
718e3744 590}
591
592/* Read up configuration file from file_name. */
77f7b4b0 593static int vtysh_read_file(FILE *confp, bool dry_run)
718e3744 594{
d62a17ae 595 struct vty *vty;
596 int ret;
597
598 vty = vty_new();
4a9746fd 599 vty->wfd = STDERR_FILENO;
d62a17ae 600 vty->type = VTY_TERM;
601 vty->node = CONFIG_NODE;
718e3744 602
d62a17ae 603 vtysh_execute_no_pager("enable");
604 vtysh_execute_no_pager("configure terminal");
718e3744 605
77f7b4b0
DS
606 if (!dry_run)
607 vtysh_execute_no_pager("XFRR_start_configuration");
f8e6ada8 608
d62a17ae 609 /* Execute configuration file. */
610 ret = vtysh_config_from_file(vty, confp);
718e3744 611
77f7b4b0
DS
612 if (!dry_run)
613 vtysh_execute_no_pager("XFRR_end_configuration");
f8e6ada8 614
d62a17ae 615 vtysh_execute_no_pager("end");
616 vtysh_execute_no_pager("disable");
718e3744 617
d62a17ae 618 vty_close(vty);
3221dca8 619
d62a17ae 620 return (ret);
718e3744 621}
622
e7168df4 623/* Read up configuration file from config_default_dir. */
77f7b4b0 624int vtysh_read_config(const char *config_default_dir, bool dry_run)
718e3744 625{
d62a17ae 626 FILE *confp = NULL;
744bc17d 627 bool save;
d62a17ae 628 int ret;
629
630 confp = fopen(config_default_dir, "r");
631 if (confp == NULL) {
632 fprintf(stderr,
633 "%% Can't open configuration file %s due to '%s'.\n",
634 config_default_dir, safe_strerror(errno));
95f7965d 635 return CMD_ERR_NO_FILE;
d62a17ae 636 }
67e29abc 637
744bc17d
CH
638 save = vtysh_add_timestamp;
639 vtysh_add_timestamp = false;
640
77f7b4b0 641 ret = vtysh_read_file(confp, dry_run);
d62a17ae 642 fclose(confp);
718e3744 643
744bc17d
CH
644 vtysh_add_timestamp = save;
645
d62a17ae 646 return (ret);
718e3744 647}
648
e7168df4 649/* We don't write vtysh specific into file from vtysh. vtysh.conf should
650 * be edited by hand. So, we handle only "write terminal" case here and
651 * integrate vtysh specific conf with conf from daemons.
652 */
4d762f26 653void vtysh_config_write(void)
718e3744 654{
36d223bb 655 const char *name;
63e653a2 656 char line[512];
d62a17ae 657
36d223bb
NB
658 name = cmd_hostname_get();
659 if (name && name[0] != '\0') {
660 snprintf(line, sizeof(line), "hostname %s", name);
d62a17ae 661 vtysh_config_parse_line(NULL, line);
662 }
3b103fec 663
36d223bb
NB
664 name = cmd_domainname_get();
665 if (name && name[0] != '\0') {
666 snprintf(line, sizeof(line), "domainname %s", name);
3b103fec
MK
667 vtysh_config_parse_line(NULL, line);
668 }
36d223bb 669
d62a17ae 670 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
671 vtysh_config_parse_line(NULL,
672 "no service integrated-vtysh-config");
673 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
674 vtysh_config_parse_line(NULL,
675 "service integrated-vtysh-config");
676
677 user_config_write();
718e3744 678}
679
4d762f26 680void vtysh_config_init(void)
718e3744 681{
d62a17ae 682 config_top = list_new();
683 config_top->del = (void (*)(void *))line_del;
684 configvec = vector_init(1);
718e3744 685}