]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_vty.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / zebra / zebra_vty.c
1 /* Zebra VTY functions
2 * Copyright (C) 2002 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 "memory.h"
24 #include "if.h"
25 #include "prefix.h"
26 #include "command.h"
27 #include "table.h"
28 #include "rib.h"
29 #include "nexthop.h"
30 #include "vrf.h"
31 #include "linklist.h"
32 #include "mpls.h"
33 #include "routemap.h"
34 #include "srcdest_table.h"
35 #include "vxlan.h"
36 #include "termtable.h"
37 #include "affinitymap.h"
38
39 #include "zebra/zebra_router.h"
40 #include "zebra/zserv.h"
41 #include "zebra/zebra_vrf.h"
42 #include "zebra/zebra_mpls.h"
43 #include "zebra/zebra_rnh.h"
44 #include "zebra/redistribute.h"
45 #include "zebra/zebra_affinitymap.h"
46 #include "zebra/zebra_routemap.h"
47 #include "lib/json.h"
48 #include "lib/route_opaque.h"
49 #include "zebra/zebra_vxlan.h"
50 #include "zebra/zebra_evpn_mh.h"
51 #include "zebra/zebra_vty_clippy.c"
52 #include "zebra/zserv.h"
53 #include "zebra/router-id.h"
54 #include "zebra/ipforward.h"
55 #include "zebra/zebra_vxlan_private.h"
56 #include "zebra/zebra_pbr.h"
57 #include "zebra/zebra_nhg.h"
58 #include "zebra/zebra_evpn_mh.h"
59 #include "zebra/interface.h"
60 #include "northbound_cli.h"
61 #include "zebra/zebra_nb.h"
62 #include "zebra/kernel_netlink.h"
63 #include "zebra/if_netlink.h"
64 #include "zebra/table_manager.h"
65 #include "zebra/zebra_script.h"
66 #include "zebra/rtadv.h"
67 #include "zebra/zebra_neigh.h"
68
69 /* context to manage dumps in multiple tables or vrfs */
70 struct route_show_ctx {
71 bool multi; /* dump multiple tables or vrf */
72 bool header_done; /* common header already displayed */
73 };
74
75 static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
76 safi_t safi, bool use_fib, bool use_json,
77 route_tag_t tag,
78 const struct prefix *longer_prefix_p,
79 bool supernets_only, int type,
80 unsigned short ospf_instance_id, uint32_t tableid,
81 bool show_ng, struct route_show_ctx *ctx);
82 static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
83 int mcast, bool use_fib, bool show_ng);
84 static void vty_show_ip_route_summary(struct vty *vty,
85 struct route_table *table, bool use_json);
86 static void vty_show_ip_route_summary_prefix(struct vty *vty,
87 struct route_table *table,
88 bool use_json);
89 /* Helper api to format a nexthop in the 'detailed' output path. */
90 static void show_nexthop_detail_helper(struct vty *vty,
91 const struct route_entry *re,
92 const struct nexthop *nexthop,
93 bool is_backup);
94
95 static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table);
96 static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop,
97 struct route_entry *re, unsigned int num);
98
99 DEFUN (ip_multicast_mode,
100 ip_multicast_mode_cmd,
101 "ip multicast rpf-lookup-mode <urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix>",
102 IP_STR
103 "Multicast options\n"
104 "RPF lookup behavior\n"
105 "Lookup in unicast RIB only\n"
106 "Lookup in multicast RIB only\n"
107 "Try multicast RIB first, fall back to unicast RIB\n"
108 "Lookup both, use entry with lower distance\n"
109 "Lookup both, use entry with longer prefix\n")
110 {
111 char *mode = argv[3]->text;
112
113 if (strmatch(mode, "urib-only"))
114 multicast_mode_ipv4_set(MCAST_URIB_ONLY);
115 else if (strmatch(mode, "mrib-only"))
116 multicast_mode_ipv4_set(MCAST_MRIB_ONLY);
117 else if (strmatch(mode, "mrib-then-urib"))
118 multicast_mode_ipv4_set(MCAST_MIX_MRIB_FIRST);
119 else if (strmatch(mode, "lower-distance"))
120 multicast_mode_ipv4_set(MCAST_MIX_DISTANCE);
121 else if (strmatch(mode, "longer-prefix"))
122 multicast_mode_ipv4_set(MCAST_MIX_PFXLEN);
123 else {
124 vty_out(vty, "Invalid mode specified\n");
125 return CMD_WARNING_CONFIG_FAILED;
126 }
127
128 return CMD_SUCCESS;
129 }
130
131 DEFUN (no_ip_multicast_mode,
132 no_ip_multicast_mode_cmd,
133 "no ip multicast rpf-lookup-mode [<urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix>]",
134 NO_STR
135 IP_STR
136 "Multicast options\n"
137 "RPF lookup behavior\n"
138 "Lookup in unicast RIB only\n"
139 "Lookup in multicast RIB only\n"
140 "Try multicast RIB first, fall back to unicast RIB\n"
141 "Lookup both, use entry with lower distance\n"
142 "Lookup both, use entry with longer prefix\n")
143 {
144 multicast_mode_ipv4_set(MCAST_NO_CONFIG);
145 return CMD_SUCCESS;
146 }
147
148
149 DEFPY (show_ip_rpf,
150 show_ip_rpf_cmd,
151 "show [ip$ip|ipv6$ipv6] rpf [json]",
152 SHOW_STR
153 IP_STR
154 IPV6_STR
155 "Display RPF information for multicast source\n"
156 JSON_STR)
157 {
158 bool uj = use_json(argc, argv);
159 struct route_show_ctx ctx = {
160 .multi = false,
161 };
162
163 return do_show_ip_route(vty, VRF_DEFAULT_NAME, ip ? AFI_IP : AFI_IP6,
164 SAFI_MULTICAST, false, uj, 0, NULL, false, 0, 0,
165 0, false, &ctx);
166 }
167
168 DEFPY (show_ip_rpf_addr,
169 show_ip_rpf_addr_cmd,
170 "show ip rpf A.B.C.D$address",
171 SHOW_STR
172 IP_STR
173 "Display RPF information for multicast source\n"
174 "IP multicast source address (e.g. 10.0.0.0)\n")
175 {
176 struct route_node *rn;
177 struct route_entry *re;
178
179 re = rib_match_multicast(AFI_IP, VRF_DEFAULT, (union g_addr *)&address,
180 &rn);
181
182 if (re)
183 vty_show_ip_route_detail(vty, rn, 1, false, false);
184 else
185 vty_out(vty, "%% No match for RPF lookup\n");
186
187 return CMD_SUCCESS;
188 }
189
190 DEFPY (show_ipv6_rpf_addr,
191 show_ipv6_rpf_addr_cmd,
192 "show ipv6 rpf X:X::X:X$address",
193 SHOW_STR
194 IPV6_STR
195 "Display RPF information for multicast source\n"
196 "IPv6 multicast source address\n")
197 {
198 struct route_node *rn;
199 struct route_entry *re;
200
201 re = rib_match_multicast(AFI_IP6, VRF_DEFAULT, (union g_addr *)&address,
202 &rn);
203
204 if (re)
205 vty_show_ip_route_detail(vty, rn, 1, false, false);
206 else
207 vty_out(vty, "%% No match for RPF lookup\n");
208
209 return CMD_SUCCESS;
210 }
211
212 static char re_status_output_char(const struct route_entry *re,
213 const struct nexthop *nhop,
214 bool is_fib)
215 {
216 if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
217 bool star_p = false;
218
219 if (nhop &&
220 !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
221 !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) {
222 /* More-specific test for 'fib' output */
223 if (is_fib) {
224 star_p = !!CHECK_FLAG(nhop->flags,
225 NEXTHOP_FLAG_FIB);
226 } else
227 star_p = true;
228 }
229
230 if (zrouter.asic_offloaded &&
231 CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
232 return 'q';
233
234 if (zrouter.asic_offloaded
235 && CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED))
236 return 't';
237
238 if (zrouter.asic_offloaded
239 && CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
240 return 'o';
241
242 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OUTOFSYNC))
243 return 'd';
244
245 if (star_p)
246 return '*';
247 else
248 return ' ';
249 }
250
251 if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) {
252 if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
253 return 'q';
254
255 return 'r';
256 }
257
258 if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
259 return 'q';
260
261 return ' ';
262 }
263
264 /*
265 * Show backup nexthop info, in the 'detailed' output path
266 */
267 static void show_nh_backup_helper(struct vty *vty,
268 const struct route_entry *re,
269 const struct nexthop *nexthop)
270 {
271 const struct nexthop *start, *backup, *temp;
272 int i, idx;
273
274 /* Double-check that there _is_ a backup */
275 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) ||
276 re->nhe->backup_info == NULL || re->nhe->backup_info->nhe == NULL ||
277 re->nhe->backup_info->nhe->nhg.nexthop == NULL)
278 return;
279
280 /* Locate the backup nexthop(s) */
281 start = re->nhe->backup_info->nhe->nhg.nexthop;
282 for (i = 0; i < nexthop->backup_num; i++) {
283 /* Format the backup(s) (indented) */
284 backup = start;
285 for (idx = 0; idx < nexthop->backup_idx[i]; idx++) {
286 backup = backup->next;
287 if (backup == NULL)
288 break;
289 }
290
291 /* It's possible for backups to be recursive too,
292 * so walk the recursive resolution list if present.
293 */
294 temp = backup;
295 while (backup) {
296 vty_out(vty, " ");
297 show_nexthop_detail_helper(vty, re, backup,
298 true /*backup*/);
299 vty_out(vty, "\n");
300
301 if (backup->resolved && temp == backup)
302 backup = backup->resolved;
303 else
304 backup = nexthop_next(backup);
305
306 if (backup == temp->next)
307 break;
308 }
309 }
310
311 }
312
313 /*
314 * Helper api to format output for a nexthop, used in the 'detailed'
315 * output path.
316 */
317 static void show_nexthop_detail_helper(struct vty *vty,
318 const struct route_entry *re,
319 const struct nexthop *nexthop,
320 bool is_backup)
321 {
322 char addrstr[32];
323 char buf[MPLS_LABEL_STRLEN];
324 int i;
325
326 if (is_backup)
327 vty_out(vty, " b%s",
328 nexthop->rparent ? " " : "");
329 else
330 vty_out(vty, " %c%s",
331 re_status_output_char(re, nexthop, false),
332 nexthop->rparent ? " " : "");
333
334 switch (nexthop->type) {
335 case NEXTHOP_TYPE_IPV4:
336 case NEXTHOP_TYPE_IPV4_IFINDEX:
337 vty_out(vty, " %pI4",
338 &nexthop->gate.ipv4);
339 if (nexthop->ifindex)
340 vty_out(vty, ", via %s",
341 ifindex2ifname(
342 nexthop->ifindex,
343 nexthop->vrf_id));
344 break;
345 case NEXTHOP_TYPE_IPV6:
346 case NEXTHOP_TYPE_IPV6_IFINDEX:
347 vty_out(vty, " %s",
348 inet_ntop(AF_INET6, &nexthop->gate.ipv6,
349 buf, sizeof(buf)));
350 if (nexthop->ifindex)
351 vty_out(vty, ", via %s",
352 ifindex2ifname(
353 nexthop->ifindex,
354 nexthop->vrf_id));
355 break;
356
357 case NEXTHOP_TYPE_IFINDEX:
358 vty_out(vty, " directly connected, %s",
359 ifindex2ifname(nexthop->ifindex,
360 nexthop->vrf_id));
361 break;
362 case NEXTHOP_TYPE_BLACKHOLE:
363 vty_out(vty, " unreachable");
364 switch (nexthop->bh_type) {
365 case BLACKHOLE_REJECT:
366 vty_out(vty, " (ICMP unreachable)");
367 break;
368 case BLACKHOLE_ADMINPROHIB:
369 vty_out(vty,
370 " (ICMP admin-prohibited)");
371 break;
372 case BLACKHOLE_NULL:
373 vty_out(vty, " (blackhole)");
374 break;
375 case BLACKHOLE_UNSPEC:
376 break;
377 }
378 break;
379 }
380
381 if (re->vrf_id != nexthop->vrf_id) {
382 struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
383
384 vty_out(vty, "(vrf %s)", VRF_LOGNAME(vrf));
385 }
386
387 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
388 vty_out(vty, " (duplicate nexthop removed)");
389
390 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
391 vty_out(vty, " inactive");
392
393 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
394 vty_out(vty, " onlink");
395
396 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN))
397 vty_out(vty, " linkdown");
398
399 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
400 vty_out(vty, " (recursive)");
401
402 /* Source specified? */
403 switch (nexthop->type) {
404 case NEXTHOP_TYPE_IPV4:
405 case NEXTHOP_TYPE_IPV4_IFINDEX:
406 if (nexthop->src.ipv4.s_addr) {
407 if (inet_ntop(AF_INET, &nexthop->src.ipv4,
408 addrstr, sizeof(addrstr)))
409 vty_out(vty, ", src %s",
410 addrstr);
411 }
412 break;
413
414 case NEXTHOP_TYPE_IPV6:
415 case NEXTHOP_TYPE_IPV6_IFINDEX:
416 if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
417 &in6addr_any)) {
418 if (inet_ntop(AF_INET6, &nexthop->src.ipv6,
419 addrstr, sizeof(addrstr)))
420 vty_out(vty, ", src %s",
421 addrstr);
422 }
423 break;
424
425 case NEXTHOP_TYPE_IFINDEX:
426 case NEXTHOP_TYPE_BLACKHOLE:
427 break;
428 }
429
430 if (re->nexthop_mtu)
431 vty_out(vty, ", mtu %u", re->nexthop_mtu);
432
433 /* Label information */
434 if (nexthop->nh_label && nexthop->nh_label->num_labels) {
435 vty_out(vty, ", label %s",
436 mpls_label2str(nexthop->nh_label->num_labels,
437 nexthop->nh_label->label, buf,
438 sizeof(buf), nexthop->nh_label_type,
439 1 /*pretty*/));
440 }
441
442 if (nexthop->weight)
443 vty_out(vty, ", weight %u", nexthop->weight);
444
445 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
446 vty_out(vty, ", backup %d", nexthop->backup_idx[0]);
447
448 for (i = 1; i < nexthop->backup_num; i++)
449 vty_out(vty, ",%d", nexthop->backup_idx[i]);
450 }
451 }
452
453 static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re,
454 struct json_object *json)
455 {
456 struct bgp_zebra_opaque bzo = {};
457 struct ospf_zebra_opaque ozo = {};
458
459 if (!re->opaque)
460 return;
461
462 switch (re->type) {
463 case ZEBRA_ROUTE_SHARP:
464 if (json)
465 json_object_string_add(json, "opaque",
466 (char *)re->opaque->data);
467 else
468 vty_out(vty, " Opaque Data: %s",
469 (char *)re->opaque->data);
470 break;
471
472 case ZEBRA_ROUTE_BGP:
473 memcpy(&bzo, re->opaque->data, re->opaque->length);
474
475 if (json) {
476 json_object_string_add(json, "asPath", bzo.aspath);
477 json_object_string_add(json, "communities",
478 bzo.community);
479 json_object_string_add(json, "largeCommunities",
480 bzo.lcommunity);
481 json_object_string_add(json, "selectionReason",
482 bzo.selection_reason);
483 } else {
484 vty_out(vty, " AS-Path : %s\n", bzo.aspath);
485
486 if (bzo.community[0] != '\0')
487 vty_out(vty, " Communities : %s\n",
488 bzo.community);
489
490 if (bzo.lcommunity[0] != '\0')
491 vty_out(vty, " Large-Communities: %s\n",
492 bzo.lcommunity);
493
494 vty_out(vty, " Selection reason : %s\n",
495 bzo.selection_reason);
496 }
497 break;
498 case ZEBRA_ROUTE_OSPF:
499 case ZEBRA_ROUTE_OSPF6:
500 memcpy(&ozo, re->opaque->data, re->opaque->length);
501
502 if (json) {
503 json_object_string_add(json, "ospfPathType",
504 ozo.path_type);
505 if (ozo.area_id[0] != '\0')
506 json_object_string_add(json, "ospfAreaId",
507 ozo.area_id);
508 if (ozo.tag[0] != '\0')
509 json_object_string_add(json, "ospfTag",
510 ozo.tag);
511 } else {
512 vty_out(vty, " OSPF path type : %s\n",
513 ozo.path_type);
514 if (ozo.area_id[0] != '\0')
515 vty_out(vty, " OSPF area ID : %s\n",
516 ozo.area_id);
517 if (ozo.tag[0] != '\0')
518 vty_out(vty, " OSPF tag : %s\n",
519 ozo.tag);
520 }
521 break;
522 default:
523 break;
524 }
525 }
526
527 static void uptime2str(time_t uptime, char *buf, size_t bufsize)
528 {
529 time_t cur;
530
531 cur = monotime(NULL);
532 cur -= uptime;
533
534 frrtime_to_interval(cur, buf, bufsize);
535 }
536
537 /* New RIB. Detailed information for IPv4 route. */
538 static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
539 int mcast, bool use_fib, bool show_ng)
540 {
541 struct route_entry *re;
542 struct nexthop *nexthop;
543 char buf[SRCDEST2STR_BUFFER];
544 struct zebra_vrf *zvrf;
545 rib_dest_t *dest;
546
547 dest = rib_dest_from_rnode(rn);
548
549 RNODE_FOREACH_RE (rn, re) {
550 /*
551 * If re not selected for forwarding, skip re
552 * for "show ip/ipv6 fib <prefix>"
553 */
554 if (use_fib && re != dest->selected_fib)
555 continue;
556
557 const char *mcast_info = "";
558 if (mcast) {
559 struct rib_table_info *info =
560 srcdest_rnode_table_info(rn);
561 mcast_info = (info->safi == SAFI_MULTICAST)
562 ? " using Multicast RIB"
563 : " using Unicast RIB";
564 }
565
566 vty_out(vty, "Routing entry for %s%s\n",
567 srcdest_rnode2str(rn, buf, sizeof(buf)), mcast_info);
568 vty_out(vty, " Known via \"%s", zebra_route_string(re->type));
569 if (re->instance)
570 vty_out(vty, "[%d]", re->instance);
571 vty_out(vty, "\"");
572 vty_out(vty, ", distance %u, metric %u", re->distance,
573 re->metric);
574 if (re->tag) {
575 vty_out(vty, ", tag %u", re->tag);
576 #if defined(SUPPORT_REALMS)
577 if (re->tag > 0 && re->tag <= 255)
578 vty_out(vty, "(realm)");
579 #endif
580 }
581 if (re->mtu)
582 vty_out(vty, ", mtu %u", re->mtu);
583 if (re->vrf_id != VRF_DEFAULT) {
584 zvrf = vrf_info_lookup(re->vrf_id);
585 vty_out(vty, ", vrf %s", zvrf_name(zvrf));
586 }
587 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
588 vty_out(vty, ", best");
589 vty_out(vty, "\n");
590
591 uptime2str(re->uptime, buf, sizeof(buf));
592
593 vty_out(vty, " Last update %s ago\n", buf);
594
595 if (show_ng) {
596 vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
597 if (re->nhe_installed_id != 0
598 && re->nhe_id != re->nhe_installed_id)
599 vty_out(vty,
600 " Installed Nexthop Group ID: %u\n",
601 re->nhe_installed_id);
602 }
603
604 for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
605 /* Use helper to format each nexthop */
606 show_nexthop_detail_helper(vty, re, nexthop,
607 false /*not backup*/);
608 vty_out(vty, "\n");
609
610 /* Include backup(s), if present */
611 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
612 show_nh_backup_helper(vty, re, nexthop);
613 }
614 zebra_show_ip_route_opaque(vty, re, NULL);
615
616 vty_out(vty, "\n");
617 }
618 }
619
620 static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
621 struct route_entry *re, json_object *json,
622 bool is_fib, bool show_ng)
623 {
624 const struct nexthop *nexthop;
625 int len = 0;
626 char buf[SRCDEST2STR_BUFFER];
627 json_object *json_nexthops = NULL;
628 json_object *json_nexthop = NULL;
629 json_object *json_route = NULL;
630 const rib_dest_t *dest = rib_dest_from_rnode(rn);
631 const struct nexthop_group *nhg;
632 char up_str[MONOTIME_STRLEN];
633 bool first_p = true;
634 bool nhg_from_backup = false;
635
636 uptime2str(re->uptime, up_str, sizeof(up_str));
637
638 /* If showing fib information, use the fib view of the
639 * nexthops.
640 */
641 if (is_fib)
642 nhg = rib_get_fib_nhg(re);
643 else
644 nhg = &(re->nhe->nhg);
645
646 if (json) {
647 json_route = json_object_new_object();
648 json_nexthops = json_object_new_array();
649
650 json_object_string_add(json_route, "prefix",
651 srcdest_rnode2str(rn, buf, sizeof(buf)));
652 json_object_int_add(json_route, "prefixLen", rn->p.prefixlen);
653 json_object_string_add(json_route, "protocol",
654 zebra_route_string(re->type));
655
656 if (re->instance)
657 json_object_int_add(json_route, "instance",
658 re->instance);
659
660 json_object_int_add(json_route, "vrfId", re->vrf_id);
661 json_object_string_add(json_route, "vrfName",
662 vrf_id_to_name(re->vrf_id));
663
664 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
665 json_object_boolean_true_add(json_route, "selected");
666
667 if (dest->selected_fib == re)
668 json_object_boolean_true_add(json_route,
669 "destSelected");
670
671 json_object_int_add(json_route, "distance",
672 re->distance);
673 json_object_int_add(json_route, "metric", re->metric);
674
675 if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
676 json_object_boolean_true_add(json_route, "installed");
677
678 if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED))
679 json_object_boolean_true_add(json_route, "failed");
680
681 if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
682 json_object_boolean_true_add(json_route, "queued");
683
684 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED))
685 json_object_boolean_true_add(json_route, "trapped");
686
687 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED))
688 json_object_boolean_true_add(json_route, "offloaded");
689
690 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
691 json_object_boolean_false_add(json_route, "offloaded");
692
693 if (re->tag)
694 json_object_int_add(json_route, "tag", re->tag);
695
696 if (re->table)
697 json_object_int_add(json_route, "table", re->table);
698
699 json_object_int_add(json_route, "internalStatus",
700 re->status);
701 json_object_int_add(json_route, "internalFlags",
702 re->flags);
703 json_object_int_add(json_route, "internalNextHopNum",
704 nexthop_group_nexthop_num(&(re->nhe->nhg)));
705 json_object_int_add(json_route, "internalNextHopActiveNum",
706 nexthop_group_active_nexthop_num(
707 &(re->nhe->nhg)));
708 json_object_int_add(json_route, "nexthopGroupId", re->nhe_id);
709
710 if (re->nhe_installed_id != 0)
711 json_object_int_add(json_route,
712 "installedNexthopGroupId",
713 re->nhe_installed_id);
714
715 json_object_string_add(json_route, "uptime", up_str);
716
717 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
718 json_nexthop = json_object_new_object();
719 show_nexthop_json_helper(json_nexthop,
720 nexthop, re);
721
722 json_object_array_add(json_nexthops,
723 json_nexthop);
724 }
725
726 json_object_object_add(json_route, "nexthops", json_nexthops);
727
728 /* If there are backup nexthops, include them */
729 if (is_fib)
730 nhg = rib_get_fib_backup_nhg(re);
731 else
732 nhg = zebra_nhg_get_backup_nhg(re->nhe);
733
734 if (nhg && nhg->nexthop) {
735 json_nexthops = json_object_new_array();
736
737 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
738 json_nexthop = json_object_new_object();
739
740 show_nexthop_json_helper(json_nexthop,
741 nexthop, re);
742 json_object_array_add(json_nexthops,
743 json_nexthop);
744 }
745
746 json_object_object_add(json_route, "backupNexthops",
747 json_nexthops);
748 }
749 zebra_show_ip_route_opaque(NULL, re, json_route);
750
751 json_object_array_add(json, json_route);
752 return;
753 }
754
755 /* Prefix information, and first nexthop. If we're showing 'fib',
756 * and there are no installed primary nexthops, see if there are any
757 * backup nexthops and start with those.
758 */
759 if (is_fib && nhg->nexthop == NULL) {
760 nhg = rib_get_fib_backup_nhg(re);
761 nhg_from_backup = true;
762 }
763
764 len = vty_out(vty, "%c", zebra_route_char(re->type));
765 if (re->instance)
766 len += vty_out(vty, "[%d]", re->instance);
767 if (nhg_from_backup && nhg->nexthop) {
768 len += vty_out(
769 vty, "%cb%c %s",
770 CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
771 re_status_output_char(re, nhg->nexthop, is_fib),
772 srcdest_rnode2str(rn, buf, sizeof(buf)));
773 } else {
774 len += vty_out(
775 vty, "%c%c %s",
776 CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
777 re_status_output_char(re, nhg->nexthop, is_fib),
778 srcdest_rnode2str(rn, buf, sizeof(buf)));
779 }
780
781 /* Distance and metric display. */
782 if (((re->type == ZEBRA_ROUTE_CONNECT) &&
783 (re->distance || re->metric)) ||
784 (re->type != ZEBRA_ROUTE_CONNECT))
785 len += vty_out(vty, " [%u/%u]", re->distance,
786 re->metric);
787
788 if (show_ng)
789 len += vty_out(vty, " (%u)", re->nhe_id);
790
791 /* Nexthop information. */
792 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
793 if (first_p) {
794 first_p = false;
795 } else if (nhg_from_backup) {
796 vty_out(vty, " b%c%*c",
797 re_status_output_char(re, nexthop, is_fib),
798 len - 3 + (2 * nexthop_level(nexthop)), ' ');
799 } else {
800 vty_out(vty, " %c%*c",
801 re_status_output_char(re, nexthop, is_fib),
802 len - 3 + (2 * nexthop_level(nexthop)), ' ');
803 }
804
805 show_route_nexthop_helper(vty, re, nexthop);
806 vty_out(vty, ", %s\n", up_str);
807 }
808
809 /* If we only had backup nexthops, we're done */
810 if (nhg_from_backup)
811 return;
812
813 /* Check for backup nexthop info if present */
814 if (is_fib)
815 nhg = rib_get_fib_backup_nhg(re);
816 else
817 nhg = zebra_nhg_get_backup_nhg(re->nhe);
818
819 if (nhg == NULL)
820 return;
821
822 /* Print backup info */
823 for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
824 bool star_p = false;
825
826 if (is_fib)
827 star_p = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
828
829 /* TODO -- it'd be nice to be able to include
830 * the entire list of backups, *and* include the
831 * real installation state.
832 */
833 vty_out(vty, " b%c %*c",
834 (star_p ? '*' : ' '),
835 len - 3 + (2 * nexthop_level(nexthop)), ' ');
836 show_route_nexthop_helper(vty, re, nexthop);
837 vty_out(vty, "\n");
838 }
839
840 }
841
842 static void vty_show_ip_route_detail_json(struct vty *vty,
843 struct route_node *rn, bool use_fib)
844 {
845 json_object *json = NULL;
846 json_object *json_prefix = NULL;
847 struct route_entry *re;
848 char buf[BUFSIZ];
849 rib_dest_t *dest;
850
851 dest = rib_dest_from_rnode(rn);
852
853 json = json_object_new_object();
854 json_prefix = json_object_new_array();
855
856 RNODE_FOREACH_RE (rn, re) {
857 /*
858 * If re not selected for forwarding, skip re
859 * for "show ip/ipv6 fib <prefix> json"
860 */
861 if (use_fib && re != dest->selected_fib)
862 continue;
863 vty_show_ip_route(vty, rn, re, json_prefix, use_fib, false);
864 }
865
866 prefix2str(&rn->p, buf, sizeof(buf));
867 json_object_object_add(json, buf, json_prefix);
868 vty_json(vty, json);
869 }
870
871 static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
872 struct route_table *table, afi_t afi,
873 bool use_fib, route_tag_t tag,
874 const struct prefix *longer_prefix_p,
875 bool supernets_only, int type,
876 unsigned short ospf_instance_id, bool use_json,
877 uint32_t tableid, bool show_ng,
878 struct route_show_ctx *ctx)
879 {
880 struct route_node *rn;
881 struct route_entry *re;
882 int first = 1;
883 rib_dest_t *dest;
884 json_object *json = NULL;
885 json_object *json_prefix = NULL;
886 uint32_t addr;
887 char buf[BUFSIZ];
888
889 /*
890 * ctx->multi indicates if we are dumping multiple tables or vrfs.
891 * if set:
892 * => display the common header at most once
893 * => add newline at each call except first
894 * => always display the VRF and table
895 * else:
896 * => display the common header if at least one entry is found
897 * => display the VRF and table if specific
898 */
899
900 if (use_json)
901 json = json_object_new_object();
902
903 /* Show all routes. */
904 for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
905 dest = rib_dest_from_rnode(rn);
906
907 RNODE_FOREACH_RE (rn, re) {
908 if (use_fib && re != dest->selected_fib)
909 continue;
910
911 if (tag && re->tag != tag)
912 continue;
913
914 if (longer_prefix_p
915 && !prefix_match(longer_prefix_p, &rn->p))
916 continue;
917
918 /* This can only be true when the afi is IPv4 */
919 if (supernets_only) {
920 addr = ntohl(rn->p.u.prefix4.s_addr);
921
922 if (IN_CLASSC(addr) && rn->p.prefixlen >= 24)
923 continue;
924
925 if (IN_CLASSB(addr) && rn->p.prefixlen >= 16)
926 continue;
927
928 if (IN_CLASSA(addr) && rn->p.prefixlen >= 8)
929 continue;
930 }
931
932 if (type && re->type != type)
933 continue;
934
935 if (ospf_instance_id
936 && (re->type != ZEBRA_ROUTE_OSPF
937 || re->instance != ospf_instance_id))
938 continue;
939
940 if (use_json) {
941 if (!json_prefix)
942 json_prefix = json_object_new_array();
943 } else if (first) {
944 if (!ctx->header_done) {
945 if (afi == AFI_IP)
946 vty_out(vty,
947 SHOW_ROUTE_V4_HEADER);
948 else
949 vty_out(vty,
950 SHOW_ROUTE_V6_HEADER);
951 }
952 if (ctx->multi && ctx->header_done)
953 vty_out(vty, "\n");
954 if (ctx->multi || zvrf_id(zvrf) != VRF_DEFAULT
955 || tableid) {
956 if (!tableid)
957 vty_out(vty, "VRF %s:\n",
958 zvrf_name(zvrf));
959 else
960 vty_out(vty,
961 "VRF %s table %u:\n",
962 zvrf_name(zvrf),
963 tableid);
964 }
965 ctx->header_done = true;
966 first = 0;
967 }
968
969 vty_show_ip_route(vty, rn, re, json_prefix, use_fib,
970 show_ng);
971 }
972
973 if (json_prefix) {
974 prefix2str(&rn->p, buf, sizeof(buf));
975 json_object_object_add(json, buf, json_prefix);
976 json_prefix = NULL;
977 }
978 }
979
980 if (use_json)
981 vty_json(vty, json);
982 }
983
984 static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf,
985 afi_t afi, bool use_fib, bool use_json,
986 route_tag_t tag,
987 const struct prefix *longer_prefix_p,
988 bool supernets_only, int type,
989 unsigned short ospf_instance_id, bool show_ng,
990 struct route_show_ctx *ctx)
991 {
992 struct zebra_router_table *zrt;
993 struct rib_table_info *info;
994
995 RB_FOREACH (zrt, zebra_router_table_head,
996 &zrouter.tables) {
997 info = route_table_get_info(zrt->table);
998
999 if (zvrf != info->zvrf)
1000 continue;
1001 if (zrt->afi != afi ||
1002 zrt->safi != SAFI_UNICAST)
1003 continue;
1004
1005 do_show_ip_route(vty, zvrf_name(zvrf), afi, SAFI_UNICAST,
1006 use_fib, use_json, tag, longer_prefix_p,
1007 supernets_only, type, ospf_instance_id,
1008 zrt->tableid, show_ng, ctx);
1009 }
1010 }
1011
1012 static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
1013 safi_t safi, bool use_fib, bool use_json,
1014 route_tag_t tag,
1015 const struct prefix *longer_prefix_p,
1016 bool supernets_only, int type,
1017 unsigned short ospf_instance_id, uint32_t tableid,
1018 bool show_ng, struct route_show_ctx *ctx)
1019 {
1020 struct route_table *table;
1021 struct zebra_vrf *zvrf = NULL;
1022
1023 if (!(zvrf = zebra_vrf_lookup_by_name(vrf_name))) {
1024 if (use_json)
1025 vty_out(vty, "{}\n");
1026 else
1027 vty_out(vty, "vrf %s not defined\n", vrf_name);
1028 return CMD_SUCCESS;
1029 }
1030
1031 if (zvrf_id(zvrf) == VRF_UNKNOWN) {
1032 if (use_json)
1033 vty_out(vty, "{}\n");
1034 else
1035 vty_out(vty, "vrf %s inactive\n", vrf_name);
1036 return CMD_SUCCESS;
1037 }
1038
1039 if (tableid)
1040 table = zebra_router_find_table(zvrf, tableid, afi, SAFI_UNICAST);
1041 else
1042 table = zebra_vrf_table(afi, safi, zvrf_id(zvrf));
1043 if (!table) {
1044 if (use_json)
1045 vty_out(vty, "{}\n");
1046 return CMD_SUCCESS;
1047 }
1048
1049 do_show_route_helper(vty, zvrf, table, afi, use_fib, tag,
1050 longer_prefix_p, supernets_only, type,
1051 ospf_instance_id, use_json, tableid, show_ng, ctx);
1052
1053 return CMD_SUCCESS;
1054 }
1055
1056 DEFPY (show_ip_nht,
1057 show_ip_nht_cmd,
1058 "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
1059 SHOW_STR
1060 IP_STR
1061 IP6_STR
1062 "IP nexthop tracking table\n"
1063 "IP import check tracking table\n"
1064 "IPv4 Address\n"
1065 "IPv6 Address\n"
1066 VRF_CMD_HELP_STR
1067 "IPv4 Address\n"
1068 "IPv6 Address\n"
1069 VRF_ALL_CMD_HELP_STR
1070 "Show Multicast (MRIB) NHT state\n"
1071 JSON_STR)
1072 {
1073 afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
1074 vrf_id_t vrf_id = VRF_DEFAULT;
1075 struct prefix prefix, *p = NULL;
1076 safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
1077 bool uj = use_json(argc, argv);
1078 json_object *json = NULL;
1079 json_object *json_vrf = NULL;
1080 json_object *json_nexthop = NULL;
1081
1082 if (uj)
1083 json = json_object_new_object();
1084
1085 if (vrf_all) {
1086 struct vrf *vrf;
1087 struct zebra_vrf *zvrf;
1088
1089 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1090 if ((zvrf = vrf->info) != NULL) {
1091 if (uj) {
1092 json_vrf = json_object_new_object();
1093 json_nexthop = json_object_new_object();
1094 json_object_object_add(json,
1095 zvrf_name(zvrf),
1096 json_vrf);
1097 json_object_object_add(json_vrf,
1098 (afi == AFI_IP)
1099 ? "ipv4"
1100 : "ipv6",
1101 json_nexthop);
1102 } else {
1103 vty_out(vty, "\nVRF %s:\n",
1104 zvrf_name(zvrf));
1105 }
1106 zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
1107 vty, NULL, json_nexthop);
1108 }
1109 }
1110
1111 if (uj)
1112 vty_json(vty, json);
1113
1114 return CMD_SUCCESS;
1115 }
1116 if (vrf_name)
1117 VRF_GET_ID(vrf_id, vrf_name, false);
1118
1119 memset(&prefix, 0, sizeof(prefix));
1120 if (addr) {
1121 p = sockunion2hostprefix(addr, &prefix);
1122 if (!p) {
1123 if (uj)
1124 json_object_free(json);
1125 return CMD_WARNING;
1126 }
1127 }
1128
1129 if (uj) {
1130 json_vrf = json_object_new_object();
1131 json_nexthop = json_object_new_object();
1132 if (vrf_name)
1133 json_object_object_add(json, vrf_name, json_vrf);
1134 else
1135 json_object_object_add(json, "default", json_vrf);
1136
1137 json_object_object_add(json_vrf,
1138 (afi == AFI_IP) ? "ipv4" : "ipv6",
1139 json_nexthop);
1140 }
1141
1142 zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
1143
1144 if (uj)
1145 vty_json(vty, json);
1146
1147 return CMD_SUCCESS;
1148 }
1149
1150 DEFUN (ip_nht_default_route,
1151 ip_nht_default_route_cmd,
1152 "ip nht resolve-via-default",
1153 IP_STR
1154 "Filter Next Hop tracking route resolution\n"
1155 "Resolve via default route\n")
1156 {
1157 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
1158
1159 if (!zvrf)
1160 return CMD_WARNING;
1161
1162 if (zvrf->zebra_rnh_ip_default_route)
1163 return CMD_SUCCESS;
1164
1165 zvrf->zebra_rnh_ip_default_route = true;
1166
1167 zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST);
1168 return CMD_SUCCESS;
1169 }
1170
1171 static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
1172 json_object *json_nhe_hdr)
1173 {
1174 struct nexthop *nexthop = NULL;
1175 struct nhg_connected *rb_node_dep = NULL;
1176 struct nexthop_group *backup_nhg;
1177 char up_str[MONOTIME_STRLEN];
1178 char time_left[MONOTIME_STRLEN];
1179 json_object *json_dependants = NULL;
1180 json_object *json_depends = NULL;
1181 json_object *json_nexthop_array = NULL;
1182 json_object *json_nexthops = NULL;
1183 json_object *json = NULL;
1184 json_object *json_backup_nexthop_array = NULL;
1185 json_object *json_backup_nexthops = NULL;
1186
1187
1188 uptime2str(nhe->uptime, up_str, sizeof(up_str));
1189
1190 if (json_nhe_hdr)
1191 json = json_object_new_object();
1192
1193 if (json) {
1194 json_object_string_add(json, "type",
1195 zebra_route_string(nhe->type));
1196 json_object_int_add(json, "refCount", nhe->refcnt);
1197 if (thread_is_scheduled(nhe->timer))
1198 json_object_string_add(
1199 json, "timeToDeletion",
1200 thread_timer_to_hhmmss(time_left,
1201 sizeof(time_left),
1202 nhe->timer));
1203 json_object_string_add(json, "uptime", up_str);
1204 json_object_string_add(json, "vrf",
1205 vrf_id_to_name(nhe->vrf_id));
1206
1207 } else {
1208 vty_out(vty, "ID: %u (%s)\n", nhe->id,
1209 zebra_route_string(nhe->type));
1210 vty_out(vty, " RefCnt: %u", nhe->refcnt);
1211 if (thread_is_scheduled(nhe->timer))
1212 vty_out(vty, " Time to Deletion: %s",
1213 thread_timer_to_hhmmss(time_left,
1214 sizeof(time_left),
1215 nhe->timer));
1216 vty_out(vty, "\n");
1217
1218 vty_out(vty, " Uptime: %s\n", up_str);
1219 vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
1220 }
1221
1222 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
1223 if (json)
1224 json_object_boolean_true_add(json, "valid");
1225 else
1226 vty_out(vty, " Valid");
1227
1228 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1229 if (json)
1230 json_object_boolean_true_add(json, "installed");
1231 else
1232 vty_out(vty, ", Installed");
1233 }
1234 if (!json)
1235 vty_out(vty, "\n");
1236 }
1237 if (nhe->ifp) {
1238 if (json)
1239 json_object_int_add(json, "interfaceIndex",
1240 nhe->ifp->ifindex);
1241 else
1242 vty_out(vty, " Interface Index: %d\n",
1243 nhe->ifp->ifindex);
1244 }
1245
1246 if (!zebra_nhg_depends_is_empty(nhe)) {
1247 if (json)
1248 json_depends = json_object_new_array();
1249 else
1250 vty_out(vty, " Depends:");
1251 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1252 if (json_depends)
1253 json_object_array_add(
1254 json_depends,
1255 json_object_new_int(
1256 rb_node_dep->nhe->id));
1257 else
1258 vty_out(vty, " (%u)", rb_node_dep->nhe->id);
1259 }
1260 if (!json_depends)
1261 vty_out(vty, "\n");
1262 else
1263 json_object_object_add(json, "depends", json_depends);
1264 }
1265
1266 /* Output nexthops */
1267 if (json)
1268 json_nexthop_array = json_object_new_array();
1269
1270
1271 for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
1272 if (json_nexthop_array) {
1273 json_nexthops = json_object_new_object();
1274 show_nexthop_json_helper(json_nexthops, nexthop, NULL);
1275 } else {
1276 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1277 vty_out(vty, " ");
1278 else
1279 /* Make recursive nexthops a bit more clear */
1280 vty_out(vty, " ");
1281 show_route_nexthop_helper(vty, NULL, nexthop);
1282 }
1283
1284 if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
1285 if (CHECK_FLAG(nexthop->flags,
1286 NEXTHOP_FLAG_HAS_BACKUP)) {
1287 if (json)
1288 json_object_int_add(
1289 json_nexthops, "backup",
1290 nexthop->backup_idx[0]);
1291 else
1292 vty_out(vty, " [backup %d]",
1293 nexthop->backup_idx[0]);
1294 }
1295
1296 if (!json)
1297 vty_out(vty, "\n");
1298 else
1299 json_object_array_add(json_nexthop_array,
1300 json_nexthops);
1301
1302 continue;
1303 }
1304
1305 if (!json) {
1306 /* TODO -- print more useful backup info */
1307 if (CHECK_FLAG(nexthop->flags,
1308 NEXTHOP_FLAG_HAS_BACKUP)) {
1309 int i;
1310
1311 vty_out(vty, "[backup");
1312 for (i = 0; i < nexthop->backup_num; i++)
1313 vty_out(vty, " %d",
1314 nexthop->backup_idx[i]);
1315 vty_out(vty, "]");
1316 }
1317 vty_out(vty, "\n");
1318 } else {
1319 json_object_array_add(json_nexthop_array,
1320 json_nexthops);
1321 }
1322 }
1323
1324 if (json)
1325 json_object_object_add(json, "nexthops", json_nexthop_array);
1326
1327 /* Output backup nexthops (if any) */
1328 backup_nhg = zebra_nhg_get_backup_nhg(nhe);
1329 if (backup_nhg) {
1330 if (json)
1331 json_backup_nexthop_array = json_object_new_array();
1332 else
1333 vty_out(vty, " Backups:\n");
1334
1335 for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
1336 if (json_backup_nexthop_array) {
1337 json_backup_nexthops = json_object_new_object();
1338 show_nexthop_json_helper(json_backup_nexthops,
1339 nexthop, NULL);
1340 json_object_array_add(json_backup_nexthop_array,
1341 json_backup_nexthops);
1342 } else {
1343
1344 if (!CHECK_FLAG(nexthop->flags,
1345 NEXTHOP_FLAG_RECURSIVE))
1346 vty_out(vty, " ");
1347 else
1348 /* Make recursive nexthops a bit more
1349 * clear
1350 */
1351 vty_out(vty, " ");
1352 show_route_nexthop_helper(vty, NULL, nexthop);
1353 vty_out(vty, "\n");
1354 }
1355 }
1356
1357 if (json)
1358 json_object_object_add(json, "backupNexthops",
1359 json_backup_nexthop_array);
1360 }
1361
1362 if (!zebra_nhg_dependents_is_empty(nhe)) {
1363 if (json)
1364 json_dependants = json_object_new_array();
1365 else
1366 vty_out(vty, " Dependents:");
1367 frr_each(nhg_connected_tree, &nhe->nhg_dependents,
1368 rb_node_dep) {
1369 if (json)
1370 json_object_array_add(
1371 json_dependants,
1372 json_object_new_int(
1373 rb_node_dep->nhe->id));
1374 else
1375 vty_out(vty, " (%u)", rb_node_dep->nhe->id);
1376 }
1377 if (json)
1378 json_object_object_add(json, "dependents",
1379 json_dependants);
1380 else
1381 vty_out(vty, "\n");
1382 }
1383
1384 if (nhe->nhg.nhgr.buckets) {
1385 if (json) {
1386 json_object_int_add(json, "buckets",
1387 nhe->nhg.nhgr.buckets);
1388 json_object_int_add(json, "idleTimer",
1389 nhe->nhg.nhgr.idle_timer);
1390 json_object_int_add(json, "unbalancedTimer",
1391 nhe->nhg.nhgr.unbalanced_timer);
1392 json_object_int_add(json, "unbalancedTime",
1393 nhe->nhg.nhgr.unbalanced_time);
1394 } else {
1395 vty_out(vty,
1396 " Buckets: %u Idle Timer: %u Unbalanced Timer: %u Unbalanced time: %" PRIu64
1397 "\n",
1398 nhe->nhg.nhgr.buckets, nhe->nhg.nhgr.idle_timer,
1399 nhe->nhg.nhgr.unbalanced_timer,
1400 nhe->nhg.nhgr.unbalanced_time);
1401 }
1402 }
1403
1404 if (json_nhe_hdr)
1405 json_object_object_addf(json_nhe_hdr, json, "%u", nhe->id);
1406 }
1407
1408 static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id,
1409 json_object *json)
1410 {
1411 struct nhg_hash_entry *nhe = NULL;
1412
1413 nhe = zebra_nhg_lookup_id(id);
1414
1415 if (nhe)
1416 show_nexthop_group_out(vty, nhe, json);
1417 else {
1418 if (json)
1419 vty_json(vty, json);
1420 else
1421 vty_out(vty, "Nexthop Group ID: %u does not exist\n",
1422 id);
1423 return CMD_WARNING;
1424 }
1425
1426 if (json)
1427 vty_json(vty, json);
1428
1429 return CMD_SUCCESS;
1430 }
1431
1432 /* Helper function for iteration through the hash of nexthop-groups/nhe-s */
1433
1434 struct nhe_show_context {
1435 struct vty *vty;
1436 vrf_id_t vrf_id;
1437 afi_t afi;
1438 int type;
1439 json_object *json;
1440 };
1441
1442 static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
1443 {
1444 struct nhe_show_context *ctx = arg;
1445 struct nhg_hash_entry *nhe;
1446
1447 nhe = bucket->data; /* We won't be offered NULL buckets */
1448
1449 if (ctx->afi && nhe->afi != ctx->afi)
1450 goto done;
1451
1452 if (ctx->vrf_id && nhe->vrf_id != ctx->vrf_id)
1453 goto done;
1454
1455 if (ctx->type && nhe->type != ctx->type)
1456 goto done;
1457
1458 show_nexthop_group_out(ctx->vty, nhe, ctx->json);
1459
1460 done:
1461 return HASHWALK_CONTINUE;
1462 }
1463
1464 static void show_nexthop_group_cmd_helper(struct vty *vty,
1465 struct zebra_vrf *zvrf, afi_t afi,
1466 int type, json_object *json)
1467 {
1468 struct nhe_show_context ctx;
1469
1470 ctx.vty = vty;
1471 ctx.afi = afi;
1472 ctx.vrf_id = zvrf->vrf->vrf_id;
1473 ctx.type = type;
1474 ctx.json = json;
1475
1476 hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
1477 }
1478
1479 static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
1480 {
1481 struct zebra_if *zebra_if = NULL;
1482 struct nhg_connected *rb_node_dep = NULL;
1483
1484 zebra_if = ifp->info;
1485
1486 if (!if_nhg_dependents_is_empty(ifp)) {
1487 vty_out(vty, "Interface %s:\n", ifp->name);
1488
1489 frr_each(nhg_connected_tree, &zebra_if->nhg_dependents,
1490 rb_node_dep) {
1491 vty_out(vty, " ");
1492 show_nexthop_group_out(vty, rb_node_dep->nhe, NULL);
1493 }
1494 }
1495 }
1496
1497 DEFPY (show_interface_nexthop_group,
1498 show_interface_nexthop_group_cmd,
1499 "show interface [IFNAME$if_name] nexthop-group",
1500 SHOW_STR
1501 "Interface status and configuration\n"
1502 "Interface name\n"
1503 "Show Nexthop Groups\n")
1504 {
1505 struct vrf *vrf = NULL;
1506 struct interface *ifp = NULL;
1507 bool found = false;
1508
1509 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1510 if (if_name) {
1511 ifp = if_lookup_by_name(if_name, vrf->vrf_id);
1512 if (ifp) {
1513 if_nexthop_group_dump_vty(vty, ifp);
1514 found = true;
1515 }
1516 } else {
1517 FOR_ALL_INTERFACES (vrf, ifp)
1518 if_nexthop_group_dump_vty(vty, ifp);
1519 found = true;
1520 }
1521 }
1522
1523 if (!found) {
1524 vty_out(vty, "%% Can't find interface %s\n", if_name);
1525 return CMD_WARNING;
1526 }
1527
1528 return CMD_SUCCESS;
1529 }
1530
1531 DEFPY(show_nexthop_group,
1532 show_nexthop_group_cmd,
1533 "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]> [json]",
1534 SHOW_STR
1535 "Show Nexthop Groups\n"
1536 "RIB information\n"
1537 "Nexthop Group ID\n"
1538 "Show Singleton Nexthop-Groups\n"
1539 IP_STR
1540 IP6_STR
1541 "Kernel (not installed via the zebra RIB)\n"
1542 "Zebra (implicitly created by zebra)\n"
1543 "Border Gateway Protocol (BGP)\n"
1544 "Super Happy Advanced Routing Protocol (SHARP)\n"
1545 VRF_FULL_CMD_HELP_STR
1546 JSON_STR)
1547 {
1548
1549 struct zebra_vrf *zvrf = NULL;
1550 afi_t afi = AFI_UNSPEC;
1551 int type = 0;
1552 bool uj = use_json(argc, argv);
1553 json_object *json = NULL;
1554 json_object *json_vrf = NULL;
1555
1556 if (uj)
1557 json = json_object_new_object();
1558
1559 if (id)
1560 return show_nexthop_group_id_cmd_helper(vty, id, json);
1561
1562 if (v4)
1563 afi = AFI_IP;
1564 else if (v6)
1565 afi = AFI_IP6;
1566
1567 if (type_str) {
1568 type = proto_redistnum((afi ? afi : AFI_IP), type_str);
1569 if (type < 0) {
1570 /* assume zebra */
1571 type = ZEBRA_ROUTE_NHG;
1572 }
1573 }
1574
1575 if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
1576 if (uj)
1577 vty_json(vty, json);
1578 else
1579 vty_out(vty,
1580 "VRF subcommand does not make any sense in l3mdev based vrf's\n");
1581 return CMD_WARNING;
1582 }
1583
1584 if (vrf_all) {
1585 struct vrf *vrf;
1586
1587 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1588 struct zebra_vrf *zvrf;
1589
1590 zvrf = vrf->info;
1591 if (!zvrf)
1592 continue;
1593 if (uj)
1594 json_vrf = json_object_new_object();
1595 else
1596 vty_out(vty, "VRF: %s\n", vrf->name);
1597
1598 show_nexthop_group_cmd_helper(vty, zvrf, afi, type,
1599 json_vrf);
1600 if (uj)
1601 json_object_object_add(json, vrf->name,
1602 json_vrf);
1603 }
1604
1605 if (uj)
1606 vty_json(vty, json);
1607
1608 return CMD_SUCCESS;
1609 }
1610
1611 if (vrf_name)
1612 zvrf = zebra_vrf_lookup_by_name(vrf_name);
1613 else
1614 zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
1615
1616 if (!zvrf) {
1617 if (uj)
1618 vty_json(vty, json);
1619 else
1620 vty_out(vty, "%% VRF '%s' specified does not exist\n",
1621 vrf_name);
1622 return CMD_WARNING;
1623 }
1624
1625 show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json);
1626
1627 if (uj)
1628 vty_json(vty, json);
1629
1630 return CMD_SUCCESS;
1631 }
1632
1633 DEFPY_HIDDEN(nexthop_group_use_enable,
1634 nexthop_group_use_enable_cmd,
1635 "[no] zebra nexthop kernel enable",
1636 NO_STR
1637 ZEBRA_STR
1638 "Nexthop configuration \n"
1639 "Configure use of kernel nexthops\n"
1640 "Enable kernel nexthops\n")
1641 {
1642 zebra_nhg_enable_kernel_nexthops(!no);
1643 return CMD_SUCCESS;
1644 }
1645
1646 DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd,
1647 "[no] zebra nexthop proto only",
1648 NO_STR ZEBRA_STR
1649 "Nexthop configuration\n"
1650 "Configure exclusive use of proto nexthops\n"
1651 "Only use proto nexthops\n")
1652 {
1653 zebra_nhg_set_proto_nexthops_only(!no);
1654 return CMD_SUCCESS;
1655 }
1656
1657 DEFPY_HIDDEN(backup_nexthop_recursive_use_enable,
1658 backup_nexthop_recursive_use_enable_cmd,
1659 "[no] zebra nexthop resolve-via-backup",
1660 NO_STR
1661 ZEBRA_STR
1662 "Nexthop configuration \n"
1663 "Configure use of backup nexthops in recursive resolution\n")
1664 {
1665 zebra_nhg_set_recursive_use_backups(!no);
1666 return CMD_SUCCESS;
1667 }
1668
1669 DEFUN (no_ip_nht_default_route,
1670 no_ip_nht_default_route_cmd,
1671 "no ip nht resolve-via-default",
1672 NO_STR
1673 IP_STR
1674 "Filter Next Hop tracking route resolution\n"
1675 "Resolve via default route\n")
1676 {
1677 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
1678
1679 if (!zvrf)
1680 return CMD_WARNING;
1681
1682 if (!zvrf->zebra_rnh_ip_default_route)
1683 return CMD_SUCCESS;
1684
1685 zvrf->zebra_rnh_ip_default_route = false;
1686 zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST);
1687 return CMD_SUCCESS;
1688 }
1689
1690 DEFUN (ipv6_nht_default_route,
1691 ipv6_nht_default_route_cmd,
1692 "ipv6 nht resolve-via-default",
1693 IP6_STR
1694 "Filter Next Hop tracking route resolution\n"
1695 "Resolve via default route\n")
1696 {
1697 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
1698
1699 if (!zvrf)
1700 return CMD_WARNING;
1701
1702 if (zvrf->zebra_rnh_ipv6_default_route)
1703 return CMD_SUCCESS;
1704
1705 zvrf->zebra_rnh_ipv6_default_route = true;
1706 zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST);
1707 return CMD_SUCCESS;
1708 }
1709
1710 DEFUN (no_ipv6_nht_default_route,
1711 no_ipv6_nht_default_route_cmd,
1712 "no ipv6 nht resolve-via-default",
1713 NO_STR
1714 IP6_STR
1715 "Filter Next Hop tracking route resolution\n"
1716 "Resolve via default route\n")
1717 {
1718 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
1719
1720 if (!zvrf)
1721 return CMD_WARNING;
1722
1723 if (!zvrf->zebra_rnh_ipv6_default_route)
1724 return CMD_SUCCESS;
1725
1726 zvrf->zebra_rnh_ipv6_default_route = false;
1727 zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST);
1728 return CMD_SUCCESS;
1729 }
1730
1731 DEFPY_HIDDEN(rnh_hide_backups, rnh_hide_backups_cmd,
1732 "[no] ip nht hide-backup-events",
1733 NO_STR
1734 IP_STR
1735 "Nexthop-tracking configuration\n"
1736 "Hide notification about backup nexthops\n")
1737 {
1738 rnh_set_hide_backups(!no);
1739 return CMD_SUCCESS;
1740 }
1741
1742 DEFPY (show_route,
1743 show_route_cmd,
1744 "show\
1745 <\
1746 ip$ipv4 <fib$fib|route> [table <(1-4294967295)$table|all$table_all>]\
1747 [vrf <NAME$vrf_name|all$vrf_all>]\
1748 [{\
1749 tag (1-4294967295)\
1750 |A.B.C.D/M$prefix longer-prefixes\
1751 |supernets-only$supernets_only\
1752 }]\
1753 [<\
1754 " FRR_IP_REDIST_STR_ZEBRA "$type_str\
1755 |ospf$type_str (1-65535)$ospf_instance_id\
1756 >]\
1757 |ipv6$ipv6 <fib$fib|route> [table <(1-4294967295)$table|all$table_all>]\
1758 [vrf <NAME$vrf_name|all$vrf_all>]\
1759 [{\
1760 tag (1-4294967295)\
1761 |X:X::X:X/M$prefix longer-prefixes\
1762 }]\
1763 [" FRR_IP6_REDIST_STR_ZEBRA "$type_str]\
1764 >\
1765 [<json$json|nexthop-group$ng>]",
1766 SHOW_STR
1767 IP_STR
1768 "IP forwarding table\n"
1769 "IP routing table\n"
1770 "Table to display\n"
1771 "The table number to display\n"
1772 "All tables\n"
1773 VRF_FULL_CMD_HELP_STR
1774 "Show only routes with tag\n"
1775 "Tag value\n"
1776 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1777 "Show route matching the specified Network/Mask pair only\n"
1778 "Show supernet entries only\n"
1779 FRR_IP_REDIST_HELP_STR_ZEBRA
1780 "Open Shortest Path First (OSPFv2)\n"
1781 "Instance ID\n"
1782 IPV6_STR
1783 "IP forwarding table\n"
1784 "IP routing table\n"
1785 "Table to display\n"
1786 "The table number to display\n"
1787 "All tables\n"
1788 VRF_FULL_CMD_HELP_STR
1789 "Show only routes with tag\n"
1790 "Tag value\n"
1791 "IPv6 prefix\n"
1792 "Show route matching the specified Network/Mask pair only\n"
1793 FRR_IP6_REDIST_HELP_STR_ZEBRA
1794 JSON_STR
1795 "Nexthop Group Information\n")
1796 {
1797 afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
1798 struct vrf *vrf;
1799 int type = 0;
1800 struct zebra_vrf *zvrf;
1801 struct route_show_ctx ctx = {
1802 .multi = vrf_all || table_all,
1803 };
1804
1805 if (!vrf_is_backend_netns()) {
1806 if ((vrf_all || vrf_name) && (table || table_all)) {
1807 if (!!json)
1808 vty_out(vty, "{}\n");
1809 else {
1810 vty_out(vty, "Linux vrf backend already points to table id\n");
1811 vty_out(vty, "Either remove table parameter or vrf parameter\n");
1812 }
1813 return CMD_SUCCESS;
1814 }
1815 }
1816 if (type_str) {
1817 type = proto_redistnum(afi, type_str);
1818 if (type < 0) {
1819 vty_out(vty, "Unknown route type\n");
1820 return CMD_WARNING;
1821 }
1822 }
1823
1824 if (vrf_all) {
1825 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1826 if ((zvrf = vrf->info) == NULL
1827 || (zvrf->table[afi][SAFI_UNICAST] == NULL))
1828 continue;
1829
1830 if (table_all)
1831 do_show_ip_route_all(
1832 vty, zvrf, afi, !!fib, !!json, tag,
1833 prefix_str ? prefix : NULL,
1834 !!supernets_only, type,
1835 ospf_instance_id, !!ng, &ctx);
1836 else
1837 do_show_ip_route(
1838 vty, zvrf_name(zvrf), afi, SAFI_UNICAST,
1839 !!fib, !!json, tag,
1840 prefix_str ? prefix : NULL,
1841 !!supernets_only, type,
1842 ospf_instance_id, table, !!ng, &ctx);
1843 }
1844 } else {
1845 vrf_id_t vrf_id = VRF_DEFAULT;
1846
1847 if (vrf_name)
1848 VRF_GET_ID(vrf_id, vrf_name, !!json);
1849 vrf = vrf_lookup_by_id(vrf_id);
1850 if (!vrf)
1851 return CMD_SUCCESS;
1852
1853 zvrf = vrf->info;
1854 if (!zvrf)
1855 return CMD_SUCCESS;
1856
1857 if (table_all)
1858 do_show_ip_route_all(vty, zvrf, afi, !!fib, !!json, tag,
1859 prefix_str ? prefix : NULL,
1860 !!supernets_only, type,
1861 ospf_instance_id, !!ng, &ctx);
1862 else
1863 do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST,
1864 !!fib, !!json, tag,
1865 prefix_str ? prefix : NULL,
1866 !!supernets_only, type,
1867 ospf_instance_id, table, !!ng, &ctx);
1868 }
1869
1870 return CMD_SUCCESS;
1871 }
1872
1873 ALIAS_HIDDEN (show_route,
1874 show_ro_cmd,
1875 "show <ip$ipv4|ipv6$ipv6> ro",
1876 SHOW_STR
1877 IP_STR
1878 IPV6_STR
1879 "IP routing table\n");
1880
1881
1882 DEFPY (show_route_detail,
1883 show_route_detail_cmd,
1884 "show\
1885 <\
1886 ip$ipv4 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\
1887 <\
1888 A.B.C.D$address\
1889 |A.B.C.D/M$prefix\
1890 >\
1891 |ipv6$ipv6 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\
1892 <\
1893 X:X::X:X$address\
1894 |X:X::X:X/M$prefix\
1895 >\
1896 >\
1897 [json$json] [nexthop-group$ng]",
1898 SHOW_STR
1899 IP_STR
1900 "IP forwarding table\n"
1901 "IP routing table\n"
1902 VRF_FULL_CMD_HELP_STR
1903 "Network in the IP routing table to display\n"
1904 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1905 IP6_STR
1906 "IPv6 forwarding table\n"
1907 "IPv6 routing table\n"
1908 VRF_FULL_CMD_HELP_STR
1909 "IPv6 Address\n"
1910 "IPv6 prefix\n"
1911 JSON_STR
1912 "Nexthop Group Information\n")
1913 {
1914 afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
1915 struct route_table *table;
1916 struct prefix p;
1917 struct route_node *rn;
1918 bool use_fib = !!fib;
1919 rib_dest_t *dest;
1920 bool network_found = false;
1921 bool show_ng = !!ng;
1922
1923 if (address_str)
1924 prefix_str = address_str;
1925 if (str2prefix(prefix_str, &p) < 0) {
1926 vty_out(vty, "%% Malformed address\n");
1927 return CMD_WARNING;
1928 }
1929
1930 if (vrf_all) {
1931 struct vrf *vrf;
1932 struct zebra_vrf *zvrf;
1933
1934 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1935 if ((zvrf = vrf->info) == NULL
1936 || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL)
1937 continue;
1938
1939 rn = route_node_match(table, &p);
1940 if (!rn)
1941 continue;
1942 if (!address_str && rn->p.prefixlen != p.prefixlen) {
1943 route_unlock_node(rn);
1944 continue;
1945 }
1946
1947 dest = rib_dest_from_rnode(rn);
1948 if (use_fib && !dest->selected_fib) {
1949 route_unlock_node(rn);
1950 continue;
1951 }
1952
1953 network_found = true;
1954 if (json)
1955 vty_show_ip_route_detail_json(vty, rn, use_fib);
1956 else
1957 vty_show_ip_route_detail(vty, rn, 0, use_fib,
1958 show_ng);
1959
1960 route_unlock_node(rn);
1961 }
1962
1963 if (!network_found) {
1964 if (json)
1965 vty_out(vty, "{}\n");
1966 else {
1967 if (use_fib)
1968 vty_out(vty,
1969 "%% Network not in FIB\n");
1970 else
1971 vty_out(vty,
1972 "%% Network not in RIB\n");
1973 }
1974 return CMD_WARNING;
1975 }
1976 } else {
1977 vrf_id_t vrf_id = VRF_DEFAULT;
1978
1979 if (vrf_name)
1980 VRF_GET_ID(vrf_id, vrf_name, false);
1981
1982 table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
1983 if (!table)
1984 return CMD_SUCCESS;
1985
1986 rn = route_node_match(table, &p);
1987 if (rn)
1988 dest = rib_dest_from_rnode(rn);
1989
1990 if (!rn || (!address_str && rn->p.prefixlen != p.prefixlen) ||
1991 (use_fib && dest && !dest->selected_fib)) {
1992 if (json)
1993 vty_out(vty, "{}\n");
1994 else {
1995 if (use_fib)
1996 vty_out(vty,
1997 "%% Network not in FIB\n");
1998 else
1999 vty_out(vty,
2000 "%% Network not in table\n");
2001 }
2002 if (rn)
2003 route_unlock_node(rn);
2004 return CMD_WARNING;
2005 }
2006
2007 if (json)
2008 vty_show_ip_route_detail_json(vty, rn, use_fib);
2009 else
2010 vty_show_ip_route_detail(vty, rn, 0, use_fib, show_ng);
2011
2012 route_unlock_node(rn);
2013 }
2014
2015 return CMD_SUCCESS;
2016 }
2017
2018 DEFPY (show_route_summary,
2019 show_route_summary_cmd,
2020 "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] \
2021 summary [table (1-4294967295)$table_id] [prefix$prefix] [json]",
2022 SHOW_STR
2023 IP_STR
2024 IP6_STR
2025 "IP routing table\n"
2026 VRF_FULL_CMD_HELP_STR
2027 "Summary of all routes\n"
2028 "Table to display summary for\n"
2029 "The table number\n"
2030 "Prefix routes\n"
2031 JSON_STR)
2032 {
2033 afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
2034 struct route_table *table;
2035 bool uj = use_json(argc, argv);
2036
2037 if (vrf_all) {
2038 struct vrf *vrf;
2039 struct zebra_vrf *zvrf;
2040
2041 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
2042 if ((zvrf = vrf->info) == NULL)
2043 continue;
2044
2045 if (table_id == 0)
2046 table = zebra_vrf_table(afi, SAFI_UNICAST,
2047 zvrf->vrf->vrf_id);
2048 else
2049 table = zebra_vrf_lookup_table_with_table_id(
2050 afi, SAFI_UNICAST, zvrf->vrf->vrf_id,
2051 table_id);
2052
2053 if (!table)
2054 continue;
2055
2056 if (prefix)
2057 vty_show_ip_route_summary_prefix(vty, table,
2058 uj);
2059 else
2060 vty_show_ip_route_summary(vty, table, uj);
2061 }
2062 } else {
2063 vrf_id_t vrf_id = VRF_DEFAULT;
2064
2065 if (vrf_name)
2066 VRF_GET_ID(vrf_id, vrf_name, false);
2067
2068 if (table_id == 0)
2069 table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
2070 else
2071 table = zebra_vrf_lookup_table_with_table_id(
2072 afi, SAFI_UNICAST, vrf_id, table_id);
2073 if (!table)
2074 return CMD_SUCCESS;
2075
2076 if (prefix)
2077 vty_show_ip_route_summary_prefix(vty, table, uj);
2078 else
2079 vty_show_ip_route_summary(vty, table, uj);
2080 }
2081
2082 return CMD_SUCCESS;
2083 }
2084
2085 DEFUN_HIDDEN (show_route_zebra_dump,
2086 show_route_zebra_dump_cmd,
2087 "show <ip|ipv6> zebra route dump [vrf VRFNAME]",
2088 SHOW_STR
2089 IP_STR
2090 IP6_STR
2091 "Zebra daemon\n"
2092 "Routing table\n"
2093 "All information\n"
2094 VRF_CMD_HELP_STR)
2095 {
2096 afi_t afi = AFI_IP;
2097 struct route_table *table;
2098 const char *vrf_name = NULL;
2099 int idx = 0;
2100
2101 afi = strmatch(argv[1]->text, "ipv6") ? AFI_IP6 : AFI_IP;
2102
2103 if (argv_find(argv, argc, "vrf", &idx))
2104 vrf_name = argv[++idx]->arg;
2105
2106 if (!vrf_name) {
2107 struct vrf *vrf;
2108 struct zebra_vrf *zvrf;
2109
2110 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
2111 zvrf = vrf->info;
2112 if ((zvrf == NULL)
2113 || (zvrf->table[afi][SAFI_UNICAST] == NULL))
2114 continue;
2115
2116 table = zvrf->table[afi][SAFI_UNICAST];
2117 show_ip_route_dump_vty(vty, table);
2118 }
2119 } else {
2120 vrf_id_t vrf_id = VRF_DEFAULT;
2121
2122 VRF_GET_ID(vrf_id, vrf_name, true);
2123
2124 table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
2125 if (!table)
2126 return CMD_SUCCESS;
2127
2128 show_ip_route_dump_vty(vty, table);
2129 }
2130
2131 return CMD_SUCCESS;
2132 }
2133
2134 static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop,
2135 struct route_entry *re, unsigned int num)
2136 {
2137
2138 char buf[SRCDEST2STR_BUFFER];
2139
2140 vty_out(vty, " Nexthop %u:\n", num);
2141 vty_out(vty, " type: %u\n", nexthop->type);
2142 vty_out(vty, " flags: %u\n", nexthop->flags);
2143 switch (nexthop->type) {
2144 case NEXTHOP_TYPE_IPV4:
2145 case NEXTHOP_TYPE_IPV4_IFINDEX:
2146 vty_out(vty, " ip address: %s\n",
2147 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
2148 sizeof(buf)));
2149 vty_out(vty, " afi: ipv4\n");
2150
2151 if (nexthop->ifindex) {
2152 vty_out(vty, " interface index: %d\n",
2153 nexthop->ifindex);
2154 vty_out(vty, " interface name: %s\n",
2155 ifindex2ifname(nexthop->ifindex,
2156 nexthop->vrf_id));
2157 }
2158
2159 if (nexthop->src.ipv4.s_addr
2160 && (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
2161 sizeof(buf))))
2162 vty_out(vty, " source: %s\n", buf);
2163 break;
2164 case NEXTHOP_TYPE_IPV6:
2165 case NEXTHOP_TYPE_IPV6_IFINDEX:
2166 vty_out(vty, " ip: %s\n",
2167 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
2168 sizeof(buf)));
2169 vty_out(vty, " afi: ipv6\n");
2170
2171 if (nexthop->ifindex) {
2172 vty_out(vty, " interface index: %d\n",
2173 nexthop->ifindex);
2174 vty_out(vty, " interface name: %s\n",
2175 ifindex2ifname(nexthop->ifindex,
2176 nexthop->vrf_id));
2177 }
2178
2179 if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
2180 if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
2181 sizeof(buf)))
2182 vty_out(vty, " source: %s\n", buf);
2183 }
2184 break;
2185 case NEXTHOP_TYPE_IFINDEX:
2186 vty_out(vty,
2187 " Nexthop is an interface (directly connected).\n");
2188 vty_out(vty, " interface index: %d\n", nexthop->ifindex);
2189 vty_out(vty, " interface name: %s\n",
2190 ifindex2ifname(nexthop->ifindex, nexthop->vrf_id));
2191 break;
2192 case NEXTHOP_TYPE_BLACKHOLE:
2193 vty_out(vty, " Nexthop type is blackhole.\n");
2194
2195 switch (nexthop->bh_type) {
2196 case BLACKHOLE_REJECT:
2197 vty_out(vty, " Blackhole type: reject\n");
2198 break;
2199 case BLACKHOLE_ADMINPROHIB:
2200 vty_out(vty,
2201 " Blackhole type: admin-prohibited\n");
2202 break;
2203 case BLACKHOLE_NULL:
2204 vty_out(vty, " Blackhole type: NULL0\n");
2205 break;
2206 case BLACKHOLE_UNSPEC:
2207 break;
2208 }
2209 break;
2210 }
2211 }
2212
2213 static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table)
2214 {
2215 struct route_node *rn;
2216 struct route_entry *re;
2217 char buf[SRCDEST2STR_BUFFER];
2218 char time[20];
2219 time_t uptime;
2220 struct tm tm;
2221 struct timeval tv;
2222 struct nexthop *nexthop = NULL;
2223 int nexthop_num = 0;
2224
2225 vty_out(vty, "\nIPv4/IPv6 Routing table dump\n");
2226 vty_out(vty, "----------------------------\n");
2227
2228 for (rn = route_top(table); rn; rn = route_next(rn)) {
2229 RNODE_FOREACH_RE (rn, re) {
2230 vty_out(vty, "Route: %s\n",
2231 srcdest_rnode2str(rn, buf, sizeof(buf)));
2232 vty_out(vty, " protocol: %s\n",
2233 zebra_route_string(re->type));
2234 vty_out(vty, " instance: %u\n", re->instance);
2235 vty_out(vty, " VRF ID: %u\n", re->vrf_id);
2236 vty_out(vty, " VRF name: %s\n",
2237 vrf_id_to_name(re->vrf_id));
2238 vty_out(vty, " flags: %u\n", re->flags);
2239
2240 if (re->type != ZEBRA_ROUTE_CONNECT) {
2241 vty_out(vty, " distance: %u\n", re->distance);
2242 vty_out(vty, " metric: %u\n", re->metric);
2243 }
2244
2245 vty_out(vty, " tag: %u\n", re->tag);
2246
2247 uptime = monotime(&tv);
2248 uptime -= re->uptime;
2249 gmtime_r(&uptime, &tm);
2250
2251 if (uptime < ONE_DAY_SECOND)
2252 snprintf(time, sizeof(time), "%02d:%02d:%02d",
2253 tm.tm_hour, tm.tm_min, tm.tm_sec);
2254 else if (uptime < ONE_WEEK_SECOND)
2255 snprintf(time, sizeof(time), "%dd%02dh%02dm",
2256 tm.tm_yday, tm.tm_hour, tm.tm_min);
2257 else
2258 snprintf(time, sizeof(time), "%02dw%dd%02dh",
2259 tm.tm_yday / 7,
2260 tm.tm_yday - ((tm.tm_yday / 7) * 7),
2261 tm.tm_hour);
2262
2263 vty_out(vty, " status: %u\n", re->status);
2264 vty_out(vty, " nexthop_num: %u\n",
2265 nexthop_group_nexthop_num(&(re->nhe->nhg)));
2266 vty_out(vty, " nexthop_active_num: %u\n",
2267 nexthop_group_active_nexthop_num(
2268 &(re->nhe->nhg)));
2269 vty_out(vty, " table: %u\n", re->table);
2270 vty_out(vty, " uptime: %s\n", time);
2271
2272 for (ALL_NEXTHOPS_PTR(&(re->nhe->nhg), nexthop)) {
2273 nexthop_num++;
2274 show_ip_route_nht_dump(vty, nexthop, re,
2275 nexthop_num);
2276 }
2277
2278 nexthop_num = 0;
2279 vty_out(vty, "\n");
2280 }
2281 }
2282 }
2283
2284 static void vty_show_ip_route_summary(struct vty *vty,
2285 struct route_table *table, bool use_json)
2286 {
2287 struct route_node *rn;
2288 struct route_entry *re;
2289 #define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX
2290 #define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1)
2291 uint32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1];
2292 uint32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1];
2293 uint32_t offload_cnt[ZEBRA_ROUTE_TOTAL + 1];
2294 uint32_t trap_cnt[ZEBRA_ROUTE_TOTAL + 1];
2295 uint32_t i;
2296 uint32_t is_ibgp;
2297 json_object *json_route_summary = NULL;
2298 json_object *json_route_routes = NULL;
2299
2300 memset(&rib_cnt, 0, sizeof(rib_cnt));
2301 memset(&fib_cnt, 0, sizeof(fib_cnt));
2302 memset(&offload_cnt, 0, sizeof(offload_cnt));
2303 memset(&trap_cnt, 0, sizeof(trap_cnt));
2304
2305 if (use_json) {
2306 json_route_summary = json_object_new_object();
2307 json_route_routes = json_object_new_array();
2308 json_object_object_add(json_route_summary, "routes",
2309 json_route_routes);
2310 }
2311
2312 for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
2313 RNODE_FOREACH_RE (rn, re) {
2314 is_ibgp = (re->type == ZEBRA_ROUTE_BGP
2315 && CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP));
2316
2317 rib_cnt[ZEBRA_ROUTE_TOTAL]++;
2318 if (is_ibgp)
2319 rib_cnt[ZEBRA_ROUTE_IBGP]++;
2320 else
2321 rib_cnt[re->type]++;
2322
2323 if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
2324 fib_cnt[ZEBRA_ROUTE_TOTAL]++;
2325
2326 if (is_ibgp)
2327 fib_cnt[ZEBRA_ROUTE_IBGP]++;
2328 else
2329 fib_cnt[re->type]++;
2330 }
2331
2332 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED)) {
2333 if (is_ibgp)
2334 trap_cnt[ZEBRA_ROUTE_IBGP]++;
2335 else
2336 trap_cnt[re->type]++;
2337 }
2338
2339 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED)) {
2340 if (is_ibgp)
2341 offload_cnt[ZEBRA_ROUTE_IBGP]++;
2342 else
2343 offload_cnt[re->type]++;
2344 }
2345 }
2346
2347 if (!use_json)
2348 vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
2349 "Routes", "FIB",
2350 zvrf_name(((struct rib_table_info *)
2351 route_table_get_info(table))
2352 ->zvrf));
2353
2354 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2355 if ((rib_cnt[i] > 0) || (i == ZEBRA_ROUTE_BGP
2356 && rib_cnt[ZEBRA_ROUTE_IBGP] > 0)) {
2357 if (i == ZEBRA_ROUTE_BGP) {
2358 if (use_json) {
2359 json_object *json_route_ebgp =
2360 json_object_new_object();
2361
2362 json_object_int_add(
2363 json_route_ebgp, "fib",
2364 fib_cnt[ZEBRA_ROUTE_BGP]);
2365 json_object_int_add(
2366 json_route_ebgp, "rib",
2367 rib_cnt[ZEBRA_ROUTE_BGP]);
2368 json_object_int_add(
2369 json_route_ebgp, "fibOffLoaded",
2370 offload_cnt[ZEBRA_ROUTE_BGP]);
2371 json_object_int_add(
2372 json_route_ebgp, "fibTrapped",
2373 trap_cnt[ZEBRA_ROUTE_BGP]);
2374
2375 json_object_string_add(json_route_ebgp,
2376 "type", "ebgp");
2377 json_object_array_add(json_route_routes,
2378 json_route_ebgp);
2379
2380 json_object *json_route_ibgp =
2381 json_object_new_object();
2382
2383 json_object_int_add(
2384 json_route_ibgp, "fib",
2385 fib_cnt[ZEBRA_ROUTE_IBGP]);
2386 json_object_int_add(
2387 json_route_ibgp, "rib",
2388 rib_cnt[ZEBRA_ROUTE_IBGP]);
2389 json_object_int_add(
2390 json_route_ibgp, "fibOffLoaded",
2391 offload_cnt[ZEBRA_ROUTE_IBGP]);
2392 json_object_int_add(
2393 json_route_ibgp, "fibTrapped",
2394 trap_cnt[ZEBRA_ROUTE_IBGP]);
2395 json_object_string_add(json_route_ibgp,
2396 "type", "ibgp");
2397 json_object_array_add(json_route_routes,
2398 json_route_ibgp);
2399 } else {
2400 vty_out(vty, "%-20s %-20d %-20d \n",
2401 "ebgp",
2402 rib_cnt[ZEBRA_ROUTE_BGP],
2403 fib_cnt[ZEBRA_ROUTE_BGP]);
2404 vty_out(vty, "%-20s %-20d %-20d \n",
2405 "ibgp",
2406 rib_cnt[ZEBRA_ROUTE_IBGP],
2407 fib_cnt[ZEBRA_ROUTE_IBGP]);
2408 }
2409 } else {
2410 if (use_json) {
2411 json_object *json_route_type =
2412 json_object_new_object();
2413
2414 json_object_int_add(json_route_type,
2415 "fib", fib_cnt[i]);
2416 json_object_int_add(json_route_type,
2417 "rib", rib_cnt[i]);
2418
2419 json_object_int_add(json_route_type,
2420 "fibOffLoaded",
2421 offload_cnt[i]);
2422 json_object_int_add(json_route_type,
2423 "fibTrapped",
2424 trap_cnt[i]);
2425 json_object_string_add(
2426 json_route_type, "type",
2427 zebra_route_string(i));
2428 json_object_array_add(json_route_routes,
2429 json_route_type);
2430 } else
2431 vty_out(vty, "%-20s %-20d %-20d \n",
2432 zebra_route_string(i),
2433 rib_cnt[i], fib_cnt[i]);
2434 }
2435 }
2436 }
2437
2438 if (use_json) {
2439 json_object_int_add(json_route_summary, "routesTotal",
2440 rib_cnt[ZEBRA_ROUTE_TOTAL]);
2441 json_object_int_add(json_route_summary, "routesTotalFib",
2442 fib_cnt[ZEBRA_ROUTE_TOTAL]);
2443
2444 vty_json(vty, json_route_summary);
2445 } else {
2446 vty_out(vty, "------\n");
2447 vty_out(vty, "%-20s %-20d %-20d \n", "Totals",
2448 rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL]);
2449 vty_out(vty, "\n");
2450 }
2451 }
2452
2453 /*
2454 * Implementation of the ip route summary prefix command.
2455 *
2456 * This command prints the primary prefixes that have been installed by various
2457 * protocols on the box.
2458 *
2459 */
2460 static void vty_show_ip_route_summary_prefix(struct vty *vty,
2461 struct route_table *table,
2462 bool use_json)
2463 {
2464 struct route_node *rn;
2465 struct route_entry *re;
2466 struct nexthop *nexthop;
2467 #define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX
2468 #define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1)
2469 uint32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1];
2470 uint32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1];
2471 uint32_t i;
2472 int cnt;
2473 json_object *json_route_summary = NULL;
2474 json_object *json_route_routes = NULL;
2475
2476 memset(&rib_cnt, 0, sizeof(rib_cnt));
2477 memset(&fib_cnt, 0, sizeof(fib_cnt));
2478
2479 if (use_json) {
2480 json_route_summary = json_object_new_object();
2481 json_route_routes = json_object_new_array();
2482 json_object_object_add(json_route_summary, "prefixRoutes",
2483 json_route_routes);
2484 }
2485
2486 for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
2487 RNODE_FOREACH_RE (rn, re) {
2488
2489 /*
2490 * In case of ECMP, count only once.
2491 */
2492 cnt = 0;
2493 if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
2494 fib_cnt[ZEBRA_ROUTE_TOTAL]++;
2495 fib_cnt[re->type]++;
2496 }
2497 for (nexthop = re->nhe->nhg.nexthop; (!cnt && nexthop);
2498 nexthop = nexthop->next) {
2499 cnt++;
2500 rib_cnt[ZEBRA_ROUTE_TOTAL]++;
2501 rib_cnt[re->type]++;
2502 if (re->type == ZEBRA_ROUTE_BGP
2503 && CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) {
2504 rib_cnt[ZEBRA_ROUTE_IBGP]++;
2505 if (CHECK_FLAG(re->status,
2506 ROUTE_ENTRY_INSTALLED))
2507 fib_cnt[ZEBRA_ROUTE_IBGP]++;
2508 }
2509 }
2510 }
2511
2512 if (!use_json)
2513 vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
2514 "Prefix Routes", "FIB",
2515 zvrf_name(((struct rib_table_info *)
2516 route_table_get_info(table))
2517 ->zvrf));
2518
2519 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
2520 if (rib_cnt[i] > 0) {
2521 if (i == ZEBRA_ROUTE_BGP) {
2522 if (use_json) {
2523 json_object *json_route_ebgp =
2524 json_object_new_object();
2525
2526 json_object_int_add(
2527 json_route_ebgp, "fib",
2528 fib_cnt[ZEBRA_ROUTE_BGP]
2529 - fib_cnt[ZEBRA_ROUTE_IBGP]);
2530 json_object_int_add(
2531 json_route_ebgp, "rib",
2532 rib_cnt[ZEBRA_ROUTE_BGP]
2533 - rib_cnt[ZEBRA_ROUTE_IBGP]);
2534 json_object_string_add(json_route_ebgp,
2535 "type", "ebgp");
2536 json_object_array_add(json_route_routes,
2537 json_route_ebgp);
2538
2539 json_object *json_route_ibgp =
2540 json_object_new_object();
2541
2542 json_object_int_add(
2543 json_route_ibgp, "fib",
2544 fib_cnt[ZEBRA_ROUTE_IBGP]);
2545 json_object_int_add(
2546 json_route_ibgp, "rib",
2547 rib_cnt[ZEBRA_ROUTE_IBGP]);
2548 json_object_string_add(json_route_ibgp,
2549 "type", "ibgp");
2550 json_object_array_add(json_route_routes,
2551 json_route_ibgp);
2552 } else {
2553 vty_out(vty, "%-20s %-20d %-20d \n",
2554 "ebgp",
2555 rib_cnt[ZEBRA_ROUTE_BGP]
2556 - rib_cnt[ZEBRA_ROUTE_IBGP],
2557 fib_cnt[ZEBRA_ROUTE_BGP]
2558 - fib_cnt[ZEBRA_ROUTE_IBGP]);
2559 vty_out(vty, "%-20s %-20d %-20d \n",
2560 "ibgp",
2561 rib_cnt[ZEBRA_ROUTE_IBGP],
2562 fib_cnt[ZEBRA_ROUTE_IBGP]);
2563 }
2564 } else {
2565 if (use_json) {
2566 json_object *json_route_type =
2567 json_object_new_object();
2568
2569 json_object_int_add(json_route_type,
2570 "fib", fib_cnt[i]);
2571 json_object_int_add(json_route_type,
2572 "rib", rib_cnt[i]);
2573 json_object_string_add(
2574 json_route_type, "type",
2575 zebra_route_string(i));
2576 json_object_array_add(json_route_routes,
2577 json_route_type);
2578 } else
2579 vty_out(vty, "%-20s %-20d %-20d \n",
2580 zebra_route_string(i),
2581 rib_cnt[i], fib_cnt[i]);
2582 }
2583 }
2584 }
2585
2586 if (use_json) {
2587 json_object_int_add(json_route_summary, "prefixRoutesTotal",
2588 rib_cnt[ZEBRA_ROUTE_TOTAL]);
2589 json_object_int_add(json_route_summary, "prefixRoutesTotalFib",
2590 fib_cnt[ZEBRA_ROUTE_TOTAL]);
2591
2592 vty_json(vty, json_route_summary);
2593 } else {
2594 vty_out(vty, "------\n");
2595 vty_out(vty, "%-20s %-20d %-20d \n", "Totals",
2596 rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL]);
2597 vty_out(vty, "\n");
2598 }
2599 }
2600
2601 DEFUN (allow_external_route_update,
2602 allow_external_route_update_cmd,
2603 "allow-external-route-update",
2604 "Allow FRR routes to be overwritten by external processes\n")
2605 {
2606 zrouter.allow_delete = true;
2607
2608 return CMD_SUCCESS;
2609 }
2610
2611 DEFUN (no_allow_external_route_update,
2612 no_allow_external_route_update_cmd,
2613 "no allow-external-route-update",
2614 NO_STR
2615 "Allow FRR routes to be overwritten by external processes\n")
2616 {
2617 zrouter.allow_delete = false;
2618
2619 return CMD_SUCCESS;
2620 }
2621
2622 /* show vrf */
2623 DEFUN (show_vrf,
2624 show_vrf_cmd,
2625 "show vrf",
2626 SHOW_STR
2627 "VRF\n")
2628 {
2629 struct vrf *vrf;
2630 struct zebra_vrf *zvrf;
2631
2632 if (vrf_is_backend_netns())
2633 vty_out(vty, "netns-based vrfs\n");
2634
2635 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
2636 if (!(zvrf = vrf->info))
2637 continue;
2638 if (zvrf_id(zvrf) == VRF_DEFAULT)
2639 continue;
2640
2641 vty_out(vty, "vrf %s ", zvrf_name(zvrf));
2642 if (zvrf_id(zvrf) == VRF_UNKNOWN || !zvrf_is_active(zvrf))
2643 vty_out(vty, "inactive");
2644 else if (zvrf_ns_name(zvrf))
2645 vty_out(vty, "id %u netns %s", zvrf_id(zvrf),
2646 zvrf_ns_name(zvrf));
2647 else
2648 vty_out(vty, "id %u table %u", zvrf_id(zvrf),
2649 zvrf->table_id);
2650 if (vrf_is_user_cfged(vrf))
2651 vty_out(vty, " (configured)");
2652 vty_out(vty, "\n");
2653 }
2654
2655 return CMD_SUCCESS;
2656 }
2657
2658 DEFPY (evpn_mh_mac_holdtime,
2659 evpn_mh_mac_holdtime_cmd,
2660 "[no$no] evpn mh mac-holdtime (0-86400)$duration",
2661 NO_STR
2662 "EVPN\n"
2663 "Multihoming\n"
2664 "MAC hold time\n"
2665 "Duration in seconds\n")
2666 {
2667 return zebra_evpn_mh_mac_holdtime_update(vty, duration,
2668 no ? true : false);
2669 }
2670
2671 DEFPY (evpn_mh_neigh_holdtime,
2672 evpn_mh_neigh_holdtime_cmd,
2673 "[no$no] evpn mh neigh-holdtime (0-86400)$duration",
2674 NO_STR
2675 "EVPN\n"
2676 "Multihoming\n"
2677 "Neighbor entry hold time\n"
2678 "Duration in seconds\n")
2679 {
2680
2681 return zebra_evpn_mh_neigh_holdtime_update(vty, duration,
2682 no ? true : false);
2683 }
2684
2685 DEFPY (evpn_mh_startup_delay,
2686 evpn_mh_startup_delay_cmd,
2687 "[no] evpn mh startup-delay(0-3600)$duration",
2688 NO_STR
2689 "EVPN\n"
2690 "Multihoming\n"
2691 "Startup delay\n"
2692 "duration in seconds\n")
2693 {
2694
2695 return zebra_evpn_mh_startup_delay_update(vty, duration,
2696 no ? true : false);
2697 }
2698
2699 DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd,
2700 "[no$no] evpn mh redirect-off",
2701 NO_STR
2702 "EVPN\n"
2703 "Multihoming\n"
2704 "ES bond redirect for fast-failover off\n")
2705 {
2706 bool redirect_off;
2707
2708 redirect_off = no ? false : true;
2709
2710 return zebra_evpn_mh_redirect_off(vty, redirect_off);
2711 }
2712
2713 DEFUN (default_vrf_vni_mapping,
2714 default_vrf_vni_mapping_cmd,
2715 "vni " CMD_VNI_RANGE "[prefix-routes-only]",
2716 "VNI corresponding to the DEFAULT VRF\n"
2717 "VNI-ID\n"
2718 "Prefix routes only \n")
2719 {
2720 char xpath[XPATH_MAXLEN];
2721 struct zebra_vrf *zvrf = NULL;
2722 int filter = 0;
2723
2724 zvrf = vrf_info_lookup(VRF_DEFAULT);
2725 if (!zvrf)
2726 return CMD_WARNING;
2727
2728 if (argc == 3)
2729 filter = 1;
2730
2731 snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
2732 VRF_DEFAULT_NAME);
2733 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2734
2735 snprintf(xpath, sizeof(xpath),
2736 FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
2737 VRF_DEFAULT_NAME);
2738 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg);
2739
2740 if (filter) {
2741 snprintf(xpath, sizeof(xpath),
2742 FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
2743 VRF_DEFAULT_NAME);
2744 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
2745 }
2746
2747 return nb_cli_apply_changes(vty, NULL);
2748 }
2749
2750 DEFUN (no_default_vrf_vni_mapping,
2751 no_default_vrf_vni_mapping_cmd,
2752 "no vni " CMD_VNI_RANGE "[prefix-routes-only]",
2753 NO_STR
2754 "VNI corresponding to DEFAULT VRF\n"
2755 "VNI-ID\n"
2756 "Prefix routes only \n")
2757 {
2758 char xpath[XPATH_MAXLEN];
2759 int filter = 0;
2760 vni_t vni = strtoul(argv[2]->arg, NULL, 10);
2761 struct zebra_vrf *zvrf = NULL;
2762
2763 zvrf = vrf_info_lookup(VRF_DEFAULT);
2764 if (!zvrf)
2765 return CMD_WARNING;
2766
2767 if (argc == 4)
2768 filter = 1;
2769
2770 if (zvrf->l3vni != vni) {
2771 vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni,
2772 zvrf->vrf->name);
2773 return CMD_WARNING;
2774 }
2775
2776 snprintf(xpath, sizeof(xpath),
2777 FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
2778 VRF_DEFAULT_NAME);
2779 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg);
2780
2781 if (filter) {
2782 snprintf(xpath, sizeof(xpath),
2783 FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
2784 VRF_DEFAULT_NAME);
2785 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true");
2786 }
2787
2788 snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
2789 VRF_DEFAULT_NAME);
2790 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2791
2792 return nb_cli_apply_changes(vty, NULL);
2793 }
2794
2795 DEFUN (vrf_vni_mapping,
2796 vrf_vni_mapping_cmd,
2797 "vni " CMD_VNI_RANGE "[prefix-routes-only]",
2798 "VNI corresponding to tenant VRF\n"
2799 "VNI-ID\n"
2800 "prefix-routes-only\n")
2801 {
2802 int filter = 0;
2803
2804 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
2805
2806 assert(vrf);
2807 assert(zvrf);
2808
2809 if (argc == 3)
2810 filter = 1;
2811
2812 nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_CREATE, NULL);
2813 nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY,
2814 argv[1]->arg);
2815
2816 if (filter)
2817 nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only",
2818 NB_OP_MODIFY, "true");
2819
2820 return nb_cli_apply_changes(vty, NULL);
2821 }
2822
2823 DEFUN (no_vrf_vni_mapping,
2824 no_vrf_vni_mapping_cmd,
2825 "no vni " CMD_VNI_RANGE "[prefix-routes-only]",
2826 NO_STR
2827 "VNI corresponding to tenant VRF\n"
2828 "VNI-ID\n"
2829 "prefix-routes-only\n")
2830 {
2831 int filter = 0;
2832
2833 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
2834 vni_t vni = strtoul(argv[2]->arg, NULL, 10);
2835
2836 assert(vrf);
2837 assert(zvrf);
2838
2839 if (argc == 4)
2840 filter = 1;
2841
2842 if (zvrf->l3vni != vni) {
2843 vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni,
2844 zvrf->vrf->name);
2845 return CMD_WARNING;
2846 }
2847
2848 nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY,
2849 argv[2]->arg);
2850
2851 if (filter)
2852 nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only",
2853 NB_OP_DESTROY, "true");
2854
2855 nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL);
2856
2857 return nb_cli_apply_changes(vty, NULL);
2858 }
2859
2860 /* show vrf */
2861 DEFPY (show_vrf_vni,
2862 show_vrf_vni_cmd,
2863 "show vrf [<NAME$vrf_name|all$vrf_all>] vni [json]",
2864 SHOW_STR
2865 VRF_FULL_CMD_HELP_STR
2866 "VNI\n"
2867 JSON_STR)
2868 {
2869 struct vrf *vrf;
2870 struct zebra_vrf *zvrf;
2871 json_object *json = NULL;
2872 json_object *json_vrfs = NULL;
2873 bool uj = use_json(argc, argv);
2874 bool use_vrf = false;
2875
2876 if (uj)
2877 json = json_object_new_object();
2878
2879 /* show vrf vni used to display across all vrfs
2880 * This is enhanced to support only for specific
2881 * vrf based output.
2882 */
2883 if (vrf_all || !vrf_name) {
2884 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
2885 zvrf = vrf->info;
2886 if (!zvrf)
2887 continue;
2888
2889 use_vrf = true;
2890 break;
2891 }
2892 if (use_vrf) {
2893 if (!uj)
2894 vty_out(vty,
2895 "%-37s %-10s %-20s %-20s %-5s %-18s\n",
2896 "VRF", "VNI", "VxLAN IF", "L3-SVI",
2897 "State", "Rmac");
2898 else
2899 json_vrfs = json_object_new_array();
2900 } else {
2901 if (uj)
2902 vty_json(vty, json);
2903 else
2904 vty_out(vty, "%% VRF does not exist\n");
2905
2906 return CMD_WARNING;
2907 }
2908 }
2909
2910 if (use_vrf) {
2911 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
2912 zvrf = vrf->info;
2913 if (!zvrf)
2914 continue;
2915
2916 zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
2917 }
2918 } else if (vrf_name) {
2919 zvrf = zebra_vrf_lookup_by_name(vrf_name);
2920 if (!zvrf) {
2921 if (uj)
2922 vty_json(vty, json);
2923 else
2924 vty_out(vty,
2925 "%% VRF '%s' specified does not exist\n",
2926 vrf_name);
2927
2928 return CMD_WARNING;
2929 }
2930
2931 if (!uj)
2932 vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n",
2933 "VRF", "VNI", "VxLAN IF", "L3-SVI", "State",
2934 "Rmac");
2935 else
2936 json_vrfs = json_object_new_array();
2937
2938 zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
2939 }
2940
2941 if (uj) {
2942 json_object_object_add(json, "vrfs", json_vrfs);
2943 vty_json(vty, json);
2944 }
2945
2946 return CMD_SUCCESS;
2947 }
2948
2949 DEFUN (show_evpn_global,
2950 show_evpn_global_cmd,
2951 "show evpn [json]",
2952 SHOW_STR
2953 "EVPN\n"
2954 JSON_STR)
2955 {
2956 bool uj = use_json(argc, argv);
2957
2958 zebra_vxlan_print_evpn(vty, uj);
2959 return CMD_SUCCESS;
2960 }
2961
2962 DEFPY(show_evpn_neigh, show_neigh_cmd, "show ip neigh",
2963 SHOW_STR IP_STR "neighbors\n")
2964
2965 {
2966 zebra_neigh_show(vty);
2967
2968 return CMD_SUCCESS;
2969 }
2970
2971 DEFPY(show_evpn_l2_nh,
2972 show_evpn_l2_nh_cmd,
2973 "show evpn l2-nh [json$json]",
2974 SHOW_STR
2975 "EVPN\n"
2976 "Layer2 nexthops\n"
2977 JSON_STR)
2978 {
2979 bool uj = !!json;
2980
2981 zebra_evpn_l2_nh_show(vty, uj);
2982
2983 return CMD_SUCCESS;
2984 }
2985
2986 DEFPY(show_evpn_es,
2987 show_evpn_es_cmd,
2988 "show evpn es [NAME$esi_str|detail$detail] [json$json]",
2989 SHOW_STR
2990 "EVPN\n"
2991 "Ethernet Segment\n"
2992 "ES ID\n"
2993 "Detailed information\n"
2994 JSON_STR)
2995 {
2996 esi_t esi;
2997 bool uj = !!json;
2998
2999 if (esi_str) {
3000 if (!str_to_esi(esi_str, &esi)) {
3001 vty_out(vty, "%% Malformed ESI\n");
3002 return CMD_WARNING;
3003 }
3004 zebra_evpn_es_show_esi(vty, uj, &esi);
3005 } else {
3006 if (detail)
3007 zebra_evpn_es_show_detail(vty, uj);
3008 else
3009 zebra_evpn_es_show(vty, uj);
3010 }
3011
3012 return CMD_SUCCESS;
3013 }
3014
3015 DEFPY(show_evpn_es_evi,
3016 show_evpn_es_evi_cmd,
3017 "show evpn es-evi [vni (1-16777215)$vni] [detail$detail] [json$json]",
3018 SHOW_STR
3019 "EVPN\n"
3020 "Ethernet Segment per EVI\n"
3021 "VxLAN Network Identifier\n"
3022 "VNI\n"
3023 "Detailed information\n"
3024 JSON_STR)
3025 {
3026 bool uj = !!json;
3027 bool ud = !!detail;
3028
3029 if (vni)
3030 zebra_evpn_es_evi_show_vni(vty, uj, vni, ud);
3031 else
3032 zebra_evpn_es_evi_show(vty, uj, ud);
3033
3034 return CMD_SUCCESS;
3035 }
3036
3037 DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd,
3038 "show evpn access-vlan [IFNAME$if_name (1-4094)$vid | detail$detail] [json$json]",
3039 SHOW_STR
3040 "EVPN\n"
3041 "Access VLANs\n"
3042 "Interface Name\n"
3043 "VLAN ID\n"
3044 "Detailed information\n" JSON_STR)
3045 {
3046 bool uj = !!json;
3047
3048 if (if_name && vid) {
3049 bool found = false;
3050 struct vrf *vrf;
3051 struct interface *ifp;
3052
3053 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
3054 if (if_name) {
3055 ifp = if_lookup_by_name(if_name, vrf->vrf_id);
3056 if (ifp) {
3057 zebra_evpn_acc_vl_show_vid(vty, uj, vid,
3058 ifp);
3059 found = true;
3060 break;
3061 }
3062 }
3063 }
3064 if (!found) {
3065 vty_out(vty, "%% Can't find interface %s\n", if_name);
3066 return CMD_WARNING;
3067 }
3068 } else {
3069 if (detail)
3070 zebra_evpn_acc_vl_show_detail(vty, uj);
3071 else
3072 zebra_evpn_acc_vl_show(vty, uj);
3073 }
3074
3075 return CMD_SUCCESS;
3076 }
3077
3078 DEFUN (show_evpn_vni,
3079 show_evpn_vni_cmd,
3080 "show evpn vni [json]",
3081 SHOW_STR
3082 "EVPN\n"
3083 "VxLAN Network Identifier\n"
3084 JSON_STR)
3085 {
3086 struct zebra_vrf *zvrf;
3087 bool uj = use_json(argc, argv);
3088
3089 zvrf = zebra_vrf_get_evpn();
3090 zebra_vxlan_print_vnis(vty, zvrf, uj);
3091 return CMD_SUCCESS;
3092 }
3093
3094 DEFUN (show_evpn_vni_detail, show_evpn_vni_detail_cmd,
3095 "show evpn vni detail [json]",
3096 SHOW_STR
3097 "EVPN\n"
3098 "VxLAN Network Identifier\n"
3099 "Detailed Information On Each VNI\n"
3100 JSON_STR)
3101 {
3102 struct zebra_vrf *zvrf;
3103 bool uj = use_json(argc, argv);
3104
3105 zvrf = zebra_vrf_get_evpn();
3106 zebra_vxlan_print_vnis_detail(vty, zvrf, uj);
3107 return CMD_SUCCESS;
3108 }
3109
3110 DEFUN (show_evpn_vni_vni,
3111 show_evpn_vni_vni_cmd,
3112 "show evpn vni " CMD_VNI_RANGE "[json]",
3113 SHOW_STR
3114 "EVPN\n"
3115 "VxLAN Network Identifier\n"
3116 "VNI number\n"
3117 JSON_STR)
3118 {
3119 struct zebra_vrf *zvrf;
3120 vni_t vni;
3121 bool uj = use_json(argc, argv);
3122
3123 vni = strtoul(argv[3]->arg, NULL, 10);
3124 zvrf = zebra_vrf_get_evpn();
3125 zebra_vxlan_print_vni(vty, zvrf, vni, uj, NULL);
3126 return CMD_SUCCESS;
3127 }
3128
3129 DEFUN (show_evpn_rmac_vni_mac,
3130 show_evpn_rmac_vni_mac_cmd,
3131 "show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]",
3132 SHOW_STR
3133 "EVPN\n"
3134 "RMAC\n"
3135 "L3 VNI\n"
3136 "VNI number\n"
3137 "MAC\n"
3138 "mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n"
3139 JSON_STR)
3140 {
3141 vni_t l3vni = 0;
3142 struct ethaddr mac;
3143 bool uj = use_json(argc, argv);
3144
3145 l3vni = strtoul(argv[4]->arg, NULL, 10);
3146 if (!prefix_str2mac(argv[6]->arg, &mac)) {
3147 vty_out(vty, "%% Malformed MAC address\n");
3148 return CMD_WARNING;
3149 }
3150 zebra_vxlan_print_specific_rmac_l3vni(vty, l3vni, &mac, uj);
3151 return CMD_SUCCESS;
3152 }
3153
3154 DEFUN (show_evpn_rmac_vni,
3155 show_evpn_rmac_vni_cmd,
3156 "show evpn rmac vni " CMD_VNI_RANGE "[json]",
3157 SHOW_STR
3158 "EVPN\n"
3159 "RMAC\n"
3160 "L3 VNI\n"
3161 "VNI number\n"
3162 JSON_STR)
3163 {
3164 vni_t l3vni = 0;
3165 bool uj = use_json(argc, argv);
3166
3167 l3vni = strtoul(argv[4]->arg, NULL, 10);
3168 zebra_vxlan_print_rmacs_l3vni(vty, l3vni, uj);
3169
3170 return CMD_SUCCESS;
3171 }
3172
3173 DEFUN (show_evpn_rmac_vni_all,
3174 show_evpn_rmac_vni_all_cmd,
3175 "show evpn rmac vni all [json]",
3176 SHOW_STR
3177 "EVPN\n"
3178 "RMAC addresses\n"
3179 "L3 VNI\n"
3180 "All VNIs\n"
3181 JSON_STR)
3182 {
3183 bool uj = use_json(argc, argv);
3184
3185 zebra_vxlan_print_rmacs_all_l3vni(vty, uj);
3186
3187 return CMD_SUCCESS;
3188 }
3189
3190 DEFUN (show_evpn_nh_vni_ip,
3191 show_evpn_nh_vni_ip_cmd,
3192 "show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]",
3193 SHOW_STR
3194 "EVPN\n"
3195 "Remote Vteps\n"
3196 "L3 VNI\n"
3197 "VNI number\n"
3198 "Ip address\n"
3199 "Host address (ipv4 or ipv6)\n"
3200 JSON_STR)
3201 {
3202 vni_t l3vni;
3203 struct ipaddr ip;
3204 bool uj = use_json(argc, argv);
3205
3206 l3vni = strtoul(argv[4]->arg, NULL, 10);
3207 if (str2ipaddr(argv[6]->arg, &ip) != 0) {
3208 if (!uj)
3209 vty_out(vty, "%% Malformed Neighbor address\n");
3210 return CMD_WARNING;
3211 }
3212 zebra_vxlan_print_specific_nh_l3vni(vty, l3vni, &ip, uj);
3213
3214 return CMD_SUCCESS;
3215 }
3216
3217 DEFUN_HIDDEN (show_evpn_nh_svd_ip,
3218 show_evpn_nh_svd_ip_cmd,
3219 "show evpn next-hops svd ip WORD [json]",
3220 SHOW_STR
3221 "EVPN\n"
3222 "Remote Vteps\n"
3223 "Single Vxlan Device\n"
3224 "Ip address\n"
3225 "Host address (ipv4 or ipv6)\n"
3226 JSON_STR)
3227 {
3228 struct ipaddr ip;
3229 bool uj = use_json(argc, argv);
3230
3231 if (str2ipaddr(argv[5]->arg, &ip) != 0) {
3232 if (!uj)
3233 vty_out(vty, "%% Malformed Neighbor address\n");
3234 return CMD_WARNING;
3235 }
3236 zebra_vxlan_print_specific_nh_l3vni(vty, 0, &ip, uj);
3237
3238 return CMD_SUCCESS;
3239 }
3240
3241 DEFUN (show_evpn_nh_vni,
3242 show_evpn_nh_vni_cmd,
3243 "show evpn next-hops vni " CMD_VNI_RANGE "[json]",
3244 SHOW_STR
3245 "EVPN\n"
3246 "Remote Vteps\n"
3247 "L3 VNI\n"
3248 "VNI number\n"
3249 JSON_STR)
3250 {
3251 vni_t l3vni;
3252 bool uj = use_json(argc, argv);
3253
3254 l3vni = strtoul(argv[4]->arg, NULL, 10);
3255 zebra_vxlan_print_nh_l3vni(vty, l3vni, uj);
3256
3257 return CMD_SUCCESS;
3258 }
3259
3260 DEFUN_HIDDEN (show_evpn_nh_svd,
3261 show_evpn_nh_svd_cmd,
3262 "show evpn next-hops svd [json]",
3263 SHOW_STR
3264 "EVPN\n"
3265 "Remote VTEPs\n"
3266 "Single Vxlan Device\n"
3267 JSON_STR)
3268 {
3269 bool uj = use_json(argc, argv);
3270
3271 zebra_vxlan_print_nh_svd(vty, uj);
3272
3273 return CMD_SUCCESS;
3274 }
3275
3276 DEFUN (show_evpn_nh_vni_all,
3277 show_evpn_nh_vni_all_cmd,
3278 "show evpn next-hops vni all [json]",
3279 SHOW_STR
3280 "EVPN\n"
3281 "Remote VTEPs\n"
3282 "L3 VNI\n"
3283 "All VNIs\n"
3284 JSON_STR)
3285 {
3286 bool uj = use_json(argc, argv);
3287
3288 zebra_vxlan_print_nh_all_l3vni(vty, uj);
3289
3290 return CMD_SUCCESS;
3291 }
3292
3293 DEFUN (show_evpn_mac_vni,
3294 show_evpn_mac_vni_cmd,
3295 "show evpn mac vni " CMD_VNI_RANGE "[json]",
3296 SHOW_STR
3297 "EVPN\n"
3298 "MAC addresses\n"
3299 "VxLAN Network Identifier\n"
3300 "VNI number\n"
3301 JSON_STR)
3302 {
3303 struct zebra_vrf *zvrf;
3304 vni_t vni;
3305 bool uj = use_json(argc, argv);
3306
3307 vni = strtoul(argv[4]->arg, NULL, 10);
3308 zvrf = zebra_vrf_get_evpn();
3309 zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj, false);
3310 return CMD_SUCCESS;
3311 }
3312
3313 DEFPY (show_evpn_mac_vni_detail,
3314 show_evpn_mac_vni_detail_cmd,
3315 "show evpn mac vni " CMD_VNI_RANGE " detail [json]",
3316 SHOW_STR
3317 "EVPN\n"
3318 "MAC addresses\n"
3319 "VXLAN Network Identifier\n"
3320 "VNI number\n"
3321 "Detailed Information On Each VNI MAC\n"
3322 JSON_STR)
3323 {
3324 struct zebra_vrf *zvrf;
3325 bool uj = use_json(argc, argv);
3326
3327 zvrf = zebra_vrf_get_evpn();
3328 zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj, true);
3329 return CMD_SUCCESS;
3330 }
3331
3332 DEFUN (show_evpn_mac_vni_all,
3333 show_evpn_mac_vni_all_cmd,
3334 "show evpn mac vni all [json]",
3335 SHOW_STR
3336 "EVPN\n"
3337 "MAC addresses\n"
3338 "VxLAN Network Identifier\n"
3339 "All VNIs\n"
3340 JSON_STR)
3341 {
3342 struct zebra_vrf *zvrf;
3343 bool uj = use_json(argc, argv);
3344
3345 zvrf = zebra_vrf_get_evpn();
3346 zebra_vxlan_print_macs_all_vni(vty, zvrf, false, uj);
3347 return CMD_SUCCESS;
3348 }
3349
3350 DEFUN (show_evpn_mac_vni_all_detail, show_evpn_mac_vni_all_detail_cmd,
3351 "show evpn mac vni all detail [json]",
3352 SHOW_STR
3353 "EVPN\n"
3354 "MAC addresses\n"
3355 "VxLAN Network Identifier\n"
3356 "All VNIs\n"
3357 "Detailed Information On Each VNI MAC\n"
3358 JSON_STR)
3359 {
3360 struct zebra_vrf *zvrf;
3361 bool uj = use_json(argc, argv);
3362
3363 zvrf = zebra_vrf_get_evpn();
3364 zebra_vxlan_print_macs_all_vni_detail(vty, zvrf, false, uj);
3365 return CMD_SUCCESS;
3366 }
3367
3368 DEFUN (show_evpn_mac_vni_all_vtep,
3369 show_evpn_mac_vni_all_vtep_cmd,
3370 "show evpn mac vni all vtep A.B.C.D [json]",
3371 SHOW_STR
3372 "EVPN\n"
3373 "MAC addresses\n"
3374 "VxLAN Network Identifier\n"
3375 "All VNIs\n"
3376 "Remote VTEP\n"
3377 "Remote VTEP IP address\n"
3378 JSON_STR)
3379 {
3380 struct zebra_vrf *zvrf;
3381 struct in_addr vtep_ip;
3382 bool uj = use_json(argc, argv);
3383
3384 if (!inet_aton(argv[6]->arg, &vtep_ip)) {
3385 if (!uj)
3386 vty_out(vty, "%% Malformed VTEP IP address\n");
3387 return CMD_WARNING;
3388 }
3389 zvrf = zebra_vrf_get_evpn();
3390 zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj);
3391
3392 return CMD_SUCCESS;
3393 }
3394
3395
3396 DEFUN (show_evpn_mac_vni_mac,
3397 show_evpn_mac_vni_mac_cmd,
3398 "show evpn mac vni " CMD_VNI_RANGE " mac WORD [json]",
3399 SHOW_STR
3400 "EVPN\n"
3401 "MAC addresses\n"
3402 "VxLAN Network Identifier\n"
3403 "VNI number\n"
3404 "MAC\n"
3405 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
3406 JSON_STR)
3407
3408 {
3409 struct zebra_vrf *zvrf;
3410 vni_t vni;
3411 struct ethaddr mac;
3412 bool uj = use_json(argc, argv);
3413
3414 vni = strtoul(argv[4]->arg, NULL, 10);
3415 if (!prefix_str2mac(argv[6]->arg, &mac)) {
3416 vty_out(vty, "%% Malformed MAC address\n");
3417 return CMD_WARNING;
3418 }
3419 zvrf = zebra_vrf_get_evpn();
3420 zebra_vxlan_print_specific_mac_vni(vty, zvrf, vni, &mac, uj);
3421 return CMD_SUCCESS;
3422 }
3423
3424 DEFUN (show_evpn_mac_vni_vtep,
3425 show_evpn_mac_vni_vtep_cmd,
3426 "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D" "[json]",
3427 SHOW_STR
3428 "EVPN\n"
3429 "MAC addresses\n"
3430 "VxLAN Network Identifier\n"
3431 "VNI number\n"
3432 "Remote VTEP\n"
3433 "Remote VTEP IP address\n"
3434 JSON_STR)
3435 {
3436 struct zebra_vrf *zvrf;
3437 vni_t vni;
3438 struct in_addr vtep_ip;
3439 bool uj = use_json(argc, argv);
3440
3441 vni = strtoul(argv[4]->arg, NULL, 10);
3442 if (!inet_aton(argv[6]->arg, &vtep_ip)) {
3443 if (!uj)
3444 vty_out(vty, "%% Malformed VTEP IP address\n");
3445 return CMD_WARNING;
3446 }
3447
3448 zvrf = zebra_vrf_get_evpn();
3449 zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
3450 return CMD_SUCCESS;
3451 }
3452
3453 DEFPY (show_evpn_mac_vni_all_dad,
3454 show_evpn_mac_vni_all_dad_cmd,
3455 "show evpn mac vni all duplicate [json]",
3456 SHOW_STR
3457 "EVPN\n"
3458 "MAC addresses\n"
3459 "VxLAN Network Identifier\n"
3460 "All VNIs\n"
3461 "Duplicate address list\n"
3462 JSON_STR)
3463 {
3464 struct zebra_vrf *zvrf;
3465 bool uj = use_json(argc, argv);
3466
3467 zvrf = zebra_vrf_get_evpn();
3468 zebra_vxlan_print_macs_all_vni(vty, zvrf, true, uj);
3469 return CMD_SUCCESS;
3470 }
3471
3472
3473 DEFPY (show_evpn_mac_vni_dad,
3474 show_evpn_mac_vni_dad_cmd,
3475 "show evpn mac vni " CMD_VNI_RANGE " duplicate [json]",
3476 SHOW_STR
3477 "EVPN\n"
3478 "MAC addresses\n"
3479 "VxLAN Network Identifier\n"
3480 "VNI number\n"
3481 "Duplicate address list\n"
3482 JSON_STR)
3483 {
3484 struct zebra_vrf *zvrf;
3485 bool uj = use_json(argc, argv);
3486
3487 zvrf = zebra_vrf_get_evpn();
3488
3489 zebra_vxlan_print_macs_vni_dad(vty, zvrf, vni, uj);
3490
3491 return CMD_SUCCESS;
3492 }
3493
3494 DEFPY (show_evpn_neigh_vni_dad,
3495 show_evpn_neigh_vni_dad_cmd,
3496 "show evpn arp-cache vni " CMD_VNI_RANGE "duplicate [json]",
3497 SHOW_STR
3498 "EVPN\n"
3499 "ARP and ND cache\n"
3500 "VxLAN Network Identifier\n"
3501 "VNI number\n"
3502 "Duplicate address list\n"
3503 JSON_STR)
3504 {
3505 struct zebra_vrf *zvrf;
3506 bool uj = use_json(argc, argv);
3507
3508 zvrf = zebra_vrf_get_evpn();
3509 zebra_vxlan_print_neigh_vni_dad(vty, zvrf, vni, uj);
3510 return CMD_SUCCESS;
3511 }
3512
3513 DEFPY (show_evpn_neigh_vni_all_dad,
3514 show_evpn_neigh_vni_all_dad_cmd,
3515 "show evpn arp-cache vni all duplicate [json]",
3516 SHOW_STR
3517 "EVPN\n"
3518 "ARP and ND cache\n"
3519 "VxLAN Network Identifier\n"
3520 "All VNIs\n"
3521 "Duplicate address list\n"
3522 JSON_STR)
3523 {
3524 struct zebra_vrf *zvrf;
3525 bool uj = use_json(argc, argv);
3526
3527 zvrf = zebra_vrf_get_evpn();
3528 zebra_vxlan_print_neigh_all_vni(vty, zvrf, true, uj);
3529 return CMD_SUCCESS;
3530 }
3531
3532
3533 DEFUN (show_evpn_neigh_vni,
3534 show_evpn_neigh_vni_cmd,
3535 "show evpn arp-cache vni " CMD_VNI_RANGE "[json]",
3536 SHOW_STR
3537 "EVPN\n"
3538 "ARP and ND cache\n"
3539 "VxLAN Network Identifier\n"
3540 "VNI number\n"
3541 JSON_STR)
3542 {
3543 struct zebra_vrf *zvrf;
3544 vni_t vni;
3545 bool uj = use_json(argc, argv);
3546
3547 vni = strtoul(argv[4]->arg, NULL, 10);
3548 zvrf = zebra_vrf_get_evpn();
3549 zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj);
3550 return CMD_SUCCESS;
3551 }
3552
3553 DEFUN (show_evpn_neigh_vni_all,
3554 show_evpn_neigh_vni_all_cmd,
3555 "show evpn arp-cache vni all [json]",
3556 SHOW_STR
3557 "EVPN\n"
3558 "ARP and ND cache\n"
3559 "VxLAN Network Identifier\n"
3560 "All VNIs\n"
3561 JSON_STR)
3562 {
3563 struct zebra_vrf *zvrf;
3564 bool uj = use_json(argc, argv);
3565
3566 zvrf = zebra_vrf_get_evpn();
3567 zebra_vxlan_print_neigh_all_vni(vty, zvrf, false, uj);
3568 return CMD_SUCCESS;
3569 }
3570
3571 DEFUN (show_evpn_neigh_vni_all_detail, show_evpn_neigh_vni_all_detail_cmd,
3572 "show evpn arp-cache vni all detail [json]",
3573 SHOW_STR
3574 "EVPN\n"
3575 "ARP and ND cache\n"
3576 "VxLAN Network Identifier\n"
3577 "All VNIs\n"
3578 "Neighbor details for all vnis in detail\n" JSON_STR)
3579 {
3580 struct zebra_vrf *zvrf;
3581 bool uj = use_json(argc, argv);
3582
3583 zvrf = zebra_vrf_get_evpn();
3584 zebra_vxlan_print_neigh_all_vni_detail(vty, zvrf, false, uj);
3585 return CMD_SUCCESS;
3586 }
3587
3588 DEFUN (show_evpn_neigh_vni_neigh,
3589 show_evpn_neigh_vni_neigh_cmd,
3590 "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD [json]",
3591 SHOW_STR
3592 "EVPN\n"
3593 "ARP and ND cache\n"
3594 "VxLAN Network Identifier\n"
3595 "VNI number\n"
3596 "Neighbor\n"
3597 "Neighbor address (IPv4 or IPv6 address)\n"
3598 JSON_STR)
3599 {
3600 struct zebra_vrf *zvrf;
3601 vni_t vni;
3602 struct ipaddr ip;
3603 bool uj = use_json(argc, argv);
3604
3605 vni = strtoul(argv[4]->arg, NULL, 10);
3606 if (str2ipaddr(argv[6]->arg, &ip) != 0) {
3607 if (!uj)
3608 vty_out(vty, "%% Malformed Neighbor address\n");
3609 return CMD_WARNING;
3610 }
3611 zvrf = zebra_vrf_get_evpn();
3612 zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj);
3613 return CMD_SUCCESS;
3614 }
3615
3616 DEFUN (show_evpn_neigh_vni_vtep,
3617 show_evpn_neigh_vni_vtep_cmd,
3618 "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D [json]",
3619 SHOW_STR
3620 "EVPN\n"
3621 "ARP and ND cache\n"
3622 "VxLAN Network Identifier\n"
3623 "VNI number\n"
3624 "Remote VTEP\n"
3625 "Remote VTEP IP address\n"
3626 JSON_STR)
3627 {
3628 struct zebra_vrf *zvrf;
3629 vni_t vni;
3630 struct in_addr vtep_ip;
3631 bool uj = use_json(argc, argv);
3632
3633 vni = strtoul(argv[4]->arg, NULL, 10);
3634 if (!inet_aton(argv[6]->arg, &vtep_ip)) {
3635 if (!uj)
3636 vty_out(vty, "%% Malformed VTEP IP address\n");
3637 return CMD_WARNING;
3638 }
3639
3640 zvrf = zebra_vrf_get_evpn();
3641 zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
3642 return CMD_SUCCESS;
3643 }
3644
3645 /* policy routing contexts */
3646 DEFUN (show_pbr_ipset,
3647 show_pbr_ipset_cmd,
3648 "show pbr ipset [WORD]",
3649 SHOW_STR
3650 "Policy-Based Routing\n"
3651 "IPset Context information\n"
3652 "IPset Name information\n")
3653 {
3654 int idx = 0;
3655 int found = 0;
3656 found = argv_find(argv, argc, "WORD", &idx);
3657 if (!found)
3658 zebra_pbr_show_ipset_list(vty, NULL);
3659 else
3660 zebra_pbr_show_ipset_list(vty, argv[idx]->arg);
3661 return CMD_SUCCESS;
3662 }
3663
3664 /* policy routing contexts */
3665 DEFUN (show_pbr_iptable,
3666 show_pbr_iptable_cmd,
3667 "show pbr iptable [WORD]",
3668 SHOW_STR
3669 "Policy-Based Routing\n"
3670 "IPtable Context information\n"
3671 "IPtable Name information\n")
3672 {
3673 int idx = 0;
3674 int found = 0;
3675
3676 found = argv_find(argv, argc, "WORD", &idx);
3677 if (!found)
3678 zebra_pbr_show_iptable(vty, NULL);
3679 else
3680 zebra_pbr_show_iptable(vty, argv[idx]->arg);
3681 return CMD_SUCCESS;
3682 }
3683
3684 /* policy routing contexts */
3685 DEFPY (show_pbr_rule,
3686 show_pbr_rule_cmd,
3687 "show pbr rule",
3688 SHOW_STR
3689 "Policy-Based Routing\n"
3690 "Rule\n")
3691 {
3692 zebra_pbr_show_rule(vty);
3693 return CMD_SUCCESS;
3694 }
3695
3696 DEFPY (pbr_nexthop_resolve,
3697 pbr_nexthop_resolve_cmd,
3698 "[no$no] pbr nexthop-resolve",
3699 NO_STR
3700 "Policy Based Routing\n"
3701 "Resolve nexthop for dataplane programming\n")
3702 {
3703 zebra_pbr_expand_action_update(!no);
3704 return CMD_SUCCESS;
3705 }
3706
3707 DEFPY (clear_evpn_dup_addr,
3708 clear_evpn_dup_addr_cmd,
3709 "clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac X:X:X:X:X:X | ip <A.B.C.D|X:X::X:X>]>",
3710 CLEAR_STR
3711 "EVPN\n"
3712 "Duplicate address \n"
3713 "VxLAN Network Identifier\n"
3714 "VNI number\n"
3715 "All VNIs\n"
3716 "MAC\n"
3717 "MAC address (e.g., 00:e0:ec:20:12:62)\n"
3718 "IP\n"
3719 "IPv4 address\n"
3720 "IPv6 address\n")
3721 {
3722 struct ipaddr host_ip = {.ipa_type = IPADDR_NONE };
3723 int ret = CMD_SUCCESS;
3724 struct list *input;
3725 struct yang_data *yang_dup = NULL, *yang_dup_ip = NULL,
3726 *yang_dup_mac = NULL;
3727
3728 input = list_new();
3729
3730 if (!vni_str) {
3731 yang_dup = yang_data_new(
3732 "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice",
3733 "all-case");
3734 } else {
3735 yang_dup = yang_data_new_uint32(
3736 "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id",
3737 vni);
3738 if (!is_zero_mac(&mac->eth_addr)) {
3739 yang_dup_mac = yang_data_new_mac(
3740 "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/mac-addr",
3741 &mac->eth_addr);
3742 if (yang_dup_mac)
3743 listnode_add(input, yang_dup_mac);
3744 } else if (ip) {
3745 if (sockunion_family(ip) == AF_INET) {
3746 host_ip.ipa_type = IPADDR_V4;
3747 host_ip.ipaddr_v4.s_addr = sockunion2ip(ip);
3748 } else {
3749 host_ip.ipa_type = IPADDR_V6;
3750 memcpy(&host_ip.ipaddr_v6, &ip->sin6.sin6_addr,
3751 sizeof(struct in6_addr));
3752 }
3753
3754 yang_dup_ip = yang_data_new_ip(
3755 "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/vni-ipaddr",
3756 &host_ip);
3757
3758 if (yang_dup_ip)
3759 listnode_add(input, yang_dup_ip);
3760 }
3761 }
3762
3763 if (yang_dup) {
3764 listnode_add(input, yang_dup);
3765 ret = nb_cli_rpc(vty, "/frr-zebra:clear-evpn-dup-addr", input,
3766 NULL);
3767 }
3768
3769 list_delete(&input);
3770
3771 return ret;
3772 }
3773
3774 DEFPY_HIDDEN (evpn_accept_bgp_seq,
3775 evpn_accept_bgp_seq_cmd,
3776 "evpn accept-bgp-seq",
3777 "EVPN\n"
3778 "Accept all sequence numbers from BGP\n")
3779 {
3780 zebra_vxlan_set_accept_bgp_seq(true);
3781 return CMD_SUCCESS;
3782 }
3783
3784 DEFPY_HIDDEN (no_evpn_accept_bgp_seq,
3785 no_evpn_accept_bgp_seq_cmd,
3786 "no evpn accept-bgp-seq",
3787 NO_STR
3788 "EVPN\n"
3789 "Accept all sequence numbers from BGP\n")
3790 {
3791 zebra_vxlan_set_accept_bgp_seq(false);
3792 return CMD_SUCCESS;
3793 }
3794
3795 /* Static ip route configuration write function. */
3796 static int zebra_ip_config(struct vty *vty)
3797 {
3798 int write = 0;
3799
3800 write += zebra_import_table_config(vty, VRF_DEFAULT);
3801
3802 return write;
3803 }
3804
3805 DEFUN (ip_zebra_import_table_distance,
3806 ip_zebra_import_table_distance_cmd,
3807 "ip import-table (1-252) [distance (1-255)] [route-map RMAP_NAME]",
3808 IP_STR
3809 "import routes from non-main kernel table\n"
3810 "kernel routing table id\n"
3811 "Distance for imported routes\n"
3812 "Default distance value\n"
3813 "route-map for filtering\n"
3814 "route-map name\n")
3815 {
3816 uint32_t table_id = 0;
3817
3818 table_id = strtoul(argv[2]->arg, NULL, 10);
3819 int distance = ZEBRA_TABLE_DISTANCE_DEFAULT;
3820 char *rmap =
3821 strmatch(argv[argc - 2]->text, "route-map")
3822 ? XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[argc - 1]->arg)
3823 : NULL;
3824 int ret;
3825
3826 if (argc == 7 || (argc == 5 && !rmap))
3827 distance = strtoul(argv[4]->arg, NULL, 10);
3828
3829 if (!is_zebra_valid_kernel_table(table_id)) {
3830 vty_out(vty,
3831 "Invalid routing table ID, %d. Must be in range 1-252\n",
3832 table_id);
3833 if (rmap)
3834 XFREE(MTYPE_ROUTE_MAP_NAME, rmap);
3835 return CMD_WARNING;
3836 }
3837
3838 if (is_zebra_main_routing_table(table_id)) {
3839 vty_out(vty,
3840 "Invalid routing table ID, %d. Must be non-default table\n",
3841 table_id);
3842 if (rmap)
3843 XFREE(MTYPE_ROUTE_MAP_NAME, rmap);
3844 return CMD_WARNING;
3845 }
3846
3847 ret = zebra_import_table(AFI_IP, VRF_DEFAULT, table_id,
3848 distance, rmap, 1);
3849 if (rmap)
3850 XFREE(MTYPE_ROUTE_MAP_NAME, rmap);
3851
3852 return ret;
3853 }
3854
3855 DEFUN_HIDDEN (zebra_packet_process,
3856 zebra_packet_process_cmd,
3857 "zebra zapi-packets (1-10000)",
3858 ZEBRA_STR
3859 "Zapi Protocol\n"
3860 "Number of packets to process before relinquishing thread\n")
3861 {
3862 uint32_t packets = strtoul(argv[2]->arg, NULL, 10);
3863
3864 atomic_store_explicit(&zrouter.packets_to_process, packets,
3865 memory_order_relaxed);
3866
3867 return CMD_SUCCESS;
3868 }
3869
3870 DEFUN_HIDDEN (no_zebra_packet_process,
3871 no_zebra_packet_process_cmd,
3872 "no zebra zapi-packets [(1-10000)]",
3873 NO_STR
3874 ZEBRA_STR
3875 "Zapi Protocol\n"
3876 "Number of packets to process before relinquishing thread\n")
3877 {
3878 atomic_store_explicit(&zrouter.packets_to_process,
3879 ZEBRA_ZAPI_PACKETS_TO_PROCESS,
3880 memory_order_relaxed);
3881
3882 return CMD_SUCCESS;
3883 }
3884
3885 DEFUN_HIDDEN (zebra_workqueue_timer,
3886 zebra_workqueue_timer_cmd,
3887 "zebra work-queue (0-10000)",
3888 ZEBRA_STR
3889 "Work Queue\n"
3890 "Time in milliseconds\n")
3891 {
3892 uint32_t timer = strtoul(argv[2]->arg, NULL, 10);
3893 zrouter.ribq->spec.hold = timer;
3894
3895 return CMD_SUCCESS;
3896 }
3897
3898 DEFUN_HIDDEN (no_zebra_workqueue_timer,
3899 no_zebra_workqueue_timer_cmd,
3900 "no zebra work-queue [(0-10000)]",
3901 NO_STR
3902 ZEBRA_STR
3903 "Work Queue\n"
3904 "Time in milliseconds\n")
3905 {
3906 zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
3907
3908 return CMD_SUCCESS;
3909 }
3910
3911 DEFUN (no_ip_zebra_import_table,
3912 no_ip_zebra_import_table_cmd,
3913 "no ip import-table (1-252) [distance (1-255)] [route-map NAME]",
3914 NO_STR
3915 IP_STR
3916 "import routes from non-main kernel table\n"
3917 "kernel routing table id\n"
3918 "Distance for imported routes\n"
3919 "Default distance value\n"
3920 "route-map for filtering\n"
3921 "route-map name\n")
3922 {
3923 uint32_t table_id = 0;
3924 table_id = strtoul(argv[3]->arg, NULL, 10);
3925
3926 if (!is_zebra_valid_kernel_table(table_id)) {
3927 vty_out(vty,
3928 "Invalid routing table ID. Must be in range 1-252\n");
3929 return CMD_WARNING;
3930 }
3931
3932 if (is_zebra_main_routing_table(table_id)) {
3933 vty_out(vty,
3934 "Invalid routing table ID, %d. Must be non-default table\n",
3935 table_id);
3936 return CMD_WARNING;
3937 }
3938
3939 if (!is_zebra_import_table_enabled(AFI_IP, VRF_DEFAULT, table_id))
3940 return CMD_SUCCESS;
3941
3942 return (zebra_import_table(AFI_IP, VRF_DEFAULT, table_id, 0, NULL, 0));
3943 }
3944
3945 DEFPY (zebra_nexthop_group_keep,
3946 zebra_nexthop_group_keep_cmd,
3947 "[no] zebra nexthop-group keep (1-3600)",
3948 NO_STR
3949 ZEBRA_STR
3950 "Nexthop-Group\n"
3951 "How long to keep\n"
3952 "Time in seconds from 1-3600\n")
3953 {
3954 if (no)
3955 zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER;
3956 else
3957 zrouter.nhg_keep = keep;
3958
3959 return CMD_SUCCESS;
3960 }
3961
3962 static int config_write_protocol(struct vty *vty)
3963 {
3964 if (zrouter.allow_delete)
3965 vty_out(vty, "allow-external-route-update\n");
3966
3967 if (zrouter.nhg_keep != ZEBRA_DEFAULT_NHG_KEEP_TIMER)
3968 vty_out(vty, "zebra nexthop-group keep %u\n", zrouter.nhg_keep);
3969
3970 if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME)
3971 vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold);
3972
3973 if (zrouter.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS)
3974 vty_out(vty, "zebra zapi-packets %u\n",
3975 zrouter.packets_to_process);
3976
3977 enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get();
3978
3979 if (ipv4_multicast_mode != MCAST_NO_CONFIG)
3980 vty_out(vty, "ip multicast rpf-lookup-mode %s\n",
3981 ipv4_multicast_mode == MCAST_URIB_ONLY
3982 ? "urib-only"
3983 : ipv4_multicast_mode == MCAST_MRIB_ONLY
3984 ? "mrib-only"
3985 : ipv4_multicast_mode
3986 == MCAST_MIX_MRIB_FIRST
3987 ? "mrib-then-urib"
3988 : ipv4_multicast_mode
3989 == MCAST_MIX_DISTANCE
3990 ? "lower-distance"
3991 : "longer-prefix");
3992
3993 /* Include dataplane info */
3994 dplane_config_write_helper(vty);
3995
3996 zebra_evpn_mh_config_write(vty);
3997
3998 zebra_pbr_config_write(vty);
3999
4000 if (!zebra_vxlan_get_accept_bgp_seq())
4001 vty_out(vty, "no evpn accept-bgp-seq\n");
4002
4003 /* Include nexthop-group config */
4004 if (!zebra_nhg_kernel_nexthops_enabled())
4005 vty_out(vty, "no zebra nexthop kernel enable\n");
4006
4007 if (zebra_nhg_proto_nexthops_only())
4008 vty_out(vty, "zebra nexthop proto only\n");
4009
4010 if (!zebra_nhg_recursive_use_backups())
4011 vty_out(vty, "no zebra nexthop resolve-via-backup\n");
4012
4013 if (rnh_get_hide_backups())
4014 vty_out(vty, "ip nht hide-backup-events\n");
4015
4016 #ifdef HAVE_NETLINK
4017 /* Include netlink info */
4018 netlink_config_write_helper(vty);
4019 #endif /* HAVE_NETLINK */
4020
4021 return 1;
4022 }
4023
4024 DEFUN (show_zebra,
4025 show_zebra_cmd,
4026 "show zebra",
4027 SHOW_STR
4028 ZEBRA_STR)
4029 {
4030 struct vrf *vrf;
4031 struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
4032 char *out;
4033
4034 ttable_rowseps(table, 0, BOTTOM, true, '-');
4035 ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get());
4036 ttable_add_row(table, "ECMP Maximum|%d", zrouter.multipath_num);
4037 ttable_add_row(table, "v4 Forwarding|%s", ipforward() ? "On" : "Off");
4038 ttable_add_row(table, "v6 Forwarding|%s",
4039 ipforward_ipv6() ? "On" : "Off");
4040 ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off");
4041 ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off");
4042 ttable_add_row(table, "Kernel socket buffer size|%d", rcvbufsize);
4043
4044
4045 #ifdef GNU_LINUX
4046 if (!vrf_is_backend_netns())
4047 ttable_add_row(table, "VRF|l3mdev Available");
4048 else
4049 ttable_add_row(table, "VRF|Namespaces");
4050 #else
4051 ttable_add_row(table, "VRF|Not Available");
4052 #endif
4053
4054 ttable_add_row(table, "ASIC offload|%s",
4055 zrouter.asic_offloaded ? "Used" : "Unavailable");
4056
4057 /*
4058 * Do not display this unless someone is actually using it
4059 *
4060 * Why this distinction? I think this is effectively dead code
4061 * and should not be exposed. Maybe someone proves me wrong.
4062 */
4063 if (zrouter.asic_notification_nexthop_control)
4064 ttable_add_row(table, "ASIC offload and nexthop control|Used");
4065
4066 ttable_add_row(table, "RA|%s",
4067 rtadv_compiled_in() ? "Compiled in" : "Not Compiled in");
4068 ttable_add_row(table, "RFC 5549|%s",
4069 rtadv_get_interfaces_configured_from_bgp()
4070 ? "BGP is using"
4071 : "BGP is not using");
4072
4073 ttable_add_row(table, "Kernel NHG|%s",
4074 zrouter.supports_nhgs ? "Available" : "Unavailable");
4075
4076 ttable_add_row(table, "Allow Non FRR route deletion|%s",
4077 zrouter.allow_delete ? "Yes" : "No");
4078 ttable_add_row(table, "v4 All LinkDown Routes|%s",
4079 zrouter.all_linkdownv4 ? "On" : "Off");
4080 ttable_add_row(table, "v4 Default LinkDown Routes|%s",
4081 zrouter.default_linkdownv4 ? "On" : "Off");
4082 ttable_add_row(table, "v6 All LinkDown Routes|%s",
4083 zrouter.all_linkdownv6 ? "On" : "Off");
4084 ttable_add_row(table, "v6 Default LinkDown Routes|%s",
4085 zrouter.default_linkdownv6 ? "On" : "Off");
4086
4087 ttable_add_row(table, "v4 All MC Forwarding|%s",
4088 zrouter.all_mc_forwardingv4 ? "On" : "Off");
4089 ttable_add_row(table, "v4 Default MC Forwarding|%s",
4090 zrouter.default_mc_forwardingv4 ? "On" : "Off");
4091 ttable_add_row(table, "v6 All MC Forwarding|%s",
4092 zrouter.all_mc_forwardingv6 ? "On" : "Off");
4093 ttable_add_row(table, "v6 Default MC Forwarding|%s",
4094 zrouter.default_mc_forwardingv6 ? "On" : "Off");
4095
4096 out = ttable_dump(table, "\n");
4097 vty_out(vty, "%s\n", out);
4098 XFREE(MTYPE_TMP, out);
4099
4100 ttable_del(table);
4101 vty_out(vty,
4102 " Route Route Neighbor LSP LSP\n");
4103 vty_out(vty,
4104 "VRF Installs Removals Updates Installs Removals\n");
4105
4106 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4107 struct zebra_vrf *zvrf = vrf->info;
4108
4109 vty_out(vty, "%-25s %10" PRIu64 " %10" PRIu64 " %10" PRIu64" %10" PRIu64 " %10" PRIu64 "\n",
4110 vrf->name, zvrf->installs, zvrf->removals,
4111 zvrf->neigh_updates, zvrf->lsp_installs,
4112 zvrf->lsp_removals);
4113 }
4114
4115 return CMD_SUCCESS;
4116 }
4117
4118 DEFUN (ip_forwarding,
4119 ip_forwarding_cmd,
4120 "ip forwarding",
4121 IP_STR
4122 "Turn on IP forwarding\n")
4123 {
4124 int ret;
4125
4126 ret = ipforward();
4127 if (ret == 0)
4128 ret = ipforward_on();
4129
4130 if (ret == 0) {
4131 vty_out(vty, "Can't turn on IP forwarding\n");
4132 return CMD_WARNING_CONFIG_FAILED;
4133 }
4134
4135 return CMD_SUCCESS;
4136 }
4137
4138 DEFUN (no_ip_forwarding,
4139 no_ip_forwarding_cmd,
4140 "no ip forwarding",
4141 NO_STR
4142 IP_STR
4143 "Turn off IP forwarding\n")
4144 {
4145 int ret;
4146
4147 ret = ipforward();
4148 if (ret != 0)
4149 ret = ipforward_off();
4150
4151 if (ret != 0) {
4152 vty_out(vty, "Can't turn off IP forwarding\n");
4153 return CMD_WARNING_CONFIG_FAILED;
4154 }
4155
4156 return CMD_SUCCESS;
4157 }
4158
4159 /* Only display ip forwarding is enabled or not. */
4160 DEFUN (show_ip_forwarding,
4161 show_ip_forwarding_cmd,
4162 "show ip forwarding",
4163 SHOW_STR
4164 IP_STR
4165 "IP forwarding status\n")
4166 {
4167 int ret;
4168
4169 ret = ipforward();
4170
4171 if (ret == 0)
4172 vty_out(vty, "IP forwarding is off\n");
4173 else
4174 vty_out(vty, "IP forwarding is on\n");
4175 return CMD_SUCCESS;
4176 }
4177
4178 /* Only display ipv6 forwarding is enabled or not. */
4179 DEFUN (show_ipv6_forwarding,
4180 show_ipv6_forwarding_cmd,
4181 "show ipv6 forwarding",
4182 SHOW_STR
4183 "IPv6 information\n"
4184 "Forwarding status\n")
4185 {
4186 int ret;
4187
4188 ret = ipforward_ipv6();
4189
4190 switch (ret) {
4191 case -1:
4192 vty_out(vty, "ipv6 forwarding is unknown\n");
4193 break;
4194 case 0:
4195 vty_out(vty, "ipv6 forwarding is %s\n", "off");
4196 break;
4197 case 1:
4198 vty_out(vty, "ipv6 forwarding is %s\n", "on");
4199 break;
4200 default:
4201 vty_out(vty, "ipv6 forwarding is %s\n", "off");
4202 break;
4203 }
4204 return CMD_SUCCESS;
4205 }
4206
4207 DEFUN (ipv6_forwarding,
4208 ipv6_forwarding_cmd,
4209 "ipv6 forwarding",
4210 IPV6_STR
4211 "Turn on IPv6 forwarding\n")
4212 {
4213 int ret;
4214
4215 ret = ipforward_ipv6();
4216 if (ret == 0)
4217 ret = ipforward_ipv6_on();
4218
4219 if (ret == 0) {
4220 vty_out(vty, "Can't turn on IPv6 forwarding\n");
4221 return CMD_WARNING_CONFIG_FAILED;
4222 }
4223
4224 return CMD_SUCCESS;
4225 }
4226
4227 DEFUN (no_ipv6_forwarding,
4228 no_ipv6_forwarding_cmd,
4229 "no ipv6 forwarding",
4230 NO_STR
4231 IPV6_STR
4232 "Turn off IPv6 forwarding\n")
4233 {
4234 int ret;
4235
4236 ret = ipforward_ipv6();
4237 if (ret != 0)
4238 ret = ipforward_ipv6_off();
4239
4240 if (ret != 0) {
4241 vty_out(vty, "Can't turn off IPv6 forwarding\n");
4242 return CMD_WARNING_CONFIG_FAILED;
4243 }
4244
4245 return CMD_SUCCESS;
4246 }
4247
4248 /* Display dataplane info */
4249 DEFUN (show_dataplane,
4250 show_dataplane_cmd,
4251 "show zebra dplane [detailed]",
4252 SHOW_STR
4253 ZEBRA_STR
4254 "Zebra dataplane information\n"
4255 "Detailed output\n")
4256 {
4257 int idx = 0;
4258 bool detailed = false;
4259
4260 if (argv_find(argv, argc, "detailed", &idx))
4261 detailed = true;
4262
4263 return dplane_show_helper(vty, detailed);
4264 }
4265
4266 /* Display dataplane providers info */
4267 DEFUN (show_dataplane_providers,
4268 show_dataplane_providers_cmd,
4269 "show zebra dplane providers [detailed]",
4270 SHOW_STR
4271 ZEBRA_STR
4272 "Zebra dataplane information\n"
4273 "Zebra dataplane provider information\n"
4274 "Detailed output\n")
4275 {
4276 int idx = 0;
4277 bool detailed = false;
4278
4279 if (argv_find(argv, argc, "detailed", &idx))
4280 detailed = true;
4281
4282 return dplane_show_provs_helper(vty, detailed);
4283 }
4284
4285 /* Configure dataplane incoming queue limit */
4286 DEFUN (zebra_dplane_queue_limit,
4287 zebra_dplane_queue_limit_cmd,
4288 "zebra dplane limit (0-10000)",
4289 ZEBRA_STR
4290 "Zebra dataplane\n"
4291 "Limit incoming queued updates\n"
4292 "Number of queued updates\n")
4293 {
4294 uint32_t limit = 0;
4295
4296 limit = strtoul(argv[3]->arg, NULL, 10);
4297
4298 dplane_set_in_queue_limit(limit, true);
4299
4300 return CMD_SUCCESS;
4301 }
4302
4303 /* Reset dataplane queue limit to default value */
4304 DEFUN (no_zebra_dplane_queue_limit,
4305 no_zebra_dplane_queue_limit_cmd,
4306 "no zebra dplane limit [(0-10000)]",
4307 NO_STR
4308 ZEBRA_STR
4309 "Zebra dataplane\n"
4310 "Limit incoming queued updates\n"
4311 "Number of queued updates\n")
4312 {
4313 dplane_set_in_queue_limit(0, false);
4314
4315 return CMD_SUCCESS;
4316 }
4317
4318 DEFUN (zebra_show_routing_tables_summary,
4319 zebra_show_routing_tables_summary_cmd,
4320 "show zebra router table summary",
4321 SHOW_STR
4322 ZEBRA_STR
4323 "The Zebra Router Information\n"
4324 "Table Information about this Zebra Router\n"
4325 "Summary Information\n")
4326 {
4327 zebra_router_show_table_summary(vty);
4328
4329 return CMD_SUCCESS;
4330 }
4331
4332 /* Table configuration write function. */
4333 static int config_write_table(struct vty *vty)
4334 {
4335 return 0;
4336 }
4337
4338 /* IPForwarding configuration write function. */
4339 static int config_write_forwarding(struct vty *vty)
4340 {
4341 if (!ipforward())
4342 vty_out(vty, "no ip forwarding\n");
4343 if (!ipforward_ipv6())
4344 vty_out(vty, "no ipv6 forwarding\n");
4345 vty_out(vty, "!\n");
4346 return 0;
4347 }
4348
4349 DEFUN_HIDDEN (show_frr,
4350 show_frr_cmd,
4351 "show frr",
4352 SHOW_STR
4353 "FRR\n")
4354 {
4355 vty_out(vty, "........ .. . .. . ..... ...77:................................................\n");
4356 vty_out(vty, ".............................7777:..............................................\n");
4357 vty_out(vty, ".............................777777,............................................\n");
4358 vty_out(vty, "... .........................77777777,..........................................\n");
4359 vty_out(vty, "............................=7777777777:........................................\n");
4360 vty_out(vty, "........................:7777777777777777,......................................\n");
4361 vty_out(vty, ".................... ~7777777777777?~,..........................................\n");
4362 vty_out(vty, "...................I7777777777+.................................................\n");
4363 vty_out(vty, "................,777777777?............ .......................................\n");
4364 vty_out(vty, "..............:77777777?..........~?77777.......................................\n");
4365 vty_out(vty, ".............77777777~........=7777777777.......................................\n");
4366 vty_out(vty, ".......... +7777777,.......?7777777777777.......................................\n");
4367 vty_out(vty, "..........7777777~......:7777777777777777......77?,.............................\n");
4368 vty_out(vty, "........:777777?......+777777777777777777......777777I,.........................\n");
4369 vty_out(vty, ".......?777777,.....+77777777777777777777......777777777?.......................\n");
4370 vty_out(vty, "......?777777......7777777777777777777777......,?777777777?.....................\n");
4371 vty_out(vty, ".....?77777?.....=7777777777777777777I~............,I7777777~...................\n");
4372 vty_out(vty, "....+77777+.....I77777777777777777:...................+777777I..................\n");
4373 vty_out(vty, "...~77777+.....7777777777777777=........................?777777...... .......\n");
4374 vty_out(vty, "...77777I.....I77777777777777~.........:?................,777777.....I777.......\n");
4375 vty_out(vty, "..777777.....I7777777777777I .......?7777..................777777.....777?......\n");
4376 vty_out(vty, ".~77777,....=7777777777777:......,7777777..................,77777+....+777......\n");
4377 vty_out(vty, ".77777I.....7777777777777,......777777777.......ONNNN.......=77777.....777~.....\n");
4378 vty_out(vty, ",77777.....I777777777777,.....:7777777777......DNNNNNN.......77777+ ...7777.....\n");
4379 vty_out(vty, "I7777I.....777777777777=.....~77777777777......NNNNNNN~......=7777I....=777.....\n");
4380 vty_out(vty, "77777:....=777777777777.....,777777777777......$NNNNND ......:77777....:777.....\n");
4381 vty_out(vty, "77777. ...777777777777~.....7777777777777........7DZ,........:77777.....777.....\n");
4382 vty_out(vty, "????? . ..777777777777.....,7777777777777....................:77777I....777.....\n");
4383 vty_out(vty, "....... ..777777777777.....+7777777777777....................=7777777+...?7.....\n");
4384 vty_out(vty, "..........77777777777I.....I7777777777777....................7777777777:........\n");
4385 vty_out(vty, "..........77777777777I.....?7777777777777...................~777777777777.......\n");
4386 vty_out(vty, "..........777777777777.....~7777777777777..................,77777777777777+.....\n");
4387 vty_out(vty, "..........777777777777......7777777777777..................77777777777777777,...\n");
4388 vty_out(vty, "..... ....?77777777777I.....~777777777777................,777777.....,:+77777I..\n");
4389 vty_out(vty, "........ .:777777777777,.....?77777777777...............?777777..............,:=\n");
4390 vty_out(vty, ".......... 7777777777777..... ?7777777777.............=7777777.....~777I........\n");
4391 vty_out(vty, "...........:777777777777I......~777777777...........I7777777~.....+777I.........\n");
4392 vty_out(vty, "..... ......7777777777777I.......I7777777.......+777777777I......7777I..........\n");
4393 vty_out(vty, ".............77777777777777........?77777......777777777?......=7777=...........\n");
4394 vty_out(vty, ".............,77777777777777+.........~77......777777I,......:77777.............\n");
4395 vty_out(vty, "..............~777777777777777~................777777......:77777=..............\n");
4396 vty_out(vty, "...............:7777777777777777?..............:777777,.....=77=................\n");
4397 vty_out(vty, "................,777777777777777777?,...........,777777:.....,..................\n");
4398 vty_out(vty, "........... ......I777777777777777777777I.........777777~.......................\n");
4399 vty_out(vty, "...................,777777777777777777777..........777777+......................\n");
4400 vty_out(vty, ".....................+7777777777777777777...........777777?.....................\n");
4401 vty_out(vty, ".......................=77777777777777777............777777I....................\n");
4402 vty_out(vty, ".........................:777777777777777.............I77777I...................\n");
4403 vty_out(vty, "............................~777777777777..............+777777..................\n");
4404 vty_out(vty, "................................~77777777...............=777777.................\n");
4405 vty_out(vty, ".....................................:=?I................~777777................\n");
4406 vty_out(vty, "..........................................................:777777,..............\n");
4407 vty_out(vty, ".... ... ... . . .... ....... ....... ....................:777777..............\n");
4408
4409 return CMD_SUCCESS;
4410 }
4411
4412 #ifdef HAVE_NETLINK
4413 DEFUN_HIDDEN(zebra_kernel_netlink_batch_tx_buf,
4414 zebra_kernel_netlink_batch_tx_buf_cmd,
4415 "zebra kernel netlink batch-tx-buf (1-1048576) (1-1048576)",
4416 ZEBRA_STR
4417 "Zebra kernel interface\n"
4418 "Set Netlink parameters\n"
4419 "Set batch buffer size and send threshold\n"
4420 "Size of the buffer\n"
4421 "Send threshold\n")
4422 {
4423 uint32_t bufsize = 0, threshold = 0;
4424
4425 bufsize = strtoul(argv[4]->arg, NULL, 10);
4426 threshold = strtoul(argv[5]->arg, NULL, 10);
4427
4428 netlink_set_batch_buffer_size(bufsize, threshold, true);
4429
4430 return CMD_SUCCESS;
4431 }
4432
4433 DEFUN_HIDDEN(no_zebra_kernel_netlink_batch_tx_buf,
4434 no_zebra_kernel_netlink_batch_tx_buf_cmd,
4435 "no zebra kernel netlink batch-tx-buf [(0-1048576)] [(0-1048576)]",
4436 NO_STR ZEBRA_STR
4437 "Zebra kernel interface\n"
4438 "Set Netlink parameters\n"
4439 "Set batch buffer size and send threshold\n"
4440 "Size of the buffer\n"
4441 "Send threshold\n")
4442 {
4443 netlink_set_batch_buffer_size(0, 0, false);
4444
4445 return CMD_SUCCESS;
4446 }
4447
4448 DEFPY (zebra_protodown_bit,
4449 zebra_protodown_bit_cmd,
4450 "zebra protodown reason-bit (0-31)$bit",
4451 ZEBRA_STR
4452 "Protodown Configuration\n"
4453 "Reason Bit used in the kernel for application\n"
4454 "Reason Bit range\n")
4455 {
4456 if_netlink_set_frr_protodown_r_bit(bit);
4457 return CMD_SUCCESS;
4458 }
4459
4460 DEFPY (no_zebra_protodown_bit,
4461 no_zebra_protodown_bit_cmd,
4462 "no zebra protodown reason-bit [(0-31)$bit]",
4463 NO_STR
4464 ZEBRA_STR
4465 "Protodown Configuration\n"
4466 "Reason Bit used in the kernel for setting protodown\n"
4467 "Reason Bit Range\n")
4468 {
4469 if_netlink_unset_frr_protodown_r_bit();
4470 return CMD_SUCCESS;
4471 }
4472
4473 #endif /* HAVE_NETLINK */
4474
4475 DEFUN(ip_table_range, ip_table_range_cmd,
4476 "[no] ip table range (1-4294967295) (1-4294967295)",
4477 NO_STR IP_STR
4478 "table configuration\n"
4479 "Configure table range\n"
4480 "Start Routing Table\n"
4481 "End Routing Table\n")
4482 {
4483 ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
4484
4485 if (!zvrf)
4486 return CMD_WARNING;
4487
4488 if (zvrf_id(zvrf) != VRF_DEFAULT && !vrf_is_backend_netns()) {
4489 vty_out(vty,
4490 "VRF subcommand does not make any sense in l3mdev based vrf's\n");
4491 return CMD_WARNING;
4492 }
4493
4494 if (strmatch(argv[0]->text, "no"))
4495 return table_manager_range(vty, false, zvrf, NULL, NULL);
4496
4497 return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg);
4498 }
4499
4500 #ifdef HAVE_SCRIPTING
4501
4502 DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd,
4503 "zebra on-rib-process script SCRIPT",
4504 ZEBRA_STR
4505 "on_rib_process_dplane_results hook call\n"
4506 "Set a script\n"
4507 "Script name (same as filename in /etc/frr/scripts/, without .lua)\n")
4508 {
4509
4510 if (frrscript_names_set_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL,
4511 argv[3]->arg)
4512 == 0) {
4513 vty_out(vty, "Successfully added script %s for hook call %s\n",
4514 argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
4515 } else {
4516 vty_out(vty, "Failed to add script %s for hook call %s\n",
4517 argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
4518 }
4519 return CMD_SUCCESS;
4520 }
4521
4522 #endif /* HAVE_SCRIPTING */
4523
4524 /* IP node for static routes. */
4525 static int zebra_ip_config(struct vty *vty);
4526 static struct cmd_node ip_node = {
4527 .name = "static ip",
4528 .node = IP_NODE,
4529 .prompt = "",
4530 .config_write = zebra_ip_config,
4531 };
4532 static int config_write_protocol(struct vty *vty);
4533 static struct cmd_node protocol_node = {
4534 .name = "protocol",
4535 .node = PROTOCOL_NODE,
4536 .prompt = "",
4537 .config_write = config_write_protocol,
4538 };
4539 /* table node for routing tables. */
4540 static int config_write_table(struct vty *vty);
4541 static struct cmd_node table_node = {
4542 .name = "table",
4543 .node = TABLE_NODE,
4544 .prompt = "",
4545 .config_write = config_write_table,
4546 };
4547 static int config_write_forwarding(struct vty *vty);
4548 static struct cmd_node forwarding_node = {
4549 .name = "forwarding",
4550 .node = FORWARDING_NODE,
4551 .prompt = "",
4552 .config_write = config_write_forwarding,
4553 };
4554
4555 /* Route VTY. */
4556 void zebra_vty_init(void)
4557 {
4558 /* Install configuration write function. */
4559 install_node(&table_node);
4560 install_node(&forwarding_node);
4561
4562 install_element(VIEW_NODE, &show_ip_forwarding_cmd);
4563 install_element(CONFIG_NODE, &ip_forwarding_cmd);
4564 install_element(CONFIG_NODE, &no_ip_forwarding_cmd);
4565 install_element(ENABLE_NODE, &show_zebra_cmd);
4566
4567 install_element(VIEW_NODE, &show_ipv6_forwarding_cmd);
4568 install_element(CONFIG_NODE, &ipv6_forwarding_cmd);
4569 install_element(CONFIG_NODE, &no_ipv6_forwarding_cmd);
4570
4571 /* Route-map */
4572 zebra_route_map_init();
4573
4574 zebra_affinity_map_init();
4575
4576 install_node(&ip_node);
4577 install_node(&protocol_node);
4578
4579 install_element(CONFIG_NODE, &allow_external_route_update_cmd);
4580 install_element(CONFIG_NODE, &no_allow_external_route_update_cmd);
4581
4582 install_element(CONFIG_NODE, &ip_multicast_mode_cmd);
4583 install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd);
4584
4585 install_element(CONFIG_NODE, &zebra_nexthop_group_keep_cmd);
4586 install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd);
4587 install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd);
4588 install_element(CONFIG_NODE, &zebra_workqueue_timer_cmd);
4589 install_element(CONFIG_NODE, &no_zebra_workqueue_timer_cmd);
4590 install_element(CONFIG_NODE, &zebra_packet_process_cmd);
4591 install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
4592 install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
4593 install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
4594 install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd);
4595
4596 install_element(VIEW_NODE, &show_nexthop_group_cmd);
4597 install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
4598
4599 install_element(VIEW_NODE, &show_vrf_cmd);
4600 install_element(VIEW_NODE, &show_vrf_vni_cmd);
4601 install_element(VIEW_NODE, &show_route_cmd);
4602 install_element(VIEW_NODE, &show_ro_cmd);
4603 install_element(VIEW_NODE, &show_route_detail_cmd);
4604 install_element(VIEW_NODE, &show_route_summary_cmd);
4605 install_element(VIEW_NODE, &show_ip_nht_cmd);
4606
4607 install_element(VIEW_NODE, &show_ip_rpf_cmd);
4608 install_element(VIEW_NODE, &show_ip_rpf_addr_cmd);
4609 install_element(VIEW_NODE, &show_ipv6_rpf_addr_cmd);
4610
4611 install_element(CONFIG_NODE, &ip_nht_default_route_cmd);
4612 install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd);
4613 install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd);
4614 install_element(CONFIG_NODE, &no_ipv6_nht_default_route_cmd);
4615 install_element(VRF_NODE, &ip_nht_default_route_cmd);
4616 install_element(VRF_NODE, &no_ip_nht_default_route_cmd);
4617 install_element(VRF_NODE, &ipv6_nht_default_route_cmd);
4618 install_element(VRF_NODE, &no_ipv6_nht_default_route_cmd);
4619 install_element(CONFIG_NODE, &rnh_hide_backups_cmd);
4620
4621 install_element(VIEW_NODE, &show_frr_cmd);
4622 install_element(VIEW_NODE, &show_evpn_global_cmd);
4623 install_element(VIEW_NODE, &show_evpn_vni_cmd);
4624 install_element(VIEW_NODE, &show_evpn_vni_detail_cmd);
4625 install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
4626 install_element(VIEW_NODE, &show_evpn_l2_nh_cmd);
4627 install_element(VIEW_NODE, &show_evpn_es_cmd);
4628 install_element(VIEW_NODE, &show_evpn_es_evi_cmd);
4629 install_element(VIEW_NODE, &show_evpn_access_vlan_cmd);
4630 install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd);
4631 install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
4632 install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
4633 install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
4634 install_element(VIEW_NODE, &show_evpn_nh_svd_ip_cmd);
4635 install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
4636 install_element(VIEW_NODE, &show_evpn_nh_svd_cmd);
4637 install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd);
4638 install_element(VIEW_NODE, &show_evpn_mac_vni_cmd);
4639 install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd);
4640 install_element(VIEW_NODE, &show_evpn_mac_vni_all_detail_cmd);
4641 install_element(VIEW_NODE, &show_evpn_mac_vni_detail_cmd);
4642 install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
4643 install_element(VIEW_NODE, &show_evpn_mac_vni_mac_cmd);
4644 install_element(VIEW_NODE, &show_evpn_mac_vni_vtep_cmd);
4645 install_element(VIEW_NODE, &show_evpn_mac_vni_dad_cmd);
4646 install_element(VIEW_NODE, &show_evpn_mac_vni_all_dad_cmd);
4647 install_element(VIEW_NODE, &show_evpn_neigh_vni_cmd);
4648 install_element(VIEW_NODE, &show_evpn_neigh_vni_all_cmd);
4649 install_element(VIEW_NODE, &show_evpn_neigh_vni_all_detail_cmd);
4650 install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
4651 install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
4652 install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd);
4653 install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd);
4654 install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd);
4655 install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd);
4656 install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd);
4657
4658 install_element(VIEW_NODE, &show_neigh_cmd);
4659
4660 install_element(VIEW_NODE, &show_pbr_ipset_cmd);
4661 install_element(VIEW_NODE, &show_pbr_iptable_cmd);
4662 install_element(VIEW_NODE, &show_pbr_rule_cmd);
4663 install_element(CONFIG_NODE, &pbr_nexthop_resolve_cmd);
4664 install_element(VIEW_NODE, &show_route_zebra_dump_cmd);
4665
4666 install_element(CONFIG_NODE, &evpn_mh_mac_holdtime_cmd);
4667 install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd);
4668 install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd);
4669 install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd);
4670 install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
4671 install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
4672 install_element(VRF_NODE, &vrf_vni_mapping_cmd);
4673 install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
4674
4675 install_element(VIEW_NODE, &show_dataplane_cmd);
4676 install_element(VIEW_NODE, &show_dataplane_providers_cmd);
4677 install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd);
4678 install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd);
4679
4680 install_element(CONFIG_NODE, &ip_table_range_cmd);
4681 install_element(VRF_NODE, &ip_table_range_cmd);
4682
4683 #ifdef HAVE_NETLINK
4684 install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd);
4685 install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);
4686 install_element(CONFIG_NODE, &zebra_protodown_bit_cmd);
4687 install_element(CONFIG_NODE, &no_zebra_protodown_bit_cmd);
4688 #endif /* HAVE_NETLINK */
4689
4690 #ifdef HAVE_SCRIPTING
4691 install_element(CONFIG_NODE, &zebra_on_rib_process_script_cmd);
4692 #endif /* HAVE_SCRIPTING */
4693
4694 install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd);
4695 }