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