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