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