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