]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
Merge pull request #1244 from donaldsharp/flush_routes
[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"
26
27#include "vtysh/vtysh.h"
88177fe3 28#include "vtysh/vtysh_user.h"
718e3744 29
4a1ab8e4 30DEFINE_MGROUP(MVTYSH, "vtysh")
d62a17ae 31DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
4a1ab8e4
DL
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
33
718e3744 34vector configvec;
35
d62a17ae 36struct config {
37 /* Configuration node name. */
38 char *name;
718e3744 39
d62a17ae 40 /* Configuration string line. */
41 struct list *line;
718e3744 42
d62a17ae 43 /* Configuration can be nest. */
44 struct config *config;
718e3744 45
d62a17ae 46 /* Index of this config. */
47 u_int32_t index;
718e3744 48};
49
50struct list *config_top;
95e735b5 51
d62a17ae 52static int line_cmp(char *c1, char *c2)
718e3744 53{
d62a17ae 54 return strcmp(c1, c2);
718e3744 55}
56
d62a17ae 57static void line_del(char *line)
718e3744 58{
d62a17ae 59 XFREE(MTYPE_VTYSH_CONFIG_LINE, line);
718e3744 60}
61
d62a17ae 62static struct config *config_new(void)
718e3744 63{
d62a17ae 64 struct config *config;
65 config = XCALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config));
66 return config;
718e3744 67}
68
d62a17ae 69static int config_cmp(struct config *c1, struct config *c2)
718e3744 70{
d62a17ae 71 return strcmp(c1->name, c2->name);
718e3744 72}
73
d62a17ae 74static void config_del(struct config *config)
718e3744 75{
d62a17ae 76 list_delete(config->line);
77 if (config->name)
78 XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
79 XFREE(MTYPE_VTYSH_CONFIG, config);
718e3744 80}
81
d62a17ae 82static struct config *config_get(int index, const char *line)
718e3744 83{
d62a17ae 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;
718e3744 115}
116
d62a17ae 117void config_add_line(struct list *config, const char *line)
718e3744 118{
d62a17ae 119 listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
718e3744 120}
121
d62a17ae 122static void config_add_line_uniq(struct list *config, const char *line)
718e3744 123{
d62a17ae 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));
718e3744 132}
133
d62a17ae 134void vtysh_config_parse_line(void *arg, const char *line)
718e3744 135{
d62a17ae 136 char c;
137 static struct config *config = NULL;
138
139 if (!line)
140 return;
141
142 c = line[0];
143
144 if (c == '\0')
145 return;
146
147 /* printf ("[%s]\n", line); */
148
149 switch (c) {
150 /* Suppress exclamation points ! and commented lines. The !s are
151 * generated
152 * dynamically in vtysh_config_dump() */
153 case '!':
154 case '#':
155 break;
156 case ' ':
157 /* Store line to current configuration. */
158 if (config) {
159 if (strncmp(line, " link-params",
160 strlen(" link-params"))
161 == 0) {
162 config_add_line(config->line, line);
163 config->index = LINK_PARAMS_NODE;
164 } else if (config->index == LINK_PARAMS_NODE
165 && strncmp(line, " exit-link-params",
166 strlen(" exit"))
167 == 0) {
168 config_add_line(config->line, line);
169 config->index = INTERFACE_NODE;
170 } else if (config->index == RMAP_NODE
171 || config->index == INTERFACE_NODE
172 || config->index == NS_NODE
173 || config->index == VTY_NODE
174 || config->index == VRF_NODE)
175 config_add_line_uniq(config->line, line);
176 else
177 config_add_line(config->line, line);
178 } else
179 config_add_line(config_top, line);
180 break;
181 default:
182 if (strncmp(line, "interface", strlen("interface")) == 0)
183 config = config_get(INTERFACE_NODE, line);
2dd0d726
RW
184 else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
185 config = config_get(PW_NODE, line);
d62a17ae 186 else if (strncmp(line, "logical-router", strlen("ns")) == 0)
187 config = config_get(NS_NODE, line);
188 else if (strncmp(line, "vrf", strlen("vrf")) == 0)
189 config = config_get(VRF_NODE, line);
190 else if (strncmp(line, "router-id", strlen("router-id")) == 0)
191 config = config_get(ZEBRA_NODE, line);
192 else if (strncmp(line, "router rip", strlen("router rip")) == 0)
193 config = config_get(RIP_NODE, line);
194 else if (strncmp(line, "router ripng", strlen("router ripng"))
195 == 0)
196 config = config_get(RIPNG_NODE, line);
197 else if (strncmp(line, "router eigrp", strlen("router eigrp"))
198 == 0)
199 config = config_get(EIGRP_NODE, line);
200 else if (strncmp(line, "router babel", strlen("router babel"))
201 == 0)
202 config = config_get(BABEL_NODE, line);
203 else if (strncmp(line, "router ospf", strlen("router ospf"))
204 == 0)
205 config = config_get(OSPF_NODE, line);
206 else if (strncmp(line, "router ospf6", strlen("router ospf6"))
207 == 0)
208 config = config_get(OSPF6_NODE, line);
209 else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
210 config = config_get(LDP_NODE, line);
211 else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
212 config = config_get(LDP_L2VPN_NODE, line);
213 else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
214 config = config_get(BGP_NODE, line);
215 else if (strncmp(line, "router isis", strlen("router isis"))
216 == 0)
217 config = config_get(ISIS_NODE, line);
218 else if (strncmp(line, "route-map", strlen("route-map")) == 0)
219 config = config_get(RMAP_NODE, line);
220 else if (strncmp(line, "access-list", strlen("access-list"))
221 == 0)
222 config = config_get(ACCESS_NODE, line);
223 else if (strncmp(line, "ipv6 access-list",
224 strlen("ipv6 access-list"))
225 == 0)
226 config = config_get(ACCESS_IPV6_NODE, line);
d37ba549
MK
227 else if (strncmp(line, "mac access-list",
228 strlen("mac access-list"))
229 == 0)
230 config = config_get(ACCESS_MAC_NODE, line);
d62a17ae 231 else if (strncmp(line, "ip prefix-list",
232 strlen("ip prefix-list"))
233 == 0)
234 config = config_get(PREFIX_NODE, line);
235 else if (strncmp(line, "ipv6 prefix-list",
236 strlen("ipv6 prefix-list"))
237 == 0)
238 config = config_get(PREFIX_IPV6_NODE, line);
239 else if (strncmp(line, "ip as-path access-list",
240 strlen("ip as-path access-list"))
241 == 0)
242 config = config_get(AS_LIST_NODE, line);
243 else if (strncmp(line, "ip community-list",
244 strlen("ip community-list"))
245 == 0
246 || strncmp(line, "ip extcommunity-list",
247 strlen("ip extcommunity-list"))
344d9016
NK
248 == 0
249 || strncmp(line, "ip large-community-list",
250 strlen("ip large-community-list"))
251 == 0)
d62a17ae 252 config = config_get(COMMUNITY_LIST_NODE, line);
253 else if (strncmp(line, "ip route", strlen("ip route")) == 0)
254 config = config_get(IP_NODE, line);
255 else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
256 config = config_get(IP_NODE, line);
257 else if (strncmp(line, "key", strlen("key")) == 0)
258 config = config_get(KEYCHAIN_NODE, line);
259 else if (strncmp(line, "line", strlen("line")) == 0)
260 config = config_get(VTY_NODE, line);
261 else if ((strncmp(line, "ipv6 forwarding",
262 strlen("ipv6 forwarding"))
263 == 0)
264 || (strncmp(line, "ip forwarding",
265 strlen("ip forwarding"))
266 == 0))
267 config = config_get(FORWARDING_NODE, line);
268 else if (strncmp(line, "service", strlen("service")) == 0)
269 config = config_get(SERVICE_NODE, line);
270 else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
271 config = config_get(VRF_DEBUG_NODE, line);
272 else if (strncmp(line, "debug", strlen("debug")) == 0)
273 config = config_get(DEBUG_NODE, line);
274 else if (strncmp(line, "password", strlen("password")) == 0
275 || strncmp(line, "enable password",
276 strlen("enable password"))
277 == 0)
278 config = config_get(AAA_NODE, line);
279 else if (strncmp(line, "ip protocol", strlen("ip protocol"))
280 == 0)
281 config = config_get(PROTOCOL_NODE, line);
282 else if (strncmp(line, "ipv6 protocol", strlen("ipv6 protocol"))
283 == 0)
284 config = config_get(PROTOCOL_NODE, line);
285 else if (strncmp(line, "ip nht", strlen("ip nht")) == 0)
286 config = config_get(PROTOCOL_NODE, line);
287 else if (strncmp(line, "ipv6 nht", strlen("ipv6 nht")) == 0)
288 config = config_get(PROTOCOL_NODE, line);
289 else if (strncmp(line, "mpls", strlen("mpls")) == 0)
290 config = config_get(MPLS_NODE, line);
291 else {
292 if (strncmp(line, "log", strlen("log")) == 0
293 || strncmp(line, "hostname", strlen("hostname"))
294 == 0
295 || strncmp(line, "frr", strlen("frr")) == 0
296 || strncmp(line, "agentx", strlen("agentx")) == 0
297 || strncmp(line, "no log", strlen("no log")) == 0)
298 config_add_line_uniq(config_top, line);
299 else
300 config_add_line(config_top, line);
301 config = NULL;
302 }
303 break;
718e3744 304 }
718e3744 305}
306
718e3744 307/* Macro to check delimiter is needed between each configuration line
95e735b5 308 * or not. */
d62a17ae 309#define NO_DELIMITER(I) \
310 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
311 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
d37ba549
MK
312 || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
313 || (I) == PREFIX_IPV6_NODE || (I) == SERVICE_NODE \
314 || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
315 || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
718e3744 316
95e735b5 317/* Display configuration to file pointer. */
d62a17ae 318void vtysh_config_dump(FILE *fp)
718e3744 319{
d62a17ae 320 struct listnode *node, *nnode;
321 struct listnode *mnode, *mnnode;
322 struct config *config;
323 struct list *master;
324 char *line;
325 unsigned int i;
326
327 for (ALL_LIST_ELEMENTS(config_top, node, nnode, line)) {
328 fprintf(fp, "%s\n", line);
329 fflush(fp);
330 }
331 fprintf(fp, "!\n");
332 fflush(fp);
333
334 for (i = 0; i < vector_active(configvec); i++)
335 if ((master = vector_slot(configvec, i)) != NULL) {
336 for (ALL_LIST_ELEMENTS(master, node, nnode, config)) {
337 /* Don't print empty sections for interface/vrf.
338 * Route maps on the
339 * other hand could have a legitimate empty
340 * section at the end.
341 */
342 if ((config->index == INTERFACE_NODE
343 || config->index == VRF_NODE)
344 && list_isempty(config->line))
345 continue;
346
347 fprintf(fp, "%s\n", config->name);
348 fflush(fp);
349
350 for (ALL_LIST_ELEMENTS(config->line, mnode,
351 mnnode, line)) {
352 fprintf(fp, "%s\n", line);
353 fflush(fp);
354 }
355 if (!NO_DELIMITER(i)) {
356 fprintf(fp, "!\n");
357 fflush(fp);
358 }
359 }
360 if (NO_DELIMITER(i)) {
361 fprintf(fp, "!\n");
362 fflush(fp);
363 }
364 }
365
366 for (i = 0; i < vector_active(configvec); i++)
367 if ((master = vector_slot(configvec, i)) != NULL) {
368 list_delete(master);
369 vector_slot(configvec, i) = NULL;
370 }
371 list_delete_all_node(config_top);
718e3744 372}
373
374/* Read up configuration file from file_name. */
d62a17ae 375static int vtysh_read_file(FILE *confp)
718e3744 376{
d62a17ae 377 struct vty *vty;
378 int ret;
379
380 vty = vty_new();
381 vty->fd = 0; /* stdout */
382 vty->type = VTY_TERM;
383 vty->node = CONFIG_NODE;
718e3744 384
d62a17ae 385 vtysh_execute_no_pager("enable");
386 vtysh_execute_no_pager("configure terminal");
718e3744 387
d62a17ae 388 /* Execute configuration file. */
389 ret = vtysh_config_from_file(vty, confp);
718e3744 390
d62a17ae 391 vtysh_execute_no_pager("end");
392 vtysh_execute_no_pager("disable");
718e3744 393
d62a17ae 394 vty_close(vty);
3221dca8 395
d62a17ae 396 return (ret);
718e3744 397}
398
e7168df4 399/* Read up configuration file from config_default_dir. */
d62a17ae 400int vtysh_read_config(const char *config_default_dir)
718e3744 401{
d62a17ae 402 FILE *confp = NULL;
403 int ret;
404
405 confp = fopen(config_default_dir, "r");
406 if (confp == NULL) {
407 fprintf(stderr,
408 "%% Can't open configuration file %s due to '%s'.\n",
409 config_default_dir, safe_strerror(errno));
410 return (CMD_ERR_NO_FILE);
411 }
67e29abc 412
d62a17ae 413 ret = vtysh_read_file(confp);
414 fclose(confp);
718e3744 415
d62a17ae 416 return (ret);
718e3744 417}
418
e7168df4 419/* We don't write vtysh specific into file from vtysh. vtysh.conf should
420 * be edited by hand. So, we handle only "write terminal" case here and
421 * integrate vtysh specific conf with conf from daemons.
422 */
d62a17ae 423void vtysh_config_write()
718e3744 424{
d62a17ae 425 char line[81];
d62a17ae 426
6b3ee3a0
MK
427 if (cmd_hostname_get()) {
428 sprintf(line, "hostname %s", cmd_hostname_get());
d62a17ae 429 vtysh_config_parse_line(NULL, line);
430 }
431 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
432 vtysh_config_parse_line(NULL,
433 "no service integrated-vtysh-config");
434 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
435 vtysh_config_parse_line(NULL,
436 "service integrated-vtysh-config");
437
438 user_config_write();
718e3744 439}
440
d62a17ae 441void vtysh_config_init()
718e3744 442{
d62a17ae 443 config_top = list_new();
444 config_top->del = (void (*)(void *))line_del;
445 configvec = vector_init(1);
718e3744 446}