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