]> git.proxmox.com Git - mirror_frr.git/blob - vtysh/vtysh.c
lib: Fix memory leak in in Link State
[mirror_frr.git] / vtysh / vtysh.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Virtual terminal interface shell.
3 * Copyright (C) 2000 Kunihiro Ishiguro
4 */
5
6 #include <zebra.h>
7
8 #include <sys/un.h>
9 #include <setjmp.h>
10 #include <sys/wait.h>
11 #include <sys/resource.h>
12 #include <sys/stat.h>
13
14 /* readline carries some ancient definitions around */
15 #pragma GCC diagnostic push
16 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
17 #include <readline/readline.h>
18 #include <readline/history.h>
19 #pragma GCC diagnostic pop
20
21 #include <dirent.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "linklist.h"
26 #include "command.h"
27 #include "memory.h"
28 #include "network.h"
29 #include "filter.h"
30 #include "vtysh/vtysh.h"
31 #include "vtysh/vtysh_daemons.h"
32 #include "log.h"
33 #include "vrf.h"
34 #include "libfrr.h"
35 #include "command_graph.h"
36 #include "frrstr.h"
37 #include "json.h"
38 #include "ferr.h"
39 #include "bgpd/bgp_vty.h"
40
41 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy");
42
43 /* Struct VTY. */
44 struct vty *vty;
45
46 /* VTY shell pager name. */
47 char *vtysh_pager_name = NULL;
48
49 /* VTY should add timestamp */
50 bool vtysh_add_timestamp;
51
52 static bool stderr_tty;
53 static bool stderr_stdout_same;
54
55 /* Some utility functions for working on vtysh-specific vty tasks */
56
57 static FILE *vty_open_pager(struct vty *vty)
58 {
59 if (vty->is_paged)
60 return vty->of;
61
62 if (!vtysh_pager_name)
63 return NULL;
64
65 vty->of_saved = vty->of;
66 vty->of = popen(vtysh_pager_name, "w");
67 if (vty->of == NULL) {
68 vty->of = vty->of_saved;
69 perror("popen");
70 exit(1);
71 }
72
73 vty->is_paged = true;
74
75 return vty->of;
76 }
77
78 static int vty_close_pager(struct vty *vty)
79 {
80 if (!vty->is_paged)
81 return 0;
82
83 fflush(vty->of);
84 if (pclose(vty->of) == -1) {
85 perror("pclose");
86 exit(1);
87 }
88
89 vty->of = vty->of_saved;
90 vty->is_paged = false;
91
92 return 0;
93 }
94
95 static void vtysh_pager_envdef(bool fallback)
96 {
97 char *pager_defined;
98
99 pager_defined = getenv("VTYSH_PAGER");
100
101 if (pager_defined)
102 vtysh_pager_name = strdup(pager_defined);
103 else if (fallback)
104 vtysh_pager_name = strdup(VTYSH_PAGER);
105 }
106
107 /* --- */
108
109 /*
110 * When updating this array, remember to change the array size here and in
111 * vtysh.h
112 */
113 struct vtysh_client vtysh_client[] = {
114 {.name = "mgmtd", .flag = VTYSH_MGMTD},
115 {.name = "zebra", .flag = VTYSH_ZEBRA},
116 {.name = "ripd", .flag = VTYSH_RIPD},
117 {.name = "ripngd", .flag = VTYSH_RIPNGD},
118 {.name = "ospfd", .flag = VTYSH_OSPFD},
119 {.name = "ospf6d", .flag = VTYSH_OSPF6D},
120 {.name = "ldpd", .flag = VTYSH_LDPD},
121 {.name = "bgpd", .flag = VTYSH_BGPD},
122 {.name = "isisd", .flag = VTYSH_ISISD},
123 {.name = "pimd", .flag = VTYSH_PIMD},
124 {.name = "nhrpd", .flag = VTYSH_NHRPD},
125 {.name = "eigrpd", .flag = VTYSH_EIGRPD},
126 {.name = "babeld", .flag = VTYSH_BABELD},
127 {.name = "sharpd", .flag = VTYSH_SHARPD},
128 {.name = "fabricd", .flag = VTYSH_FABRICD},
129 {.name = "watchfrr", .flag = VTYSH_WATCHFRR},
130 {.name = "pbrd", .flag = VTYSH_PBRD},
131 {.name = "staticd", .flag = VTYSH_STATICD},
132 {.name = "bfdd", .flag = VTYSH_BFDD},
133 {.name = "vrrpd", .flag = VTYSH_VRRPD},
134 {.name = "pathd", .flag = VTYSH_PATHD},
135 {.name = "pim6d", .flag = VTYSH_PIM6D},
136 };
137
138 /* Searches for client by name, returns index */
139 static int vtysh_client_lookup(const char *name)
140 {
141 int idx = -1;
142
143 for (unsigned int i = 0; i < array_size(vtysh_client); i++) {
144 if (strmatch(vtysh_client[i].name, name)) {
145 idx = i;
146 break;
147 }
148 }
149
150 return idx;
151 }
152
153 enum vtysh_write_integrated vtysh_write_integrated =
154 WRITE_INTEGRATED_UNSPECIFIED;
155
156 static int vtysh_reconnect(struct vtysh_client *vclient);
157
158 static void vclient_close(struct vtysh_client *vclient)
159 {
160 if (vclient->fd >= 0) {
161 if (vty->of)
162 vty_out(vty,
163 "Warning: closing connection to %s because of an I/O error!\n",
164 vclient->name);
165 close(vclient->fd);
166 /* indicate as candidate for reconnect */
167 vclient->fd = VTYSH_WAS_ACTIVE;
168 }
169 }
170
171 static ssize_t vtysh_client_receive(struct vtysh_client *vclient, char *buf,
172 size_t bufsz, int *pass_fd)
173 {
174 struct iovec iov[1] = {
175 {
176 .iov_base = buf,
177 .iov_len = bufsz,
178 },
179 };
180 union {
181 uint8_t buf[CMSG_SPACE(sizeof(int))];
182 struct cmsghdr align;
183 } u;
184 struct msghdr mh = {
185 .msg_iov = iov,
186 .msg_iovlen = array_size(iov),
187 .msg_control = u.buf,
188 .msg_controllen = sizeof(u.buf),
189 };
190 struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
191 ssize_t ret;
192
193 cmh->cmsg_level = SOL_SOCKET;
194 cmh->cmsg_type = SCM_RIGHTS;
195 cmh->cmsg_len = CMSG_LEN(sizeof(int));
196 memset(CMSG_DATA(cmh), -1, sizeof(int));
197
198 do {
199 ret = recvmsg(vclient->fd, &mh, 0);
200 if (ret >= 0 || (errno != EINTR && errno != EAGAIN))
201 break;
202 } while (true);
203
204 if (cmh->cmsg_len == CMSG_LEN(sizeof(int))) {
205 int fd;
206
207 memcpy(&fd, CMSG_DATA(cmh), sizeof(int));
208 if (fd != -1) {
209 if (pass_fd)
210 *pass_fd = fd;
211 else
212 close(fd);
213 }
214 }
215 return ret;
216 }
217
218 /*
219 * Send a CLI command to a client and read the response.
220 *
221 * Output will be printed to vty->of. If you want to suppress output, set that
222 * to NULL.
223 *
224 * vclient
225 * the client to send the command to
226 *
227 * line
228 * the command to send
229 *
230 * callback
231 * if non-null, this will be called with each line of output received from
232 * the client passed in the second parameter
233 *
234 * cbarg
235 * optional first argument to pass to callback
236 *
237 * Returns:
238 * a status code
239 */
240 static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
241 void (*callback)(void *, const char *), void *cbarg,
242 int *pass_fd)
243 {
244 int ret;
245 char stackbuf[4096];
246 char *buf = stackbuf;
247 size_t bufsz = sizeof(stackbuf);
248 char *bufvalid, *end = NULL;
249 char terminator[3] = {0, 0, 0};
250
251 /* vclinet was previously active, try to reconnect */
252 if (vclient->fd == VTYSH_WAS_ACTIVE) {
253 ret = vtysh_reconnect(vclient);
254 if (ret < 0)
255 goto out_err;
256 }
257
258 if (vclient->fd < 0)
259 return CMD_SUCCESS;
260
261 ret = write(vclient->fd, line, strlen(line) + 1);
262 if (ret <= 0) {
263 /* close connection and try to reconnect */
264 vclient_close(vclient);
265 ret = vtysh_reconnect(vclient);
266 if (ret < 0)
267 goto out_err;
268 /* retry line */
269 ret = write(vclient->fd, line, strlen(line) + 1);
270 if (ret <= 0)
271 goto out_err;
272 }
273
274 bufvalid = buf;
275 do {
276 ssize_t nread;
277
278 nread = vtysh_client_receive(
279 vclient, bufvalid, buf + bufsz - bufvalid - 1, pass_fd);
280
281 if (nread < 0 && (errno == EINTR || errno == EAGAIN))
282 continue;
283
284 if (nread <= 0) {
285 if (vty->of)
286 vty_out(vty,
287 "vtysh: error reading from %s: %s (%d)",
288 vclient->name, safe_strerror(errno),
289 errno);
290 goto out_err;
291 }
292
293 bufvalid += nread;
294
295 /* Null terminate so we may pass this to *printf later. */
296 bufvalid[0] = '\0';
297
298 /*
299 * We expect string output from daemons, so instead of looking
300 * for the full 3 null bytes of the terminator, we check for
301 * just one instead and assume it is the first byte of the
302 * terminator. The presence of the full terminator is checked
303 * later.
304 */
305 if (bufvalid - buf >= 4)
306 end = memmem(bufvalid - 4, 4, "\0", 1);
307
308 /*
309 * calculate # bytes we have, up to & not including the
310 * terminator if present
311 */
312 size_t textlen = (end ? end : bufvalid) - buf;
313 bool b = false;
314
315 /* feed line processing callback if present */
316 while (callback && bufvalid > buf && (end > buf || !end)) {
317 textlen = (end ? end : bufvalid) - buf;
318 char *eol = memchr(buf, '\n', textlen);
319 if (eol)
320 /* line break */
321 *eol++ = '\0';
322 else if (end == buf)
323 /*
324 * no line break, end of input, no text left
325 * before end; nothing to write
326 */
327 b = true;
328 else if (end)
329 /* no nl, end of input, but some text left */
330 eol = end;
331 else if (bufvalid == buf + bufsz - 1) {
332 /*
333 * no nl, no end of input, no buffer space;
334 * realloc
335 */
336 char *new;
337
338 bufsz *= 2;
339 if (buf == stackbuf) {
340 new = XMALLOC(MTYPE_TMP, bufsz);
341 memcpy(new, stackbuf, sizeof(stackbuf));
342 } else
343 new = XREALLOC(MTYPE_TMP, buf, bufsz);
344
345 bufvalid = bufvalid - buf + new;
346 buf = new;
347 /* if end != NULL, we won't be reading more
348 * data... */
349 assert(end == NULL);
350 b = true;
351 } else
352 b = true;
353
354 if (b)
355 break;
356
357 /* eol is at line end now, either \n => \0 or \0\0\0 */
358 assert(eol && eol <= bufvalid);
359
360 if (vty->of)
361 vty_out(vty, "%s\n", buf);
362
363 callback(cbarg, buf);
364
365 /* shift back data and adjust bufvalid */
366 memmove(buf, eol, bufvalid - eol);
367 bufvalid -= eol - buf;
368 if (end)
369 end -= eol - buf;
370 }
371
372 /* else if no callback, dump raw */
373 if (!callback) {
374 if (vty->of)
375 vty_out(vty, "%s", buf);
376 memmove(buf, buf + textlen, bufvalid - buf - textlen);
377 bufvalid -= textlen;
378 if (end)
379 end -= textlen;
380
381 /*
382 * ----------------------------------------------------
383 * At this point `buf` should be in one of two states:
384 * - Empty (i.e. buf == bufvalid)
385 * - Contains up to 4 bytes of the terminator
386 * ----------------------------------------------------
387 */
388 assert(((buf == bufvalid)
389 || (bufvalid - buf <= 4 && buf[0] == 0x00)));
390 }
391
392 /* if we have the terminator, break */
393 if (end && bufvalid - buf == 4) {
394 assert(!memcmp(buf, terminator, 3));
395 ret = buf[3];
396 break;
397 }
398
399 } while (true);
400 goto out;
401
402 out_err:
403 vclient_close(vclient);
404 ret = CMD_SUCCESS;
405 out:
406 if (buf != stackbuf)
407 XFREE(MTYPE_TMP, buf);
408 return ret;
409 }
410
411 static int vtysh_client_run_all(struct vtysh_client *head_client,
412 const char *line, int continue_on_err,
413 void (*callback)(void *, const char *),
414 void *cbarg)
415 {
416 struct vtysh_client *client;
417 int rc, rc_all = CMD_SUCCESS;
418 int correct_instance = 0, wrong_instance = 0;
419
420 for (client = head_client; client; client = client->next) {
421 rc = vtysh_client_run(client, line, callback, cbarg, NULL);
422 if (rc == CMD_NOT_MY_INSTANCE) {
423 wrong_instance++;
424 continue;
425 }
426 if (client->fd > 0)
427 correct_instance++;
428 if (rc != CMD_SUCCESS) {
429 if (!continue_on_err)
430 return rc;
431 rc_all = rc;
432 }
433 }
434 if (wrong_instance && !correct_instance && vty->of) {
435 vty_out(vty,
436 "%% [%s]: command ignored as it targets an instance that is not running\n",
437 head_client->name);
438 rc_all = CMD_WARNING_CONFIG_FAILED;
439 }
440 return rc_all;
441 }
442
443 /*
444 * Execute command against all daemons.
445 *
446 * head_client
447 * where to start walking in the daemon list
448 *
449 * line
450 * the specific command to execute
451 *
452 * Returns:
453 * a status code
454 */
455 static int vtysh_client_execute(struct vtysh_client *head_client,
456 const char *line)
457 {
458 return vtysh_client_run_all(head_client, line, 0, NULL, NULL);
459 }
460
461 /* Execute by name */
462 static int vtysh_client_execute_name(const char *name, const char *line)
463 {
464 int ret = CMD_SUCCESS;
465 int idx_client = -1;
466
467 idx_client = vtysh_client_lookup(name);
468 if (idx_client != -1)
469 ret = vtysh_client_execute(&vtysh_client[idx_client], line);
470 else {
471 vty_out(vty, "Client not found\n");
472 ret = CMD_WARNING;
473 }
474
475 return ret;
476 }
477
478 /*
479 * Retrieve all running config from daemons and parse it with the vtysh config
480 * parser. Returned output is not displayed to the user.
481 *
482 * head_client
483 * where to start walking in the daemon list
484 *
485 * line
486 * the specific command to execute
487 */
488 static void vtysh_client_config(struct vtysh_client *head_client, char *line)
489 {
490 /* watchfrr currently doesn't load any config, and has some hardcoded
491 * settings that show up in "show run". skip it here (for now at
492 * least) so we don't get that mangled up in config-write.
493 */
494 if (head_client->flag == VTYSH_WATCHFRR)
495 return;
496
497 /* suppress output to user */
498 vty->of_saved = vty->of;
499 vty->of = NULL;
500 vtysh_client_run_all(head_client, line, 1, vtysh_config_parse_line,
501 NULL);
502 vty->of = vty->of_saved;
503 }
504
505 /* Command execution over the vty interface. */
506 static int vtysh_execute_func(const char *line, int pager)
507 {
508 int ret, cmd_stat;
509 unsigned int i;
510 vector vline;
511 const struct cmd_element *cmd;
512 int tried = 0;
513 int saved_ret, saved_node;
514
515 /* Split readline string up into the vector. */
516 vline = cmd_make_strvec(line);
517
518 if (vline == NULL)
519 return CMD_SUCCESS;
520
521 if (vtysh_add_timestamp && strncmp(line, "exit", 4)) {
522 char ts[48];
523
524 (void)frr_timestamp(3, ts, sizeof(ts));
525 vty_out(vty, "%% %s\n\n", ts);
526 }
527
528 saved_ret = ret = cmd_execute(vty, line, &cmd, 1);
529 saved_node = vty->node;
530
531 /*
532 * If command doesn't succeeded in current node, try to walk up in node
533 * tree. Changing vty->node is enough to try it just out without actual
534 * walkup in the vtysh.
535 */
536 while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
537 && ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
538 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
539 && vty->node > CONFIG_NODE) {
540 vty->node = node_parent(vty->node);
541 ret = cmd_execute(vty, line, &cmd, 1);
542 tried++;
543 }
544
545 vty->node = saved_node;
546
547 /*
548 * If command succeeded in any other node than current (tried > 0) we
549 * have to move into node in the vtysh where it succeeded.
550 */
551 if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
552 || ret == CMD_WARNING) {
553 while (tried-- > 0)
554 vtysh_execute("exit");
555 }
556 /*
557 * If command didn't succeed in any node, continue with return value
558 * from first try.
559 */
560 else if (tried) {
561 ret = saved_ret;
562 }
563
564 cmd_free_strvec(vline);
565
566 cmd_stat = ret;
567 switch (ret) {
568 case CMD_WARNING:
569 case CMD_WARNING_CONFIG_FAILED:
570 if (vty->type == VTY_FILE)
571 vty_out(vty, "Warning...\n");
572 break;
573 case CMD_ERR_AMBIGUOUS:
574 vty_out(vty, "%% Ambiguous command: %s\n", line);
575 break;
576 case CMD_ERR_NO_MATCH:
577 vty_out(vty, "%% Unknown command: %s\n", line);
578 break;
579 case CMD_ERR_INCOMPLETE:
580 vty_out(vty, "%% Command incomplete: %s\n", line);
581 break;
582 case CMD_SUCCESS_DAEMON: {
583 /*
584 * FIXME: Don't open pager for exit commands. popen() causes
585 * problems if exited from vtysh at all. This hack shouldn't
586 * cause any problem but is really ugly.
587 */
588 if (pager && strncmp(line, "exit", 4))
589 vty_open_pager(vty);
590
591 if (!strcmp(cmd->string, "configure")) {
592 for (i = 0; i < array_size(vtysh_client); i++) {
593 cmd_stat = vtysh_client_execute(
594 &vtysh_client[i], line);
595 if (cmd_stat == CMD_WARNING)
596 break;
597 }
598
599 if (cmd_stat) {
600 line = "end";
601 vline = cmd_make_strvec(line);
602
603
604 if (vline == NULL) {
605 if (vty->is_paged)
606 vty_close_pager(vty);
607 return CMD_SUCCESS;
608 }
609
610 ret = cmd_execute_command(vline, vty, &cmd, 1);
611 cmd_free_strvec(vline);
612 if (ret != CMD_SUCCESS_DAEMON)
613 break;
614 } else if (cmd->func) {
615 (*cmd->func)(cmd, vty, 0, NULL);
616 break;
617 }
618 }
619
620 cmd_stat = CMD_SUCCESS;
621 struct vtysh_client *vc;
622 for (i = 0; i < array_size(vtysh_client); i++) {
623 if (cmd->daemon & vtysh_client[i].flag) {
624 if (vtysh_client[i].fd < 0
625 && (cmd->daemon == vtysh_client[i].flag)) {
626 for (vc = &vtysh_client[i]; vc;
627 vc = vc->next)
628 if (vc->fd == VTYSH_WAS_ACTIVE)
629 vtysh_reconnect(vc);
630 }
631 if (vtysh_client[i].fd < 0
632 && (cmd->daemon == vtysh_client[i].flag)) {
633 bool any_inst = false;
634 for (vc = &vtysh_client[i]; vc;
635 vc = vc->next)
636 any_inst = any_inst
637 || (vc->fd > 0);
638 if (!any_inst) {
639 fprintf(stderr,
640 "%s is not running\n",
641 vtysh_client[i].name);
642 cmd_stat = CMD_ERR_NO_DAEMON;
643 break;
644 }
645 }
646 cmd_stat = vtysh_client_execute(
647 &vtysh_client[i], line);
648 if (cmd_stat != CMD_SUCCESS)
649 break;
650 }
651 }
652 if (cmd_stat != CMD_SUCCESS && cmd_stat != CMD_ERR_NO_DAEMON)
653 break;
654
655 if (cmd->func)
656 (*cmd->func)(cmd, vty, 0, NULL);
657 }
658 }
659 if (vty->is_paged)
660 vty_close_pager(vty);
661
662 return cmd_stat;
663 }
664
665 int vtysh_execute_no_pager(const char *line)
666 {
667 return vtysh_execute_func(line, 0);
668 }
669
670 int vtysh_execute(const char *line)
671 {
672 return vtysh_execute_func(line, 1);
673 }
674
675 static char *trim(char *s)
676 {
677 size_t size;
678 char *end;
679
680 size = strlen(s);
681
682 if (!size)
683 return s;
684
685 end = s + size - 1;
686 while (end >= s && isspace((unsigned char)*end))
687 end--;
688 *(end + 1) = '\0';
689
690 while (*s && isspace((unsigned char)*s))
691 s++;
692
693 return s;
694 }
695
696 int vtysh_mark_file(const char *filename)
697 {
698 struct vty *vty;
699 FILE *confp = NULL;
700 int ret;
701 vector vline;
702 int tried = 0;
703 const struct cmd_element *cmd;
704 int saved_ret, prev_node;
705 int lineno = 0;
706 char *vty_buf_copy = NULL;
707 char *vty_buf_trimmed = NULL;
708
709 if (strncmp("-", filename, 1) == 0)
710 confp = stdin;
711 else
712 confp = fopen(filename, "r");
713
714 if (confp == NULL) {
715 fprintf(stderr, "%% Can't open config file %s due to '%s'.\n",
716 filename, safe_strerror(errno));
717 return CMD_ERR_NO_FILE;
718 }
719
720 vty = vty_new();
721 vty->wfd = STDOUT_FILENO;
722 vty->type = VTY_TERM;
723 vty->node = CONFIG_NODE;
724
725 vtysh_execute_no_pager("enable");
726 vtysh_execute_no_pager("configure");
727 vty_buf_copy = XCALLOC(MTYPE_VTYSH_CMD, VTY_BUFSIZ);
728
729 while (fgets(vty->buf, VTY_BUFSIZ, confp)) {
730 lineno++;
731 tried = 0;
732 strlcpy(vty_buf_copy, vty->buf, VTY_BUFSIZ);
733 vty_buf_trimmed = trim(vty_buf_copy);
734
735 if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') {
736 vty_out(vty, "%s", vty->buf);
737 continue;
738 }
739
740 /* Split readline string up into the vector. */
741 vline = cmd_make_strvec(vty->buf);
742
743 if (vline == NULL) {
744 vty_out(vty, "%s", vty->buf);
745 continue;
746 }
747
748 /*
749 * Ignore the "end" lines, we will generate these where
750 * appropriate
751 */
752 if (strlen(vty_buf_trimmed) == 3
753 && strncmp("end", vty_buf_trimmed, 3) == 0) {
754 cmd_free_strvec(vline);
755 continue;
756 }
757
758 prev_node = vty->node;
759 saved_ret = ret = cmd_execute_command_strict(vline, vty, &cmd);
760
761 /*
762 * If command doesn't succeeded in current node, try to walk up
763 * in node tree. Changing vty->node is enough to try it just
764 * out without actual walkup in the vtysh.
765 */
766 while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
767 && ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
768 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
769 && vty->node > CONFIG_NODE) {
770 vty->node = node_parent(vty->node);
771 ret = cmd_execute_command_strict(vline, vty, &cmd);
772 tried++;
773 }
774
775 /*
776 * If command succeeded in any other node than current (tried >
777 * 0) we have to move into node in the vtysh where it
778 * succeeded.
779 */
780 if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
781 || ret == CMD_WARNING) {
782 while (tried-- > 0)
783 vty_out(vty, "exit\n");
784 }
785 /*
786 * If command didn't succeed in any node, continue with return
787 * value from first try.
788 */
789 else if (tried) {
790 ret = saved_ret;
791 vty->node = prev_node;
792 }
793
794 cmd_free_strvec(vline);
795 switch (ret) {
796 case CMD_WARNING:
797 case CMD_WARNING_CONFIG_FAILED:
798 if (vty->type == VTY_FILE)
799 fprintf(stderr, "line %d: Warning...: %s\n",
800 lineno, vty->buf);
801 fclose(confp);
802 vty_close(vty);
803 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
804 return ret;
805 case CMD_ERR_AMBIGUOUS:
806 fprintf(stderr, "line %d: %% Ambiguous command: %s\n",
807 lineno, vty->buf);
808 fclose(confp);
809 vty_close(vty);
810 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
811 return CMD_ERR_AMBIGUOUS;
812 case CMD_ERR_NO_MATCH:
813 fprintf(stderr, "line %d: %% Unknown command: %s\n",
814 lineno, vty->buf);
815 fclose(confp);
816 vty_close(vty);
817 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
818 return CMD_ERR_NO_MATCH;
819 case CMD_ERR_INCOMPLETE:
820 fprintf(stderr, "line %d: %% Command incomplete: %s\n",
821 lineno, vty->buf);
822 fclose(confp);
823 vty_close(vty);
824 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
825 return CMD_ERR_INCOMPLETE;
826 case CMD_SUCCESS:
827 vty_out(vty, "%s", vty->buf);
828 if (strmatch(vty_buf_trimmed, "exit-vrf"))
829 vty_out(vty, "end\n");
830 break;
831 case CMD_SUCCESS_DAEMON: {
832 int cmd_stat;
833
834 vty_out(vty, "%s", vty->buf);
835 if (strmatch(vty_buf_trimmed, "exit-vrf"))
836 vty_out(vty, "end\n");
837 cmd_stat = vtysh_client_execute(&vtysh_client[0],
838 vty->buf);
839 if (cmd_stat != CMD_SUCCESS)
840 break;
841
842 if (cmd->func)
843 (*cmd->func)(cmd, vty, 0, NULL);
844 }
845 }
846 }
847 /* This is the end */
848 vty_out(vty, "\nend\n");
849 vty_close(vty);
850 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
851
852 if (confp != stdin)
853 fclose(confp);
854
855 return 0;
856 }
857
858 /* Configuration make from file. */
859 int vtysh_config_from_file(struct vty *vty, FILE *fp)
860 {
861 int ret;
862 const struct cmd_element *cmd;
863 int lineno = 0;
864 /* once we have an error, we remember & return that */
865 int retcode = CMD_SUCCESS;
866 char *vty_buf_copy = XCALLOC(MTYPE_VTYSH_CMD, VTY_BUFSIZ);
867 char *vty_buf_trimmed = NULL;
868
869 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
870 lineno++;
871
872 strlcpy(vty_buf_copy, vty->buf, VTY_BUFSIZ);
873 vty_buf_trimmed = trim(vty_buf_copy);
874
875 /*
876 * Ignore the "end" lines, we will generate these where
877 * appropriate, otherwise we never execute
878 * XFRR_end_configuration, and start/end markers do not work.
879 */
880 if (strmatch(vty_buf_trimmed, "end"))
881 continue;
882
883 ret = command_config_read_one_line(vty, &cmd, lineno, 1);
884
885 switch (ret) {
886 case CMD_WARNING:
887 case CMD_WARNING_CONFIG_FAILED:
888 if (vty->type == VTY_FILE)
889 fprintf(stderr, "line %d: Warning[%d]...: %s\n",
890 lineno, vty->node, vty->buf);
891 retcode = ret;
892
893 break;
894 case CMD_ERR_AMBIGUOUS:
895 fprintf(stderr,
896 "line %d: %% Ambiguous command[%d]: %s\n",
897 lineno, vty->node, vty->buf);
898 retcode = CMD_ERR_AMBIGUOUS;
899 break;
900 case CMD_ERR_NO_MATCH:
901 fprintf(stderr, "line %d: %% Unknown command[%d]: %s",
902 lineno, vty->node, vty->buf);
903 retcode = CMD_ERR_NO_MATCH;
904 break;
905 case CMD_ERR_INCOMPLETE:
906 fprintf(stderr,
907 "line %d: %% Command incomplete[%d]: %s\n",
908 lineno, vty->node, vty->buf);
909 retcode = CMD_ERR_INCOMPLETE;
910 break;
911 case CMD_SUCCESS_DAEMON: {
912 unsigned int i;
913 int cmd_stat = CMD_SUCCESS;
914
915 for (i = 0; i < array_size(vtysh_client); i++) {
916 if (cmd->daemon & vtysh_client[i].flag) {
917 cmd_stat = vtysh_client_execute(
918 &vtysh_client[i], vty->buf);
919 /*
920 * CMD_WARNING - Can mean that the
921 * command was parsed successfully but
922 * it was already entered in a few
923 * spots. As such if we receive a
924 * CMD_WARNING from a daemon we
925 * shouldn't stop talking to the other
926 * daemons for the particular command.
927 */
928 if (cmd_stat != CMD_SUCCESS
929 && cmd_stat != CMD_WARNING) {
930 fprintf(stderr,
931 "line %d: Failure to communicate[%d] to %s, line: %s\n",
932 lineno, cmd_stat,
933 vtysh_client[i].name,
934 vty->buf);
935 retcode = cmd_stat;
936 break;
937 }
938 }
939 }
940 if (cmd_stat != CMD_SUCCESS)
941 break;
942
943 if (cmd->func)
944 (*cmd->func)(cmd, vty, 0, NULL);
945 }
946 }
947 }
948
949 XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
950
951 return (retcode);
952 }
953
954 /*
955 * Function processes cli commands terminated with '?' character when entered
956 * through either 'vtysh' or 'vtysh -c' interfaces.
957 */
958 static int vtysh_process_questionmark(const char *input, int input_len)
959 {
960 int ret, width = 0;
961 unsigned int i;
962 vector vline, describe;
963 struct cmd_token *token;
964
965 if (!input)
966 return 1;
967
968 vline = cmd_make_strvec(input);
969
970 /* In case of '> ?'. */
971 if (vline == NULL) {
972 vline = vector_init(1);
973 vector_set(vline, NULL);
974 } else if (input_len && isspace((unsigned char)input[input_len - 1]))
975 vector_set(vline, NULL);
976
977 describe = cmd_describe_command(vline, vty, &ret);
978
979 /* Ambiguous and no match error. */
980 switch (ret) {
981 case CMD_ERR_AMBIGUOUS:
982 cmd_free_strvec(vline);
983 vector_free(describe);
984 vty_out(vty, "%% Ambiguous command.\n");
985 rl_on_new_line();
986 return 0;
987 case CMD_ERR_NO_MATCH:
988 cmd_free_strvec(vline);
989 if (describe)
990 vector_free(describe);
991 vty_out(vty, "%% There is no matched command.\n");
992 rl_on_new_line();
993 return 0;
994 }
995
996 /* Get width of command string. */
997 width = 0;
998 for (i = 0; i < vector_active(describe); i++)
999 if ((token = vector_slot(describe, i)) != NULL) {
1000 if (token->text[0] == '\0')
1001 continue;
1002
1003 int len = strlen(token->text);
1004
1005 if (width < len)
1006 width = len;
1007 }
1008
1009 for (i = 0; i < vector_active(describe); i++)
1010 if ((token = vector_slot(describe, i)) != NULL) {
1011 if (!token->desc)
1012 vty_out(vty, " %-s\n", token->text);
1013 else
1014 vty_out(vty, " %-*s %s\n", width, token->text,
1015 token->desc);
1016
1017 if (IS_VARYING_TOKEN(token->type)) {
1018 const char *ref = vector_slot(
1019 vline, vector_active(vline) - 1);
1020
1021 vector varcomps = vector_init(VECTOR_MIN_SIZE);
1022 cmd_variable_complete(token, ref, varcomps);
1023
1024 if (vector_active(varcomps) > 0) {
1025 int rows, cols;
1026 rl_get_screen_size(&rows, &cols);
1027
1028 char *ac = cmd_variable_comp2str(
1029 varcomps, cols);
1030 vty_out(vty, "%s\n", ac);
1031 XFREE(MTYPE_TMP, ac);
1032 }
1033
1034 vector_free(varcomps);
1035 }
1036 }
1037
1038 cmd_free_strvec(vline);
1039 vector_free(describe);
1040
1041 return 0;
1042 }
1043
1044 /*
1045 * Entry point for user commands terminated with '?' character and typed through
1046 * the usual vtysh's stdin interface. This is the function being registered with
1047 * readline() api's.
1048 */
1049 static int vtysh_rl_describe(int a, int b)
1050 {
1051 int ret;
1052
1053 vty_out(vty, "\n");
1054
1055 ret = vtysh_process_questionmark(rl_line_buffer, rl_end);
1056 rl_on_new_line();
1057
1058 return ret;
1059 }
1060
1061 /*
1062 * Function in charged of processing vtysh instructions terminating with '?'
1063 * character and received through the 'vtysh -c' interface. If user's
1064 * instruction is well-formatted, we will call the same processing routine
1065 * utilized by the traditional vtysh's stdin interface.
1066 */
1067 int vtysh_execute_command_questionmark(char *input)
1068 {
1069 int input_len, qmark_count = 0;
1070 const char *str;
1071
1072 if (!(input && *input))
1073 return 1;
1074
1075 /* Finding out question_mark count and strlen */
1076 for (str = input; *str; ++str) {
1077 if (*str == '?')
1078 qmark_count++;
1079 }
1080 input_len = str - input;
1081
1082 /*
1083 * Verify that user's input terminates in '?' and that patterns such as
1084 * 'cmd ? subcmd ?' are prevented.
1085 */
1086 if (qmark_count != 1 || input[input_len - 1] != '?')
1087 return 1;
1088
1089 /*
1090 * Questionmark-processing function is not expecting to receive '?'
1091 * character in input string.
1092 */
1093 input[input_len - 1] = '\0';
1094
1095 return vtysh_process_questionmark(input, input_len - 1);
1096 }
1097
1098 /* Result of cmd_complete_command() call will be stored here
1099 * and used in new_completion() in order to put the space in
1100 * correct places only. */
1101 int complete_status;
1102
1103 static char *command_generator(const char *text, int state)
1104 {
1105 vector vline;
1106 static char **matched = NULL;
1107 static int index = 0;
1108
1109 /* First call. */
1110 if (!state) {
1111 index = 0;
1112
1113 if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1114 return NULL;
1115
1116 vline = cmd_make_strvec(rl_line_buffer);
1117 if (vline == NULL)
1118 return NULL;
1119
1120 if (rl_end &&
1121 isspace((unsigned char)rl_line_buffer[rl_end - 1]))
1122 vector_set(vline, NULL);
1123
1124 matched = cmd_complete_command(vline, vty, &complete_status);
1125 cmd_free_strvec(vline);
1126 }
1127
1128 if (matched && matched[index]) {
1129 XCOUNTFREE(MTYPE_COMPLETION, matched[index]);
1130 return matched[index++];
1131 }
1132
1133 XFREE(MTYPE_TMP, matched);
1134
1135 return NULL;
1136 }
1137
1138 static char **new_completion(const char *text, int start, int end)
1139 {
1140 char **matches;
1141
1142 matches = rl_completion_matches(text, command_generator);
1143
1144 if (matches) {
1145 rl_point = rl_end;
1146 if (complete_status != CMD_COMPLETE_FULL_MATCH)
1147 /* only append a space on full match */
1148 rl_completion_append_character = '\0';
1149 }
1150
1151 return matches;
1152 }
1153
1154 /* Vty node structures. */
1155 #ifdef HAVE_BGPD
1156 static struct cmd_node bgp_node = {
1157 .name = "bgp",
1158 .node = BGP_NODE,
1159 .parent_node = CONFIG_NODE,
1160 .prompt = "%s(config-router)# ",
1161 };
1162 #endif /* HAVE_BGPD */
1163
1164 static struct cmd_node rip_node = {
1165 .name = "rip",
1166 .node = RIP_NODE,
1167 .parent_node = CONFIG_NODE,
1168 .prompt = "%s(config-router)# ",
1169 };
1170
1171 #ifdef HAVE_ISISD
1172 static struct cmd_node isis_node = {
1173 .name = "isis",
1174 .node = ISIS_NODE,
1175 .parent_node = CONFIG_NODE,
1176 .prompt = "%s(config-router)# ",
1177 };
1178 #endif /* HAVE_ISISD */
1179
1180 #ifdef HAVE_FABRICD
1181 static struct cmd_node openfabric_node = {
1182 .name = "openfabric",
1183 .node = OPENFABRIC_NODE,
1184 .parent_node = CONFIG_NODE,
1185 .prompt = "%s(config-router)# ",
1186 };
1187 #endif /* HAVE_FABRICD */
1188
1189 static struct cmd_node interface_node = {
1190 .name = "interface",
1191 .node = INTERFACE_NODE,
1192 .parent_node = CONFIG_NODE,
1193 .prompt = "%s(config-if)# ",
1194 };
1195
1196 static struct cmd_node pw_node = {
1197 .name = "pw",
1198 .node = PW_NODE,
1199 .parent_node = CONFIG_NODE,
1200 .prompt = "%s(config-pw)# ",
1201 };
1202
1203 static struct cmd_node segment_routing_node = {
1204 .name = "segment-routing",
1205 .node = SEGMENT_ROUTING_NODE,
1206 .parent_node = CONFIG_NODE,
1207 .prompt = "%s(config-sr)# ",
1208 };
1209
1210 #if defined(HAVE_PATHD)
1211 static struct cmd_node sr_traffic_eng_node = {
1212 .name = "sr traffic-eng",
1213 .node = SR_TRAFFIC_ENG_NODE,
1214 .parent_node = SEGMENT_ROUTING_NODE,
1215 .prompt = "%s(config-sr-te)# ",
1216 };
1217
1218 static struct cmd_node srte_segment_list_node = {
1219 .name = "srte segment-list",
1220 .node = SR_SEGMENT_LIST_NODE,
1221 .parent_node = SR_TRAFFIC_ENG_NODE,
1222 .prompt = "%s(config-sr-te-segment-list)# ",
1223 };
1224
1225 static struct cmd_node srte_policy_node = {
1226 .name = "srte policy",
1227 .node = SR_POLICY_NODE,
1228 .parent_node = SR_TRAFFIC_ENG_NODE,
1229 .prompt = "%s(config-sr-te-policy)# ",
1230 };
1231
1232 static struct cmd_node srte_candidate_dyn_node = {
1233 .name = "srte candidate-dyn",
1234 .node = SR_CANDIDATE_DYN_NODE,
1235 .parent_node = SR_POLICY_NODE,
1236 .prompt = "%s(config-sr-te-candidate)# ",
1237 };
1238
1239 static struct cmd_node pcep_node = {
1240 .name = "srte pcep",
1241 .node = PCEP_NODE,
1242 .parent_node = SR_TRAFFIC_ENG_NODE,
1243 .prompt = "%s(config-sr-te-pcep)# "
1244 };
1245
1246 static struct cmd_node pcep_pcc_node = {
1247 .name = "srte pcep pcc",
1248 .node = PCEP_PCC_NODE,
1249 .parent_node = PCEP_NODE,
1250 .prompt = "%s(config-sr-te-pcep-pcc)# ",
1251 };
1252
1253 static struct cmd_node pcep_pce_node = {
1254 .name = "srte pcep pce-peer",
1255 .node = PCEP_PCE_NODE,
1256 .parent_node = PCEP_NODE,
1257 .prompt = "%s(config-sr-te-pcep-pce-peer)# ",
1258 };
1259
1260 static struct cmd_node pcep_pce_config_node = {
1261 .name = "srte pcep pce-config",
1262 .node = PCEP_PCE_CONFIG_NODE,
1263 .parent_node = PCEP_NODE,
1264 .prompt = "%s(pcep-sr-te-pcep-pce-config)# ",
1265 };
1266 #endif /* HAVE_PATHD */
1267
1268 static struct cmd_node vrf_node = {
1269 .name = "vrf",
1270 .node = VRF_NODE,
1271 .parent_node = CONFIG_NODE,
1272 .prompt = "%s(config-vrf)# ",
1273 };
1274
1275 static struct cmd_node nh_group_node = {
1276 .name = "nexthop-group",
1277 .node = NH_GROUP_NODE,
1278 .parent_node = CONFIG_NODE,
1279 .prompt = "%s(config-nh-group)# ",
1280 };
1281
1282 static struct cmd_node rmap_node = {
1283 .name = "routemap",
1284 .node = RMAP_NODE,
1285 .parent_node = CONFIG_NODE,
1286 .prompt = "%s(config-route-map)# ",
1287 };
1288
1289 static struct cmd_node srv6_node = {
1290 .name = "srv6",
1291 .node = SRV6_NODE,
1292 .parent_node = SEGMENT_ROUTING_NODE,
1293 .prompt = "%s(config-srv6)# ",
1294 };
1295
1296 static struct cmd_node srv6_locs_node = {
1297 .name = "srv6-locators",
1298 .node = SRV6_LOCS_NODE,
1299 .parent_node = SRV6_NODE,
1300 .prompt = "%s(config-srv6-locators)# ",
1301 };
1302
1303 static struct cmd_node srv6_loc_node = {
1304 .name = "srv6-locator",
1305 .node = SRV6_LOC_NODE,
1306 .parent_node = SRV6_LOCS_NODE,
1307 .prompt = "%s(config-srv6-locator)# ",
1308 };
1309
1310 #ifdef HAVE_PBRD
1311 static struct cmd_node pbr_map_node = {
1312 .name = "pbr-map",
1313 .node = PBRMAP_NODE,
1314 .parent_node = CONFIG_NODE,
1315 .prompt = "%s(config-pbr-map)# ",
1316 };
1317 #endif /* HAVE_PBRD */
1318
1319 static struct cmd_node zebra_node = {
1320 .name = "zebra",
1321 .node = ZEBRA_NODE,
1322 .parent_node = CONFIG_NODE,
1323 .prompt = "%s(config-router)# ",
1324 };
1325
1326 #ifdef HAVE_BGPD
1327 static struct cmd_node bgp_vpnv4_node = {
1328 .name = "bgp vpnv4",
1329 .node = BGP_VPNV4_NODE,
1330 .parent_node = BGP_NODE,
1331 .prompt = "%s(config-router-af)# ",
1332 .no_xpath = true,
1333 };
1334
1335 static struct cmd_node bgp_vpnv6_node = {
1336 .name = "bgp vpnv6",
1337 .node = BGP_VPNV6_NODE,
1338 .parent_node = BGP_NODE,
1339 .prompt = "%s(config-router-af)# ",
1340 .no_xpath = true,
1341 };
1342
1343 static struct cmd_node bgp_flowspecv4_node = {
1344 .name = "bgp ipv4 flowspec",
1345 .node = BGP_FLOWSPECV4_NODE,
1346 .parent_node = BGP_NODE,
1347 .prompt = "%s(config-router-af)# ",
1348 .no_xpath = true,
1349 };
1350
1351 static struct cmd_node bgp_flowspecv6_node = {
1352 .name = "bgp ipv6 flowspec",
1353 .node = BGP_FLOWSPECV6_NODE,
1354 .parent_node = BGP_NODE,
1355 .prompt = "%s(config-router-af)# ",
1356 .no_xpath = true,
1357 };
1358
1359 static struct cmd_node bgp_ipv4_node = {
1360 .name = "bgp ipv4 unicast",
1361 .node = BGP_IPV4_NODE,
1362 .parent_node = BGP_NODE,
1363 .prompt = "%s(config-router-af)# ",
1364 .no_xpath = true,
1365 };
1366
1367 static struct cmd_node bgp_ipv4m_node = {
1368 .name = "bgp ipv4 multicast",
1369 .node = BGP_IPV4M_NODE,
1370 .parent_node = BGP_NODE,
1371 .prompt = "%s(config-router-af)# ",
1372 .no_xpath = true,
1373 };
1374
1375 static struct cmd_node bgp_ipv4l_node = {
1376 .name = "bgp ipv4 labeled unicast",
1377 .node = BGP_IPV4L_NODE,
1378 .parent_node = BGP_NODE,
1379 .prompt = "%s(config-router-af)# ",
1380 .no_xpath = true,
1381 };
1382
1383 static struct cmd_node bgp_ipv6_node = {
1384 .name = "bgp ipv6",
1385 .node = BGP_IPV6_NODE,
1386 .parent_node = BGP_NODE,
1387 .prompt = "%s(config-router-af)# ",
1388 .no_xpath = true,
1389 };
1390
1391 static struct cmd_node bgp_ipv6m_node = {
1392 .name = "bgp ipv6 multicast",
1393 .node = BGP_IPV6M_NODE,
1394 .parent_node = BGP_NODE,
1395 .prompt = "%s(config-router-af)# ",
1396 .no_xpath = true,
1397 };
1398
1399 static struct cmd_node bgp_evpn_node = {
1400 .name = "bgp evpn",
1401 .node = BGP_EVPN_NODE,
1402 .parent_node = BGP_NODE,
1403 .prompt = "%s(config-router-af)# ",
1404 .no_xpath = true,
1405 };
1406
1407 static struct cmd_node bgp_evpn_vni_node = {
1408 .name = "bgp evpn vni",
1409 .node = BGP_EVPN_VNI_NODE,
1410 .parent_node = BGP_EVPN_NODE,
1411 .prompt = "%s(config-router-af-vni)# ",
1412 };
1413
1414 static struct cmd_node bgp_ipv6l_node = {
1415 .name = "bgp ipv6 labeled unicast",
1416 .node = BGP_IPV6L_NODE,
1417 .parent_node = BGP_NODE,
1418 .prompt = "%s(config-router-af)# ",
1419 .no_xpath = true,
1420 };
1421
1422 #ifdef ENABLE_BGP_VNC
1423 static struct cmd_node bgp_vnc_defaults_node = {
1424 .name = "bgp vnc defaults",
1425 .node = BGP_VNC_DEFAULTS_NODE,
1426 .parent_node = BGP_NODE,
1427 .prompt = "%s(config-router-vnc-defaults)# ",
1428 };
1429
1430 static struct cmd_node bgp_vnc_nve_group_node = {
1431 .name = "bgp vnc nve",
1432 .node = BGP_VNC_NVE_GROUP_NODE,
1433 .parent_node = BGP_NODE,
1434 .prompt = "%s(config-router-vnc-nve-group)# ",
1435 };
1436
1437 static struct cmd_node bgp_vrf_policy_node = {
1438 .name = "bgp vrf policy",
1439 .node = BGP_VRF_POLICY_NODE,
1440 .parent_node = BGP_NODE,
1441 .prompt = "%s(config-router-vrf-policy)# ",
1442 };
1443
1444 static struct cmd_node bgp_vnc_l2_group_node = {
1445 .name = "bgp vnc l2",
1446 .node = BGP_VNC_L2_GROUP_NODE,
1447 .parent_node = BGP_NODE,
1448 .prompt = "%s(config-router-vnc-l2-group)# ",
1449 };
1450 #endif /* ENABLE_BGP_VNC */
1451
1452 static struct cmd_node bmp_node = {
1453 .name = "bmp",
1454 .node = BMP_NODE,
1455 .parent_node = BGP_NODE,
1456 .prompt = "%s(config-bgp-bmp)# "
1457 };
1458
1459 static struct cmd_node bgp_srv6_node = {
1460 .name = "bgp srv6",
1461 .node = BGP_SRV6_NODE,
1462 .parent_node = BGP_NODE,
1463 .prompt = "%s(config-router-srv6)# ",
1464 };
1465 #endif /* HAVE_BGPD */
1466
1467 #ifdef HAVE_OSPFD
1468 static struct cmd_node ospf_node = {
1469 .name = "ospf",
1470 .node = OSPF_NODE,
1471 .parent_node = CONFIG_NODE,
1472 .prompt = "%s(config-router)# ",
1473 };
1474 #endif /* HAVE_OSPFD */
1475
1476 #ifdef HAVE_EIGRPD
1477 static struct cmd_node eigrp_node = {
1478 .name = "eigrp",
1479 .node = EIGRP_NODE,
1480 .parent_node = CONFIG_NODE,
1481 .prompt = "%s(config-router)# ",
1482 };
1483 #endif /* HAVE_EIGRPD */
1484
1485 #ifdef HAVE_BABELD
1486 static struct cmd_node babel_node = {
1487 .name = "babel",
1488 .node = BABEL_NODE,
1489 .parent_node = CONFIG_NODE,
1490 .prompt = "%s(config-router)# ",
1491 };
1492 #endif /* HAVE_BABELD */
1493
1494 static struct cmd_node ripng_node = {
1495 .name = "ripng",
1496 .node = RIPNG_NODE,
1497 .parent_node = CONFIG_NODE,
1498 .prompt = "%s(config-router)# ",
1499 };
1500
1501 #ifdef HAVE_OSPF6D
1502 static struct cmd_node ospf6_node = {
1503 .name = "ospf6",
1504 .node = OSPF6_NODE,
1505 .parent_node = CONFIG_NODE,
1506 .prompt = "%s(config-ospf6)# ",
1507 };
1508 #endif /* HAVE_OSPF6D */
1509
1510 #ifdef HAVE_LDPD
1511 static struct cmd_node ldp_node = {
1512 .name = "ldp",
1513 .node = LDP_NODE,
1514 .parent_node = CONFIG_NODE,
1515 .prompt = "%s(config-ldp)# ",
1516 };
1517
1518 static struct cmd_node ldp_ipv4_node = {
1519 .name = "ldp ipv4",
1520 .node = LDP_IPV4_NODE,
1521 .parent_node = LDP_NODE,
1522 .prompt = "%s(config-ldp-af)# ",
1523 };
1524
1525 static struct cmd_node ldp_ipv6_node = {
1526 .name = "ldp ipv6",
1527 .node = LDP_IPV6_NODE,
1528 .parent_node = LDP_NODE,
1529 .prompt = "%s(config-ldp-af)# ",
1530 };
1531
1532 static struct cmd_node ldp_ipv4_iface_node = {
1533 .name = "ldp ipv4 interface",
1534 .node = LDP_IPV4_IFACE_NODE,
1535 .parent_node = LDP_IPV4_NODE,
1536 .prompt = "%s(config-ldp-af-if)# ",
1537 };
1538
1539 static struct cmd_node ldp_ipv6_iface_node = {
1540 .name = "ldp ipv6 interface",
1541 .node = LDP_IPV6_IFACE_NODE,
1542 .parent_node = LDP_IPV6_NODE,
1543 .prompt = "%s(config-ldp-af-if)# ",
1544 };
1545
1546 static struct cmd_node ldp_l2vpn_node = {
1547 .name = "ldp l2vpn",
1548 .node = LDP_L2VPN_NODE,
1549 .parent_node = CONFIG_NODE,
1550 .prompt = "%s(config-l2vpn)# ",
1551 };
1552
1553 static struct cmd_node ldp_pseudowire_node = {
1554 .name = "ldp",
1555 .node = LDP_PSEUDOWIRE_NODE,
1556 .parent_node = LDP_L2VPN_NODE,
1557 .prompt = "%s(config-l2vpn-pw)# ",
1558 };
1559 #endif /* HAVE_LDPD */
1560
1561 static struct cmd_node keychain_node = {
1562 .name = "keychain",
1563 .node = KEYCHAIN_NODE,
1564 .parent_node = CONFIG_NODE,
1565 .prompt = "%s(config-keychain)# ",
1566 };
1567
1568 static struct cmd_node keychain_key_node = {
1569 .name = "keychain key",
1570 .node = KEYCHAIN_KEY_NODE,
1571 .parent_node = KEYCHAIN_NODE,
1572 .prompt = "%s(config-keychain-key)# ",
1573 };
1574
1575 struct cmd_node link_params_node = {
1576 .name = "link-params",
1577 .node = LINK_PARAMS_NODE,
1578 .parent_node = INTERFACE_NODE,
1579 .prompt = "%s(config-link-params)# ",
1580 .no_xpath = true,
1581 };
1582
1583 #ifdef HAVE_BGPD
1584 static struct cmd_node rpki_node = {
1585 .name = "rpki",
1586 .node = RPKI_NODE,
1587 .parent_node = CONFIG_NODE,
1588 .prompt = "%s(config-rpki)# ",
1589 };
1590 #endif /* HAVE_BGPD */
1591
1592 #if HAVE_BFDD > 0
1593 static struct cmd_node bfd_node = {
1594 .name = "bfd",
1595 .node = BFD_NODE,
1596 .parent_node = CONFIG_NODE,
1597 .prompt = "%s(config-bfd)# ",
1598 };
1599
1600 static struct cmd_node bfd_peer_node = {
1601 .name = "bfd peer",
1602 .node = BFD_PEER_NODE,
1603 .parent_node = BFD_NODE,
1604 .prompt = "%s(config-bfd-peer)# ",
1605 };
1606
1607 static struct cmd_node bfd_profile_node = {
1608 .name = "bfd profile",
1609 .node = BFD_PROFILE_NODE,
1610 .parent_node = BFD_NODE,
1611 .prompt = "%s(config-bfd-profile)# ",
1612 };
1613 #endif /* HAVE_BFDD */
1614
1615 /* Defined in lib/vty.c */
1616 extern struct cmd_node vty_node;
1617
1618 /* When '^Z' is received from vty, move down to the enable mode. */
1619 static int vtysh_end(void)
1620 {
1621 switch (vty->node) {
1622 case VIEW_NODE:
1623 case ENABLE_NODE:
1624 /* Nothing to do. */
1625 break;
1626 default:
1627 vty->node = ENABLE_NODE;
1628 break;
1629 }
1630 return CMD_SUCCESS;
1631 }
1632
1633 #include "vtysh/vtysh_clippy.c"
1634
1635 DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
1636 "End current mode and change to enable mode\n")
1637 {
1638 return vtysh_end();
1639 }
1640
1641 DEFUNSH(VTYSH_ZEBRA, srv6, srv6_cmd,
1642 "srv6",
1643 "Segment-Routing SRv6 configuration\n")
1644 {
1645 vty->node = SRV6_NODE;
1646 return CMD_SUCCESS;
1647 }
1648
1649 DEFUNSH(VTYSH_ZEBRA, srv6_locators, srv6_locators_cmd,
1650 "locators",
1651 "Segment-Routing SRv6 locators configuration\n")
1652 {
1653 vty->node = SRV6_LOCS_NODE;
1654 return CMD_SUCCESS;
1655 }
1656
1657 DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd,
1658 "locator WORD",
1659 "Segment Routing SRv6 locator\n"
1660 "Specify locator-name\n")
1661 {
1662 vty->node = SRV6_LOC_NODE;
1663 return CMD_SUCCESS;
1664 }
1665
1666 #ifdef HAVE_BGPD
1667 DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
1668 "router bgp [ASNUM [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
1669 ROUTER_STR BGP_STR AS_STR
1670 "BGP view\nBGP VRF\n"
1671 "View/VRF name\n"
1672 "Force the AS notation output\n"
1673 "use 'AA.BB' format for AS 4 byte values\n"
1674 "use 'AA.BB' format for all AS values\n"
1675 "use plain format for all AS values\n")
1676 {
1677 vty->node = BGP_NODE;
1678 return CMD_SUCCESS;
1679 }
1680
1681 #ifdef KEEP_OLD_VPN_COMMANDS
1682 DEFUNSH(VTYSH_BGPD, address_family_vpnv4, address_family_vpnv4_cmd,
1683 "address-family vpnv4 [unicast]",
1684 "Enter Address Family command mode\n"
1685 BGP_AF_STR
1686 BGP_AF_MODIFIER_STR)
1687 {
1688 vty->node = BGP_VPNV4_NODE;
1689 return CMD_SUCCESS;
1690 }
1691
1692 DEFUNSH(VTYSH_BGPD, address_family_vpnv6, address_family_vpnv6_cmd,
1693 "address-family vpnv6 [unicast]",
1694 "Enter Address Family command mode\n"
1695 BGP_AF_STR
1696 BGP_AF_MODIFIER_STR)
1697 {
1698 vty->node = BGP_VPNV6_NODE;
1699 return CMD_SUCCESS;
1700 }
1701 #endif /* KEEP_OLD_VPN_COMMANDS */
1702
1703 DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd,
1704 "address-family ipv4 [unicast]",
1705 "Enter Address Family command mode\n"
1706 BGP_AF_STR
1707 BGP_AF_MODIFIER_STR)
1708 {
1709 vty->node = BGP_IPV4_NODE;
1710 return CMD_SUCCESS;
1711 }
1712
1713 DEFUNSH(VTYSH_BGPD, address_family_flowspecv4, address_family_flowspecv4_cmd,
1714 "address-family ipv4 flowspec",
1715 "Enter Address Family command mode\n"
1716 BGP_AF_STR
1717 BGP_AF_MODIFIER_STR)
1718 {
1719 vty->node = BGP_FLOWSPECV4_NODE;
1720 return CMD_SUCCESS;
1721 }
1722
1723 DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd,
1724 "address-family ipv6 flowspec",
1725 "Enter Address Family command mode\n"
1726 BGP_AF_STR
1727 BGP_AF_MODIFIER_STR)
1728 {
1729 vty->node = BGP_FLOWSPECV6_NODE;
1730 return CMD_SUCCESS;
1731 }
1732
1733 DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast,
1734 address_family_ipv4_multicast_cmd, "address-family ipv4 multicast",
1735 "Enter Address Family command mode\n"
1736 BGP_AF_STR
1737 BGP_AF_MODIFIER_STR)
1738 {
1739 vty->node = BGP_IPV4M_NODE;
1740 return CMD_SUCCESS;
1741 }
1742
1743 DEFUNSH(VTYSH_BGPD, address_family_ipv4_vpn, address_family_ipv4_vpn_cmd,
1744 "address-family ipv4 vpn",
1745 "Enter Address Family command mode\n"
1746 BGP_AF_STR
1747 BGP_AF_MODIFIER_STR)
1748 {
1749 vty->node = BGP_VPNV4_NODE;
1750 return CMD_SUCCESS;
1751 }
1752
1753 DEFUNSH(VTYSH_BGPD, address_family_ipv4_labeled_unicast,
1754 address_family_ipv4_labeled_unicast_cmd,
1755 "address-family ipv4 labeled-unicast",
1756 "Enter Address Family command mode\n"
1757 BGP_AF_STR
1758 BGP_AF_MODIFIER_STR)
1759 {
1760 vty->node = BGP_IPV4L_NODE;
1761 return CMD_SUCCESS;
1762 }
1763
1764 DEFUNSH(VTYSH_BGPD, address_family_ipv6, address_family_ipv6_cmd,
1765 "address-family ipv6 [unicast]",
1766 "Enter Address Family command mode\n"
1767 BGP_AF_STR
1768 BGP_AF_MODIFIER_STR)
1769 {
1770 vty->node = BGP_IPV6_NODE;
1771 return CMD_SUCCESS;
1772 }
1773
1774 DEFUNSH(VTYSH_BGPD, address_family_ipv6_multicast,
1775 address_family_ipv6_multicast_cmd, "address-family ipv6 multicast",
1776 "Enter Address Family command mode\n"
1777 BGP_AF_STR
1778 BGP_AF_MODIFIER_STR)
1779 {
1780 vty->node = BGP_IPV6M_NODE;
1781 return CMD_SUCCESS;
1782 }
1783
1784 DEFUNSH(VTYSH_BGPD, address_family_ipv6_vpn, address_family_ipv6_vpn_cmd,
1785 "address-family ipv6 vpn",
1786 "Enter Address Family command mode\n"
1787 BGP_AF_STR
1788 BGP_AF_MODIFIER_STR)
1789 {
1790 vty->node = BGP_VPNV6_NODE;
1791 return CMD_SUCCESS;
1792 }
1793
1794 DEFUNSH(VTYSH_BGPD, address_family_ipv6_labeled_unicast,
1795 address_family_ipv6_labeled_unicast_cmd,
1796 "address-family ipv6 labeled-unicast",
1797 "Enter Address Family command mode\n"
1798 BGP_AF_STR
1799 BGP_AF_MODIFIER_STR)
1800 {
1801 vty->node = BGP_IPV6L_NODE;
1802 return CMD_SUCCESS;
1803 }
1804
1805 DEFUNSH(VTYSH_BGPD,
1806 rpki,
1807 rpki_cmd,
1808 "rpki",
1809 "Enable rpki and enter rpki configuration mode\n")
1810 {
1811 vty->node = RPKI_NODE;
1812 return CMD_SUCCESS;
1813 }
1814
1815 DEFUNSH(VTYSH_BGPD,
1816 bmp_targets,
1817 bmp_targets_cmd,
1818 "bmp targets BMPTARGETS",
1819 "BGP Monitoring Protocol\n"
1820 "Create BMP target group\n"
1821 "Name of the BMP target group\n")
1822 {
1823 vty->node = BMP_NODE;
1824 return CMD_SUCCESS;
1825 }
1826
1827 DEFUNSH(VTYSH_BGPD,
1828 bgp_srv6,
1829 bgp_srv6_cmd,
1830 "segment-routing srv6",
1831 "Segment-Routing configuration\n"
1832 "Segment-Routing SRv6 configuration\n")
1833 {
1834 vty->node = BGP_SRV6_NODE;
1835 return CMD_SUCCESS;
1836 }
1837
1838 DEFUNSH(VTYSH_BGPD,
1839 exit_bgp_srv6,
1840 exit_bgp_srv6_cmd,
1841 "exit",
1842 "exit Segment-Routing SRv6 configuration\n")
1843 {
1844 if (vty->node == BGP_SRV6_NODE)
1845 vty->node = BGP_NODE;
1846 return CMD_SUCCESS;
1847 }
1848
1849 DEFUNSH(VTYSH_BGPD,
1850 quit_bgp_srv6,
1851 quit_bgp_srv6_cmd,
1852 "quit",
1853 "quit Segment-Routing SRv6 configuration\n")
1854 {
1855 if (vty->node == BGP_SRV6_NODE)
1856 vty->node = BGP_NODE;
1857 return CMD_SUCCESS;
1858 }
1859
1860 DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
1861 "address-family <l2vpn evpn>",
1862 "Enter Address Family command mode\n"
1863 BGP_AF_STR
1864 BGP_AF_MODIFIER_STR)
1865 {
1866 vty->node = BGP_EVPN_NODE;
1867 return CMD_SUCCESS;
1868 }
1869
1870 DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni " CMD_VNI_RANGE,
1871 "VXLAN Network Identifier\n"
1872 "VNI number\n")
1873 {
1874 vty->node = BGP_EVPN_VNI_NODE;
1875 return CMD_SUCCESS;
1876 }
1877
1878 #if defined(ENABLE_BGP_VNC)
1879 DEFUNSH(VTYSH_BGPD, vnc_defaults, vnc_defaults_cmd, "vnc defaults",
1880 "VNC/RFP related configuration\n"
1881 "Configure default NVE group\n")
1882 {
1883 vty->node = BGP_VNC_DEFAULTS_NODE;
1884 return CMD_SUCCESS;
1885 }
1886
1887 DEFUNSH(VTYSH_BGPD, vnc_nve_group, vnc_nve_group_cmd, "vnc nve-group NAME",
1888 "VNC/RFP related configuration\n"
1889 "Configure a NVE group\n"
1890 "Group name\n")
1891 {
1892 vty->node = BGP_VNC_NVE_GROUP_NODE;
1893 return CMD_SUCCESS;
1894 }
1895
1896 DEFUNSH(VTYSH_BGPD, vnc_vrf_policy, vnc_vrf_policy_cmd, "vrf-policy NAME",
1897 "Configure a VRF policy group\n"
1898 "Group name\n")
1899 {
1900 vty->node = BGP_VRF_POLICY_NODE;
1901 return CMD_SUCCESS;
1902 }
1903
1904 DEFUNSH(VTYSH_BGPD, vnc_l2_group, vnc_l2_group_cmd, "vnc l2-group NAME",
1905 "VNC/RFP related configuration\n"
1906 "Configure a L2 group\n"
1907 "Group name\n")
1908 {
1909 vty->node = BGP_VNC_L2_GROUP_NODE;
1910 return CMD_SUCCESS;
1911 }
1912
1913 DEFUNSH(VTYSH_BGPD, exit_vnc_config, exit_vnc_config_cmd, "exit-vnc",
1914 "Exit from VNC configuration mode\n")
1915 {
1916 if (vty->node == BGP_VNC_DEFAULTS_NODE
1917 || vty->node == BGP_VNC_NVE_GROUP_NODE
1918 || vty->node == BGP_VNC_L2_GROUP_NODE)
1919 vty->node = BGP_NODE;
1920 return CMD_SUCCESS;
1921 }
1922
1923 DEFUNSH(VTYSH_BGPD, exit_vrf_policy, exit_vrf_policy_cmd, "exit-vrf-policy",
1924 "Exit from VRF policy configuration mode\n")
1925 {
1926 if (vty->node == BGP_VRF_POLICY_NODE)
1927 vty->node = BGP_NODE;
1928 return CMD_SUCCESS;
1929 }
1930 #endif
1931 #endif /* HAVE_BGPD */
1932
1933 DEFUNSH(VTYSH_KEYS, key_chain, key_chain_cmd, "key chain WORD",
1934 "Authentication key management\n"
1935 "Key-chain management\n"
1936 "Key-chain name\n")
1937 {
1938 vty->node = KEYCHAIN_NODE;
1939 return CMD_SUCCESS;
1940 }
1941
1942 DEFUNSH(VTYSH_KEYS, key, key_cmd, "key (0-2147483647)",
1943 "Configure a key\n"
1944 "Key identifier number\n")
1945 {
1946 vty->node = KEYCHAIN_KEY_NODE;
1947 return CMD_SUCCESS;
1948 }
1949
1950 #ifdef HAVE_RIPD
1951 DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]",
1952 ROUTER_STR "RIP\n" VRF_CMD_HELP_STR)
1953 {
1954 vty->node = RIP_NODE;
1955 return CMD_SUCCESS;
1956 }
1957 #endif /* HAVE_RIPD */
1958
1959 #ifdef HAVE_RIPNGD
1960 DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]",
1961 ROUTER_STR "RIPng\n" VRF_CMD_HELP_STR)
1962 {
1963 vty->node = RIPNG_NODE;
1964 return CMD_SUCCESS;
1965 }
1966 #endif /* HAVE_RIPNGD */
1967
1968 #ifdef HAVE_OSPFD
1969 DEFUNSH(VTYSH_OSPFD, router_ospf, router_ospf_cmd,
1970 "router ospf [(1-65535)] [vrf NAME]",
1971 "Enable a routing process\n"
1972 "Start OSPF configuration\n"
1973 "Instance ID\n"
1974 VRF_CMD_HELP_STR)
1975 {
1976 vty->node = OSPF_NODE;
1977 return CMD_SUCCESS;
1978 }
1979 #endif /* HAVE_OSPFD */
1980
1981 #ifdef HAVE_EIGRPD
1982 DEFUNSH(VTYSH_EIGRPD, router_eigrp, router_eigrp_cmd, "router eigrp (1-65535) [vrf NAME]",
1983 "Enable a routing process\n"
1984 "Start EIGRP configuration\n"
1985 "AS number to use\n"
1986 VRF_CMD_HELP_STR)
1987 {
1988 vty->node = EIGRP_NODE;
1989 return CMD_SUCCESS;
1990 }
1991 #endif /* HAVE_EIGRPD */
1992
1993 #ifdef HAVE_BABELD
1994 DEFUNSH(VTYSH_BABELD, router_babel, router_babel_cmd, "router babel",
1995 "Enable a routing process\n"
1996 "Make Babel instance command\n")
1997 {
1998 vty->node = BABEL_NODE;
1999 return CMD_SUCCESS;
2000 }
2001 #endif /* HAVE_BABELD */
2002
2003 #ifdef HAVE_OSPF6D
2004 DEFUNSH(VTYSH_OSPF6D, router_ospf6, router_ospf6_cmd, "router ospf6 [vrf NAME]",
2005 ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR)
2006 {
2007 vty->node = OSPF6_NODE;
2008 return CMD_SUCCESS;
2009 }
2010 #endif
2011
2012 #if defined(HAVE_LDPD)
2013 DEFUNSH(VTYSH_LDPD, ldp_mpls_ldp, ldp_mpls_ldp_cmd, "mpls ldp",
2014 "Global MPLS configuration subcommands\n"
2015 "Label Distribution Protocol\n")
2016 {
2017 vty->node = LDP_NODE;
2018 return CMD_SUCCESS;
2019 }
2020
2021 DEFUNSH(VTYSH_LDPD, ldp_address_family_ipv4, ldp_address_family_ipv4_cmd,
2022 "address-family ipv4",
2023 "Configure Address Family and its parameters\n"
2024 "IPv4\n")
2025 {
2026 vty->node = LDP_IPV4_NODE;
2027 return CMD_SUCCESS;
2028 }
2029
2030 DEFUNSH(VTYSH_LDPD, ldp_address_family_ipv6, ldp_address_family_ipv6_cmd,
2031 "address-family ipv6",
2032 "Configure Address Family and its parameters\n"
2033 "IPv6\n")
2034 {
2035 vty->node = LDP_IPV6_NODE;
2036 return CMD_SUCCESS;
2037 }
2038
2039 DEFUNSH(VTYSH_LDPD, ldp_exit_address_family, ldp_exit_address_family_cmd,
2040 "exit-address-family", "Exit from Address Family configuration mode\n")
2041 {
2042 if (vty->node == LDP_IPV4_NODE || vty->node == LDP_IPV6_NODE)
2043 vty->node = LDP_NODE;
2044 return CMD_SUCCESS;
2045 }
2046
2047 DEFUNSH(VTYSH_LDPD, ldp_interface_ifname, ldp_interface_ifname_cmd,
2048 "interface IFNAME",
2049 "Enable LDP on an interface and enter interface submode\n"
2050 "Interface's name\n")
2051 {
2052 switch (vty->node) {
2053 case LDP_IPV4_NODE:
2054 vty->node = LDP_IPV4_IFACE_NODE;
2055 break;
2056 case LDP_IPV6_NODE:
2057 vty->node = LDP_IPV6_IFACE_NODE;
2058 break;
2059 default:
2060 break;
2061 }
2062
2063 return CMD_SUCCESS;
2064 }
2065
2066 DEFUNSH(VTYSH_LDPD, ldp_l2vpn_word_type_vpls, ldp_l2vpn_word_type_vpls_cmd,
2067 "l2vpn WORD type vpls",
2068 "Configure l2vpn commands\n"
2069 "L2VPN name\n"
2070 "L2VPN type\n"
2071 "Virtual Private LAN Service\n")
2072 {
2073 vty->node = LDP_L2VPN_NODE;
2074 return CMD_SUCCESS;
2075 }
2076
2077 DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
2078 ldp_member_pseudowire_ifname_cmd, "member pseudowire IFNAME",
2079 "L2VPN member configuration\n"
2080 "Pseudowire interface\n"
2081 "Interface's name\n")
2082 {
2083 vty->node = LDP_PSEUDOWIRE_NODE;
2084 return CMD_SUCCESS;
2085 }
2086 #endif
2087
2088 #ifdef HAVE_ISISD
2089 DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
2090 "router isis WORD [vrf NAME]",
2091 ROUTER_STR
2092 "ISO IS-IS\n"
2093 "ISO Routing area tag\n" VRF_CMD_HELP_STR)
2094 {
2095 vty->node = ISIS_NODE;
2096 return CMD_SUCCESS;
2097 }
2098 #endif /* HAVE_ISISD */
2099
2100 #ifdef HAVE_FABRICD
2101 DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfabric WORD",
2102 ROUTER_STR
2103 "OpenFabric routing protocol\n"
2104 "ISO Routing area tag\n")
2105 {
2106 vty->node = OPENFABRIC_NODE;
2107 return CMD_SUCCESS;
2108 }
2109 #endif /* HAVE_FABRICD */
2110
2111 DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd,
2112 "segment-routing",
2113 "Configure segment routing\n")
2114 {
2115 vty->node = SEGMENT_ROUTING_NODE;
2116 return CMD_SUCCESS;
2117 }
2118
2119 #if defined (HAVE_PATHD)
2120 DEFUNSH(VTYSH_PATHD, sr_traffic_eng, sr_traffic_eng_cmd,
2121 "traffic-eng",
2122 "Configure SR traffic engineering\n")
2123 {
2124 vty->node = SR_TRAFFIC_ENG_NODE;
2125 return CMD_SUCCESS;
2126 }
2127
2128 DEFUNSH(VTYSH_PATHD, srte_segment_list, srte_segment_list_cmd,
2129 "segment-list WORD$name",
2130 "Segment List\n"
2131 "Segment List Name\n")
2132 {
2133 vty->node = SR_SEGMENT_LIST_NODE;
2134 return CMD_SUCCESS;
2135 }
2136
2137 DEFUNSH(VTYSH_PATHD, srte_policy, srte_policy_cmd,
2138 "policy color (0-4294967295) endpoint <A.B.C.D|X:X::X:X>",
2139 "Segment Routing Policy\n"
2140 "SR Policy color\n"
2141 "SR Policy color value\n"
2142 "SR Policy endpoint\n"
2143 "SR Policy endpoint IPv4 address\n"
2144 "SR Policy endpoint IPv6 address\n")
2145 {
2146 vty->node = SR_POLICY_NODE;
2147 return CMD_SUCCESS;
2148 }
2149
2150 DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path,
2151 srte_policy_candidate_dyn_path_cmd,
2152 "candidate-path preference (0-4294967295) name WORD dynamic",
2153 "Segment Routing Policy Candidate Path\n"
2154 "Segment Routing Policy Candidate Path Preference\n"
2155 "Administrative Preference\n"
2156 "Segment Routing Policy Candidate Path Name\n"
2157 "Symbolic Name\n"
2158 "Dynamic Path\n")
2159 {
2160 vty->node = SR_CANDIDATE_DYN_NODE;
2161 return CMD_SUCCESS;
2162 }
2163
2164 DEFUNSH(VTYSH_PATHD, pcep, pcep_cmd,
2165 "pcep",
2166 "Configure SR pcep\n")
2167 {
2168 vty->node = PCEP_NODE;
2169 return CMD_SUCCESS;
2170 }
2171
2172 DEFUNSH(VTYSH_PATHD, pcep_cli_pcc, pcep_cli_pcc_cmd,
2173 "pcc",
2174 "PCC configuration\n")
2175 {
2176 vty->node = PCEP_PCC_NODE;
2177 return CMD_SUCCESS;
2178 }
2179
2180 DEFUNSH(VTYSH_PATHD, pcep_cli_pce, pcep_cli_pce_cmd,
2181 "pce WORD",
2182 "PCE configuration\n"
2183 "Peer name\n")
2184 {
2185 vty->node = PCEP_PCE_NODE;
2186 return CMD_SUCCESS;
2187 }
2188
2189 DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd,
2190 "pce-config WORD",
2191 "PCEP peer Configuration Group\n"
2192 "PCEP peer Configuration Group name\n")
2193 {
2194 vty->node = PCEP_PCE_CONFIG_NODE;
2195 return CMD_SUCCESS;
2196 }
2197
2198 #endif /* HAVE_PATHD */
2199
2200 /* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */
2201 DEFUNSH(VTYSH_AFFMAP, affinity_map, vtysh_affinity_map_cmd,
2202 "affinity-map NAME bit-position (0-1023)",
2203 "Affinity map configuration\n"
2204 "Affinity attribute name\n"
2205 "Bit position for affinity attribute value\n"
2206 "Bit position\n")
2207 {
2208 return CMD_SUCCESS;
2209 }
2210
2211 /* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */
2212 DEFUNSH(VTYSH_AFFMAP, no_affinity_map, vtysh_no_affinity_map_cmd,
2213 "no affinity-map NAME$name [bit-position (0-1023)$position]",
2214 NO_STR
2215 "Affinity map configuration\n"
2216 "Affinity attribute name\n"
2217 "Bit position for affinity attribute value\n"
2218 "Bit position\n")
2219 {
2220 return CMD_SUCCESS;
2221 }
2222
2223 DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
2224 "route-map RMAP_NAME <deny|permit> (1-65535)",
2225 "Create route-map or enter route-map command mode\n"
2226 "Route map tag\n"
2227 "Route map denies set operations\n"
2228 "Route map permits set operations\n"
2229 "Sequence to insert to/delete from existing route-map entry\n")
2230 {
2231 vty->node = RMAP_NODE;
2232 return CMD_SUCCESS;
2233 }
2234
2235 #ifdef HAVE_PBRD
2236 DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
2237 "pbr-map PBRMAP seq (1-700)",
2238 "Create pbr-map or enter pbr-map command mode\n"
2239 "The name of the PBR MAP\n"
2240 "Sequence to insert to/delete from existing pbr-map entry\n"
2241 "Sequence number\n")
2242 {
2243 vty->node = PBRMAP_NODE;
2244 return CMD_SUCCESS;
2245 }
2246
2247 DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
2248 NO_STR
2249 "Delete pbr-map\n"
2250 "The name of the PBR MAP\n"
2251 "Sequence to delete from existing pbr-map entry\n"
2252 "Sequence number\n")
2253 #endif /* HAVE_PBRD */
2254
2255 #if HAVE_BFDD > 0
2256 DEFUNSH(VTYSH_BFDD, bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
2257 {
2258 vty->node = BFD_NODE;
2259 return CMD_SUCCESS;
2260 }
2261
2262 DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd,
2263 "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
2264 "Configure peer\n"
2265 "IPv4 peer address\n"
2266 "IPv6 peer address\n"
2267 "Configure multihop\n"
2268 "Configure local address\n"
2269 "IPv4 local address\n"
2270 "IPv6 local address\n"
2271 INTERFACE_STR
2272 "Configure interface name to use\n"
2273 "Configure VRF\n"
2274 "Configure VRF name\n")
2275 {
2276 vty->node = BFD_PEER_NODE;
2277 return CMD_SUCCESS;
2278 }
2279
2280 DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd,
2281 "profile BFDPROF",
2282 BFD_PROFILE_STR
2283 BFD_PROFILE_NAME_STR)
2284 {
2285 vty->node = BFD_PROFILE_NODE;
2286 return CMD_SUCCESS;
2287 }
2288 #endif /* HAVE_BFDD */
2289
2290 DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty",
2291 "Configure a terminal line\n"
2292 "Virtual terminal\n")
2293 {
2294 vty->node = VTY_NODE;
2295 return CMD_SUCCESS;
2296 }
2297
2298 DEFUNSH(VTYSH_REALLYALL, vtysh_enable, vtysh_enable_cmd, "enable",
2299 "Turn on privileged mode command\n")
2300 {
2301 vty->node = ENABLE_NODE;
2302 return CMD_SUCCESS;
2303 }
2304
2305 DEFUNSH(VTYSH_REALLYALL, vtysh_disable, vtysh_disable_cmd, "disable",
2306 "Turn off privileged mode command\n")
2307 {
2308 if (vty->node == ENABLE_NODE)
2309 vty->node = VIEW_NODE;
2310 return CMD_SUCCESS;
2311 }
2312
2313 DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd,
2314 "configure [terminal]",
2315 "Configuration from vty interface\n"
2316 "Configuration terminal\n")
2317 {
2318 vty->node = CONFIG_NODE;
2319 return CMD_SUCCESS;
2320 }
2321
2322 static int vtysh_exit(struct vty *vty)
2323 {
2324 struct cmd_node *cnode = vector_lookup(cmdvec, vty->node);
2325
2326 if (vty->node == VIEW_NODE || vty->node == ENABLE_NODE)
2327 exit(0);
2328 if (cnode->node_exit)
2329 cnode->node_exit(vty);
2330 if (cnode->parent_node)
2331 vty->node = cnode->parent_node;
2332
2333 if (vty->node == CONFIG_NODE) {
2334 /* resync in case one of the daemons is somewhere else */
2335 vtysh_execute("end");
2336 vtysh_execute("configure");
2337 }
2338 return CMD_SUCCESS;
2339 }
2340
2341 DEFUNSH(VTYSH_REALLYALL, vtysh_exit_all, vtysh_exit_all_cmd, "exit",
2342 "Exit current mode and down to previous mode\n")
2343 {
2344 return vtysh_exit(vty);
2345 }
2346
2347 DEFUNSH(VTYSH_REALLYALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit",
2348 "Exit current mode and down to previous mode\n")
2349 {
2350 return vtysh_exit_all(self, vty, argc, argv);
2351 }
2352
2353 #ifdef HAVE_BGPD
2354 DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd,
2355 "exit-address-family", "Exit from Address Family configuration mode\n")
2356 {
2357 if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE
2358 || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE
2359 || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE
2360 || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE
2361 || vty->node == BGP_EVPN_NODE
2362 || vty->node == BGP_FLOWSPECV4_NODE
2363 || vty->node == BGP_FLOWSPECV6_NODE)
2364 vty->node = BGP_NODE;
2365 return CMD_SUCCESS;
2366 }
2367
2368 DEFUNSH(VTYSH_BGPD, exit_vni, exit_vni_cmd, "exit-vni", "Exit from VNI mode\n")
2369 {
2370 if (vty->node == BGP_EVPN_VNI_NODE)
2371 vty->node = BGP_EVPN_NODE;
2372 return CMD_SUCCESS;
2373 }
2374
2375 DEFUNSH(VTYSH_BGPD, rpki_exit, rpki_exit_cmd, "exit",
2376 "Exit current mode and down to previous mode\n")
2377 {
2378 vtysh_exit(vty);
2379 return CMD_SUCCESS;
2380 }
2381
2382 DEFUNSH(VTYSH_BGPD, rpki_quit, rpki_quit_cmd, "quit",
2383 "Exit current mode and down to previous mode\n")
2384 {
2385 return rpki_exit(self, vty, argc, argv);
2386 }
2387
2388 DEFUNSH(VTYSH_BGPD, bmp_exit, bmp_exit_cmd, "exit",
2389 "Exit current mode and down to previous mode\n")
2390 {
2391 vtysh_exit(vty);
2392 return CMD_SUCCESS;
2393 }
2394
2395 DEFUNSH(VTYSH_BGPD, bmp_quit, bmp_quit_cmd, "quit",
2396 "Exit current mode and down to previous mode\n")
2397 {
2398 return bmp_exit(self, vty, argc, argv);
2399 }
2400 #endif /* HAVE_BGPD */
2401
2402 DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
2403 "Exit from VRF configuration mode\n")
2404 {
2405 if (vty->node == VRF_NODE)
2406 vty->node = CONFIG_NODE;
2407 return CMD_SUCCESS;
2408 }
2409
2410 DEFUNSH(VTYSH_ZEBRA, exit_srv6_config, exit_srv6_config_cmd, "exit",
2411 "Exit from SRv6 configuration mode\n")
2412 {
2413 if (vty->node == SRV6_NODE)
2414 vty->node = SEGMENT_ROUTING_NODE;
2415 return CMD_SUCCESS;
2416 }
2417
2418 DEFUNSH(VTYSH_ZEBRA, exit_srv6_locs_config, exit_srv6_locs_config_cmd, "exit",
2419 "Exit from SRv6-locator configuration mode\n")
2420 {
2421 if (vty->node == SRV6_LOCS_NODE)
2422 vty->node = SRV6_NODE;
2423 return CMD_SUCCESS;
2424 }
2425
2426 DEFUNSH(VTYSH_ZEBRA, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit",
2427 "Exit from SRv6-locators configuration mode\n")
2428 {
2429 if (vty->node == SRV6_LOC_NODE)
2430 vty->node = SRV6_LOCS_NODE;
2431 return CMD_SUCCESS;
2432 }
2433
2434 #ifdef HAVE_RIPD
2435 DEFUNSH(VTYSH_RIPD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit",
2436 "Exit current mode and down to previous mode\n")
2437 {
2438 return vtysh_exit(vty);
2439 }
2440
2441 DEFUNSH(VTYSH_RIPD, vtysh_quit_ripd, vtysh_quit_ripd_cmd, "quit",
2442 "Exit current mode and down to previous mode\n")
2443 {
2444 return vtysh_exit_ripd(self, vty, argc, argv);
2445 }
2446 #endif /* HAVE_RIPD */
2447
2448 #ifdef HAVE_RIPNGD
2449 DEFUNSH(VTYSH_RIPNGD, vtysh_exit_ripngd, vtysh_exit_ripngd_cmd, "exit",
2450 "Exit current mode and down to previous mode\n")
2451 {
2452 return vtysh_exit(vty);
2453 }
2454
2455 DEFUNSH(VTYSH_RIPNGD, vtysh_quit_ripngd, vtysh_quit_ripngd_cmd, "quit",
2456 "Exit current mode and down to previous mode\n")
2457 {
2458 return vtysh_exit_ripngd(self, vty, argc, argv);
2459 }
2460 #endif /* HAVE_RIPNGD */
2461
2462 DEFUNSH(VTYSH_RMAP, vtysh_exit_rmap, vtysh_exit_rmap_cmd, "exit",
2463 "Exit current mode and down to previous mode\n")
2464 {
2465 return vtysh_exit(vty);
2466 }
2467
2468 DEFUNSH(VTYSH_RMAP, vtysh_quit_rmap, vtysh_quit_rmap_cmd, "quit",
2469 "Exit current mode and down to previous mode\n")
2470 {
2471 return vtysh_exit_rmap(self, vty, argc, argv);
2472 }
2473
2474 #ifdef HAVE_PBRD
2475 DEFUNSH(VTYSH_PBRD, vtysh_exit_pbr_map, vtysh_exit_pbr_map_cmd, "exit",
2476 "Exit current mode and down to previous mode\n")
2477 {
2478 return vtysh_exit(vty);
2479 }
2480
2481 DEFUNSH(VTYSH_PBRD, vtysh_quit_pbr_map, vtysh_quit_pbr_map_cmd, "quit",
2482 "Exit current mode and down to previous mode\n")
2483 {
2484 return vtysh_exit_rmap(self, vty, argc, argv);
2485 }
2486 #endif /* HAVE_PBRD */
2487
2488 #ifdef HAVE_BGPD
2489 DEFUNSH(VTYSH_BGPD, vtysh_exit_bgpd, vtysh_exit_bgpd_cmd, "exit",
2490 "Exit current mode and down to previous mode\n")
2491 {
2492 return vtysh_exit(vty);
2493 }
2494
2495 DEFUNSH(VTYSH_BGPD, vtysh_quit_bgpd, vtysh_quit_bgpd_cmd, "quit",
2496 "Exit current mode and down to previous mode\n")
2497 {
2498 return vtysh_exit_bgpd(self, vty, argc, argv);
2499 }
2500 #endif /* HAVE_BGPD */
2501
2502 #ifdef HAVE_OSPFD
2503 DEFUNSH(VTYSH_OSPFD, vtysh_exit_ospfd, vtysh_exit_ospfd_cmd, "exit",
2504 "Exit current mode and down to previous mode\n")
2505 {
2506 return vtysh_exit(vty);
2507 }
2508
2509 DEFUNSH(VTYSH_OSPFD, vtysh_quit_ospfd, vtysh_quit_ospfd_cmd, "quit",
2510 "Exit current mode and down to previous mode\n")
2511 {
2512 return vtysh_exit_ospfd(self, vty, argc, argv);
2513 }
2514 #endif /* HAVE_OSPFD */
2515
2516 #ifdef HAVE_EIGRPD
2517 DEFUNSH(VTYSH_EIGRPD, vtysh_exit_eigrpd, vtysh_exit_eigrpd_cmd, "exit",
2518 "Exit current mode and down to previous mode\n")
2519 {
2520 return vtysh_exit(vty);
2521 }
2522
2523 DEFUNSH(VTYSH_EIGRPD, vtysh_quit_eigrpd, vtysh_quit_eigrpd_cmd, "quit",
2524 "Exit current mode and down to previous mode\n")
2525 {
2526 return vtysh_exit(vty);
2527 }
2528 #endif /* HAVE_EIGRPD */
2529
2530 #ifdef HAVE_BABELD
2531 DEFUNSH(VTYSH_BABELD, vtysh_exit_babeld, vtysh_exit_babeld_cmd, "exit",
2532 "Exit current mode and down to previous mode\n")
2533 {
2534 return vtysh_exit(vty);
2535 }
2536
2537 DEFUNSH(VTYSH_BABELD, vtysh_quit_babeld, vtysh_quit_babeld_cmd, "quit",
2538 "Exit current mode and down to previous mode\n")
2539 {
2540 return vtysh_exit(vty);
2541 }
2542 #endif /* HAVE_BABELD */
2543
2544 #ifdef HAVE_OSPF6D
2545 DEFUNSH(VTYSH_OSPF6D, vtysh_exit_ospf6d, vtysh_exit_ospf6d_cmd, "exit",
2546 "Exit current mode and down to previous mode\n")
2547 {
2548 return vtysh_exit(vty);
2549 }
2550
2551 DEFUNSH(VTYSH_OSPF6D, vtysh_quit_ospf6d, vtysh_quit_ospf6d_cmd, "quit",
2552 "Exit current mode and down to previous mode\n")
2553 {
2554 return vtysh_exit_ospf6d(self, vty, argc, argv);
2555 }
2556 #endif /* HAVE_OSPF6D */
2557
2558 #if defined(HAVE_LDPD)
2559 DEFUNSH(VTYSH_LDPD, vtysh_exit_ldpd, vtysh_exit_ldpd_cmd, "exit",
2560 "Exit current mode and down to previous mode\n")
2561 {
2562 return vtysh_exit(vty);
2563 }
2564
2565 ALIAS(vtysh_exit_ldpd, vtysh_quit_ldpd_cmd, "quit",
2566 "Exit current mode and down to previous mode\n")
2567 #endif
2568
2569 #ifdef HAVE_ISISD
2570 DEFUNSH(VTYSH_ISISD, vtysh_exit_isisd, vtysh_exit_isisd_cmd, "exit",
2571 "Exit current mode and down to previous mode\n")
2572 {
2573 return vtysh_exit(vty);
2574 }
2575
2576 DEFUNSH(VTYSH_ISISD, vtysh_quit_isisd, vtysh_quit_isisd_cmd, "quit",
2577 "Exit current mode and down to previous mode\n")
2578 {
2579 return vtysh_exit_isisd(self, vty, argc, argv);
2580 }
2581 #endif /* HAVE_ISISD */
2582
2583 #if HAVE_BFDD > 0
2584 DEFUNSH(VTYSH_BFDD, vtysh_exit_bfdd, vtysh_exit_bfdd_cmd, "exit",
2585 "Exit current mode and down to previous mode\n")
2586 {
2587 return vtysh_exit(vty);
2588 }
2589
2590 ALIAS(vtysh_exit_bfdd, vtysh_quit_bfdd_cmd, "quit",
2591 "Exit current mode and down to previous mode\n")
2592 #endif
2593
2594 #ifdef HAVE_FABRICD
2595 DEFUNSH(VTYSH_FABRICD, vtysh_exit_fabricd, vtysh_exit_fabricd_cmd, "exit",
2596 "Exit current mode and down to previous mode\n")
2597 {
2598 return vtysh_exit(vty);
2599 }
2600
2601 DEFUNSH(VTYSH_FABRICD, vtysh_quit_fabricd, vtysh_quit_fabricd_cmd, "quit",
2602 "Exit current mode and down to previous mode\n")
2603 {
2604 return vtysh_exit_fabricd(self, vty, argc, argv);
2605 }
2606 #endif /* HAVE_FABRICD */
2607
2608 DEFUNSH(VTYSH_KEYS, vtysh_exit_keys, vtysh_exit_keys_cmd, "exit",
2609 "Exit current mode and down to previous mode\n")
2610 {
2611 return vtysh_exit(vty);
2612 }
2613
2614 DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
2615 "Exit current mode and down to previous mode\n")
2616 {
2617 return vtysh_exit_keys(self, vty, argc, argv);
2618 }
2619
2620 DEFUNSH(VTYSH_SR, vtysh_exit_sr, vtysh_exit_sr_cmd, "exit",
2621 "Exit current mode and down to previous mode\n")
2622 {
2623 return vtysh_exit(vty);
2624 }
2625
2626 DEFUNSH(VTYSH_SR, vtysh_quit_sr, vtysh_quit_sr_cmd, "quit",
2627 "Exit current mode and down to previous mode\n")
2628 {
2629 return vtysh_exit(vty);
2630 }
2631
2632 #if defined(HAVE_PATHD)
2633 DEFUNSH(VTYSH_PATHD, vtysh_exit_pathd, vtysh_exit_pathd_cmd, "exit",
2634 "Exit current mode and down to previous mode\n")
2635 {
2636 return vtysh_exit(vty);
2637 }
2638
2639 DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit",
2640 "Exit current mode and down to previous mode\n")
2641 {
2642 return vtysh_exit_pathd(self, vty, argc, argv);
2643 }
2644 #endif /* HAVE_PATHD */
2645
2646 DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
2647 "Exit current mode and down to previous mode\n")
2648 {
2649 return vtysh_exit(vty);
2650 }
2651
2652 DEFUNSH(VTYSH_ALL, vtysh_quit_line_vty, vtysh_quit_line_vty_cmd, "quit",
2653 "Exit current mode and down to previous mode\n")
2654 {
2655 return vtysh_exit_line_vty(self, vty, argc, argv);
2656 }
2657
2658 DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd,
2659 "interface IFNAME [vrf NAME]",
2660 "Select an interface to configure\n"
2661 "Interface's name\n" VRF_CMD_HELP_STR)
2662 {
2663 vty->node = INTERFACE_NODE;
2664 return CMD_SUCCESS;
2665 }
2666
2667 DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd,
2668 "pseudowire IFNAME",
2669 "Static pseudowire configuration\n"
2670 "Pseudowire name\n")
2671 {
2672 vty->node = PW_NODE;
2673 return CMD_SUCCESS;
2674 }
2675
2676 DEFUNSH(VTYSH_NH_GROUP,
2677 vtysh_nexthop_group, vtysh_nexthop_group_cmd,
2678 "nexthop-group NHGNAME",
2679 "Nexthop Group configuration\n"
2680 "Name of the Nexthop Group\n")
2681 {
2682 vty->node = NH_GROUP_NODE;
2683 return CMD_SUCCESS;
2684 }
2685
2686 DEFSH(VTYSH_NH_GROUP, vtysh_no_nexthop_group_cmd,
2687 "no nexthop-group NHGNAME",
2688 NO_STR
2689 "Nexthop Group Configuration\n"
2690 "Name of the Nexthop Group\n")
2691
2692 DEFUNSH(VTYSH_VRF, vtysh_vrf, vtysh_vrf_cmd, "vrf NAME",
2693 "Select a VRF to configure\n"
2694 "VRF's name\n")
2695 {
2696 vty->node = VRF_NODE;
2697 return CMD_SUCCESS;
2698 }
2699
2700 DEFUNSH(VTYSH_VRF, vtysh_exit_vrf, vtysh_exit_vrf_cmd, "exit",
2701 "Exit current mode and down to previous mode\n")
2702 {
2703 return vtysh_exit(vty);
2704 }
2705
2706 DEFUNSH(VTYSH_VRF, vtysh_quit_vrf, vtysh_quit_vrf_cmd, "quit",
2707 "Exit current mode and down to previous mode\n")
2708 {
2709 return vtysh_exit_vrf(self, vty, argc, argv);
2710 }
2711
2712 DEFUNSH(VTYSH_NH_GROUP,
2713 vtysh_exit_nexthop_group, vtysh_exit_nexthop_group_cmd,
2714 "exit", "Exit current mode and down to previous mode\n")
2715 {
2716 return vtysh_exit(vty);
2717 }
2718
2719 DEFUNSH(VTYSH_NH_GROUP,
2720 vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd,
2721 "quit", "Exit current mode and down to previous mode\n")
2722 {
2723 return vtysh_exit_nexthop_group(self, vty, argc, argv);
2724 }
2725
2726 DEFUNSH(VTYSH_INTERFACE, vtysh_exit_interface, vtysh_exit_interface_cmd, "exit",
2727 "Exit current mode and down to previous mode\n")
2728 {
2729 return vtysh_exit(vty);
2730 }
2731
2732 DEFUNSH(VTYSH_INTERFACE, vtysh_quit_interface, vtysh_quit_interface_cmd, "quit",
2733 "Exit current mode and down to previous mode\n")
2734 {
2735 return vtysh_exit_interface(self, vty, argc, argv);
2736 }
2737
2738 DEFUNSH(VTYSH_ZEBRA, vtysh_exit_pseudowire, vtysh_exit_pseudowire_cmd, "exit",
2739 "Exit current mode and down to previous mode\n")
2740 {
2741 return vtysh_exit(vty);
2742 }
2743
2744 DEFUNSH(VTYSH_ZEBRA, vtysh_quit_pseudowire, vtysh_quit_pseudowire_cmd, "quit",
2745 "Exit current mode and down to previous mode\n")
2746 {
2747 return vtysh_exit_pseudowire(self, vty, argc, argv);
2748 }
2749
2750 static char *do_prepend(struct vty *vty, struct cmd_token **argv, int argc)
2751 {
2752 const char *argstr[argc + 1];
2753 int i, off = 0;
2754
2755 if (vty->node != VIEW_NODE) {
2756 off = 1;
2757 argstr[0] = "do";
2758 }
2759
2760 for (i = 0; i < argc; i++)
2761 argstr[i + off] = argv[i]->arg;
2762
2763 return frrstr_join(argstr, argc + off, " ");
2764 }
2765
2766 #pragma GCC diagnostic push
2767 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
2768 /* 'headline' is a format string with a %s for the daemon name
2769 *
2770 * Also for some reason GCC emits the warning on the end of the function
2771 * (optimization maybe?) rather than on the vty_out line, so this pragma
2772 * wraps the entire function rather than just the vty_out line.
2773 */
2774
2775 static int show_per_daemon(struct vty *vty, struct cmd_token **argv, int argc,
2776 const char *headline)
2777 {
2778 unsigned int i;
2779 int ret = CMD_SUCCESS;
2780 char *line = do_prepend(vty, argv, argc);
2781
2782 for (i = 0; i < array_size(vtysh_client); i++)
2783 if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) {
2784 vty_out(vty, headline, vtysh_client[i].name);
2785 ret = vtysh_client_execute(&vtysh_client[i], line);
2786 vty_out(vty, "\n");
2787 }
2788
2789 XFREE(MTYPE_TMP, line);
2790
2791 return ret;
2792 }
2793 #pragma GCC diagnostic pop
2794
2795 static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc,
2796 const char *name)
2797 {
2798 int ret;
2799 char *line = do_prepend(vty, argv, argc);
2800
2801 ret = vtysh_client_execute_name(name, line);
2802
2803 XFREE(MTYPE_TMP, line);
2804
2805 return ret;
2806 }
2807
2808 DEFUN (vtysh_show_thread_timer,
2809 vtysh_show_thread_timer_cmd,
2810 "show thread timers",
2811 SHOW_STR
2812 "Thread information\n"
2813 "Show all timers and how long they have in the system\n")
2814 {
2815 return show_per_daemon(vty, argv, argc, "Thread timers for %s:\n");
2816 }
2817
2818 DEFUN (vtysh_show_poll,
2819 vtysh_show_poll_cmd,
2820 "show thread poll",
2821 SHOW_STR
2822 "Thread information\n"
2823 "Thread Poll Information\n")
2824 {
2825 return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
2826 }
2827
2828 DEFUN (vtysh_show_thread,
2829 vtysh_show_thread_cmd,
2830 "show thread cpu [FILTER]",
2831 SHOW_STR
2832 "Thread information\n"
2833 "Thread CPU usage\n"
2834 "Display filter (rwtexb)\n")
2835 {
2836 return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
2837 }
2838
2839 DEFUN (vtysh_show_work_queues,
2840 vtysh_show_work_queues_cmd,
2841 "show work-queues",
2842 SHOW_STR
2843 "Work Queue information\n")
2844 {
2845 return show_per_daemon(vty, argv, argc,
2846 "Work queue statistics for %s:\n");
2847 }
2848
2849 DEFUN (vtysh_show_work_queues_daemon,
2850 vtysh_show_work_queues_daemon_cmd,
2851 "show work-queues " DAEMONS_LIST,
2852 SHOW_STR
2853 "Work Queue information\n"
2854 DAEMONS_STR)
2855 {
2856 return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
2857 }
2858
2859 DEFUNSH(VTYSH_ZEBRA, vtysh_link_params, vtysh_link_params_cmd, "link-params",
2860 LINK_PARAMS_STR)
2861 {
2862 vty->node = LINK_PARAMS_NODE;
2863 return CMD_SUCCESS;
2864 }
2865
2866 DEFUNSH(VTYSH_ZEBRA, exit_link_params, exit_link_params_cmd, "exit-link-params",
2867 "Exit from Link Params configuration node\n")
2868 {
2869 if (vty->node == LINK_PARAMS_NODE)
2870 vty->node = INTERFACE_NODE;
2871 return CMD_SUCCESS;
2872 }
2873
2874 DEFUNSH(VTYSH_ZEBRA, vtysh_exit_link_params, vtysh_exit_link_params_cmd, "exit",
2875 "Exit current mode and down to previous mode\n")
2876 {
2877 if (vty->node == LINK_PARAMS_NODE)
2878 vty->node = INTERFACE_NODE;
2879 return CMD_SUCCESS;
2880 }
2881
2882 DEFUNSH(VTYSH_ZEBRA, vtysh_quit_link_params, vtysh_quit_link_params_cmd, "quit",
2883 "Exit current mode and down to previous mode\n")
2884 {
2885 return vtysh_exit_link_params(self, vty, argc, argv);
2886 }
2887
2888 DEFUNSH_HIDDEN (0x00,
2889 vtysh_debug_all,
2890 vtysh_debug_all_cmd,
2891 "[no] debug all",
2892 NO_STR
2893 DEBUG_STR
2894 "Toggle all debugs on or off\n")
2895 {
2896 return CMD_SUCCESS;
2897 }
2898
2899 DEFUN (vtysh_show_debugging,
2900 vtysh_show_debugging_cmd,
2901 "show debugging",
2902 SHOW_STR
2903 DEBUG_STR)
2904 {
2905 return show_per_daemon(vty, argv, argc, "");
2906 }
2907
2908 DEFUN (vtysh_show_debugging_hashtable,
2909 vtysh_show_debugging_hashtable_cmd,
2910 "show debugging hashtable [statistics]",
2911 SHOW_STR
2912 DEBUG_STR
2913 "Statistics about hash tables\n"
2914 "Statistics about hash tables\n")
2915 {
2916 bool stats = strmatch(argv[argc - 1]->text, "statistics");
2917
2918 vty_out(vty, "\n");
2919 vty_out(vty,
2920 "Load factor (LF) - average number of elements across all buckets\n");
2921 vty_out(vty,
2922 "Full load factor (FLF) - average number of elements across full buckets\n\n");
2923 vty_out(vty,
2924 "Standard deviation (SD) is calculated for both the LF and FLF\n");
2925 vty_out(vty,
2926 "and indicates the typical deviation of bucket chain length\n");
2927 vty_out(vty, "from the value in the corresponding load factor.\n\n");
2928
2929 return show_per_daemon(vty, argv, stats ? argc - 1 : argc,
2930 "Hashtable statistics for %s:\n");
2931 }
2932
2933 DEFUN (vtysh_show_error_code,
2934 vtysh_show_error_code_cmd,
2935 "show error <(1-4294967296)|all> [json]",
2936 SHOW_STR
2937 "Information on errors\n"
2938 "Error code to get info about\n"
2939 "Information on all errors\n"
2940 JSON_STR)
2941 {
2942 uint32_t arg = 0;
2943
2944 if (!strmatch(argv[2]->text, "all"))
2945 arg = strtoul(argv[2]->arg, NULL, 10);
2946
2947 /* If it's not a shared code, send it to all the daemons */
2948 if (arg < LIB_FERR_START || arg > LIB_FERR_END) {
2949 show_per_daemon(vty, argv, argc, "");
2950 /* Otherwise, print it ourselves to avoid duplication */
2951 } else {
2952 bool json = strmatch(argv[argc - 1]->text, "json");
2953
2954 if (!strmatch(argv[2]->text, "all"))
2955 arg = strtoul(argv[2]->arg, NULL, 10);
2956
2957 log_ref_display(vty, arg, json);
2958 }
2959
2960 return CMD_SUCCESS;
2961 }
2962
2963 /* Northbound. */
2964 DEFUN_HIDDEN (show_config_running,
2965 show_config_running_cmd,
2966 "show configuration running\
2967 [<json|xml> [translate WORD]]\
2968 [with-defaults] " DAEMONS_LIST,
2969 SHOW_STR
2970 "Configuration information\n"
2971 "Running configuration\n"
2972 "Change output format to JSON\n"
2973 "Change output format to XML\n"
2974 "Translate output\n"
2975 "YANG module translator\n"
2976 "Show default values\n"
2977 DAEMONS_STR)
2978 {
2979 return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
2980 }
2981
2982 DEFUN (show_yang_operational_data,
2983 show_yang_operational_data_cmd,
2984 "show yang operational-data XPATH\
2985 [{\
2986 format <json|xml>\
2987 |translate WORD\
2988 |with-config\
2989 }] " DAEMONS_LIST,
2990 SHOW_STR
2991 "YANG information\n"
2992 "Show YANG operational data\n"
2993 "XPath expression specifying the YANG data path\n"
2994 "Set the output format\n"
2995 "JavaScript Object Notation\n"
2996 "Extensible Markup Language\n"
2997 "Translate operational data\n"
2998 "YANG module translator\n"
2999 "Merge configuration data\n"
3000 DAEMONS_STR)
3001 {
3002 return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
3003 }
3004
3005 DEFUN(show_yang_module, show_yang_module_cmd,
3006 "show yang module [module-translator WORD] " DAEMONS_LIST,
3007 SHOW_STR
3008 "YANG information\n"
3009 "Show loaded modules\n"
3010 "YANG module translator\n"
3011 "YANG module translator\n" DAEMONS_STR)
3012 {
3013 return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
3014 }
3015
3016 DEFUN(show_yang_module_detail, show_yang_module_detail_cmd,
3017 "show yang module\
3018 [module-translator WORD]\
3019 WORD <compiled|summary|tree|yang|yin> " DAEMONS_LIST,
3020 SHOW_STR
3021 "YANG information\n"
3022 "Show loaded modules\n"
3023 "YANG module translator\n"
3024 "YANG module translator\n"
3025 "Module name\n"
3026 "Display compiled module in YANG format\n"
3027 "Display summary information about the module\n"
3028 "Display module in the tree (RFC 8340) format\n"
3029 "Display module in the YANG format\n"
3030 "Display module in the YIN format\n" DAEMONS_STR)
3031 {
3032 return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text);
3033 }
3034
3035
3036 DEFUNSH(VTYSH_ALL, debug_nb,
3037 debug_nb_cmd,
3038 "[no] debug northbound\
3039 [<\
3040 callbacks [{configuration|state|rpc}]\
3041 |notifications\
3042 |events\
3043 |libyang\
3044 >]",
3045 NO_STR
3046 DEBUG_STR
3047 "Northbound debugging\n"
3048 "Callbacks\n"
3049 "Configuration\n"
3050 "State\n"
3051 "RPC\n"
3052 "Notifications\n"
3053 "Events\n"
3054 "libyang debugging\n")
3055 {
3056 return CMD_SUCCESS;
3057 }
3058
3059 DEFUN (vtysh_show_history,
3060 vtysh_show_history_cmd,
3061 "show history",
3062 SHOW_STR
3063 "The list of commands stored in history\n")
3064 {
3065 HIST_ENTRY **hlist = history_list();
3066 int i = 0;
3067
3068 while (hlist[i]) {
3069 vty_out(vty, "%s\n", hlist[i]->line);
3070 i++;
3071 }
3072 return CMD_SUCCESS;
3073 }
3074
3075 /* Memory */
3076 DEFUN (vtysh_show_memory,
3077 vtysh_show_memory_cmd,
3078 "show memory [" DAEMONS_LIST "]",
3079 SHOW_STR
3080 "Memory statistics\n"
3081 DAEMONS_STR)
3082 {
3083 if (argc == 3)
3084 return show_one_daemon(vty, argv, argc - 1,
3085 argv[argc - 1]->text);
3086
3087 return show_per_daemon(vty, argv, argc, "Memory statistics for %s:\n");
3088 }
3089
3090 DEFUN (vtysh_show_modules,
3091 vtysh_show_modules_cmd,
3092 "show modules",
3093 SHOW_STR
3094 "Loaded modules\n")
3095 {
3096 return show_per_daemon(vty, argv, argc, "Module information for %s:\n");
3097 }
3098
3099 /* Logging commands. */
3100 DEFUN (vtysh_show_logging,
3101 vtysh_show_logging_cmd,
3102 "show logging",
3103 SHOW_STR
3104 "Show current logging configuration\n")
3105 {
3106 return show_per_daemon(vty, argv, argc,
3107 "Logging configuration for %s:\n");
3108 }
3109
3110 DEFUNSH(VTYSH_ALL, vtysh_debug_memstats,
3111 vtysh_debug_memstats_cmd, "[no] debug memstats-at-exit",
3112 NO_STR
3113 "Debug\n"
3114 "Print memory statistics at exit\n")
3115 {
3116 return CMD_SUCCESS;
3117 }
3118
3119 DEFUN(vtysh_debug_uid_backtrace,
3120 vtysh_debug_uid_backtrace_cmd,
3121 "[no] debug unique-id UID backtrace",
3122 NO_STR
3123 DEBUG_STR
3124 "Options per individual log message, by unique ID\n"
3125 "Log message unique ID (XXXXX-XXXXX)\n"
3126 "Add backtrace to log when message is printed\n")
3127 {
3128 unsigned int i, ok = 0;
3129 int err = CMD_SUCCESS, ret;
3130 const char *uid;
3131 char line[64];
3132
3133 if (!strcmp(argv[0]->text, "no")) {
3134 uid = argv[3]->arg;
3135 snprintfrr(line, sizeof(line),
3136 "no debug unique-id %s backtrace", uid);
3137 } else {
3138 uid = argv[2]->arg;
3139 snprintfrr(line, sizeof(line), "debug unique-id %s backtrace",
3140 uid);
3141 }
3142
3143 for (i = 0; i < array_size(vtysh_client); i++)
3144 if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) {
3145 ret = vtysh_client_execute(&vtysh_client[i], line);
3146 switch (ret) {
3147 case CMD_SUCCESS:
3148 ok++;
3149 break;
3150 case CMD_ERR_NOTHING_TODO:
3151 /* ignore this daemon
3152 *
3153 * note this doesn't need to handle instances
3154 * of the same daemon individually because
3155 * the same daemon will have the same UIDs
3156 */
3157 break;
3158 default:
3159 if (err == CMD_SUCCESS)
3160 err = ret;
3161 break;
3162 }
3163 }
3164
3165 if (err == CMD_SUCCESS && !ok) {
3166 vty_out(vty, "%% no running daemon recognizes unique-ID %s\n",
3167 uid);
3168 err = CMD_WARNING;
3169 }
3170 return err;
3171 }
3172
3173 DEFUNSH(VTYSH_ALL, vtysh_allow_reserved_ranges, vtysh_allow_reserved_ranges_cmd,
3174 "allow-reserved-ranges",
3175 "Allow using IPv4 (Class E) reserved IP space\n")
3176 {
3177 return CMD_SUCCESS;
3178 }
3179
3180 DEFUNSH(VTYSH_ALL, no_vtysh_allow_reserved_ranges,
3181 no_vtysh_allow_reserved_ranges_cmd, "no allow-reserved-ranges",
3182 NO_STR "Allow using IPv4 (Class E) reserved IP space\n")
3183 {
3184 return CMD_SUCCESS;
3185 }
3186
3187 DEFUNSH(VTYSH_ALL, vtysh_service_password_encrypt,
3188 vtysh_service_password_encrypt_cmd, "service password-encryption",
3189 "Set up miscellaneous service\n"
3190 "Enable encrypted passwords\n")
3191 {
3192 return CMD_SUCCESS;
3193 }
3194
3195 DEFUNSH(VTYSH_ALL, no_vtysh_service_password_encrypt,
3196 no_vtysh_service_password_encrypt_cmd, "no service password-encryption",
3197 NO_STR
3198 "Set up miscellaneous service\n"
3199 "Enable encrypted passwords\n")
3200 {
3201 return CMD_SUCCESS;
3202 }
3203
3204 DEFUNSH(VTYSH_ALL, vtysh_config_password, vtysh_password_cmd,
3205 "password [(8-8)] LINE",
3206 "Modify the terminal connection password\n"
3207 "Specifies a HIDDEN password will follow\n"
3208 "The password string\n")
3209 {
3210 return CMD_SUCCESS;
3211 }
3212
3213 DEFUNSH(VTYSH_ALL, no_vtysh_config_password, no_vtysh_password_cmd,
3214 "no password", NO_STR
3215 "Modify the terminal connection password\n")
3216 {
3217 vty_out(vty, NO_PASSWD_CMD_WARNING);
3218
3219 return CMD_SUCCESS;
3220 }
3221
3222 DEFUNSH(VTYSH_ALL, vtysh_config_enable_password, vtysh_enable_password_cmd,
3223 "enable password [(8-8)] LINE",
3224 "Modify enable password parameters\n"
3225 "Assign the privileged level password\n"
3226 "Specifies a HIDDEN password will follow\n"
3227 "The 'enable' password string\n")
3228 {
3229 return CMD_SUCCESS;
3230 }
3231
3232 DEFUNSH(VTYSH_ALL, no_vtysh_config_enable_password,
3233 no_vtysh_enable_password_cmd, "no enable password", NO_STR
3234 "Modify enable password parameters\n"
3235 "Assign the privileged level password\n")
3236 {
3237 vty_out(vty, NO_PASSWD_CMD_WARNING);
3238
3239 return CMD_SUCCESS;
3240 }
3241
3242 DEFUN (vtysh_write_terminal,
3243 vtysh_write_terminal_cmd,
3244 "write terminal ["DAEMONS_LIST"] [no-header]",
3245 "Write running configuration to memory, network, or terminal\n"
3246 "Write to terminal\n"
3247 DAEMONS_STR
3248 "Skip \"Building configuration...\" header\n")
3249 {
3250 unsigned int i;
3251 char line[] = "do write terminal";
3252
3253 if (!strcmp(argv[argc - 1]->arg, "no-header"))
3254 argc--;
3255 else {
3256 vty_out(vty, "Building configuration...\n");
3257 vty_out(vty, "\nCurrent configuration:\n");
3258 vty_out(vty, "!\n");
3259 }
3260
3261 for (i = 0; i < array_size(vtysh_client); i++)
3262 if ((argc < 3)
3263 || (strmatch(vtysh_client[i].name, argv[2]->text)))
3264 vtysh_client_config(&vtysh_client[i], line);
3265
3266 /* Integrate vtysh specific configuration. */
3267 vty_open_pager(vty);
3268 vtysh_config_write();
3269 vtysh_config_dump();
3270 vty_close_pager(vty);
3271 vty_out(vty, "end\n");
3272
3273 return CMD_SUCCESS;
3274 }
3275
3276 DEFUN (vtysh_show_running_config,
3277 vtysh_show_running_config_cmd,
3278 "show running-config ["DAEMONS_LIST"] [no-header]",
3279 SHOW_STR
3280 "Current operating configuration\n"
3281 DAEMONS_STR
3282 "Skip \"Building configuration...\" header\n")
3283 {
3284 return vtysh_write_terminal(self, vty, argc, argv);
3285 }
3286
3287 DEFUN (vtysh_integrated_config,
3288 vtysh_integrated_config_cmd,
3289 "service integrated-vtysh-config",
3290 "Set up miscellaneous service\n"
3291 "Write configuration into integrated file\n")
3292 {
3293 vtysh_write_integrated = WRITE_INTEGRATED_YES;
3294 return CMD_SUCCESS;
3295 }
3296
3297 DEFUN (no_vtysh_integrated_config,
3298 no_vtysh_integrated_config_cmd,
3299 "no service integrated-vtysh-config",
3300 NO_STR
3301 "Set up miscellaneous service\n"
3302 "Write configuration into integrated file\n")
3303 {
3304 vtysh_write_integrated = WRITE_INTEGRATED_NO;
3305 return CMD_SUCCESS;
3306 }
3307
3308 static void backup_config_file(const char *fbackup)
3309 {
3310 char *integrate_sav = NULL;
3311
3312 size_t integrate_sav_sz = strlen(fbackup) + strlen(CONF_BACKUP_EXT) + 1;
3313 integrate_sav = malloc(integrate_sav_sz);
3314 strlcpy(integrate_sav, fbackup, integrate_sav_sz);
3315 strlcat(integrate_sav, CONF_BACKUP_EXT, integrate_sav_sz);
3316
3317 /* Move current configuration file to backup config file. */
3318 if (unlink(integrate_sav) != 0 && errno != ENOENT)
3319 vty_out(vty, "Unlink failed for %s: %s\n", integrate_sav,
3320 strerror(errno));
3321 if (rename(fbackup, integrate_sav) != 0 && errno != ENOENT)
3322 vty_out(vty, "Error renaming %s to %s: %s\n", fbackup,
3323 integrate_sav, strerror(errno));
3324 free(integrate_sav);
3325 }
3326
3327 int vtysh_write_config_integrated(void)
3328 {
3329 unsigned int i;
3330 char line[] = "do write terminal";
3331 FILE *fp;
3332 int fd;
3333 #ifdef FRR_USER
3334 struct passwd *pwentry;
3335 #endif
3336 #ifdef FRR_GROUP
3337 struct group *grentry;
3338 #endif
3339 uid_t uid = -1;
3340 gid_t gid = -1;
3341 struct stat st;
3342 int err = 0;
3343
3344 vty_out(vty, "Building Configuration...\n");
3345
3346 backup_config_file(frr_config);
3347 fp = fopen(frr_config, "w");
3348 if (fp == NULL) {
3349 vty_out(vty,
3350 "%% Error: failed to open configuration file %s: %s\n",
3351 frr_config, safe_strerror(errno));
3352 return CMD_WARNING_CONFIG_FAILED;
3353 }
3354 fd = fileno(fp);
3355
3356 for (i = 0; i < array_size(vtysh_client); i++)
3357 vtysh_client_config(&vtysh_client[i], line);
3358
3359 vtysh_config_write();
3360 vty->of_saved = vty->of;
3361 vty->of = fp;
3362 vtysh_config_dump();
3363 vty->of = vty->of_saved;
3364
3365 if (fchmod(fd, CONFIGFILE_MASK) != 0) {
3366 printf("%% Warning: can't chmod configuration file %s: %s\n",
3367 frr_config, safe_strerror(errno));
3368 err++;
3369 }
3370
3371 #ifdef FRR_USER
3372 pwentry = getpwnam(FRR_USER);
3373 if (pwentry)
3374 uid = pwentry->pw_uid;
3375 else {
3376 printf("%% Warning: could not look up user \"%s\"\n", FRR_USER);
3377 err++;
3378 }
3379 #endif
3380 #ifdef FRR_GROUP
3381 grentry = getgrnam(FRR_GROUP);
3382 if (grentry)
3383 gid = grentry->gr_gid;
3384 else {
3385 printf("%% Warning: could not look up group \"%s\"\n",
3386 FRR_GROUP);
3387 err++;
3388 }
3389 #endif
3390
3391 if (!fstat(fd, &st)) {
3392 if (st.st_uid == uid)
3393 uid = -1;
3394 if (st.st_gid == gid)
3395 gid = -1;
3396 if ((uid != (uid_t)-1 || gid != (gid_t)-1)
3397 && fchown(fd, uid, gid)) {
3398 printf("%% Warning: can't chown configuration file %s: %s\n",
3399 frr_config, safe_strerror(errno));
3400 err++;
3401 }
3402 } else {
3403 printf("%% Warning: stat() failed on %s: %s\n", frr_config,
3404 safe_strerror(errno));
3405 err++;
3406 }
3407
3408 if (fflush(fp) != 0) {
3409 printf("%% Warning: fflush() failed on %s: %s\n", frr_config,
3410 safe_strerror(errno));
3411 err++;
3412 }
3413
3414 if (fsync(fd) < 0) {
3415 printf("%% Warning: fsync() failed on %s: %s\n", frr_config,
3416 safe_strerror(errno));
3417 err++;
3418 }
3419
3420 fclose(fp);
3421
3422 printf("Integrated configuration saved to %s\n", frr_config);
3423 if (err)
3424 return CMD_WARNING;
3425
3426 printf("[OK]\n");
3427 return CMD_SUCCESS;
3428 }
3429
3430 DEFUN_HIDDEN(start_config, start_config_cmd, "XFRR_start_configuration",
3431 "The Beginning of Configuration\n")
3432 {
3433 unsigned int i;
3434 char line[] = "XFRR_start_configuration";
3435
3436 for (i = 0; i < array_size(vtysh_client); i++)
3437 vtysh_client_execute(&vtysh_client[i], line);
3438
3439 return CMD_SUCCESS;
3440 }
3441
3442 DEFUN_HIDDEN(end_config, end_config_cmd, "XFRR_end_configuration",
3443 "The End of Configuration\n")
3444 {
3445 unsigned int i;
3446 char line[] = "XFRR_end_configuration";
3447
3448 for (i = 0; i < array_size(vtysh_client); i++)
3449 vtysh_client_execute(&vtysh_client[i], line);
3450
3451 return CMD_SUCCESS;
3452 }
3453
3454 static bool want_config_integrated(void)
3455 {
3456 struct stat s;
3457
3458 switch (vtysh_write_integrated) {
3459 case WRITE_INTEGRATED_UNSPECIFIED:
3460 if (stat(frr_config, &s) && errno == ENOENT)
3461 return false;
3462 return true;
3463 case WRITE_INTEGRATED_NO:
3464 return false;
3465 case WRITE_INTEGRATED_YES:
3466 return true;
3467 }
3468 return true;
3469 }
3470
3471 DEFUN (vtysh_write_memory,
3472 vtysh_write_memory_cmd,
3473 "write [<memory|file>]",
3474 "Write running configuration to memory, network, or terminal\n"
3475 "Write configuration to the file (same as write file)\n"
3476 "Write configuration to the file (same as write memory)\n")
3477 {
3478 int ret = CMD_SUCCESS;
3479 char line[] = "do write memory";
3480 unsigned int i;
3481
3482 vty_out(vty, "Note: this version of vtysh never writes vtysh.conf\n");
3483
3484 /* If integrated frr.conf explicitly set. */
3485 if (want_config_integrated()) {
3486 ret = CMD_WARNING_CONFIG_FAILED;
3487
3488 /* first attempt to use watchfrr if it's available */
3489 bool used_watchfrr = false;
3490
3491 for (i = 0; i < array_size(vtysh_client); i++)
3492 if (vtysh_client[i].flag == VTYSH_WATCHFRR)
3493 break;
3494 if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1) {
3495 used_watchfrr = true;
3496 ret = vtysh_client_execute(&vtysh_client[i],
3497 "do write integrated");
3498 }
3499
3500 /*
3501 * If we didn't use watchfrr, fallback to writing the config
3502 * ourselves
3503 */
3504 if (!used_watchfrr) {
3505 printf("\nWarning: attempting direct configuration write without watchfrr.\nFile permissions and ownership may be incorrect, or write may fail.\n\n");
3506 ret = vtysh_write_config_integrated();
3507 }
3508 return ret;
3509 }
3510
3511 vty_out(vty, "Building Configuration...\n");
3512
3513 for (i = 0; i < array_size(vtysh_client); i++)
3514 ret = vtysh_client_execute(&vtysh_client[i], line);
3515
3516 return ret;
3517 }
3518
3519 DEFUN (vtysh_copy_running_config,
3520 vtysh_copy_running_config_cmd,
3521 "copy running-config startup-config",
3522 "Copy from one file to another\n"
3523 "Copy from current system configuration\n"
3524 "Copy to startup configuration\n")
3525 {
3526 return vtysh_write_memory(self, vty, argc, argv);
3527 }
3528
3529 DEFUN (vtysh_copy_to_running,
3530 vtysh_copy_to_running_cmd,
3531 "copy FILENAME running-config",
3532 "Apply a configuration file\n"
3533 "Configuration file to read\n"
3534 "Apply to current configuration\n")
3535 {
3536 int ret;
3537 const char *fname = argv[1]->arg;
3538
3539 ret = vtysh_apply_config(fname, true, false);
3540
3541 /* Return to enable mode - the 'read_config' api leaves us up a level */
3542 vtysh_execute_no_pager("enable");
3543
3544 return ret;
3545 }
3546
3547 DEFUN (vtysh_terminal_paginate,
3548 vtysh_terminal_paginate_cmd,
3549 "[no] terminal paginate",
3550 NO_STR
3551 "Set terminal line parameters\n"
3552 "Use pager for output scrolling\n")
3553 {
3554 free(vtysh_pager_name);
3555 vtysh_pager_name = NULL;
3556
3557 if (strcmp(argv[0]->text, "no"))
3558 vtysh_pager_envdef(true);
3559 return CMD_SUCCESS;
3560 }
3561
3562 DEFUN (vtysh_terminal_length,
3563 vtysh_terminal_length_cmd,
3564 "[no] terminal length (0-4294967295)",
3565 NO_STR
3566 "Set terminal line parameters\n"
3567 "Set number of lines on a screen\n"
3568 "Number of lines on screen (0 for no pausing, nonzero to use pager)\n")
3569 {
3570 int idx_number = 2;
3571 unsigned long lines;
3572
3573 free(vtysh_pager_name);
3574 vtysh_pager_name = NULL;
3575
3576 if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) {
3577 /* "terminal no length" = use VTYSH_PAGER */
3578 vtysh_pager_envdef(true);
3579 return CMD_SUCCESS;
3580 }
3581
3582 lines = strtoul(argv[idx_number]->arg, NULL, 10);
3583 if (lines != 0) {
3584 vty_out(vty,
3585 "%% The \"terminal length\" command is deprecated and its value is ignored.\n"
3586 "%% Please use \"terminal paginate\" instead with OS TTY length handling.\n");
3587 vtysh_pager_envdef(true);
3588 }
3589
3590 return CMD_SUCCESS;
3591 }
3592
3593 ALIAS_DEPRECATED(vtysh_terminal_length,
3594 vtysh_terminal_no_length_cmd,
3595 "terminal no length",
3596 "Set terminal line parameters\n"
3597 NO_STR
3598 "Set number of lines on a screen\n")
3599
3600 DEFUN (vtysh_show_daemons,
3601 vtysh_show_daemons_cmd,
3602 "show daemons",
3603 SHOW_STR
3604 "Show list of running daemons\n")
3605 {
3606 unsigned int i;
3607
3608 for (i = 0; i < array_size(vtysh_client); i++)
3609 if (vtysh_client[i].fd >= 0)
3610 vty_out(vty, " %s", vtysh_client[i].name);
3611 vty_out(vty, "\n");
3612
3613 return CMD_SUCCESS;
3614 }
3615
3616 struct visual_prio {
3617 /* 4 characters for nice alignment */
3618 const char *label;
3619
3620 int c256_background;
3621 int c256_formatarg;
3622 };
3623
3624 /* clang-format off */
3625 struct visual_prio visual_prios[] = {
3626 [LOG_EMERG] = {
3627 .label = "\e[31;1mEMRG",
3628 .c256_background = 53,
3629 .c256_formatarg = 225,
3630 },
3631 [LOG_ALERT] = {
3632 .label = "\e[31;1mALRT",
3633 .c256_background = 53,
3634 .c256_formatarg = 225,
3635 },
3636 [LOG_CRIT] = {
3637 .label = "\e[31;1mCRIT",
3638 .c256_background = 53,
3639 .c256_formatarg = 225,
3640 },
3641 [LOG_ERR] = {
3642 .label = "\e[38;5;202mERR!",
3643 .c256_background = 52,
3644 .c256_formatarg = 224,
3645 },
3646 [LOG_WARNING] = {
3647 .label = "\e[38;5;222mWARN",
3648 .c256_background = 58,
3649 .c256_formatarg = 230,
3650 },
3651 [LOG_NOTICE] = {
3652 .label = "NTFY",
3653 .c256_background = 234,
3654 .c256_formatarg = 195,
3655 },
3656 [LOG_INFO] = {
3657 .label = "\e[38;5;192mINFO",
3658 .c256_background = 236,
3659 .c256_formatarg = 195,
3660 },
3661 [LOG_DEBUG] = {
3662 .label = "\e[38;5;116mDEBG",
3663 .c256_background = 238,
3664 .c256_formatarg = 195,
3665 },
3666 };
3667 /* clang-format on */
3668
3669 static void vtysh_log_print(struct vtysh_client *vclient,
3670 struct zlog_live_hdr *hdr, const char *text)
3671 {
3672 size_t textlen = hdr->textlen, textpos = 0;
3673 time_t ts = hdr->ts_sec;
3674 struct visual_prio *vis;
3675 struct tm tm;
3676 char ts_buf[32];
3677
3678 if (hdr->prio >= array_size(visual_prios))
3679 vis = &visual_prios[LOG_CRIT];
3680 else
3681 vis = &visual_prios[hdr->prio];
3682
3683 localtime_r(&ts, &tm);
3684 strftime(ts_buf, sizeof(ts_buf), "%Y-%m-%d %H:%M:%S", &tm);
3685
3686 if (!stderr_tty) {
3687 const char *label = vis->label + strlen(vis->label) - 4;
3688
3689 fprintf(stderr, "%s.%03u [%s] %s: %.*s\n", ts_buf,
3690 hdr->ts_nsec / 1000000U, label, vclient->name,
3691 (int)textlen, text);
3692 return;
3693 }
3694
3695 fprintf(stderr,
3696 "\e[48;5;%dm\e[38;5;247m%s.%03u [%s\e[38;5;247m] \e[38;5;255m%s\e[38;5;247m: \e[38;5;251m",
3697 vis->c256_background, ts_buf, hdr->ts_nsec / 1000000U,
3698 vis->label, vclient->name);
3699
3700 for (size_t fmtpos = 0; fmtpos < hdr->n_argpos; fmtpos++) {
3701 struct fmt_outpos *fmt = &hdr->argpos[fmtpos];
3702
3703 if (fmt->off_start < textpos || fmt->off_end < fmt->off_start ||
3704 fmt->off_end > textlen)
3705 continue;
3706
3707 while (fmt->off_end > fmt->off_start &&
3708 text[fmt->off_end - 1] == ' ')
3709 fmt->off_end--;
3710
3711 fprintf(stderr, "%.*s\e[38;5;%dm%.*s\e[38;5;251m",
3712 (int)(fmt->off_start - textpos), text + textpos,
3713 vis->c256_formatarg,
3714 (int)(fmt->off_end - fmt->off_start),
3715 text + fmt->off_start);
3716 textpos = fmt->off_end;
3717 }
3718 fprintf(stderr, "%.*s\033[K\033[m\n", (int)(textlen - textpos),
3719 text + textpos);
3720 }
3721
3722 static void vtysh_log_read(struct event *thread)
3723 {
3724 struct vtysh_client *vclient = EVENT_ARG(thread);
3725 struct {
3726 struct zlog_live_hdr hdr;
3727 char text[4096];
3728 } buf;
3729 const char *text;
3730 ssize_t ret;
3731
3732 event_add_read(master, vtysh_log_read, vclient, vclient->log_fd,
3733 &vclient->log_reader);
3734
3735 ret = recv(vclient->log_fd, &buf, sizeof(buf), 0);
3736
3737 if (ret < 0 && ERRNO_IO_RETRY(errno))
3738 return;
3739
3740 if (stderr_stdout_same) {
3741 #ifdef HAVE_RL_CLEAR_VISIBLE_LINE
3742 rl_clear_visible_line();
3743 #else
3744 puts("\r");
3745 #endif
3746 fflush(stdout);
3747 }
3748
3749 if (ret <= 0) {
3750 struct timespec ts;
3751
3752 buf.text[0] = '\0'; /* coverity */
3753
3754 if (ret != 0)
3755 snprintfrr(buf.text, sizeof(buf.text),
3756 "log monitor connection error: %m");
3757 else
3758 snprintfrr(
3759 buf.text, sizeof(buf.text),
3760 "log monitor connection closed unexpectedly");
3761 buf.hdr.textlen = strlen(buf.text);
3762
3763 EVENT_OFF(vclient->log_reader);
3764 close(vclient->log_fd);
3765 vclient->log_fd = -1;
3766
3767 clock_gettime(CLOCK_REALTIME, &ts);
3768 buf.hdr.ts_sec = ts.tv_sec;
3769 buf.hdr.ts_nsec = ts.tv_nsec;
3770 buf.hdr.prio = LOG_ERR;
3771 buf.hdr.flags = 0;
3772 buf.hdr.texthdrlen = 0;
3773 buf.hdr.n_argpos = 0;
3774 } else {
3775 int32_t lost_msgs = buf.hdr.lost_msgs - vclient->lost_msgs;
3776
3777 if (lost_msgs > 0) {
3778 vclient->lost_msgs = buf.hdr.lost_msgs;
3779 fprintf(stderr,
3780 "%d log messages from %s lost (vtysh reading too slowly)\n",
3781 lost_msgs, vclient->name);
3782 }
3783 }
3784
3785 text = buf.text + sizeof(buf.hdr.argpos[0]) * buf.hdr.n_argpos;
3786 vtysh_log_print(vclient, &buf.hdr, text);
3787
3788 if (stderr_stdout_same)
3789 rl_forced_update_display();
3790
3791 return;
3792 }
3793
3794 #ifdef CLIPPY
3795 /* clippy/clidef can't process the DEFPY below without some value for this */
3796 #define DAEMONS_LIST "daemon"
3797 #endif
3798
3799 DEFPY (vtysh_terminal_monitor,
3800 vtysh_terminal_monitor_cmd,
3801 "terminal monitor ["DAEMONS_LIST"]$daemon",
3802 "Set terminal line parameters\n"
3803 "Receive log messages to active VTY session\n"
3804 DAEMONS_STR)
3805 {
3806 static const char line[] = "terminal monitor";
3807 int ret_all = CMD_SUCCESS, ret, fd;
3808 size_t i, ok = 0;
3809
3810 for (i = 0; i < array_size(vtysh_client); i++) {
3811 struct vtysh_client *vclient = &vtysh_client[i];
3812
3813 if (daemon && strcmp(vclient->name, daemon))
3814 continue;
3815
3816 for (; vclient; vclient = vclient->next) {
3817 if (vclient->log_fd != -1) {
3818 vty_out(vty, "%% %s: already monitoring logs\n",
3819 vclient->name);
3820 ok++;
3821 continue;
3822 }
3823
3824 fd = -1;
3825 ret = vtysh_client_run(vclient, line, NULL, NULL, &fd);
3826 if (fd != -1) {
3827 set_nonblocking(fd);
3828 vclient->log_fd = fd;
3829 event_add_read(master, vtysh_log_read, vclient,
3830 vclient->log_fd,
3831 &vclient->log_reader);
3832 }
3833 if (ret != CMD_SUCCESS) {
3834 vty_out(vty, "%% failed to enable logs on %s\n",
3835 vclient->name);
3836 ret_all = CMD_WARNING;
3837 } else
3838 ok++;
3839 }
3840 }
3841
3842 if (!ok && ret_all == CMD_SUCCESS) {
3843 vty_out(vty,
3844 "%% command had no effect, relevant daemons not connected?\n");
3845 ret_all = CMD_WARNING;
3846 }
3847 return ret_all;
3848 }
3849
3850 DEFPY (no_vtysh_terminal_monitor,
3851 no_vtysh_terminal_monitor_cmd,
3852 "no terminal monitor ["DAEMONS_LIST"]$daemon",
3853 NO_STR
3854 "Set terminal line parameters\n"
3855 "Receive log messages to active VTY session\n"
3856 DAEMONS_STR)
3857 {
3858 static const char line[] = "no terminal monitor";
3859 int ret_all = CMD_SUCCESS, ret;
3860 size_t i, ok = 0;
3861
3862 for (i = 0; i < array_size(vtysh_client); i++) {
3863 struct vtysh_client *vclient = &vtysh_client[i];
3864
3865 if (daemon && strcmp(vclient->name, daemon))
3866 continue;
3867
3868 for (; vclient; vclient = vclient->next) {
3869 /* run this even if log_fd == -1, in case something
3870 * got desync'd
3871 */
3872 ret = vtysh_client_run(vclient, line, NULL, NULL, NULL);
3873 if (ret != CMD_SUCCESS) {
3874 vty_out(vty,
3875 "%% failed to disable logs on %s\n",
3876 vclient->name);
3877 ret_all = CMD_WARNING;
3878 } else
3879 ok++;
3880
3881 /* with this being a datagram socket, we can't expect
3882 * a close notification...
3883 */
3884 if (vclient->log_fd != -1) {
3885 EVENT_OFF(vclient->log_reader);
3886
3887 close(vclient->log_fd);
3888 vclient->log_fd = -1;
3889 }
3890 }
3891 }
3892
3893 if (!ok && ret_all == CMD_SUCCESS) {
3894 vty_out(vty,
3895 "%% command had no effect, relevant daemons not connected?\n");
3896 ret_all = CMD_WARNING;
3897 }
3898 return ret_all;
3899 }
3900
3901
3902 /* Execute command in child process. */
3903 static void execute_command(const char *command, int argc, const char *arg1,
3904 const char *arg2)
3905 {
3906 pid_t pid;
3907 int status;
3908
3909 /* Call fork(). */
3910 pid = fork();
3911
3912 if (pid < 0) {
3913 /* Failure of fork(). */
3914 fprintf(stderr, "Can't fork: %s\n", safe_strerror(errno));
3915 exit(1);
3916 } else if (pid == 0) {
3917 /* This is child process. */
3918 switch (argc) {
3919 case 0:
3920 execlp(command, command, (const char *)NULL);
3921 break;
3922 case 1:
3923 execlp(command, command, arg1, (const char *)NULL);
3924 break;
3925 case 2:
3926 execlp(command, command, arg1, arg2,
3927 (const char *)NULL);
3928 break;
3929 }
3930
3931 /* When execlp suceed, this part is not executed. */
3932 fprintf(stderr, "Can't execute %s: %s\n", command,
3933 safe_strerror(errno));
3934 exit(1);
3935 } else {
3936 /* This is parent. */
3937 execute_flag = 1;
3938 wait4(pid, &status, 0, NULL);
3939 execute_flag = 0;
3940 }
3941 }
3942
3943 DEFUN (vtysh_ping,
3944 vtysh_ping_cmd,
3945 "ping WORD",
3946 "Send echo messages\n"
3947 "Ping destination address or hostname\n")
3948 {
3949 int idx = 1;
3950
3951 argv_find(argv, argc, "WORD", &idx);
3952 execute_command("ping", 1, argv[idx]->arg, NULL);
3953 return CMD_SUCCESS;
3954 }
3955
3956 DEFUN(vtysh_motd, vtysh_motd_cmd, "show motd", SHOW_STR "Show motd\n")
3957 {
3958 vty_hello(vty);
3959 return CMD_SUCCESS;
3960 }
3961
3962 ALIAS(vtysh_ping, vtysh_ping_ip_cmd, "ping ip WORD",
3963 "Send echo messages\n"
3964 "IP echo\n"
3965 "Ping destination address or hostname\n")
3966
3967 DEFUN (vtysh_traceroute,
3968 vtysh_traceroute_cmd,
3969 "traceroute WORD",
3970 "Trace route to destination\n"
3971 "Trace route to destination address or hostname\n")
3972 {
3973 int idx = 1;
3974
3975 argv_find(argv, argc, "WORD", &idx);
3976 execute_command("traceroute", 1, argv[idx]->arg, NULL);
3977 return CMD_SUCCESS;
3978 }
3979
3980 ALIAS(vtysh_traceroute, vtysh_traceroute_ip_cmd, "traceroute ip WORD",
3981 "Trace route to destination\n"
3982 "IP trace\n"
3983 "Trace route to destination address or hostname\n")
3984
3985 DEFUN (vtysh_mtrace,
3986 vtysh_mtrace_cmd,
3987 "mtrace WORD [WORD]",
3988 "Multicast trace route to multicast source\n"
3989 "Multicast trace route to multicast source address\n"
3990 "Multicast trace route for multicast group address\n")
3991 {
3992 if (argc == 2)
3993 execute_command("mtracebis", 1, argv[1]->arg, NULL);
3994 else
3995 execute_command("mtracebis", 2, argv[1]->arg, argv[2]->arg);
3996 return CMD_SUCCESS;
3997 }
3998
3999 DEFUN (vtysh_ping6,
4000 vtysh_ping6_cmd,
4001 "ping ipv6 WORD",
4002 "Send echo messages\n"
4003 "IPv6 echo\n"
4004 "Ping destination address or hostname\n")
4005 {
4006 execute_command("ping6", 1, argv[2]->arg, NULL);
4007 return CMD_SUCCESS;
4008 }
4009
4010 DEFUN (vtysh_traceroute6,
4011 vtysh_traceroute6_cmd,
4012 "traceroute ipv6 WORD",
4013 "Trace route to destination\n"
4014 "IPv6 trace\n"
4015 "Trace route to destination address or hostname\n")
4016 {
4017 execute_command("traceroute6", 1, argv[2]->arg, NULL);
4018 return CMD_SUCCESS;
4019 }
4020
4021 #if CONFDATE > 20240201
4022 CPP_NOTICE("Remove HAVE_SHELL_ACCESS and it's documentation");
4023 #endif
4024 #if defined(HAVE_SHELL_ACCESS)
4025 DEFUN (vtysh_telnet,
4026 vtysh_telnet_cmd,
4027 "telnet WORD",
4028 "Open a telnet connection\n"
4029 "IP address or hostname of a remote system\n")
4030 {
4031 execute_command("telnet", 1, argv[1]->arg, NULL);
4032 return CMD_SUCCESS;
4033 }
4034
4035 DEFUN (vtysh_telnet_port,
4036 vtysh_telnet_port_cmd,
4037 "telnet WORD PORT",
4038 "Open a telnet connection\n"
4039 "IP address or hostname of a remote system\n"
4040 "TCP Port number\n")
4041 {
4042 execute_command("telnet", 2, argv[1]->arg, argv[2]->arg);
4043 return CMD_SUCCESS;
4044 }
4045
4046 DEFUN (vtysh_ssh,
4047 vtysh_ssh_cmd,
4048 "ssh WORD",
4049 "Open an ssh connection\n"
4050 "[user@]host\n")
4051 {
4052 execute_command("ssh", 1, argv[1]->arg, NULL);
4053 return CMD_SUCCESS;
4054 }
4055
4056 DEFUN (vtysh_start_shell,
4057 vtysh_start_shell_cmd,
4058 "start-shell",
4059 "Start UNIX shell\n")
4060 {
4061 execute_command("sh", 0, NULL, NULL);
4062 return CMD_SUCCESS;
4063 }
4064
4065 DEFUN (vtysh_start_bash,
4066 vtysh_start_bash_cmd,
4067 "start-shell bash",
4068 "Start UNIX shell\n"
4069 "Start bash\n")
4070 {
4071 execute_command("bash", 0, NULL, NULL);
4072 return CMD_SUCCESS;
4073 }
4074
4075 DEFUN (vtysh_start_zsh,
4076 vtysh_start_zsh_cmd,
4077 "start-shell zsh",
4078 "Start UNIX shell\n"
4079 "Start Z shell\n")
4080 {
4081 execute_command("zsh", 0, NULL, NULL);
4082 return CMD_SUCCESS;
4083 }
4084 #endif
4085
4086 DEFUN (config_list,
4087 config_list_cmd,
4088 "list [permutations]",
4089 "Print command list\n"
4090 "Print all possible command permutations\n")
4091 {
4092 return cmd_list_cmds(vty, argc == 2);
4093 }
4094
4095 DEFUN (vtysh_output_file,
4096 vtysh_output_file_cmd,
4097 "output file FILE",
4098 "Direct vtysh output to file\n"
4099 "Direct vtysh output to file\n"
4100 "Path to dump output to\n")
4101 {
4102 const char *path = argv[argc - 1]->arg;
4103 vty->of = fopen(path, "a");
4104 if (!vty->of) {
4105 vty_out(vty, "Failed to open file '%s': %s\n", path,
4106 safe_strerror(errno));
4107 vty->of = stdout;
4108 }
4109 return CMD_SUCCESS;
4110 }
4111
4112 DEFUN (no_vtysh_output_file,
4113 no_vtysh_output_file_cmd,
4114 "no output file [FILE]",
4115 NO_STR
4116 "Direct vtysh output to file\n"
4117 "Direct vtysh output to file\n"
4118 "Path to dump output to\n")
4119 {
4120 if (vty->of != stdout) {
4121 fclose(vty->of);
4122 vty->of = stdout;
4123 }
4124 return CMD_SUCCESS;
4125 }
4126
4127 DEFUN(find,
4128 find_cmd,
4129 "find REGEX...",
4130 "Find CLI command matching a regular expression\n"
4131 "Search pattern (POSIX regex)\n")
4132 {
4133 return cmd_find_cmds(vty, argv, argc);
4134 }
4135
4136 DEFUN_HIDDEN(show_cli_graph_vtysh,
4137 show_cli_graph_vtysh_cmd,
4138 "show cli graph",
4139 SHOW_STR
4140 "CLI reflection\n"
4141 "Dump current command space as DOT graph\n")
4142 {
4143 struct cmd_node *cn = vector_slot(cmdvec, vty->node);
4144 char *dot = cmd_graph_dump_dot(cn->cmdgraph);
4145
4146 vty_out(vty, "%s\n", dot);
4147 XFREE(MTYPE_TMP, dot);
4148 return CMD_SUCCESS;
4149 }
4150
4151 static void vtysh_install_default(enum node_type node)
4152 {
4153 _install_element(node, &config_list_cmd);
4154 _install_element(node, &find_cmd);
4155 _install_element(node, &show_cli_graph_vtysh_cmd);
4156 _install_element(node, &vtysh_output_file_cmd);
4157 _install_element(node, &no_vtysh_output_file_cmd);
4158 }
4159
4160 /* Making connection to protocol daemon. */
4161 static int vtysh_connect(struct vtysh_client *vclient)
4162 {
4163 int ret;
4164 int sock, len;
4165 struct sockaddr_un addr;
4166 struct stat s_stat;
4167 const char *path;
4168
4169 if (!vclient->path[0])
4170 snprintf(vclient->path, sizeof(vclient->path), "%s/%s.vty",
4171 vtydir, vclient->name);
4172 path = vclient->path;
4173
4174 /* Stat socket to see if we have permission to access it. */
4175 ret = stat(path, &s_stat);
4176 if (ret < 0 && errno != ENOENT) {
4177 fprintf(stderr, "vtysh_connect(%s): stat = %s\n", path,
4178 safe_strerror(errno));
4179 exit(1);
4180 }
4181
4182 if (ret >= 0) {
4183 if (!S_ISSOCK(s_stat.st_mode)) {
4184 fprintf(stderr, "vtysh_connect(%s): Not a socket\n",
4185 path);
4186 exit(1);
4187 }
4188 }
4189
4190 sock = socket(AF_UNIX, SOCK_STREAM, 0);
4191 if (sock < 0) {
4192 #ifdef DEBUG
4193 fprintf(stderr, "vtysh_connect(%s): socket = %s\n", path,
4194 safe_strerror(errno));
4195 #endif /* DEBUG */
4196 return -1;
4197 }
4198
4199 memset(&addr, 0, sizeof(addr));
4200 addr.sun_family = AF_UNIX;
4201 strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
4202 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
4203 len = addr.sun_len = SUN_LEN(&addr);
4204 #else
4205 len = sizeof(addr.sun_family) + strlen(addr.sun_path);
4206 #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
4207
4208 ret = connect(sock, (struct sockaddr *)&addr, len);
4209 if (ret < 0) {
4210 #ifdef DEBUG
4211 fprintf(stderr, "vtysh_connect(%s): connect = %s\n", path,
4212 safe_strerror(errno));
4213 #endif /* DEBUG */
4214 close(sock);
4215 return -1;
4216 }
4217 vclient->fd = sock;
4218
4219 return 0;
4220 }
4221
4222 static int vtysh_reconnect(struct vtysh_client *vclient)
4223 {
4224 int ret;
4225
4226 fprintf(stderr, "Warning: connecting to %s...", vclient->name);
4227 ret = vtysh_connect(vclient);
4228 if (ret < 0) {
4229 fprintf(stderr, "failed!\n");
4230 return ret;
4231 }
4232 fprintf(stderr, "success!\n");
4233 if (vtysh_client_execute(vclient, "enable") < 0)
4234 return -1;
4235 return vtysh_execute_no_pager("end");
4236 }
4237
4238 /* Return true if str ends with suffix, else return false */
4239 static int ends_with(const char *str, const char *suffix)
4240 {
4241 if (!str || !suffix)
4242 return 0;
4243 size_t lenstr = strlen(str);
4244 size_t lensuffix = strlen(suffix);
4245 if (lensuffix > lenstr)
4246 return 0;
4247 return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
4248 }
4249
4250 static void vtysh_client_sorted_insert(struct vtysh_client *head_client,
4251 struct vtysh_client *client)
4252 {
4253 struct vtysh_client *prev_node, *current_node;
4254
4255 prev_node = head_client;
4256 current_node = head_client->next;
4257 while (current_node) {
4258 if (strcmp(current_node->path, client->path) > 0)
4259 break;
4260
4261 prev_node = current_node;
4262 current_node = current_node->next;
4263 }
4264 client->next = current_node;
4265 prev_node->next = client;
4266 }
4267
4268 #define MAXIMUM_INSTANCES 10
4269
4270 static void vtysh_update_all_instances(struct vtysh_client *head_client)
4271 {
4272 struct vtysh_client *client;
4273 DIR *dir;
4274 struct dirent *file;
4275 int n = 0;
4276
4277 if (head_client->flag != VTYSH_OSPFD)
4278 return;
4279
4280 /* ls vty_sock_dir and look for all files ending in .vty */
4281 dir = opendir(vtydir);
4282 if (dir) {
4283 while ((file = readdir(dir)) != NULL) {
4284 if (frrstr_startswith(file->d_name, "ospfd-")
4285 && ends_with(file->d_name, ".vty")) {
4286 if (n == MAXIMUM_INSTANCES) {
4287 fprintf(stderr,
4288 "Parsing %s, client limit(%d) reached!\n",
4289 vtydir, n);
4290 break;
4291 }
4292 client = (struct vtysh_client *)malloc(
4293 sizeof(struct vtysh_client));
4294 client->fd = -1;
4295 client->name = "ospfd";
4296 client->flag = VTYSH_OSPFD;
4297 snprintf(client->path, sizeof(client->path),
4298 "%s/%s", vtydir, file->d_name);
4299 client->next = NULL;
4300 vtysh_client_sorted_insert(head_client, client);
4301 n++;
4302 }
4303 }
4304 closedir(dir);
4305 }
4306 }
4307
4308 static int vtysh_connect_all_instances(struct vtysh_client *head_client)
4309 {
4310 struct vtysh_client *client;
4311 int rc = 0;
4312
4313 vtysh_update_all_instances(head_client);
4314
4315 client = head_client->next;
4316 while (client) {
4317 if (vtysh_connect(client) == 0)
4318 rc++;
4319 client = client->next;
4320 }
4321
4322 return rc;
4323 }
4324
4325 int vtysh_connect_all(const char *daemon_name)
4326 {
4327 unsigned int i;
4328 int rc = 0;
4329 int matches = 0;
4330
4331 for (i = 0; i < array_size(vtysh_client); i++) {
4332 if (!daemon_name
4333 || !strcmp(daemon_name, vtysh_client[i].name)) {
4334 matches++;
4335 if (vtysh_connect(&vtysh_client[i]) == 0)
4336 rc++;
4337
4338 rc += vtysh_connect_all_instances(&vtysh_client[i]);
4339 }
4340 }
4341 if (!matches)
4342 fprintf(stderr, "Error: no daemons match name %s!\n",
4343 daemon_name);
4344 return rc;
4345 }
4346
4347 /* To disable readline's filename completion. */
4348 static char *vtysh_completion_entry_function(const char *ignore,
4349 int invoking_key)
4350 {
4351 return NULL;
4352 }
4353
4354 void vtysh_readline_init(void)
4355 {
4356 /* readline related settings. */
4357 char *disable_bracketed_paste =
4358 XSTRDUP(MTYPE_TMP, "set enable-bracketed-paste off");
4359
4360 rl_initialize();
4361 rl_parse_and_bind(disable_bracketed_paste);
4362 rl_bind_key('?', (rl_command_func_t *)vtysh_rl_describe);
4363 rl_completion_entry_function = vtysh_completion_entry_function;
4364 rl_attempted_completion_function = new_completion;
4365
4366 XFREE(MTYPE_TMP, disable_bracketed_paste);
4367 }
4368
4369 char *vtysh_prompt(void)
4370 {
4371 static char buf[512];
4372
4373 #pragma GCC diagnostic push
4374 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
4375 /* prompt formatting has a %s in the cmd_node prompt string. */
4376 snprintf(buf, sizeof(buf), cmd_prompt(vty->node), cmd_hostname_get());
4377 #pragma GCC diagnostic pop
4378 return buf;
4379 }
4380
4381 static void vtysh_ac_line(void *arg, const char *line)
4382 {
4383 vector comps = arg;
4384 size_t i;
4385 for (i = 0; i < vector_active(comps); i++)
4386 if (!strcmp(line, (char *)vector_slot(comps, i)))
4387 return;
4388 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, line));
4389 }
4390
4391 static void vtysh_autocomplete(vector comps, struct cmd_token *token)
4392 {
4393 char accmd[256];
4394 size_t i;
4395
4396 snprintf(accmd, sizeof(accmd), "autocomplete %d %s %s", token->type,
4397 token->text, token->varname ? token->varname : "-");
4398
4399 vty->of_saved = vty->of;
4400 vty->of = NULL;
4401 for (i = 0; i < array_size(vtysh_client); i++)
4402 vtysh_client_run_all(&vtysh_client[i], accmd, 1, vtysh_ac_line,
4403 comps);
4404 vty->of = vty->of_saved;
4405 }
4406
4407 static const struct cmd_variable_handler vtysh_var_handler[] = {
4408 {/* match all */
4409 .tokenname = NULL,
4410 .varname = NULL,
4411 .completions = vtysh_autocomplete},
4412 {.completions = NULL}};
4413
4414 void vtysh_uninit(void)
4415 {
4416 if (vty->of != stdout)
4417 fclose(vty->of);
4418 }
4419
4420 void vtysh_init_vty(void)
4421 {
4422 struct stat st_out, st_err;
4423
4424 cmd_defer_tree(true);
4425
4426 for (size_t i = 0; i < array_size(vtysh_client); i++) {
4427 vtysh_client[i].fd = -1;
4428 vtysh_client[i].log_fd = -1;
4429 }
4430
4431 stderr_tty = isatty(STDERR_FILENO);
4432
4433 if (fstat(STDOUT_FILENO, &st_out) || fstat(STDERR_FILENO, &st_err) ||
4434 (st_out.st_dev == st_err.st_dev && st_out.st_ino == st_err.st_ino))
4435 stderr_stdout_same = true;
4436
4437 /* Make vty structure. */
4438 vty = vty_new();
4439 vty->type = VTY_SHELL;
4440 vty->node = VIEW_NODE;
4441
4442 /* set default output */
4443 vty->of = stdout;
4444 vtysh_pager_envdef(false);
4445
4446 /* Initialize commands. */
4447 cmd_init(0);
4448 cmd_variable_handler_register(vtysh_var_handler);
4449
4450 /* bgpd */
4451 #ifdef HAVE_BGPD
4452 install_node(&bgp_node);
4453 install_element(CONFIG_NODE, &router_bgp_cmd);
4454 install_element(BGP_NODE, &vtysh_exit_bgpd_cmd);
4455 install_element(BGP_NODE, &vtysh_quit_bgpd_cmd);
4456 install_element(BGP_NODE, &vtysh_end_all_cmd);
4457
4458 install_node(&bgp_vpnv4_node);
4459 install_element(BGP_NODE, &address_family_ipv4_vpn_cmd);
4460 #ifdef KEEP_OLD_VPN_COMMANDS
4461 install_element(BGP_NODE, &address_family_vpnv4_cmd);
4462 #endif /* KEEP_OLD_VPN_COMMANDS */
4463 install_element(BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd);
4464 install_element(BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd);
4465 install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd);
4466 install_element(BGP_VPNV4_NODE, &exit_address_family_cmd);
4467
4468 install_node(&bgp_vpnv6_node);
4469 install_element(BGP_NODE, &address_family_ipv6_vpn_cmd);
4470 #ifdef KEEP_OLD_VPN_COMMANDS
4471 install_element(BGP_NODE, &address_family_vpnv6_cmd);
4472 #endif /* KEEP_OLD_VPN_COMMANDS */
4473 install_element(BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd);
4474 install_element(BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd);
4475 install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd);
4476 install_element(BGP_VPNV6_NODE, &exit_address_family_cmd);
4477
4478 install_node(&bgp_flowspecv4_node);
4479 install_element(BGP_NODE, &address_family_flowspecv4_cmd);
4480 install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd);
4481 install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd);
4482 install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd);
4483 install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd);
4484
4485 install_node(&bgp_flowspecv6_node);
4486 install_element(BGP_NODE, &address_family_flowspecv6_cmd);
4487 install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd);
4488 install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd);
4489 install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd);
4490 install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
4491
4492 install_node(&bgp_ipv4_node);
4493 install_element(BGP_NODE, &address_family_ipv4_cmd);
4494 install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd);
4495 install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
4496 install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd);
4497 install_element(BGP_IPV4_NODE, &exit_address_family_cmd);
4498
4499 install_node(&bgp_ipv4m_node);
4500 install_element(BGP_NODE, &address_family_ipv4_multicast_cmd);
4501 install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
4502 install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
4503 install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd);
4504 install_element(BGP_IPV4M_NODE, &exit_address_family_cmd);
4505
4506 install_node(&bgp_ipv4l_node);
4507 install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd);
4508 install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
4509 install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
4510 install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd);
4511 install_element(BGP_IPV4L_NODE, &exit_address_family_cmd);
4512
4513 install_node(&bgp_ipv6_node);
4514 install_element(BGP_NODE, &address_family_ipv6_cmd);
4515 install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
4516 install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
4517 install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd);
4518 install_element(BGP_IPV6_NODE, &exit_address_family_cmd);
4519
4520 install_node(&bgp_ipv6m_node);
4521 install_element(BGP_NODE, &address_family_ipv6_multicast_cmd);
4522 install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
4523 install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
4524 install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd);
4525 install_element(BGP_IPV6M_NODE, &exit_address_family_cmd);
4526
4527 install_node(&bgp_ipv6l_node);
4528 install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd);
4529 install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
4530 install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
4531 install_element(BGP_IPV6L_NODE, &vtysh_end_all_cmd);
4532 install_element(BGP_IPV6L_NODE, &exit_address_family_cmd);
4533
4534 #if defined(ENABLE_BGP_VNC)
4535 install_node(&bgp_vrf_policy_node);
4536 install_element(BGP_NODE, &vnc_vrf_policy_cmd);
4537 install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
4538 install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
4539 install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
4540 install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
4541
4542 install_node(&bgp_vnc_defaults_node);
4543 install_element(BGP_NODE, &vnc_defaults_cmd);
4544 install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
4545 install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
4546 install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
4547 install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
4548
4549 install_node(&bgp_vnc_nve_group_node);
4550 install_element(BGP_NODE, &vnc_nve_group_cmd);
4551 install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
4552 install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd);
4553 install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
4554 install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
4555
4556 install_node(&bgp_vnc_l2_group_node);
4557 install_element(BGP_NODE, &vnc_l2_group_cmd);
4558 install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd);
4559 install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd);
4560 install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
4561 install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);
4562 #endif
4563
4564 install_node(&bgp_evpn_node);
4565 install_element(BGP_NODE, &address_family_evpn_cmd);
4566 install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
4567 install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd);
4568 install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd);
4569 install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
4570
4571 install_node(&bgp_evpn_vni_node);
4572 install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
4573 install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd);
4574 install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
4575 install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd);
4576 install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);
4577
4578 install_node(&rpki_node);
4579 install_element(CONFIG_NODE, &rpki_cmd);
4580 install_element(RPKI_NODE, &rpki_exit_cmd);
4581 install_element(RPKI_NODE, &rpki_quit_cmd);
4582 install_element(RPKI_NODE, &vtysh_end_all_cmd);
4583
4584 install_node(&bmp_node);
4585 install_element(BGP_NODE, &bmp_targets_cmd);
4586 install_element(BMP_NODE, &bmp_exit_cmd);
4587 install_element(BMP_NODE, &bmp_quit_cmd);
4588 install_element(BMP_NODE, &vtysh_end_all_cmd);
4589
4590 install_node(&bgp_srv6_node);
4591 install_element(BGP_NODE, &bgp_srv6_cmd);
4592 install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd);
4593 install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd);
4594 install_element(BGP_SRV6_NODE, &vtysh_end_all_cmd);
4595 #endif /* HAVE_BGPD */
4596
4597 /* ripd */
4598 install_node(&rip_node);
4599 #ifdef HAVE_RIPD
4600 install_element(CONFIG_NODE, &router_rip_cmd);
4601 install_element(RIP_NODE, &vtysh_exit_ripd_cmd);
4602 install_element(RIP_NODE, &vtysh_quit_ripd_cmd);
4603 install_element(RIP_NODE, &vtysh_end_all_cmd);
4604 #endif /* HAVE_RIPD */
4605
4606 /* ripngd */
4607 install_node(&ripng_node);
4608 #ifdef HAVE_RIPNGD
4609 install_element(CONFIG_NODE, &router_ripng_cmd);
4610 install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd);
4611 install_element(RIPNG_NODE, &vtysh_quit_ripngd_cmd);
4612 install_element(RIPNG_NODE, &vtysh_end_all_cmd);
4613 #endif /* HAVE_RIPNGD */
4614
4615 /* ospfd */
4616 #ifdef HAVE_OSPFD
4617 install_node(&ospf_node);
4618 install_element(CONFIG_NODE, &router_ospf_cmd);
4619 install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd);
4620 install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd);
4621 install_element(OSPF_NODE, &vtysh_end_all_cmd);
4622 #endif /* HAVE_OSPFD */
4623
4624 /* ospf6d */
4625 #ifdef HAVE_OSPF6D
4626 install_node(&ospf6_node);
4627 install_element(CONFIG_NODE, &router_ospf6_cmd);
4628 install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd);
4629 install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd);
4630 install_element(OSPF6_NODE, &vtysh_end_all_cmd);
4631 #endif /* HAVE_OSPF6D */
4632
4633 /* ldpd */
4634 #if defined(HAVE_LDPD)
4635 install_node(&ldp_node);
4636 install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd);
4637 install_element(LDP_NODE, &vtysh_exit_ldpd_cmd);
4638 install_element(LDP_NODE, &vtysh_quit_ldpd_cmd);
4639 install_element(LDP_NODE, &vtysh_end_all_cmd);
4640
4641 install_node(&ldp_ipv4_node);
4642 install_element(LDP_NODE, &ldp_address_family_ipv4_cmd);
4643 install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd);
4644 install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd);
4645 install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd);
4646 install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd);
4647
4648 install_node(&ldp_ipv6_node);
4649 install_element(LDP_NODE, &ldp_address_family_ipv6_cmd);
4650 install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd);
4651 install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd);
4652 install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd);
4653 install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd);
4654
4655 install_node(&ldp_ipv4_iface_node);
4656 install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd);
4657 install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd);
4658 install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd);
4659 install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd);
4660
4661 install_node(&ldp_ipv6_iface_node);
4662 install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd);
4663 install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd);
4664 install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd);
4665 install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd);
4666
4667 install_node(&ldp_l2vpn_node);
4668 install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd);
4669 install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd);
4670 install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd);
4671 install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd);
4672
4673 install_node(&ldp_pseudowire_node);
4674 install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd);
4675 install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd);
4676 install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd);
4677 install_element(LDP_PSEUDOWIRE_NODE, &vtysh_end_all_cmd);
4678 #endif
4679
4680 /* eigrpd */
4681 #ifdef HAVE_EIGRPD
4682 install_node(&eigrp_node);
4683 install_element(CONFIG_NODE, &router_eigrp_cmd);
4684 install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd);
4685 install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd);
4686 install_element(EIGRP_NODE, &vtysh_end_all_cmd);
4687 #endif /* HAVE_EIGRPD */
4688
4689 /* babeld */
4690 #ifdef HAVE_BABELD
4691 install_node(&babel_node);
4692 install_element(CONFIG_NODE, &router_babel_cmd);
4693 install_element(BABEL_NODE, &vtysh_exit_babeld_cmd);
4694 install_element(BABEL_NODE, &vtysh_quit_babeld_cmd);
4695 install_element(BABEL_NODE, &vtysh_end_all_cmd);
4696 #endif /* HAVE_BABELD */
4697
4698 /* isisd */
4699 #ifdef HAVE_ISISD
4700 install_node(&isis_node);
4701 install_element(CONFIG_NODE, &router_isis_cmd);
4702 install_element(ISIS_NODE, &vtysh_exit_isisd_cmd);
4703 install_element(ISIS_NODE, &vtysh_quit_isisd_cmd);
4704 install_element(ISIS_NODE, &vtysh_end_all_cmd);
4705 #endif /* HAVE_ISISD */
4706
4707 /* fabricd */
4708 #ifdef HAVE_FABRICD
4709 install_node(&openfabric_node);
4710 install_element(CONFIG_NODE, &router_openfabric_cmd);
4711 install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd);
4712 install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd);
4713 install_element(OPENFABRIC_NODE, &vtysh_end_all_cmd);
4714 #endif /* HAVE_FABRICD */
4715
4716 /* pbrd */
4717 #ifdef HAVE_PBRD
4718 install_node(&pbr_map_node);
4719 install_element(CONFIG_NODE, &vtysh_pbr_map_cmd);
4720 install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd);
4721 install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd);
4722 install_element(PBRMAP_NODE, &vtysh_quit_pbr_map_cmd);
4723 install_element(PBRMAP_NODE, &vtysh_end_all_cmd);
4724 #endif /* HAVE_PBRD */
4725
4726 /* bfdd */
4727 #if HAVE_BFDD > 0
4728 install_node(&bfd_node);
4729 install_element(CONFIG_NODE, &bfd_enter_cmd);
4730 install_element(BFD_NODE, &vtysh_exit_bfdd_cmd);
4731 install_element(BFD_NODE, &vtysh_quit_bfdd_cmd);
4732 install_element(BFD_NODE, &vtysh_end_all_cmd);
4733
4734 install_node(&bfd_peer_node);
4735 install_element(BFD_NODE, &bfd_peer_enter_cmd);
4736 install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd);
4737 install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd);
4738 install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
4739
4740 install_node(&bfd_profile_node);
4741 install_element(BFD_NODE, &bfd_profile_enter_cmd);
4742 install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd);
4743 install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd);
4744 install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
4745 #endif /* HAVE_BFDD */
4746
4747 install_node(&segment_routing_node);
4748 install_element(CONFIG_NODE, &segment_routing_cmd);
4749 install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd);
4750 install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd);
4751 install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
4752
4753 #if defined(HAVE_PATHD)
4754 install_node(&sr_traffic_eng_node);
4755 install_node(&srte_segment_list_node);
4756 install_node(&srte_policy_node);
4757 install_node(&srte_candidate_dyn_node);
4758
4759 install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd);
4760 install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd);
4761 install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd);
4762 install_element(SR_SEGMENT_LIST_NODE, &vtysh_quit_pathd_cmd);
4763 install_element(SR_POLICY_NODE, &vtysh_exit_pathd_cmd);
4764 install_element(SR_POLICY_NODE, &vtysh_quit_pathd_cmd);
4765 install_element(SR_CANDIDATE_DYN_NODE, &vtysh_exit_pathd_cmd);
4766 install_element(SR_CANDIDATE_DYN_NODE, &vtysh_quit_pathd_cmd);
4767
4768
4769 install_element(SR_TRAFFIC_ENG_NODE, &vtysh_end_all_cmd);
4770 install_element(SR_SEGMENT_LIST_NODE, &vtysh_end_all_cmd);
4771 install_element(SR_POLICY_NODE, &vtysh_end_all_cmd);
4772 install_element(SR_CANDIDATE_DYN_NODE, &vtysh_end_all_cmd);
4773
4774 install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
4775 install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
4776 install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd);
4777 install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd);
4778
4779 install_node(&pcep_node);
4780 install_node(&pcep_pcc_node);
4781 install_node(&pcep_pce_node);
4782 install_node(&pcep_pce_config_node);
4783
4784 install_element(PCEP_NODE, &vtysh_exit_pathd_cmd);
4785 install_element(PCEP_NODE, &vtysh_quit_pathd_cmd);
4786 install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd);
4787 install_element(PCEP_PCC_NODE, &vtysh_quit_pathd_cmd);
4788 install_element(PCEP_PCE_NODE, &vtysh_exit_pathd_cmd);
4789 install_element(PCEP_PCE_NODE, &vtysh_quit_pathd_cmd);
4790 install_element(PCEP_PCE_CONFIG_NODE, &vtysh_exit_pathd_cmd);
4791 install_element(PCEP_PCE_CONFIG_NODE, &vtysh_quit_pathd_cmd);
4792
4793 install_element(PCEP_NODE, &vtysh_end_all_cmd);
4794 install_element(PCEP_PCC_NODE, &vtysh_end_all_cmd);
4795 install_element(PCEP_PCE_NODE, &vtysh_end_all_cmd);
4796 install_element(PCEP_PCE_CONFIG_NODE, &vtysh_end_all_cmd);
4797
4798 install_element(SR_TRAFFIC_ENG_NODE, &pcep_cmd);
4799 install_element(PCEP_NODE, &pcep_cli_pcc_cmd);
4800 install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd);
4801 install_element(PCEP_NODE, &pcep_cli_pce_cmd);
4802
4803 #endif /* HAVE_PATHD */
4804
4805 /* keychain */
4806 install_node(&keychain_node);
4807 install_element(CONFIG_NODE, &key_chain_cmd);
4808 install_element(KEYCHAIN_NODE, &key_chain_cmd);
4809 install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd);
4810 install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd);
4811 install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
4812
4813 install_node(&keychain_key_node);
4814 install_element(KEYCHAIN_NODE, &key_cmd);
4815 install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd);
4816 install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd);
4817 install_element(KEYCHAIN_KEY_NODE, &vtysh_quit_keys_cmd);
4818 install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
4819
4820 /* nexthop-group */
4821 install_node(&nh_group_node);
4822 install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd);
4823 install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd);
4824 install_element(NH_GROUP_NODE, &vtysh_end_all_cmd);
4825 install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd);
4826 install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd);
4827
4828 /* zebra and all */
4829 install_node(&zebra_node);
4830
4831 install_node(&interface_node);
4832 install_element(CONFIG_NODE, &vtysh_interface_cmd);
4833 install_element(INTERFACE_NODE, &vtysh_end_all_cmd);
4834 install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd);
4835 install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd);
4836
4837 install_node(&link_params_node);
4838 install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
4839 install_element(LINK_PARAMS_NODE, &exit_link_params_cmd);
4840 install_element(LINK_PARAMS_NODE, &vtysh_end_all_cmd);
4841 install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd);
4842 install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd);
4843
4844 install_node(&pw_node);
4845 install_element(CONFIG_NODE, &vtysh_pseudowire_cmd);
4846 install_element(PW_NODE, &vtysh_end_all_cmd);
4847 install_element(PW_NODE, &vtysh_exit_pseudowire_cmd);
4848 install_element(PW_NODE, &vtysh_quit_pseudowire_cmd);
4849
4850 install_node(&vrf_node);
4851 install_element(CONFIG_NODE, &vtysh_vrf_cmd);
4852 install_element(VRF_NODE, &exit_vrf_config_cmd);
4853 install_element(VRF_NODE, &vtysh_end_all_cmd);
4854 install_element(VRF_NODE, &vtysh_exit_vrf_cmd);
4855 install_element(VRF_NODE, &vtysh_quit_vrf_cmd);
4856
4857 install_element(CONFIG_NODE, &vtysh_affinity_map_cmd);
4858 install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd);
4859
4860 install_node(&rmap_node);
4861 install_element(CONFIG_NODE, &vtysh_route_map_cmd);
4862 install_element(RMAP_NODE, &vtysh_exit_rmap_cmd);
4863 install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
4864 install_element(RMAP_NODE, &vtysh_end_all_cmd);
4865
4866 install_node(&vty_node);
4867 install_element(CONFIG_NODE, &vtysh_line_vty_cmd);
4868 install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
4869 install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
4870 install_element(VTY_NODE, &vtysh_end_all_cmd);
4871
4872
4873 struct cmd_node *node;
4874 for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
4875 node = vector_slot(cmdvec, i);
4876 if (!node || node->node == VIEW_NODE)
4877 continue;
4878 vtysh_install_default(node->node);
4879 }
4880
4881 /* vtysh */
4882
4883 if (!user_mode)
4884 install_element(VIEW_NODE, &vtysh_enable_cmd);
4885 install_element(ENABLE_NODE, &vtysh_config_terminal_cmd);
4886 install_element(ENABLE_NODE, &vtysh_disable_cmd);
4887
4888 /* "exit" command. */
4889 install_element(VIEW_NODE, &vtysh_exit_all_cmd);
4890 install_element(CONFIG_NODE, &vtysh_exit_all_cmd);
4891 install_element(VIEW_NODE, &vtysh_quit_all_cmd);
4892 install_element(CONFIG_NODE, &vtysh_quit_all_cmd);
4893
4894 /* "end" command. */
4895 install_element(CONFIG_NODE, &vtysh_end_all_cmd);
4896 install_element(ENABLE_NODE, &vtysh_end_all_cmd);
4897
4898 /* SRv6 Data-plane */
4899 install_node(&srv6_node);
4900 install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
4901 install_element(SRV6_NODE, &srv6_locators_cmd);
4902 install_element(SRV6_NODE, &exit_srv6_config_cmd);
4903 install_element(SRV6_NODE, &vtysh_end_all_cmd);
4904
4905 install_node(&srv6_locs_node);
4906 install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
4907 install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd);
4908 install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd);
4909
4910 install_node(&srv6_loc_node);
4911 install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd);
4912 install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd);
4913
4914 install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
4915 install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
4916 install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
4917
4918 /* "write terminal" command. */
4919 install_element(ENABLE_NODE, &vtysh_write_terminal_cmd);
4920
4921 install_element(CONFIG_NODE, &vtysh_integrated_config_cmd);
4922 install_element(CONFIG_NODE, &no_vtysh_integrated_config_cmd);
4923
4924 /* "write memory" command. */
4925 install_element(ENABLE_NODE, &vtysh_write_memory_cmd);
4926
4927 install_element(CONFIG_NODE, &start_config_cmd);
4928 install_element(CONFIG_NODE, &end_config_cmd);
4929
4930 install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd);
4931 install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd);
4932 install_element(VIEW_NODE, &vtysh_terminal_length_cmd);
4933 install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd);
4934 install_element(VIEW_NODE, &vtysh_show_daemons_cmd);
4935
4936 install_element(VIEW_NODE, &vtysh_terminal_monitor_cmd);
4937 install_element(VIEW_NODE, &no_vtysh_terminal_monitor_cmd);
4938
4939 install_element(VIEW_NODE, &vtysh_ping_cmd);
4940 install_element(VIEW_NODE, &vtysh_motd_cmd);
4941 install_element(VIEW_NODE, &vtysh_ping_ip_cmd);
4942 install_element(VIEW_NODE, &vtysh_traceroute_cmd);
4943 install_element(VIEW_NODE, &vtysh_traceroute_ip_cmd);
4944 install_element(VIEW_NODE, &vtysh_mtrace_cmd);
4945 install_element(VIEW_NODE, &vtysh_ping6_cmd);
4946 install_element(VIEW_NODE, &vtysh_traceroute6_cmd);
4947 #if defined(HAVE_SHELL_ACCESS)
4948 install_element(VIEW_NODE, &vtysh_telnet_cmd);
4949 install_element(VIEW_NODE, &vtysh_telnet_port_cmd);
4950 install_element(VIEW_NODE, &vtysh_ssh_cmd);
4951 #endif
4952 #if defined(HAVE_SHELL_ACCESS)
4953 install_element(ENABLE_NODE, &vtysh_start_shell_cmd);
4954 install_element(ENABLE_NODE, &vtysh_start_bash_cmd);
4955 install_element(ENABLE_NODE, &vtysh_start_zsh_cmd);
4956 #endif
4957
4958 /* debugging */
4959 install_element(VIEW_NODE, &vtysh_show_error_code_cmd);
4960 install_element(ENABLE_NODE, &vtysh_show_debugging_cmd);
4961 install_element(ENABLE_NODE, &vtysh_show_debugging_hashtable_cmd);
4962 install_element(ENABLE_NODE, &vtysh_debug_all_cmd);
4963 install_element(CONFIG_NODE, &vtysh_debug_all_cmd);
4964 install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd);
4965 install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd);
4966 install_element(ENABLE_NODE, &vtysh_debug_uid_backtrace_cmd);
4967 install_element(CONFIG_NODE, &vtysh_debug_uid_backtrace_cmd);
4968
4969 /* northbound */
4970 install_element(ENABLE_NODE, &show_config_running_cmd);
4971 install_element(ENABLE_NODE, &show_yang_operational_data_cmd);
4972 install_element(ENABLE_NODE, &show_yang_module_cmd);
4973 install_element(ENABLE_NODE, &show_yang_module_detail_cmd);
4974 install_element(ENABLE_NODE, &debug_nb_cmd);
4975 install_element(CONFIG_NODE, &debug_nb_cmd);
4976
4977 /* misc lib show commands */
4978 install_element(VIEW_NODE, &vtysh_show_history_cmd);
4979 install_element(VIEW_NODE, &vtysh_show_memory_cmd);
4980 install_element(VIEW_NODE, &vtysh_show_modules_cmd);
4981 install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
4982 install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
4983 install_element(VIEW_NODE, &vtysh_show_thread_cmd);
4984 install_element(VIEW_NODE, &vtysh_show_poll_cmd);
4985 install_element(VIEW_NODE, &vtysh_show_thread_timer_cmd);
4986
4987 /* Logging */
4988 install_element(VIEW_NODE, &vtysh_show_logging_cmd);
4989
4990 install_element(CONFIG_NODE, &vtysh_service_password_encrypt_cmd);
4991 install_element(CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd);
4992
4993 install_element(CONFIG_NODE, &vtysh_allow_reserved_ranges_cmd);
4994 install_element(CONFIG_NODE, &no_vtysh_allow_reserved_ranges_cmd);
4995
4996 install_element(CONFIG_NODE, &vtysh_password_cmd);
4997 install_element(CONFIG_NODE, &no_vtysh_password_cmd);
4998 install_element(CONFIG_NODE, &vtysh_enable_password_cmd);
4999 install_element(CONFIG_NODE, &no_vtysh_enable_password_cmd);
5000 }