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