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