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