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