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