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