]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_vty.c
Merge pull request #12334 from ylopez/patch-1
[mirror_frr.git] / staticd / static_vty.c
1 /*
2 * STATICd - vty code
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program 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 Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * 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 #include <zebra.h>
21
22 #include "command.h"
23 #include "vty.h"
24 #include "vrf.h"
25 #include "prefix.h"
26 #include "nexthop.h"
27 #include "table.h"
28 #include "srcdest_table.h"
29 #include "mpls.h"
30 #include "northbound.h"
31 #include "libfrr.h"
32 #include "routing_nb.h"
33 #include "northbound_cli.h"
34
35 #include "static_vrf.h"
36 #include "static_vty.h"
37 #include "static_routes.h"
38 #include "static_debug.h"
39 #include "staticd/static_vty_clippy.c"
40 #include "static_nb.h"
41
42 #define STATICD_STR "Static route daemon\n"
43
44 /** All possible route parameters available in CLI. */
45 struct static_route_args {
46 /** "no" command? */
47 bool delete;
48 /** Is VRF obtained from XPath? */
49 bool xpath_vrf;
50
51 bool onlink;
52 afi_t afi;
53 safi_t safi;
54
55 const char *vrf;
56 const char *nexthop_vrf;
57 const char *prefix;
58 const char *prefix_mask;
59 const char *source;
60 const char *gateway;
61 const char *interface_name;
62 const char *flag;
63 const char *tag;
64 const char *distance;
65 const char *label;
66 const char *table;
67 const char *color;
68 };
69
70 static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
71 {
72 int ret;
73 struct prefix p, src;
74 struct in_addr mask;
75 enum static_nh_type type;
76 const char *bh_type;
77 char xpath_prefix[XPATH_MAXLEN];
78 char xpath_nexthop[XPATH_MAXLEN];
79 char xpath_mpls[XPATH_MAXLEN];
80 char xpath_label[XPATH_MAXLEN];
81 char ab_xpath[XPATH_MAXLEN];
82 char buf_prefix[PREFIX_STRLEN];
83 char buf_src_prefix[PREFIX_STRLEN] = {};
84 char buf_nh_type[PREFIX_STRLEN] = {};
85 char buf_tag[PREFIX_STRLEN];
86 uint8_t label_stack_id = 0;
87 const char *buf_gate_str;
88 uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
89 route_tag_t tag = 0;
90 uint32_t table_id = 0;
91 const struct lyd_node *dnode;
92 const struct lyd_node *vrf_dnode;
93
94 if (args->xpath_vrf) {
95 vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
96 VTY_CURR_XPATH);
97 if (vrf_dnode == NULL) {
98 vty_out(vty,
99 "%% Failed to get vrf dnode in candidate db\n");
100 return CMD_WARNING_CONFIG_FAILED;
101 }
102
103 args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
104 } else {
105 if (args->vrf == NULL)
106 args->vrf = VRF_DEFAULT_NAME;
107 }
108 if (args->nexthop_vrf == NULL)
109 args->nexthop_vrf = args->vrf;
110
111 if (args->interface_name &&
112 !strcasecmp(args->interface_name, "Null0")) {
113 args->flag = "Null0";
114 args->interface_name = NULL;
115 }
116
117 assert(!!str2prefix(args->prefix, &p));
118
119 switch (args->afi) {
120 case AFI_IP:
121 /* Cisco like mask notation. */
122 if (args->prefix_mask) {
123 assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
124 1);
125 p.prefixlen = ip_masklen(mask);
126 }
127 break;
128 case AFI_IP6:
129 /* srcdest routing */
130 if (args->source)
131 assert(!!str2prefix(args->source, &src));
132 break;
133 default:
134 break;
135 }
136
137 /* Apply mask for given prefix. */
138 apply_mask(&p);
139 prefix2str(&p, buf_prefix, sizeof(buf_prefix));
140
141 if (args->source)
142 prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
143 if (args->gateway)
144 buf_gate_str = args->gateway;
145 else
146 buf_gate_str = "";
147
148 if (args->gateway == NULL && args->interface_name == NULL)
149 type = STATIC_BLACKHOLE;
150 else if (args->gateway && args->interface_name) {
151 if (args->afi == AFI_IP)
152 type = STATIC_IPV4_GATEWAY_IFNAME;
153 else
154 type = STATIC_IPV6_GATEWAY_IFNAME;
155 } else if (args->interface_name)
156 type = STATIC_IFNAME;
157 else {
158 if (args->afi == AFI_IP)
159 type = STATIC_IPV4_GATEWAY;
160 else
161 type = STATIC_IPV6_GATEWAY;
162 }
163
164 /* Administrative distance. */
165 if (args->distance)
166 distance = strtol(args->distance, NULL, 10);
167
168 /* tag */
169 if (args->tag)
170 tag = strtoul(args->tag, NULL, 10);
171
172 /* TableID */
173 if (args->table)
174 table_id = strtol(args->table, NULL, 10);
175
176 static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
177 if (!args->delete) {
178 if (args->source)
179 snprintf(ab_xpath, sizeof(ab_xpath),
180 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
181 "frr-staticd:staticd", "staticd", args->vrf,
182 buf_prefix,
183 yang_afi_safi_value2identity(args->afi,
184 args->safi),
185 buf_src_prefix, table_id, buf_nh_type,
186 args->nexthop_vrf, buf_gate_str,
187 args->interface_name);
188 else
189 snprintf(ab_xpath, sizeof(ab_xpath),
190 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
191 "frr-staticd:staticd", "staticd", args->vrf,
192 buf_prefix,
193 yang_afi_safi_value2identity(args->afi,
194 args->safi),
195 table_id, buf_nh_type, args->nexthop_vrf,
196 buf_gate_str, args->interface_name);
197
198 /*
199 * If there's already the same nexthop but with a different
200 * distance, then remove it for the replacement.
201 */
202 dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
203 if (dnode) {
204 dnode = yang_get_subtree_with_no_sibling(dnode);
205 assert(dnode);
206 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
207
208 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY,
209 NULL);
210 }
211
212 /* route + path procesing */
213 if (args->source)
214 snprintf(xpath_prefix, sizeof(xpath_prefix),
215 FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
216 "frr-staticd:staticd", "staticd", args->vrf,
217 buf_prefix,
218 yang_afi_safi_value2identity(args->afi,
219 args->safi),
220 buf_src_prefix, table_id, distance);
221 else
222 snprintf(xpath_prefix, sizeof(xpath_prefix),
223 FRR_STATIC_ROUTE_INFO_KEY_XPATH,
224 "frr-staticd:staticd", "staticd", args->vrf,
225 buf_prefix,
226 yang_afi_safi_value2identity(args->afi,
227 args->safi),
228 table_id, distance);
229
230 nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
231
232 /* Tag processing */
233 snprintf(buf_tag, sizeof(buf_tag), "%u", tag);
234 strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
235 strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TAG_XPATH,
236 sizeof(ab_xpath));
237 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
238
239 /* nexthop processing */
240
241 snprintf(ab_xpath, sizeof(ab_xpath),
242 FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
243 args->nexthop_vrf, buf_gate_str, args->interface_name);
244 strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
245 strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
246 nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
247
248 if (type == STATIC_BLACKHOLE) {
249 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
250 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_BH_XPATH,
251 sizeof(ab_xpath));
252
253 /* Route flags */
254 if (args->flag) {
255 switch (args->flag[0]) {
256 case 'r':
257 bh_type = "reject";
258 break;
259 case 'b':
260 bh_type = "unspec";
261 break;
262 case 'N':
263 bh_type = "null";
264 break;
265 default:
266 bh_type = NULL;
267 break;
268 }
269 nb_cli_enqueue_change(vty, ab_xpath,
270 NB_OP_MODIFY, bh_type);
271 } else {
272 nb_cli_enqueue_change(vty, ab_xpath,
273 NB_OP_MODIFY, "null");
274 }
275 }
276 if (type == STATIC_IPV4_GATEWAY_IFNAME
277 || type == STATIC_IPV6_GATEWAY_IFNAME) {
278 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
279 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
280 sizeof(ab_xpath));
281
282 if (args->onlink)
283 nb_cli_enqueue_change(vty, ab_xpath,
284 NB_OP_MODIFY, "true");
285 else
286 nb_cli_enqueue_change(vty, ab_xpath,
287 NB_OP_MODIFY, "false");
288 }
289 if (type == STATIC_IPV4_GATEWAY
290 || type == STATIC_IPV6_GATEWAY
291 || type == STATIC_IPV4_GATEWAY_IFNAME
292 || type == STATIC_IPV6_GATEWAY_IFNAME) {
293 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
294 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
295 sizeof(ab_xpath));
296 if (args->color)
297 nb_cli_enqueue_change(vty, ab_xpath,
298 NB_OP_MODIFY,
299 args->color);
300 }
301 if (args->label) {
302 /* copy of label string (start) */
303 char *ostr;
304 /* pointer to next segment */
305 char *nump;
306
307 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
308 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
309 sizeof(xpath_mpls));
310
311 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
312 NULL);
313
314 ostr = XSTRDUP(MTYPE_TMP, args->label);
315 while ((nump = strsep(&ostr, "/")) != NULL) {
316 snprintf(ab_xpath, sizeof(ab_xpath),
317 FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
318 label_stack_id);
319 strlcpy(xpath_label, xpath_mpls,
320 sizeof(xpath_label));
321 strlcat(xpath_label, ab_xpath,
322 sizeof(xpath_label));
323 nb_cli_enqueue_change(vty, xpath_label,
324 NB_OP_MODIFY, nump);
325 label_stack_id++;
326 }
327 XFREE(MTYPE_TMP, ostr);
328 } else {
329 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
330 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
331 sizeof(xpath_mpls));
332 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
333 NULL);
334 }
335 ret = nb_cli_apply_changes(vty, xpath_prefix);
336 } else {
337 if (args->source)
338 snprintf(ab_xpath, sizeof(ab_xpath),
339 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
340 "frr-staticd:staticd", "staticd", args->vrf,
341 buf_prefix,
342 yang_afi_safi_value2identity(args->afi,
343 args->safi),
344 buf_src_prefix, table_id, buf_nh_type,
345 args->nexthop_vrf, buf_gate_str,
346 args->interface_name);
347 else
348 snprintf(ab_xpath, sizeof(ab_xpath),
349 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
350 "frr-staticd:staticd", "staticd", args->vrf,
351 buf_prefix,
352 yang_afi_safi_value2identity(args->afi,
353 args->safi),
354 table_id, buf_nh_type, args->nexthop_vrf,
355 buf_gate_str, args->interface_name);
356
357 dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
358 if (!dnode) {
359 vty_out(vty,
360 "%% Refusing to remove a non-existent route\n");
361 return CMD_SUCCESS;
362 }
363
364 dnode = yang_get_subtree_with_no_sibling(dnode);
365 assert(dnode);
366 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
367
368 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
369 ret = nb_cli_apply_changes(vty, ab_xpath);
370 }
371
372 return ret;
373 }
374
375 /* Static unicast routes for multicast RPF lookup. */
376 DEFPY_YANG (ip_mroute_dist,
377 ip_mroute_dist_cmd,
378 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
379 NO_STR
380 IP_STR
381 "Configure static unicast route into MRIB for multicast RPF lookup\n"
382 "IP destination prefix (e.g. 10.0.0.0/8)\n"
383 "Nexthop address\n"
384 "Nexthop interface name\n"
385 "Distance\n")
386 {
387 struct static_route_args args = {
388 .delete = !!no,
389 .afi = AFI_IP,
390 .safi = SAFI_MULTICAST,
391 .prefix = prefix_str,
392 .gateway = gate_str,
393 .interface_name = ifname,
394 .distance = distance_str,
395 };
396
397 return static_route_nb_run(vty, &args);
398 }
399
400 /* Static route configuration. */
401 DEFPY_YANG(ip_route_blackhole,
402 ip_route_blackhole_cmd,
403 "[no] ip route\
404 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
405 <reject|blackhole>$flag \
406 [{ \
407 tag (1-4294967295) \
408 |(1-255)$distance \
409 |vrf NAME \
410 |label WORD \
411 |table (1-4294967295) \
412 }]",
413 NO_STR IP_STR
414 "Establish static routes\n"
415 "IP destination prefix (e.g. 10.0.0.0/8)\n"
416 "IP destination prefix\n"
417 "IP destination prefix mask\n"
418 "Emit an ICMP unreachable when matched\n"
419 "Silently discard pkts when matched\n"
420 "Set tag for this route\n"
421 "Tag value\n"
422 "Distance value for this route\n"
423 VRF_CMD_HELP_STR
424 MPLS_LABEL_HELPSTR
425 "Table to configure\n"
426 "The table number to configure\n")
427 {
428 struct static_route_args args = {
429 .delete = !!no,
430 .afi = AFI_IP,
431 .safi = SAFI_UNICAST,
432 .prefix = prefix,
433 .prefix_mask = mask_str,
434 .flag = flag,
435 .tag = tag_str,
436 .distance = distance_str,
437 .label = label,
438 .table = table_str,
439 .vrf = vrf,
440 };
441
442 return static_route_nb_run(vty, &args);
443 }
444
445 DEFPY_YANG(ip_route_blackhole_vrf,
446 ip_route_blackhole_vrf_cmd,
447 "[no] ip route\
448 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
449 <reject|blackhole>$flag \
450 [{ \
451 tag (1-4294967295) \
452 |(1-255)$distance \
453 |label WORD \
454 |table (1-4294967295) \
455 }]",
456 NO_STR IP_STR
457 "Establish static routes\n"
458 "IP destination prefix (e.g. 10.0.0.0/8)\n"
459 "IP destination prefix\n"
460 "IP destination prefix mask\n"
461 "Emit an ICMP unreachable when matched\n"
462 "Silently discard pkts when matched\n"
463 "Set tag for this route\n"
464 "Tag value\n"
465 "Distance value for this route\n"
466 MPLS_LABEL_HELPSTR
467 "Table to configure\n"
468 "The table number to configure\n")
469 {
470 struct static_route_args args = {
471 .delete = !!no,
472 .afi = AFI_IP,
473 .safi = SAFI_UNICAST,
474 .prefix = prefix,
475 .prefix_mask = mask_str,
476 .flag = flag,
477 .tag = tag_str,
478 .distance = distance_str,
479 .label = label,
480 .table = table_str,
481 .xpath_vrf = true,
482 };
483
484 /*
485 * Coverity is complaining that prefix could
486 * be dereferenced, but we know that prefix will
487 * valid. Add an assert to make it happy
488 */
489 assert(args.prefix);
490
491 return static_route_nb_run(vty, &args);
492 }
493
494 DEFPY_YANG(ip_route_address_interface,
495 ip_route_address_interface_cmd,
496 "[no] ip route\
497 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
498 A.B.C.D$gate \
499 <INTERFACE|Null0>$ifname \
500 [{ \
501 tag (1-4294967295) \
502 |(1-255)$distance \
503 |vrf NAME \
504 |label WORD \
505 |table (1-4294967295) \
506 |nexthop-vrf NAME \
507 |onlink$onlink \
508 |color (1-4294967295) \
509 }]",
510 NO_STR IP_STR
511 "Establish static routes\n"
512 "IP destination prefix (e.g. 10.0.0.0/8)\n"
513 "IP destination prefix\n"
514 "IP destination prefix mask\n"
515 "IP gateway address\n"
516 "IP gateway interface name\n"
517 "Null interface\n"
518 "Set tag for this route\n"
519 "Tag value\n"
520 "Distance value for this route\n"
521 VRF_CMD_HELP_STR
522 MPLS_LABEL_HELPSTR
523 "Table to configure\n"
524 "The table number to configure\n"
525 VRF_CMD_HELP_STR
526 "Treat the nexthop as directly attached to the interface\n"
527 "SR-TE color\n"
528 "The SR-TE color to configure\n")
529 {
530 struct static_route_args args = {
531 .delete = !!no,
532 .afi = AFI_IP,
533 .safi = SAFI_UNICAST,
534 .prefix = prefix,
535 .prefix_mask = mask_str,
536 .gateway = gate_str,
537 .interface_name = ifname,
538 .tag = tag_str,
539 .distance = distance_str,
540 .label = label,
541 .table = table_str,
542 .color = color_str,
543 .onlink = !!onlink,
544 .vrf = vrf,
545 .nexthop_vrf = nexthop_vrf,
546 };
547
548 return static_route_nb_run(vty, &args);
549 }
550
551 DEFPY_YANG(ip_route_address_interface_vrf,
552 ip_route_address_interface_vrf_cmd,
553 "[no] ip route\
554 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
555 A.B.C.D$gate \
556 <INTERFACE|Null0>$ifname \
557 [{ \
558 tag (1-4294967295) \
559 |(1-255)$distance \
560 |label WORD \
561 |table (1-4294967295) \
562 |nexthop-vrf NAME \
563 |onlink$onlink \
564 |color (1-4294967295) \
565 }]",
566 NO_STR IP_STR
567 "Establish static routes\n"
568 "IP destination prefix (e.g. 10.0.0.0/8)\n"
569 "IP destination prefix\n"
570 "IP destination prefix mask\n"
571 "IP gateway address\n"
572 "IP gateway interface name\n"
573 "Null interface\n"
574 "Set tag for this route\n"
575 "Tag value\n"
576 "Distance value for this route\n"
577 MPLS_LABEL_HELPSTR
578 "Table to configure\n"
579 "The table number to configure\n"
580 VRF_CMD_HELP_STR
581 "Treat the nexthop as directly attached to the interface\n"
582 "SR-TE color\n"
583 "The SR-TE color to configure\n")
584 {
585 struct static_route_args args = {
586 .delete = !!no,
587 .afi = AFI_IP,
588 .safi = SAFI_UNICAST,
589 .prefix = prefix,
590 .prefix_mask = mask_str,
591 .gateway = gate_str,
592 .interface_name = ifname,
593 .tag = tag_str,
594 .distance = distance_str,
595 .label = label,
596 .table = table_str,
597 .color = color_str,
598 .onlink = !!onlink,
599 .xpath_vrf = true,
600 .nexthop_vrf = nexthop_vrf,
601 };
602
603 return static_route_nb_run(vty, &args);
604 }
605
606 DEFPY_YANG(ip_route,
607 ip_route_cmd,
608 "[no] ip route\
609 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
610 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
611 [{ \
612 tag (1-4294967295) \
613 |(1-255)$distance \
614 |vrf NAME \
615 |label WORD \
616 |table (1-4294967295) \
617 |nexthop-vrf NAME \
618 |color (1-4294967295) \
619 }]",
620 NO_STR IP_STR
621 "Establish static routes\n"
622 "IP destination prefix (e.g. 10.0.0.0/8)\n"
623 "IP destination prefix\n"
624 "IP destination prefix mask\n"
625 "IP gateway address\n"
626 "IP gateway interface name\n"
627 "Null interface\n"
628 "Set tag for this route\n"
629 "Tag value\n"
630 "Distance value for this route\n"
631 VRF_CMD_HELP_STR
632 MPLS_LABEL_HELPSTR
633 "Table to configure\n"
634 "The table number to configure\n"
635 VRF_CMD_HELP_STR
636 "SR-TE color\n"
637 "The SR-TE color to configure\n")
638 {
639 struct static_route_args args = {
640 .delete = !!no,
641 .afi = AFI_IP,
642 .safi = SAFI_UNICAST,
643 .prefix = prefix,
644 .prefix_mask = mask_str,
645 .gateway = gate_str,
646 .interface_name = ifname,
647 .tag = tag_str,
648 .distance = distance_str,
649 .label = label,
650 .table = table_str,
651 .color = color_str,
652 .vrf = vrf,
653 .nexthop_vrf = nexthop_vrf,
654 };
655
656 return static_route_nb_run(vty, &args);
657 }
658
659 DEFPY_YANG(ip_route_vrf,
660 ip_route_vrf_cmd,
661 "[no] ip route\
662 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
663 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
664 [{ \
665 tag (1-4294967295) \
666 |(1-255)$distance \
667 |label WORD \
668 |table (1-4294967295) \
669 |nexthop-vrf NAME \
670 |color (1-4294967295) \
671 }]",
672 NO_STR IP_STR
673 "Establish static routes\n"
674 "IP destination prefix (e.g. 10.0.0.0/8)\n"
675 "IP destination prefix\n"
676 "IP destination prefix mask\n"
677 "IP gateway address\n"
678 "IP gateway interface name\n"
679 "Null interface\n"
680 "Set tag for this route\n"
681 "Tag value\n"
682 "Distance value for this route\n"
683 MPLS_LABEL_HELPSTR
684 "Table to configure\n"
685 "The table number to configure\n"
686 VRF_CMD_HELP_STR
687 "SR-TE color\n"
688 "The SR-TE color to configure\n")
689 {
690 struct static_route_args args = {
691 .delete = !!no,
692 .afi = AFI_IP,
693 .safi = SAFI_UNICAST,
694 .prefix = prefix,
695 .prefix_mask = mask_str,
696 .gateway = gate_str,
697 .interface_name = ifname,
698 .tag = tag_str,
699 .distance = distance_str,
700 .label = label,
701 .table = table_str,
702 .color = color_str,
703 .xpath_vrf = true,
704 .nexthop_vrf = nexthop_vrf,
705 };
706
707 return static_route_nb_run(vty, &args);
708 }
709
710 DEFPY_YANG(ipv6_route_blackhole,
711 ipv6_route_blackhole_cmd,
712 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
713 <reject|blackhole>$flag \
714 [{ \
715 tag (1-4294967295) \
716 |(1-255)$distance \
717 |vrf NAME \
718 |label WORD \
719 |table (1-4294967295) \
720 }]",
721 NO_STR
722 IPV6_STR
723 "Establish static routes\n"
724 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
725 "IPv6 source-dest route\n"
726 "IPv6 source prefix\n"
727 "Emit an ICMP unreachable when matched\n"
728 "Silently discard pkts when matched\n"
729 "Set tag for this route\n"
730 "Tag value\n"
731 "Distance value for this prefix\n"
732 VRF_CMD_HELP_STR
733 MPLS_LABEL_HELPSTR
734 "Table to configure\n"
735 "The table number to configure\n")
736 {
737 struct static_route_args args = {
738 .delete = !!no,
739 .afi = AFI_IP6,
740 .safi = SAFI_UNICAST,
741 .prefix = prefix_str,
742 .source = from_str,
743 .flag = flag,
744 .tag = tag_str,
745 .distance = distance_str,
746 .label = label,
747 .table = table_str,
748 .vrf = vrf,
749 };
750
751 return static_route_nb_run(vty, &args);
752 }
753
754 DEFPY_YANG(ipv6_route_blackhole_vrf,
755 ipv6_route_blackhole_vrf_cmd,
756 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
757 <reject|blackhole>$flag \
758 [{ \
759 tag (1-4294967295) \
760 |(1-255)$distance \
761 |label WORD \
762 |table (1-4294967295) \
763 }]",
764 NO_STR
765 IPV6_STR
766 "Establish static routes\n"
767 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
768 "IPv6 source-dest route\n"
769 "IPv6 source prefix\n"
770 "Emit an ICMP unreachable when matched\n"
771 "Silently discard pkts when matched\n"
772 "Set tag for this route\n"
773 "Tag value\n"
774 "Distance value for this prefix\n"
775 MPLS_LABEL_HELPSTR
776 "Table to configure\n"
777 "The table number to configure\n")
778 {
779 struct static_route_args args = {
780 .delete = !!no,
781 .afi = AFI_IP6,
782 .safi = SAFI_UNICAST,
783 .prefix = prefix_str,
784 .source = from_str,
785 .flag = flag,
786 .tag = tag_str,
787 .distance = distance_str,
788 .label = label,
789 .table = table_str,
790 .xpath_vrf = true,
791 };
792
793 /*
794 * Coverity is complaining that prefix could
795 * be dereferenced, but we know that prefix will
796 * valid. Add an assert to make it happy
797 */
798 assert(args.prefix);
799
800 return static_route_nb_run(vty, &args);
801 }
802
803 DEFPY_YANG(ipv6_route_address_interface,
804 ipv6_route_address_interface_cmd,
805 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
806 X:X::X:X$gate \
807 <INTERFACE|Null0>$ifname \
808 [{ \
809 tag (1-4294967295) \
810 |(1-255)$distance \
811 |vrf NAME \
812 |label WORD \
813 |table (1-4294967295) \
814 |nexthop-vrf NAME \
815 |onlink$onlink \
816 |color (1-4294967295) \
817 }]",
818 NO_STR
819 IPV6_STR
820 "Establish static routes\n"
821 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
822 "IPv6 source-dest route\n"
823 "IPv6 source prefix\n"
824 "IPv6 gateway address\n"
825 "IPv6 gateway interface name\n"
826 "Null interface\n"
827 "Set tag for this route\n"
828 "Tag value\n"
829 "Distance value for this prefix\n"
830 VRF_CMD_HELP_STR
831 MPLS_LABEL_HELPSTR
832 "Table to configure\n"
833 "The table number to configure\n"
834 VRF_CMD_HELP_STR
835 "Treat the nexthop as directly attached to the interface\n"
836 "SR-TE color\n"
837 "The SR-TE color to configure\n")
838 {
839 struct static_route_args args = {
840 .delete = !!no,
841 .afi = AFI_IP6,
842 .safi = SAFI_UNICAST,
843 .prefix = prefix_str,
844 .source = from_str,
845 .gateway = gate_str,
846 .interface_name = ifname,
847 .tag = tag_str,
848 .distance = distance_str,
849 .label = label,
850 .table = table_str,
851 .color = color_str,
852 .onlink = !!onlink,
853 .vrf = vrf,
854 .nexthop_vrf = nexthop_vrf,
855 };
856
857 return static_route_nb_run(vty, &args);
858 }
859
860 DEFPY_YANG(ipv6_route_address_interface_vrf,
861 ipv6_route_address_interface_vrf_cmd,
862 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
863 X:X::X:X$gate \
864 <INTERFACE|Null0>$ifname \
865 [{ \
866 tag (1-4294967295) \
867 |(1-255)$distance \
868 |label WORD \
869 |table (1-4294967295) \
870 |nexthop-vrf NAME \
871 |onlink$onlink \
872 |color (1-4294967295) \
873 }]",
874 NO_STR
875 IPV6_STR
876 "Establish static routes\n"
877 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
878 "IPv6 source-dest route\n"
879 "IPv6 source prefix\n"
880 "IPv6 gateway address\n"
881 "IPv6 gateway interface name\n"
882 "Null interface\n"
883 "Set tag for this route\n"
884 "Tag value\n"
885 "Distance value for this prefix\n"
886 MPLS_LABEL_HELPSTR
887 "Table to configure\n"
888 "The table number to configure\n"
889 VRF_CMD_HELP_STR
890 "Treat the nexthop as directly attached to the interface\n"
891 "SR-TE color\n"
892 "The SR-TE color to configure\n")
893 {
894 struct static_route_args args = {
895 .delete = !!no,
896 .afi = AFI_IP6,
897 .safi = SAFI_UNICAST,
898 .prefix = prefix_str,
899 .source = from_str,
900 .gateway = gate_str,
901 .interface_name = ifname,
902 .tag = tag_str,
903 .distance = distance_str,
904 .label = label,
905 .table = table_str,
906 .color = color_str,
907 .onlink = !!onlink,
908 .xpath_vrf = true,
909 .nexthop_vrf = nexthop_vrf,
910 };
911
912 return static_route_nb_run(vty, &args);
913 }
914
915 DEFPY_YANG(ipv6_route,
916 ipv6_route_cmd,
917 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
918 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
919 [{ \
920 tag (1-4294967295) \
921 |(1-255)$distance \
922 |vrf NAME \
923 |label WORD \
924 |table (1-4294967295) \
925 |nexthop-vrf NAME \
926 |color (1-4294967295) \
927 }]",
928 NO_STR
929 IPV6_STR
930 "Establish static routes\n"
931 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
932 "IPv6 source-dest route\n"
933 "IPv6 source prefix\n"
934 "IPv6 gateway address\n"
935 "IPv6 gateway interface name\n"
936 "Null interface\n"
937 "Set tag for this route\n"
938 "Tag value\n"
939 "Distance value for this prefix\n"
940 VRF_CMD_HELP_STR
941 MPLS_LABEL_HELPSTR
942 "Table to configure\n"
943 "The table number to configure\n"
944 VRF_CMD_HELP_STR
945 "SR-TE color\n"
946 "The SR-TE color to configure\n")
947 {
948 struct static_route_args args = {
949 .delete = !!no,
950 .afi = AFI_IP6,
951 .safi = SAFI_UNICAST,
952 .prefix = prefix_str,
953 .source = from_str,
954 .gateway = gate_str,
955 .interface_name = ifname,
956 .tag = tag_str,
957 .distance = distance_str,
958 .label = label,
959 .table = table_str,
960 .color = color_str,
961 .vrf = vrf,
962 .nexthop_vrf = nexthop_vrf,
963 };
964
965 return static_route_nb_run(vty, &args);
966 }
967
968 DEFPY_YANG(ipv6_route_vrf,
969 ipv6_route_vrf_cmd,
970 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
971 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
972 [{ \
973 tag (1-4294967295) \
974 |(1-255)$distance \
975 |label WORD \
976 |table (1-4294967295) \
977 |nexthop-vrf NAME \
978 |color (1-4294967295) \
979 }]",
980 NO_STR
981 IPV6_STR
982 "Establish static routes\n"
983 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
984 "IPv6 source-dest route\n"
985 "IPv6 source prefix\n"
986 "IPv6 gateway address\n"
987 "IPv6 gateway interface name\n"
988 "Null interface\n"
989 "Set tag for this route\n"
990 "Tag value\n"
991 "Distance value for this prefix\n"
992 MPLS_LABEL_HELPSTR
993 "Table to configure\n"
994 "The table number to configure\n"
995 VRF_CMD_HELP_STR
996 "SR-TE color\n"
997 "The SR-TE color to configure\n")
998 {
999 struct static_route_args args = {
1000 .delete = !!no,
1001 .afi = AFI_IP6,
1002 .safi = SAFI_UNICAST,
1003 .prefix = prefix_str,
1004 .source = from_str,
1005 .gateway = gate_str,
1006 .interface_name = ifname,
1007 .tag = tag_str,
1008 .distance = distance_str,
1009 .label = label,
1010 .table = table_str,
1011 .color = color_str,
1012 .xpath_vrf = true,
1013 .nexthop_vrf = nexthop_vrf,
1014 };
1015
1016 return static_route_nb_run(vty, &args);
1017 }
1018
1019 void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
1020 bool show_defaults)
1021 {
1022 const char *vrf;
1023
1024 vrf = yang_dnode_get_string(dnode, "../vrf");
1025 if (strcmp(vrf, VRF_DEFAULT_NAME))
1026 vty_out(vty, "vrf %s\n", vrf);
1027 }
1028
1029 void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
1030 {
1031 const char *vrf;
1032
1033 vrf = yang_dnode_get_string(dnode, "../vrf");
1034 if (strcmp(vrf, VRF_DEFAULT_NAME))
1035 vty_out(vty, "exit-vrf\n");
1036 }
1037
1038 struct mpls_label_iter {
1039 struct vty *vty;
1040 bool first;
1041 };
1042
1043 static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg)
1044 {
1045 struct mpls_label_iter *iter = arg;
1046
1047 if (yang_dnode_exists(dnode, "./label")) {
1048 if (iter->first)
1049 vty_out(iter->vty, " label %s",
1050 yang_dnode_get_string(dnode, "./label"));
1051 else
1052 vty_out(iter->vty, "/%s",
1053 yang_dnode_get_string(dnode, "./label"));
1054 iter->first = false;
1055 }
1056
1057 return YANG_ITER_CONTINUE;
1058 }
1059
1060 static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route,
1061 const struct lyd_node *src,
1062 const struct lyd_node *path,
1063 const struct lyd_node *nexthop, bool show_defaults)
1064 {
1065 const char *vrf;
1066 const char *afi_safi;
1067 afi_t afi;
1068 safi_t safi;
1069 enum static_nh_type nh_type;
1070 enum static_blackhole_type bh_type;
1071 uint32_t tag;
1072 uint8_t distance;
1073 struct mpls_label_iter iter;
1074 const char *nexthop_vrf;
1075 uint32_t table_id;
1076 bool onlink;
1077
1078 vrf = yang_dnode_get_string(route, "../../vrf");
1079
1080 afi_safi = yang_dnode_get_string(route, "./afi-safi");
1081 yang_afi_safi_identity2value(afi_safi, &afi, &safi);
1082
1083 if (afi == AFI_IP)
1084 vty_out(vty, "%sip",
1085 strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
1086 else
1087 vty_out(vty, "%sipv6",
1088 strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
1089
1090 if (safi == SAFI_UNICAST)
1091 vty_out(vty, " route");
1092 else
1093 vty_out(vty, " mroute");
1094
1095 vty_out(vty, " %s", yang_dnode_get_string(route, "./prefix"));
1096
1097 if (src)
1098 vty_out(vty, " from %s",
1099 yang_dnode_get_string(src, "./src-prefix"));
1100
1101 nh_type = yang_dnode_get_enum(nexthop, "./nh-type");
1102 switch (nh_type) {
1103 case STATIC_IFNAME:
1104 vty_out(vty, " %s",
1105 yang_dnode_get_string(nexthop, "./interface"));
1106 break;
1107 case STATIC_IPV4_GATEWAY:
1108 case STATIC_IPV6_GATEWAY:
1109 vty_out(vty, " %s",
1110 yang_dnode_get_string(nexthop, "./gateway"));
1111 break;
1112 case STATIC_IPV4_GATEWAY_IFNAME:
1113 case STATIC_IPV6_GATEWAY_IFNAME:
1114 vty_out(vty, " %s",
1115 yang_dnode_get_string(nexthop, "./gateway"));
1116 vty_out(vty, " %s",
1117 yang_dnode_get_string(nexthop, "./interface"));
1118 break;
1119 case STATIC_BLACKHOLE:
1120 bh_type = yang_dnode_get_enum(nexthop, "./bh-type");
1121 switch (bh_type) {
1122 case STATIC_BLACKHOLE_DROP:
1123 vty_out(vty, " blackhole");
1124 break;
1125 case STATIC_BLACKHOLE_NULL:
1126 vty_out(vty, " Null0");
1127 break;
1128 case STATIC_BLACKHOLE_REJECT:
1129 vty_out(vty, " reject");
1130 break;
1131 }
1132 break;
1133 }
1134
1135 if (yang_dnode_exists(path, "./tag")) {
1136 tag = yang_dnode_get_uint32(path, "./tag");
1137 if (tag != 0 || show_defaults)
1138 vty_out(vty, " tag %" PRIu32, tag);
1139 }
1140
1141 distance = yang_dnode_get_uint8(path, "./distance");
1142 if (distance != ZEBRA_STATIC_DISTANCE_DEFAULT || show_defaults)
1143 vty_out(vty, " %" PRIu8, distance);
1144
1145 iter.vty = vty;
1146 iter.first = true;
1147 yang_dnode_iterate(mpls_label_iter_cb, &iter, nexthop,
1148 "./mpls-label-stack/entry");
1149
1150 nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf");
1151 if (strcmp(vrf, nexthop_vrf))
1152 vty_out(vty, " nexthop-vrf %s", nexthop_vrf);
1153
1154 table_id = yang_dnode_get_uint32(path, "./table-id");
1155 if (table_id || show_defaults)
1156 vty_out(vty, " table %" PRIu32, table_id);
1157
1158 if (yang_dnode_exists(nexthop, "./onlink")) {
1159 onlink = yang_dnode_get_bool(nexthop, "./onlink");
1160 if (onlink)
1161 vty_out(vty, " onlink");
1162 }
1163
1164 if (yang_dnode_exists(nexthop, "./srte-color"))
1165 vty_out(vty, " color %s",
1166 yang_dnode_get_string(nexthop, "./srte-color"));
1167
1168 vty_out(vty, "\n");
1169 }
1170
1171 void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
1172 bool show_defaults)
1173 {
1174 const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
1175 const struct lyd_node *route =
1176 yang_dnode_get_parent(path, "route-list");
1177
1178 nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults);
1179 }
1180
1181 void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
1182 bool show_defaults)
1183 {
1184 const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
1185 const struct lyd_node *src = yang_dnode_get_parent(path, "src-list");
1186 const struct lyd_node *route = yang_dnode_get_parent(src, "route-list");
1187
1188 nexthop_cli_show(vty, route, src, path, dnode, show_defaults);
1189 }
1190
1191 int static_nexthop_cli_cmp(const struct lyd_node *dnode1,
1192 const struct lyd_node *dnode2)
1193 {
1194 enum static_nh_type nh_type1, nh_type2;
1195 struct prefix prefix1, prefix2;
1196 int ret = 0;
1197
1198 nh_type1 = yang_dnode_get_enum(dnode1, "./nh-type");
1199 nh_type2 = yang_dnode_get_enum(dnode2, "./nh-type");
1200
1201 if (nh_type1 != nh_type2)
1202 return (int)nh_type1 - (int)nh_type2;
1203
1204 switch (nh_type1) {
1205 case STATIC_IFNAME:
1206 ret = if_cmp_name_func(
1207 yang_dnode_get_string(dnode1, "./interface"),
1208 yang_dnode_get_string(dnode2, "./interface"));
1209 break;
1210 case STATIC_IPV4_GATEWAY:
1211 case STATIC_IPV6_GATEWAY:
1212 yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
1213 yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
1214 ret = prefix_cmp(&prefix1, &prefix2);
1215 break;
1216 case STATIC_IPV4_GATEWAY_IFNAME:
1217 case STATIC_IPV6_GATEWAY_IFNAME:
1218 yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
1219 yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
1220 ret = prefix_cmp(&prefix1, &prefix2);
1221 if (!ret)
1222 ret = if_cmp_name_func(
1223 yang_dnode_get_string(dnode1, "./interface"),
1224 yang_dnode_get_string(dnode2, "./interface"));
1225 break;
1226 case STATIC_BLACKHOLE:
1227 /* There's only one blackhole nexthop per route */
1228 ret = 0;
1229 break;
1230 }
1231
1232 if (ret)
1233 return ret;
1234
1235 return if_cmp_name_func(yang_dnode_get_string(dnode1, "./vrf"),
1236 yang_dnode_get_string(dnode2, "./vrf"));
1237 }
1238
1239 int static_route_list_cli_cmp(const struct lyd_node *dnode1,
1240 const struct lyd_node *dnode2)
1241 {
1242 const char *afi_safi1, *afi_safi2;
1243 afi_t afi1, afi2;
1244 safi_t safi1, safi2;
1245 struct prefix prefix1, prefix2;
1246
1247 afi_safi1 = yang_dnode_get_string(dnode1, "./afi-safi");
1248 yang_afi_safi_identity2value(afi_safi1, &afi1, &safi1);
1249
1250 afi_safi2 = yang_dnode_get_string(dnode2, "./afi-safi");
1251 yang_afi_safi_identity2value(afi_safi2, &afi2, &safi2);
1252
1253 if (afi1 != afi2)
1254 return (int)afi1 - (int)afi2;
1255
1256 if (safi1 != safi2)
1257 return (int)safi1 - (int)safi2;
1258
1259 yang_dnode_get_prefix(&prefix1, dnode1, "./prefix");
1260 yang_dnode_get_prefix(&prefix2, dnode2, "./prefix");
1261
1262 return prefix_cmp(&prefix1, &prefix2);
1263 }
1264
1265 int static_src_list_cli_cmp(const struct lyd_node *dnode1,
1266 const struct lyd_node *dnode2)
1267 {
1268 struct prefix prefix1, prefix2;
1269
1270 yang_dnode_get_prefix(&prefix1, dnode1, "./src-prefix");
1271 yang_dnode_get_prefix(&prefix2, dnode2, "./src-prefix");
1272
1273 return prefix_cmp(&prefix1, &prefix2);
1274 }
1275
1276 int static_path_list_cli_cmp(const struct lyd_node *dnode1,
1277 const struct lyd_node *dnode2)
1278 {
1279 uint32_t table_id1, table_id2;
1280 uint8_t distance1, distance2;
1281
1282 table_id1 = yang_dnode_get_uint32(dnode1, "./table-id");
1283 table_id2 = yang_dnode_get_uint32(dnode2, "./table-id");
1284
1285 if (table_id1 != table_id2)
1286 return (int)table_id1 - (int)table_id2;
1287
1288 distance1 = yang_dnode_get_uint8(dnode1, "./distance");
1289 distance2 = yang_dnode_get_uint8(dnode2, "./distance");
1290
1291 return (int)distance1 - (int)distance2;
1292 }
1293
1294 DEFPY_YANG(debug_staticd, debug_staticd_cmd,
1295 "[no] debug static [{events$events|route$route}]",
1296 NO_STR DEBUG_STR STATICD_STR
1297 "Debug events\n"
1298 "Debug route\n")
1299 {
1300 /* If no specific category, change all */
1301 if (strmatch(argv[argc - 1]->text, "static"))
1302 static_debug_set(vty->node, !no, true, true);
1303 else
1304 static_debug_set(vty->node, !no, !!events, !!route);
1305
1306 return CMD_SUCCESS;
1307 }
1308
1309 DEFUN_NOSH (show_debugging_static,
1310 show_debugging_static_cmd,
1311 "show debugging [static]",
1312 SHOW_STR
1313 DEBUG_STR
1314 "Static Information\n")
1315 {
1316 vty_out(vty, "Staticd debugging status\n");
1317
1318 static_debug_status_write(vty);
1319
1320 cmd_show_lib_debugs(vty);
1321
1322 return CMD_SUCCESS;
1323 }
1324
1325 static struct cmd_node debug_node = {
1326 .name = "debug",
1327 .node = DEBUG_NODE,
1328 .prompt = "",
1329 .config_write = static_config_write_debug,
1330 };
1331
1332 void static_vty_init(void)
1333 {
1334 install_node(&debug_node);
1335
1336 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1337
1338 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1339 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1340 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1341 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1342 install_element(CONFIG_NODE, &ip_route_cmd);
1343 install_element(VRF_NODE, &ip_route_vrf_cmd);
1344
1345 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1346 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1347 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1348 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1349 install_element(CONFIG_NODE, &ipv6_route_cmd);
1350 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1351
1352 install_element(ENABLE_NODE, &show_debugging_static_cmd);
1353 install_element(ENABLE_NODE, &debug_staticd_cmd);
1354 install_element(CONFIG_NODE, &debug_staticd_cmd);
1355 }