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