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