]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_vty.c
Merge pull request #7840 from pguibert6WIND/bfd_misc_fixes_vrflite
[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 return ret;
299
300 dnode = yang_get_subtree_with_no_sibling(dnode);
301 assert(dnode);
302 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
303
304 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
305 ret = nb_cli_apply_changes(vty, ab_xpath);
306 }
307
308 return ret;
309 }
310 static int static_route(struct vty *vty, afi_t afi, safi_t safi,
311 const char *negate, const char *dest_str,
312 const char *mask_str, const char *src_str,
313 const char *gate_str, const char *ifname,
314 const char *flag_str, const char *tag_str,
315 const char *distance_str, const char *vrf_name,
316 const char *label_str, const char *table_str)
317 {
318 if (!vrf_name)
319 vrf_name = VRF_DEFAULT_NAME;
320
321 return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
322 dest_str, mask_str, src_str, gate_str, ifname,
323 flag_str, tag_str, distance_str, label_str,
324 table_str, false, NULL);
325 }
326
327 /* Write static route configuration. */
328 int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
329 safi_t safi, const char *cmd)
330 {
331 char spacing[100];
332 struct route_node *rn;
333 struct static_nexthop *nh;
334 struct static_path *pn;
335 struct route_table *stable;
336 struct static_route_info *si;
337 char buf[SRCDEST2STR_BUFFER];
338 int write = 0;
339 struct stable_info *info;
340
341 stable = svrf->stable[afi][safi];
342 if (stable == NULL)
343 return write;
344
345 snprintf(spacing, sizeof(spacing), "%s%s",
346 (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", cmd);
347
348 for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
349 si = static_route_info_from_rnode(rn);
350 if (!si)
351 continue;
352 info = static_get_stable_info(rn);
353 frr_each(static_path_list, &si->path_list, pn) {
354 frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
355 vty_out(vty, "%s %s", spacing,
356 srcdest_rnode2str(rn, buf,
357 sizeof(buf)));
358
359 switch (nh->type) {
360 case STATIC_IPV4_GATEWAY:
361 vty_out(vty, " %pI4", &nh->addr.ipv4);
362 break;
363 case STATIC_IPV6_GATEWAY:
364 vty_out(vty, " %s",
365 inet_ntop(AF_INET6,
366 &nh->addr.ipv6, buf,
367 sizeof(buf)));
368 break;
369 case STATIC_IFNAME:
370 vty_out(vty, " %s", nh->ifname);
371 break;
372 case STATIC_BLACKHOLE:
373 switch (nh->bh_type) {
374 case STATIC_BLACKHOLE_DROP:
375 vty_out(vty, " blackhole");
376 break;
377 case STATIC_BLACKHOLE_NULL:
378 vty_out(vty, " Null0");
379 break;
380 case STATIC_BLACKHOLE_REJECT:
381 vty_out(vty, " reject");
382 break;
383 }
384 break;
385 case STATIC_IPV4_GATEWAY_IFNAME:
386 vty_out(vty, " %s %s",
387 inet_ntop(AF_INET,
388 &nh->addr.ipv4, buf,
389 sizeof(buf)),
390 nh->ifname);
391 break;
392 case STATIC_IPV6_GATEWAY_IFNAME:
393 vty_out(vty, " %s %s",
394 inet_ntop(AF_INET6,
395 &nh->addr.ipv6, buf,
396 sizeof(buf)),
397 nh->ifname);
398 break;
399 }
400
401 if (pn->tag)
402 vty_out(vty, " tag %" ROUTE_TAG_PRI,
403 pn->tag);
404
405 if (pn->distance
406 != ZEBRA_STATIC_DISTANCE_DEFAULT)
407 vty_out(vty, " %u", pn->distance);
408
409 /* Label information */
410 if (nh->snh_label.num_labels)
411 vty_out(vty, " label %s",
412 mpls_label2str(
413 nh->snh_label
414 .num_labels,
415 nh->snh_label.label,
416 buf, sizeof(buf), 0));
417
418 if (!strmatch(nh->nh_vrfname,
419 info->svrf->vrf->name))
420 vty_out(vty, " nexthop-vrf %s",
421 nh->nh_vrfname);
422
423 /*
424 * table ID from VRF overrides
425 * configured
426 */
427 if (pn->table_id
428 && svrf->vrf->data.l.table_id
429 == RT_TABLE_MAIN)
430 vty_out(vty, " table %u", pn->table_id);
431
432 if (nh->onlink)
433 vty_out(vty, " onlink");
434
435 /*
436 * SR-TE color
437 */
438 if (nh->color != 0)
439 vty_out(vty, " color %u", nh->color);
440
441 vty_out(vty, "\n");
442
443 write = 1;
444 }
445 }
446 }
447 return write;
448 }
449
450 /* Static unicast routes for multicast RPF lookup. */
451 DEFPY_YANG (ip_mroute_dist,
452 ip_mroute_dist_cmd,
453 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
454 NO_STR
455 IP_STR
456 "Configure static unicast route into MRIB for multicast RPF lookup\n"
457 "IP destination prefix (e.g. 10.0.0.0/8)\n"
458 "Nexthop address\n"
459 "Nexthop interface name\n"
460 "Distance\n")
461 {
462 return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
463 NULL, NULL, gate_str, ifname, NULL, NULL,
464 distance_str, NULL, NULL, NULL);
465 }
466
467 /* Static route configuration. */
468 DEFPY_YANG(ip_route_blackhole,
469 ip_route_blackhole_cmd,
470 "[no] ip route\
471 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
472 <reject|blackhole>$flag \
473 [{ \
474 tag (1-4294967295) \
475 |(1-255)$distance \
476 |vrf NAME \
477 |label WORD \
478 |table (1-4294967295) \
479 }]",
480 NO_STR IP_STR
481 "Establish static routes\n"
482 "IP destination prefix (e.g. 10.0.0.0/8)\n"
483 "IP destination prefix\n"
484 "IP destination prefix mask\n"
485 "Emit an ICMP unreachable when matched\n"
486 "Silently discard pkts when matched\n"
487 "Set tag for this route\n"
488 "Tag value\n"
489 "Distance value for this route\n"
490 VRF_CMD_HELP_STR
491 MPLS_LABEL_HELPSTR
492 "Table to configure\n"
493 "The table number to configure\n")
494 {
495 return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
496 mask_str, NULL, NULL, NULL, flag, tag_str,
497 distance_str, vrf, label, table_str);
498 }
499
500 DEFPY_YANG(ip_route_blackhole_vrf,
501 ip_route_blackhole_vrf_cmd,
502 "[no] ip route\
503 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
504 <reject|blackhole>$flag \
505 [{ \
506 tag (1-4294967295) \
507 |(1-255)$distance \
508 |label WORD \
509 |table (1-4294967295) \
510 }]",
511 NO_STR IP_STR
512 "Establish static routes\n"
513 "IP destination prefix (e.g. 10.0.0.0/8)\n"
514 "IP destination prefix\n"
515 "IP destination prefix mask\n"
516 "Emit an ICMP unreachable when matched\n"
517 "Silently discard pkts when matched\n"
518 "Set tag for this route\n"
519 "Tag value\n"
520 "Distance value for this route\n"
521 MPLS_LABEL_HELPSTR
522 "Table to configure\n"
523 "The table number to configure\n")
524 {
525 const struct lyd_node *vrf_dnode;
526 const char *vrfname;
527
528 vrf_dnode =
529 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
530 if (!vrf_dnode) {
531 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
532 return CMD_WARNING_CONFIG_FAILED;
533 }
534 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
535 /*
536 * Coverity is complaining that prefix could
537 * be dereferenced, but we know that prefix will
538 * valid. Add an assert to make it happy
539 */
540 assert(prefix);
541 return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
542 no, prefix, mask_str, NULL, NULL, NULL, flag,
543 tag_str, distance_str, label, table_str,
544 false, NULL);
545 }
546
547 DEFPY_YANG(ip_route_address_interface,
548 ip_route_address_interface_cmd,
549 "[no] ip route\
550 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
551 A.B.C.D$gate \
552 <INTERFACE|Null0>$ifname \
553 [{ \
554 tag (1-4294967295) \
555 |(1-255)$distance \
556 |vrf NAME \
557 |label WORD \
558 |table (1-4294967295) \
559 |nexthop-vrf NAME \
560 |onlink$onlink \
561 |color (1-4294967295) \
562 }]",
563 NO_STR IP_STR
564 "Establish static routes\n"
565 "IP destination prefix (e.g. 10.0.0.0/8)\n"
566 "IP destination prefix\n"
567 "IP destination prefix mask\n"
568 "IP gateway address\n"
569 "IP gateway interface name\n"
570 "Null interface\n"
571 "Set tag for this route\n"
572 "Tag value\n"
573 "Distance value for this route\n"
574 VRF_CMD_HELP_STR
575 MPLS_LABEL_HELPSTR
576 "Table to configure\n"
577 "The table number to configure\n"
578 VRF_CMD_HELP_STR
579 "Treat the nexthop as directly attached to the interface\n"
580 "SR-TE color\n"
581 "The SR-TE color to configure\n")
582 {
583 const char *nh_vrf;
584 const char *flag = NULL;
585
586 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
587 flag = "Null0";
588 ifname = NULL;
589 }
590 if (!vrf)
591 vrf = VRF_DEFAULT_NAME;
592
593 if (nexthop_vrf)
594 nh_vrf = nexthop_vrf;
595 else
596 nh_vrf = vrf;
597
598 return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
599 prefix, mask_str, NULL, gate_str, ifname, flag,
600 tag_str, distance_str, label, table_str,
601 !!onlink, color_str);
602 }
603
604 DEFPY_YANG(ip_route_address_interface_vrf,
605 ip_route_address_interface_vrf_cmd,
606 "[no] ip route\
607 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
608 A.B.C.D$gate \
609 <INTERFACE|Null0>$ifname \
610 [{ \
611 tag (1-4294967295) \
612 |(1-255)$distance \
613 |label WORD \
614 |table (1-4294967295) \
615 |nexthop-vrf NAME \
616 |onlink$onlink \
617 |color (1-4294967295) \
618 }]",
619 NO_STR IP_STR
620 "Establish static routes\n"
621 "IP destination prefix (e.g. 10.0.0.0/8)\n"
622 "IP destination prefix\n"
623 "IP destination prefix mask\n"
624 "IP gateway address\n"
625 "IP gateway interface name\n"
626 "Null interface\n"
627 "Set tag for this route\n"
628 "Tag value\n"
629 "Distance value for this route\n"
630 MPLS_LABEL_HELPSTR
631 "Table to configure\n"
632 "The table number to configure\n"
633 VRF_CMD_HELP_STR
634 "Treat the nexthop as directly attached to the interface\n"
635 "SR-TE color\n"
636 "The SR-TE color to configure\n")
637 {
638 const char *nh_vrf;
639 const char *flag = NULL;
640 const struct lyd_node *vrf_dnode;
641 const char *vrfname;
642
643 vrf_dnode =
644 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
645 if (!vrf_dnode) {
646 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
647 return CMD_WARNING_CONFIG_FAILED;
648 }
649 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
650
651 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
652 flag = "Null0";
653 ifname = NULL;
654 }
655 if (nexthop_vrf)
656 nh_vrf = nexthop_vrf;
657 else
658 nh_vrf = vrfname;
659
660 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
661 prefix, mask_str, NULL, gate_str, ifname, flag,
662 tag_str, distance_str, label, table_str,
663 !!onlink, color_str);
664 }
665
666 DEFPY_YANG(ip_route,
667 ip_route_cmd,
668 "[no] ip route\
669 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
670 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
671 [{ \
672 tag (1-4294967295) \
673 |(1-255)$distance \
674 |vrf NAME \
675 |label WORD \
676 |table (1-4294967295) \
677 |nexthop-vrf NAME \
678 |color (1-4294967295) \
679 }]",
680 NO_STR IP_STR
681 "Establish static routes\n"
682 "IP destination prefix (e.g. 10.0.0.0/8)\n"
683 "IP destination prefix\n"
684 "IP destination prefix mask\n"
685 "IP gateway address\n"
686 "IP gateway interface name\n"
687 "Null interface\n"
688 "Set tag for this route\n"
689 "Tag value\n"
690 "Distance value for this route\n"
691 VRF_CMD_HELP_STR
692 MPLS_LABEL_HELPSTR
693 "Table to configure\n"
694 "The table number to configure\n"
695 VRF_CMD_HELP_STR
696 "SR-TE color\n"
697 "The SR-TE color to configure\n")
698 {
699 const char *nh_vrf;
700 const char *flag = NULL;
701
702 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
703 flag = "Null0";
704 ifname = NULL;
705 }
706
707 if (!vrf)
708 vrf = VRF_DEFAULT_NAME;
709
710 if (nexthop_vrf)
711 nh_vrf = nexthop_vrf;
712 else
713 nh_vrf = vrf;
714
715 return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
716 prefix, mask_str, NULL, gate_str, ifname, flag,
717 tag_str, distance_str, label, table_str,
718 false, color_str);
719 }
720
721 DEFPY_YANG(ip_route_vrf,
722 ip_route_vrf_cmd,
723 "[no] ip route\
724 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
725 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
726 [{ \
727 tag (1-4294967295) \
728 |(1-255)$distance \
729 |label WORD \
730 |table (1-4294967295) \
731 |nexthop-vrf NAME \
732 |color (1-4294967295) \
733 }]",
734 NO_STR IP_STR
735 "Establish static routes\n"
736 "IP destination prefix (e.g. 10.0.0.0/8)\n"
737 "IP destination prefix\n"
738 "IP destination prefix mask\n"
739 "IP gateway address\n"
740 "IP gateway interface name\n"
741 "Null interface\n"
742 "Set tag for this route\n"
743 "Tag value\n"
744 "Distance value for this route\n"
745 MPLS_LABEL_HELPSTR
746 "Table to configure\n"
747 "The table number to configure\n"
748 VRF_CMD_HELP_STR
749 "SR-TE color\n"
750 "The SR-TE color to configure\n")
751 {
752 const char *nh_vrf;
753 const char *flag = NULL;
754 const struct lyd_node *vrf_dnode;
755 const char *vrfname;
756
757 vrf_dnode =
758 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
759 if (!vrf_dnode) {
760 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
761 return CMD_WARNING_CONFIG_FAILED;
762 }
763
764 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
765
766 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
767 flag = "Null0";
768 ifname = NULL;
769 }
770 if (nexthop_vrf)
771 nh_vrf = nexthop_vrf;
772 else
773 nh_vrf = vrfname;
774
775 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
776 prefix, mask_str, NULL, gate_str, ifname, flag,
777 tag_str, distance_str, label, table_str,
778 false, color_str);
779 }
780
781 DEFPY_YANG(ipv6_route_blackhole,
782 ipv6_route_blackhole_cmd,
783 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
784 <reject|blackhole>$flag \
785 [{ \
786 tag (1-4294967295) \
787 |(1-255)$distance \
788 |vrf NAME \
789 |label WORD \
790 |table (1-4294967295) \
791 }]",
792 NO_STR
793 IPV6_STR
794 "Establish static routes\n"
795 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
796 "IPv6 source-dest route\n"
797 "IPv6 source prefix\n"
798 "Emit an ICMP unreachable when matched\n"
799 "Silently discard pkts when matched\n"
800 "Set tag for this route\n"
801 "Tag value\n"
802 "Distance value for this prefix\n"
803 VRF_CMD_HELP_STR
804 MPLS_LABEL_HELPSTR
805 "Table to configure\n"
806 "The table number to configure\n")
807 {
808 return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
809 NULL, from_str, NULL, NULL, flag, tag_str,
810 distance_str, vrf, label, table_str);
811 }
812
813 DEFPY_YANG(ipv6_route_blackhole_vrf,
814 ipv6_route_blackhole_vrf_cmd,
815 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
816 <reject|blackhole>$flag \
817 [{ \
818 tag (1-4294967295) \
819 |(1-255)$distance \
820 |label WORD \
821 |table (1-4294967295) \
822 }]",
823 NO_STR
824 IPV6_STR
825 "Establish static routes\n"
826 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
827 "IPv6 source-dest route\n"
828 "IPv6 source prefix\n"
829 "Emit an ICMP unreachable when matched\n"
830 "Silently discard pkts when matched\n"
831 "Set tag for this route\n"
832 "Tag value\n"
833 "Distance value for this prefix\n"
834 MPLS_LABEL_HELPSTR
835 "Table to configure\n"
836 "The table number to configure\n")
837 {
838 const struct lyd_node *vrf_dnode;
839 const char *vrfname;
840
841 vrf_dnode =
842 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
843 if (!vrf_dnode) {
844 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
845 return CMD_WARNING_CONFIG_FAILED;
846 }
847 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
848
849 /*
850 * Coverity is complaining that prefix could
851 * be dereferenced, but we know that prefix will
852 * valid. Add an assert to make it happy
853 */
854 assert(prefix);
855
856 return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
857 no, prefix_str, NULL, from_str, NULL, NULL,
858 flag, tag_str, distance_str, label, table_str,
859 false, NULL);
860 }
861
862 DEFPY_YANG(ipv6_route_address_interface,
863 ipv6_route_address_interface_cmd,
864 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
865 X:X::X:X$gate \
866 <INTERFACE|Null0>$ifname \
867 [{ \
868 tag (1-4294967295) \
869 |(1-255)$distance \
870 |vrf NAME \
871 |label WORD \
872 |table (1-4294967295) \
873 |nexthop-vrf NAME \
874 |onlink$onlink \
875 |color (1-4294967295) \
876 }]",
877 NO_STR
878 IPV6_STR
879 "Establish static routes\n"
880 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
881 "IPv6 source-dest route\n"
882 "IPv6 source prefix\n"
883 "IPv6 gateway address\n"
884 "IPv6 gateway interface name\n"
885 "Null interface\n"
886 "Set tag for this route\n"
887 "Tag value\n"
888 "Distance value for this prefix\n"
889 VRF_CMD_HELP_STR
890 MPLS_LABEL_HELPSTR
891 "Table to configure\n"
892 "The table number to configure\n"
893 VRF_CMD_HELP_STR
894 "Treat the nexthop as directly attached to the interface\n"
895 "SR-TE color\n"
896 "The SR-TE color to configure\n")
897 {
898 const char *nh_vrf;
899 const char *flag = NULL;
900
901 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
902 flag = "Null0";
903 ifname = NULL;
904 }
905
906 if (!vrf)
907 vrf = VRF_DEFAULT_NAME;
908
909 if (nexthop_vrf)
910 nh_vrf = nexthop_vrf;
911 else
912 nh_vrf = vrf;
913
914 return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
915 prefix_str, NULL, from_str, gate_str, ifname,
916 flag, tag_str, distance_str, label, table_str,
917 !!onlink, color_str);
918 }
919
920 DEFPY_YANG(ipv6_route_address_interface_vrf,
921 ipv6_route_address_interface_vrf_cmd,
922 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
923 X:X::X:X$gate \
924 <INTERFACE|Null0>$ifname \
925 [{ \
926 tag (1-4294967295) \
927 |(1-255)$distance \
928 |label WORD \
929 |table (1-4294967295) \
930 |nexthop-vrf NAME \
931 |onlink$onlink \
932 |color (1-4294967295) \
933 }]",
934 NO_STR
935 IPV6_STR
936 "Establish static routes\n"
937 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
938 "IPv6 source-dest route\n"
939 "IPv6 source prefix\n"
940 "IPv6 gateway address\n"
941 "IPv6 gateway interface name\n"
942 "Null interface\n"
943 "Set tag for this route\n"
944 "Tag value\n"
945 "Distance value for this prefix\n"
946 MPLS_LABEL_HELPSTR
947 "Table to configure\n"
948 "The table number to configure\n"
949 VRF_CMD_HELP_STR
950 "Treat the nexthop as directly attached to the interface\n"
951 "SR-TE color\n"
952 "The SR-TE color to configure\n")
953 {
954 const char *nh_vrf;
955 const char *flag = NULL;
956 const struct lyd_node *vrf_dnode;
957 const char *vrfname;
958
959 vrf_dnode =
960 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
961 if (!vrf_dnode) {
962 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
963 return CMD_WARNING_CONFIG_FAILED;
964 }
965 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
966
967 if (nexthop_vrf)
968 nh_vrf = nexthop_vrf;
969 else
970 nh_vrf = vrfname;
971
972 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
973 flag = "Null0";
974 ifname = NULL;
975 }
976 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
977 no, prefix_str, NULL, from_str, gate_str,
978 ifname, flag, tag_str, distance_str, label,
979 table_str, !!onlink, color_str);
980 }
981
982 DEFPY_YANG(ipv6_route,
983 ipv6_route_cmd,
984 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
985 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
986 [{ \
987 tag (1-4294967295) \
988 |(1-255)$distance \
989 |vrf NAME \
990 |label WORD \
991 |table (1-4294967295) \
992 |nexthop-vrf NAME \
993 |color (1-4294967295) \
994 }]",
995 NO_STR
996 IPV6_STR
997 "Establish static routes\n"
998 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
999 "IPv6 source-dest route\n"
1000 "IPv6 source prefix\n"
1001 "IPv6 gateway address\n"
1002 "IPv6 gateway interface name\n"
1003 "Null interface\n"
1004 "Set tag for this route\n"
1005 "Tag value\n"
1006 "Distance value for this prefix\n"
1007 VRF_CMD_HELP_STR
1008 MPLS_LABEL_HELPSTR
1009 "Table to configure\n"
1010 "The table number to configure\n"
1011 VRF_CMD_HELP_STR
1012 "SR-TE color\n"
1013 "The SR-TE color to configure\n")
1014 {
1015 const char *nh_vrf;
1016 const char *flag = NULL;
1017
1018 if (!vrf)
1019 vrf = VRF_DEFAULT_NAME;
1020
1021 if (nexthop_vrf)
1022 nh_vrf = nexthop_vrf;
1023 else
1024 nh_vrf = vrf;
1025
1026 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1027 flag = "Null0";
1028 ifname = NULL;
1029 }
1030 return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
1031 prefix_str, NULL, from_str, gate_str, ifname,
1032 flag, tag_str, distance_str, label, table_str,
1033 false, color_str);
1034 }
1035
1036 DEFPY_YANG(ipv6_route_vrf,
1037 ipv6_route_vrf_cmd,
1038 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1039 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1040 [{ \
1041 tag (1-4294967295) \
1042 |(1-255)$distance \
1043 |label WORD \
1044 |table (1-4294967295) \
1045 |nexthop-vrf NAME \
1046 |color (1-4294967295) \
1047 }]",
1048 NO_STR
1049 IPV6_STR
1050 "Establish static routes\n"
1051 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1052 "IPv6 source-dest route\n"
1053 "IPv6 source prefix\n"
1054 "IPv6 gateway address\n"
1055 "IPv6 gateway interface name\n"
1056 "Null interface\n"
1057 "Set tag for this route\n"
1058 "Tag value\n"
1059 "Distance value for this prefix\n"
1060 MPLS_LABEL_HELPSTR
1061 "Table to configure\n"
1062 "The table number to configure\n"
1063 VRF_CMD_HELP_STR
1064 "SR-TE color\n"
1065 "The SR-TE color to configure\n")
1066 {
1067 const char *nh_vrf;
1068 const char *flag = NULL;
1069 const struct lyd_node *vrf_dnode;
1070 const char *vrfname;
1071
1072 vrf_dnode =
1073 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
1074 if (!vrf_dnode) {
1075 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
1076 return CMD_WARNING_CONFIG_FAILED;
1077 }
1078 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
1079
1080 if (nexthop_vrf)
1081 nh_vrf = nexthop_vrf;
1082 else
1083 nh_vrf = vrfname;
1084
1085 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1086 flag = "Null0";
1087 ifname = NULL;
1088 }
1089 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
1090 no, prefix_str, NULL, from_str, gate_str,
1091 ifname, flag, tag_str, distance_str, label,
1092 table_str, false, color_str);
1093 }
1094 DEFPY_YANG(debug_staticd, debug_staticd_cmd,
1095 "[no] debug static [{events$events|route$route}]",
1096 NO_STR DEBUG_STR STATICD_STR
1097 "Debug events\n"
1098 "Debug route\n")
1099 {
1100 /* If no specific category, change all */
1101 if (strmatch(argv[argc - 1]->text, "static"))
1102 static_debug_set(vty->node, !no, true, true);
1103 else
1104 static_debug_set(vty->node, !no, !!events, !!route);
1105
1106 return CMD_SUCCESS;
1107 }
1108
1109 DEFUN_NOSH (show_debugging_static,
1110 show_debugging_static_cmd,
1111 "show debugging [static]",
1112 SHOW_STR
1113 DEBUG_STR
1114 "Static Information\n")
1115 {
1116 vty_out(vty, "Staticd debugging status\n");
1117
1118 static_debug_status_write(vty);
1119
1120 return CMD_SUCCESS;
1121 }
1122
1123 static struct cmd_node debug_node = {
1124 .name = "debug",
1125 .node = DEBUG_NODE,
1126 .prompt = "",
1127 .config_write = static_config_write_debug,
1128 };
1129
1130 void static_vty_init(void)
1131 {
1132 install_node(&debug_node);
1133
1134 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1135
1136 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1137 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1138 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1139 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1140 install_element(CONFIG_NODE, &ip_route_cmd);
1141 install_element(VRF_NODE, &ip_route_vrf_cmd);
1142
1143 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1144 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1145 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1146 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1147 install_element(CONFIG_NODE, &ipv6_route_cmd);
1148 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1149
1150 install_element(ENABLE_NODE, &show_debugging_static_cmd);
1151 install_element(ENABLE_NODE, &debug_staticd_cmd);
1152 install_element(CONFIG_NODE, &debug_staticd_cmd);
1153 }