]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_vty.c
pimd: Create pimreg interface when we start any interface config
[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
31 #include "static_vrf.h"
32 #include "static_memory.h"
33 #include "static_vty.h"
34 #include "static_routes.h"
35 #ifndef VTYSH_EXTRACT_PL
36 #include "staticd/static_vty_clippy.c"
37 #endif
38
39 static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
40 const char *vrf_name)
41 {
42 struct static_vrf *svrf;
43 struct vrf *vrf;
44
45 svrf = static_vrf_lookup_by_name(vrf_name);
46
47 if (svrf)
48 return svrf;
49
50 vrf = vrf_get(VRF_UNKNOWN, vrf_name);
51 if (!vrf) {
52 vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
53 return NULL;
54 }
55 svrf = vrf->info;
56 if (!svrf) {
57 vty_out(vty, "%% Could not create vrf-info %s\n",
58 vrf_name);
59 return NULL;
60 }
61 /* Mark as having FRR configuration */
62 vrf_set_user_cfged(vrf);
63
64 return svrf;
65 }
66
67 struct static_hold_route {
68 char *vrf_name;
69 char *nhvrf_name;
70 afi_t afi;
71 safi_t safi;
72 char *dest_str;
73 char *mask_str;
74 char *src_str;
75 char *gate_str;
76 char *ifname;
77 char *flag_str;
78 char *tag_str;
79 char *distance_str;
80 char *label_str;
81 char *table_str;
82 bool onlink;
83
84 /* processed & masked destination, used for config display */
85 struct prefix dest;
86 };
87
88 static struct list *static_list;
89
90 static int static_list_compare_helper(const char *s1, const char *s2)
91 {
92 /* extra (!s1 && !s2) to keep SA happy */
93 if (s1 == s2 || (!s1 && !s2))
94 return 0;
95
96 if (!s1 && s2)
97 return -1;
98
99 if (s1 && !s2)
100 return 1;
101
102 return strcmp(s1, s2);
103 }
104
105 static void static_list_delete(struct static_hold_route *shr)
106 {
107 XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
108 XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
109 XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
110 XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
111 XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
112 XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
113 XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
114 XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
115 XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
116 XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
117 XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
118 XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
119
120 XFREE(MTYPE_STATIC_ROUTE, shr);
121 }
122
123 static int static_list_compare(void *arg1, void *arg2)
124 {
125 struct static_hold_route *shr1 = arg1;
126 struct static_hold_route *shr2 = arg2;
127 int ret;
128
129 ret = strcmp(shr1->vrf_name, shr2->vrf_name);
130 if (ret)
131 return ret;
132
133 ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
134 if (ret)
135 return ret;
136
137 ret = shr1->afi - shr2->afi;
138 if (ret)
139 return ret;
140
141 ret = shr1->safi - shr2->safi;
142 if (ret)
143 return ret;
144
145 ret = prefix_cmp(&shr1->dest, &shr2->dest);
146 if (ret)
147 return ret;
148
149 ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
150 if (ret)
151 return ret;
152
153 ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
154 if (ret)
155 return ret;
156
157 ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
158 if (ret)
159 return ret;
160
161 ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
162 if (ret)
163 return ret;
164
165 ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
166 if (ret)
167 return ret;
168
169 ret = static_list_compare_helper(shr1->distance_str,
170 shr2->distance_str);
171 if (ret)
172 return ret;
173
174 ret = static_list_compare_helper(shr1->table_str,
175 shr2->table_str);
176 if (ret)
177 return ret;
178
179 return static_list_compare_helper(shr1->label_str, shr2->label_str);
180 }
181
182
183 /* General function for static route. */
184 static int zebra_static_route_holdem(
185 struct static_vrf *svrf, struct static_vrf *nh_svrf, afi_t afi,
186 safi_t safi, const char *negate, struct prefix *dest,
187 const char *dest_str, const char *mask_str, const char *src_str,
188 const char *gate_str, const char *ifname, const char *flag_str,
189 const char *tag_str, const char *distance_str, const char *label_str,
190 const char *table_str, bool onlink)
191 {
192 struct static_hold_route *shr, *lookup;
193 struct listnode *node;
194
195 zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
196 dest_str);
197
198 shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
199 shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, svrf->vrf->name);
200 shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_svrf->vrf->name);
201 shr->afi = afi;
202 shr->safi = safi;
203 shr->onlink = onlink;
204 if (dest)
205 prefix_copy(&shr->dest, dest);
206 if (dest_str)
207 shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
208 if (mask_str)
209 shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
210 if (src_str)
211 shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
212 if (gate_str)
213 shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
214 if (ifname)
215 shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
216 if (flag_str)
217 shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
218 if (tag_str)
219 shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
220 if (distance_str)
221 shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
222 if (label_str)
223 shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
224 if (table_str)
225 shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str);
226
227 for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
228 if (static_list_compare(shr, lookup) == 0)
229 break;
230 }
231
232 if (lookup) {
233 if (negate) {
234 listnode_delete(static_list, lookup);
235 static_list_delete(shr);
236 static_list_delete(lookup);
237
238 return CMD_SUCCESS;
239 }
240
241 /*
242 * If a person enters the same line again
243 * we need to silently accept it
244 */
245 goto shr_cleanup;
246 }
247
248 if (!negate) {
249 listnode_add_sort(static_list, shr);
250 return CMD_SUCCESS;
251 }
252
253 shr_cleanup:
254 XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
255 XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
256 XFREE(MTYPE_STATIC_ROUTE, shr);
257
258 return CMD_SUCCESS;
259 }
260
261 static int static_route_leak(
262 struct vty *vty, struct static_vrf *svrf, struct static_vrf *nh_svrf,
263 afi_t afi, safi_t safi, const char *negate, const char *dest_str,
264 const char *mask_str, const char *src_str, const char *gate_str,
265 const char *ifname, const char *flag_str, const char *tag_str,
266 const char *distance_str, const char *label_str, const char *table_str,
267 bool onlink)
268 {
269 int ret;
270 uint8_t distance;
271 struct prefix p, src;
272 struct prefix_ipv6 *src_p = NULL;
273 union g_addr gate;
274 union g_addr *gatep = NULL;
275 struct in_addr mask;
276 enum static_blackhole_type bh_type = 0;
277 route_tag_t tag = 0;
278 uint8_t type;
279 struct static_nh_label snh_label;
280 uint32_t table_id = 0;
281
282 ret = str2prefix(dest_str, &p);
283 if (ret <= 0) {
284 if (vty)
285 vty_out(vty, "%% Malformed address\n");
286 else
287 zlog_warn("%s: Malformed address: %s",
288 __PRETTY_FUNCTION__, dest_str);
289 return CMD_WARNING_CONFIG_FAILED;
290 }
291
292 switch (afi) {
293 case AFI_IP:
294 /* Cisco like mask notation. */
295 if (mask_str) {
296 ret = inet_aton(mask_str, &mask);
297 if (ret == 0) {
298 if (vty)
299 vty_out(vty, "%% Malformed address\n");
300 else
301 zlog_warn("%s: Malformed address: %s",
302 __PRETTY_FUNCTION__,
303 mask_str);
304 return CMD_WARNING_CONFIG_FAILED;
305 }
306 p.prefixlen = ip_masklen(mask);
307 }
308 break;
309 case AFI_IP6:
310 /* srcdest routing */
311 if (src_str) {
312 ret = str2prefix(src_str, &src);
313 if (ret <= 0 || src.family != AF_INET6) {
314 if (vty)
315 vty_out(vty,
316 "%% Malformed source address\n");
317 else
318 zlog_warn(
319 "%s: Malformed source address: %s",
320 __PRETTY_FUNCTION__, src_str);
321 return CMD_WARNING_CONFIG_FAILED;
322 }
323 src_p = (struct prefix_ipv6 *)&src;
324 }
325 break;
326 default:
327 break;
328 }
329
330 /* Apply mask for given prefix. */
331 apply_mask(&p);
332
333 if (svrf->vrf->vrf_id == VRF_UNKNOWN
334 || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) {
335 vrf_set_user_cfged(svrf->vrf);
336 return zebra_static_route_holdem(
337 svrf, nh_svrf, afi, safi, negate, &p, dest_str,
338 mask_str, src_str, gate_str, ifname, flag_str, tag_str,
339 distance_str, label_str, table_str, onlink);
340 }
341
342 if (table_str) {
343 /* table configured. check consistent with vrf config
344 */
345 if (svrf->vrf->data.l.table_id != RT_TABLE_MAIN) {
346 if (vty)
347 vty_out(vty,
348 "%% Table %s overlaps vrf table %u\n",
349 table_str, svrf->vrf->data.l.table_id);
350 else
351 zlog_warn(
352 "%s: Table %s overlaps vrf table %u",
353 __PRETTY_FUNCTION__,
354 table_str, svrf->vrf->data.l.table_id);
355 return CMD_WARNING_CONFIG_FAILED;
356 }
357 }
358
359 /* Administrative distance. */
360 if (distance_str)
361 distance = atoi(distance_str);
362 else
363 distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
364
365 /* tag */
366 if (tag_str)
367 tag = strtoul(tag_str, NULL, 10);
368
369 /* Labels */
370 memset(&snh_label, 0, sizeof(struct static_nh_label));
371 if (label_str) {
372 if (!mpls_enabled) {
373 if (vty)
374 vty_out(vty,
375 "%% MPLS not turned on in kernel, ignoring command\n");
376 else
377 zlog_warn(
378 "%s: MPLS not turned on in kernel ignoring static route to %s",
379 __PRETTY_FUNCTION__, dest_str);
380 return CMD_WARNING_CONFIG_FAILED;
381 }
382 int rc = mpls_str2label(label_str, &snh_label.num_labels,
383 snh_label.label);
384 if (rc < 0) {
385 switch (rc) {
386 case -1:
387 if (vty)
388 vty_out(vty, "%% Malformed label(s)\n");
389 else
390 zlog_warn(
391 "%s: Malformed labels specified for route %s",
392 __PRETTY_FUNCTION__, dest_str);
393 break;
394 case -2:
395 if (vty)
396 vty_out(vty,
397 "%% Cannot use reserved label(s) (%d-%d)\n",
398 MPLS_LABEL_RESERVED_MIN,
399 MPLS_LABEL_RESERVED_MAX);
400 else
401 zlog_warn(
402 "%s: Cannot use reserved labels (%d-%d) for %s",
403 __PRETTY_FUNCTION__,
404 MPLS_LABEL_RESERVED_MIN,
405 MPLS_LABEL_RESERVED_MAX,
406 dest_str);
407 break;
408 case -3:
409 if (vty)
410 vty_out(vty,
411 "%% Too many labels. Enter %d or fewer\n",
412 MPLS_MAX_LABELS);
413 else
414 zlog_warn(
415 "%s: Too many labels, Enter %d or fewer for %s",
416 __PRETTY_FUNCTION__,
417 MPLS_MAX_LABELS, dest_str);
418 break;
419 }
420 return CMD_WARNING_CONFIG_FAILED;
421 }
422 }
423
424 /* TableID */
425 if (table_str)
426 table_id = atol(table_str);
427
428 /* Null0 static route. */
429 if (ifname != NULL) {
430 if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0
431 || strncasecmp(ifname, "reject", strlen(ifname)) == 0
432 || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) {
433 if (vty)
434 vty_out(vty,
435 "%% Nexthop interface cannot be Null0, reject or blackhole\n");
436 else
437 zlog_warn(
438 "%s: Nexthop interface cannot be Null0, reject or blackhole for %s",
439 __PRETTY_FUNCTION__, dest_str);
440 return CMD_WARNING_CONFIG_FAILED;
441 }
442 }
443
444 /* Route flags */
445 if (flag_str) {
446 switch (flag_str[0]) {
447 case 'r':
448 bh_type = STATIC_BLACKHOLE_REJECT;
449 break;
450 case 'b':
451 bh_type = STATIC_BLACKHOLE_DROP;
452 break;
453 case 'N':
454 bh_type = STATIC_BLACKHOLE_NULL;
455 break;
456 default:
457 if (vty)
458 vty_out(vty, "%% Malformed flag %s \n",
459 flag_str);
460 else
461 zlog_warn("%s: Malformed flag %s for %s",
462 __PRETTY_FUNCTION__, flag_str,
463 dest_str);
464 return CMD_WARNING_CONFIG_FAILED;
465 }
466 }
467
468 if (gate_str) {
469 if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
470 if (vty)
471 vty_out(vty,
472 "%% Malformed nexthop address %s\n",
473 gate_str);
474 else
475 zlog_warn(
476 "%s: Malformed nexthop address %s for %s",
477 __PRETTY_FUNCTION__, gate_str,
478 dest_str);
479 return CMD_WARNING_CONFIG_FAILED;
480 }
481 gatep = &gate;
482 }
483
484 if (gate_str == NULL && ifname == NULL)
485 type = STATIC_BLACKHOLE;
486 else if (gate_str && ifname) {
487 if (afi == AFI_IP)
488 type = STATIC_IPV4_GATEWAY_IFNAME;
489 else
490 type = STATIC_IPV6_GATEWAY_IFNAME;
491 } else if (ifname)
492 type = STATIC_IFNAME;
493 else {
494 if (afi == AFI_IP)
495 type = STATIC_IPV4_GATEWAY;
496 else
497 type = STATIC_IPV6_GATEWAY;
498 }
499
500 if (!negate) {
501 static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
502 bh_type, tag, distance, svrf, nh_svrf,
503 &snh_label, table_id, onlink);
504 /* Mark as having FRR configuration */
505 vrf_set_user_cfged(svrf->vrf);
506 } else {
507 static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
508 tag, distance, svrf, &snh_label, table_id);
509 /* If no other FRR config for this VRF, mark accordingly. */
510 if (!static_vrf_has_config(svrf))
511 vrf_reset_user_cfged(svrf->vrf);
512 }
513
514 return CMD_SUCCESS;
515 }
516
517 static int static_route(struct vty *vty, afi_t afi, safi_t safi,
518 const char *negate, const char *dest_str,
519 const char *mask_str, const char *src_str,
520 const char *gate_str, const char *ifname,
521 const char *flag_str, const char *tag_str,
522 const char *distance_str, const char *vrf_name,
523 const char *label_str, const char *table_str)
524 {
525 struct static_vrf *svrf;
526
527 /* VRF id */
528 svrf = static_vrf_lookup_by_name(vrf_name);
529
530 /* When trying to delete, the VRF must exist. */
531 if (negate && !svrf) {
532 vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
533 return CMD_WARNING_CONFIG_FAILED;
534 }
535
536 /* When trying to create, create the VRF if it doesn't exist.
537 * Note: The VRF isn't active until we hear about it from the kernel.
538 */
539 if (!svrf) {
540 svrf = static_vty_get_unknown_vrf(vty, vrf_name);
541 if (!svrf)
542 return CMD_WARNING_CONFIG_FAILED;
543 }
544 return static_route_leak(vty, svrf, svrf, afi, safi, negate, dest_str,
545 mask_str, src_str, gate_str, ifname, flag_str,
546 tag_str, distance_str, label_str, table_str,
547 false);
548 }
549
550 void static_config_install_delayed_routes(struct static_vrf *svrf)
551 {
552 struct listnode *node, *nnode;
553 struct static_hold_route *shr;
554 struct static_vrf *osvrf, *nh_svrf;
555 int installed;
556
557 for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) {
558 osvrf = static_vrf_lookup_by_name(shr->vrf_name);
559 nh_svrf = static_vrf_lookup_by_name(shr->nhvrf_name);
560
561 if (osvrf != svrf && nh_svrf != svrf)
562 continue;
563
564 if (osvrf->vrf->vrf_id == VRF_UNKNOWN
565 || nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
566 continue;
567
568 installed = static_route_leak(
569 NULL, osvrf, nh_svrf, shr->afi, shr->safi, NULL,
570 shr->dest_str, shr->mask_str, shr->src_str,
571 shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str,
572 shr->distance_str, shr->label_str, shr->table_str,
573 shr->onlink);
574
575 if (installed != CMD_SUCCESS)
576 zlog_debug(
577 "%s: Attempt to install %s as a route and it was rejected",
578 __PRETTY_FUNCTION__, shr->dest_str);
579 listnode_delete(static_list, shr);
580 static_list_delete(shr);
581 }
582 }
583
584 /* Write static route configuration. */
585 int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
586 safi_t safi, const char *cmd)
587 {
588 struct static_hold_route *shr;
589 struct listnode *node;
590 char spacing[100];
591 struct route_node *rn;
592 struct static_route *si;
593 struct route_table *stable;
594 char buf[SRCDEST2STR_BUFFER];
595 int write = 0;
596
597 stable = svrf->stable[afi][safi];
598 if (stable == NULL)
599 return write;
600
601 sprintf(spacing, "%s%s", (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ",
602 cmd);
603
604 /*
605 * Static routes for vrfs not fully inited
606 */
607 for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) {
608 if (shr->afi != afi || shr->safi != safi)
609 continue;
610
611 if (strcmp(svrf->vrf->name, shr->vrf_name) != 0)
612 continue;
613
614 char dest_str[PREFIX_STRLEN];
615
616 prefix2str(&shr->dest, dest_str, sizeof(dest_str));
617
618 vty_out(vty, "%s ", spacing);
619 if (shr->dest_str)
620 vty_out(vty, "%s ", dest_str);
621 if (shr->src_str)
622 vty_out(vty, "from %s ", shr->src_str);
623 if (shr->gate_str)
624 vty_out(vty, "%s ", shr->gate_str);
625 if (shr->ifname)
626 vty_out(vty, "%s ", shr->ifname);
627 if (shr->flag_str)
628 vty_out(vty, "%s ", shr->flag_str);
629 if (shr->tag_str)
630 vty_out(vty, "tag %s ", shr->tag_str);
631 if (shr->distance_str)
632 vty_out(vty, "%s ", shr->distance_str);
633 if (shr->label_str)
634 vty_out(vty, "label %s ", shr->label_str);
635 if (shr->table_str)
636 vty_out(vty, "table %s", shr->table_str);
637 if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0)
638 vty_out(vty, "nexthop-vrf %s ", shr->nhvrf_name);
639 if (shr->onlink)
640 vty_out(vty, "onlink");
641 vty_out(vty, "\n");
642 }
643
644 for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
645 for (si = rn->info; si; si = si->next) {
646 vty_out(vty, "%s %s", spacing,
647 srcdest_rnode2str(rn, buf, sizeof(buf)));
648
649 switch (si->type) {
650 case STATIC_IPV4_GATEWAY:
651 vty_out(vty, " %s", inet_ntoa(si->addr.ipv4));
652 break;
653 case STATIC_IPV6_GATEWAY:
654 vty_out(vty, " %s",
655 inet_ntop(AF_INET6, &si->addr.ipv6, buf,
656 sizeof(buf)));
657 break;
658 case STATIC_IFNAME:
659 vty_out(vty, " %s", si->ifname);
660 break;
661 case STATIC_BLACKHOLE:
662 switch (si->bh_type) {
663 case STATIC_BLACKHOLE_DROP:
664 vty_out(vty, " blackhole");
665 break;
666 case STATIC_BLACKHOLE_NULL:
667 vty_out(vty, " Null0");
668 break;
669 case STATIC_BLACKHOLE_REJECT:
670 vty_out(vty, " reject");
671 break;
672 }
673 break;
674 case STATIC_IPV4_GATEWAY_IFNAME:
675 vty_out(vty, " %s %s",
676 inet_ntop(AF_INET, &si->addr.ipv4, buf,
677 sizeof(buf)),
678 si->ifname);
679 break;
680 case STATIC_IPV6_GATEWAY_IFNAME:
681 vty_out(vty, " %s %s",
682 inet_ntop(AF_INET6, &si->addr.ipv6, buf,
683 sizeof(buf)),
684 si->ifname);
685 break;
686 }
687
688 if (si->tag)
689 vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag);
690
691 if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
692 vty_out(vty, " %d", si->distance);
693
694 /* Label information */
695 if (si->snh_label.num_labels)
696 vty_out(vty, " label %s",
697 mpls_label2str(si->snh_label.num_labels,
698 si->snh_label.label, buf,
699 sizeof(buf), 0));
700
701 if (si->nh_vrf_id != si->vrf_id)
702 vty_out(vty, " nexthop-vrf %s", si->nh_vrfname);
703
704 /*
705 * table ID from VRF overrides configured
706 */
707 if (si->table_id &&
708 svrf->vrf->data.l.table_id == RT_TABLE_MAIN)
709 vty_out(vty, " table %u", si->table_id);
710
711 if (si->onlink)
712 vty_out(vty, " onlink");
713
714 vty_out(vty, "\n");
715
716 write = 1;
717 }
718 return write;
719 }
720
721 /* Static unicast routes for multicast RPF lookup. */
722 DEFPY (ip_mroute_dist,
723 ip_mroute_dist_cmd,
724 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
725 NO_STR
726 IP_STR
727 "Configure static unicast route into MRIB for multicast RPF lookup\n"
728 "IP destination prefix (e.g. 10.0.0.0/8)\n"
729 "Nexthop address\n"
730 "Nexthop interface name\n"
731 "Distance\n")
732 {
733 return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
734 NULL, NULL, gate_str, ifname, NULL, NULL,
735 distance_str, NULL, NULL, NULL);
736 }
737
738 /* Static route configuration. */
739 DEFPY(ip_route_blackhole,
740 ip_route_blackhole_cmd,
741 "[no] ip route\
742 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
743 <reject|blackhole>$flag \
744 [{ \
745 tag (1-4294967295) \
746 |(1-255)$distance \
747 |vrf NAME \
748 |label WORD \
749 |table (1-4294967295) \
750 }]",
751 NO_STR IP_STR
752 "Establish static routes\n"
753 "IP destination prefix (e.g. 10.0.0.0/8)\n"
754 "IP destination prefix\n"
755 "IP destination prefix mask\n"
756 "Emit an ICMP unreachable when matched\n"
757 "Silently discard pkts when matched\n"
758 "Set tag for this route\n"
759 "Tag value\n"
760 "Distance value for this route\n"
761 VRF_CMD_HELP_STR
762 MPLS_LABEL_HELPSTR
763 "Table to configure\n"
764 "The table number to configure\n")
765 {
766 if (table_str && vrf && !vrf_is_backend_netns()) {
767 vty_out(vty,
768 "%% table param only available when running on netns-based vrfs\n");
769 return CMD_WARNING_CONFIG_FAILED;
770 }
771
772 return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
773 mask_str, NULL, NULL, NULL, flag, tag_str,
774 distance_str, vrf, label, table_str);
775 }
776
777 DEFPY(ip_route_blackhole_vrf,
778 ip_route_blackhole_vrf_cmd,
779 "[no] ip route\
780 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
781 <reject|blackhole>$flag \
782 [{ \
783 tag (1-4294967295) \
784 |(1-255)$distance \
785 |label WORD \
786 |table (1-4294967295) \
787 }]",
788 NO_STR IP_STR
789 "Establish static routes\n"
790 "IP destination prefix (e.g. 10.0.0.0/8)\n"
791 "IP destination prefix\n"
792 "IP destination prefix mask\n"
793 "Emit an ICMP unreachable when matched\n"
794 "Silently discard pkts when matched\n"
795 "Set tag for this route\n"
796 "Tag value\n"
797 "Distance value for this route\n"
798 MPLS_LABEL_HELPSTR
799 "Table to configure\n"
800 "The table number to configure\n")
801 {
802 VTY_DECLVAR_CONTEXT(vrf, vrf);
803 struct static_vrf *svrf = vrf->info;
804
805 if (table_str && !vrf_is_backend_netns()) {
806 vty_out(vty,
807 "%% table param only available when running on netns-based vrfs\n");
808 return CMD_WARNING_CONFIG_FAILED;
809 }
810
811 /*
812 * Coverity is complaining that prefix could
813 * be dereferenced, but we know that prefix will
814 * valid. Add an assert to make it happy
815 */
816 assert(prefix);
817 return static_route_leak(vty, svrf, svrf, AFI_IP, SAFI_UNICAST, no,
818 prefix, mask_str, NULL, NULL, NULL, flag,
819 tag_str, distance_str, label, table_str,
820 false);
821 }
822
823 DEFPY(ip_route_address_interface,
824 ip_route_address_interface_cmd,
825 "[no] ip route\
826 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
827 A.B.C.D$gate \
828 <INTERFACE|Null0>$ifname \
829 [{ \
830 tag (1-4294967295) \
831 |(1-255)$distance \
832 |vrf NAME \
833 |label WORD \
834 |table (1-4294967295) \
835 |nexthop-vrf NAME \
836 |onlink$onlink \
837 }]",
838 NO_STR IP_STR
839 "Establish static routes\n"
840 "IP destination prefix (e.g. 10.0.0.0/8)\n"
841 "IP destination prefix\n"
842 "IP destination prefix mask\n"
843 "IP gateway address\n"
844 "IP gateway interface name\n"
845 "Null interface\n"
846 "Set tag for this route\n"
847 "Tag value\n"
848 "Distance value for this route\n"
849 VRF_CMD_HELP_STR
850 MPLS_LABEL_HELPSTR
851 "Table to configure\n"
852 "The table number to configure\n"
853 VRF_CMD_HELP_STR
854 "Treat the nexthop as directly attached to the interface")
855 {
856 struct static_vrf *svrf;
857 struct static_vrf *nh_svrf;
858 const char *flag = NULL;
859
860 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
861 flag = "Null0";
862 ifname = NULL;
863 }
864
865 svrf = static_vty_get_unknown_vrf(vty, vrf);
866 if (!svrf) {
867 vty_out(vty, "%% vrf %s is not defined\n", vrf);
868 return CMD_WARNING_CONFIG_FAILED;
869 }
870
871 if (table_str && vrf && !vrf_is_backend_netns()) {
872 vty_out(vty,
873 "%% table param only available when running on netns-based vrfs\n");
874 return CMD_WARNING_CONFIG_FAILED;
875 }
876
877 if (nexthop_vrf)
878 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
879 else
880 nh_svrf = svrf;
881
882 if (!nh_svrf) {
883 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
884 return CMD_WARNING_CONFIG_FAILED;
885 }
886
887 return static_route_leak(vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no,
888 prefix, mask_str, NULL, gate_str, ifname, flag,
889 tag_str, distance_str, label, table_str,
890 !!onlink);
891 }
892
893 DEFPY(ip_route_address_interface_vrf,
894 ip_route_address_interface_vrf_cmd,
895 "[no] ip route\
896 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
897 A.B.C.D$gate \
898 <INTERFACE|Null0>$ifname \
899 [{ \
900 tag (1-4294967295) \
901 |(1-255)$distance \
902 |label WORD \
903 |table (1-4294967295) \
904 |nexthop-vrf NAME \
905 |onlink$onlink \
906 }]",
907 NO_STR IP_STR
908 "Establish static routes\n"
909 "IP destination prefix (e.g. 10.0.0.0/8)\n"
910 "IP destination prefix\n"
911 "IP destination prefix mask\n"
912 "IP gateway address\n"
913 "IP gateway interface name\n"
914 "Null interface\n"
915 "Set tag for this route\n"
916 "Tag value\n"
917 "Distance value for this route\n"
918 MPLS_LABEL_HELPSTR
919 "Table to configure\n"
920 "The table number to configure\n"
921 VRF_CMD_HELP_STR
922 "Treat the nexthop as directly attached to the interface")
923 {
924 VTY_DECLVAR_CONTEXT(vrf, vrf);
925 const char *flag = NULL;
926 struct static_vrf *svrf = vrf->info;
927 struct static_vrf *nh_svrf;
928
929 if (table_str && !vrf_is_backend_netns()) {
930 vty_out(vty,
931 "%% table param only available when running on netns-based vrfs\n");
932 return CMD_WARNING_CONFIG_FAILED;
933 }
934
935 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
936 flag = "Null0";
937 ifname = NULL;
938 }
939
940 if (nexthop_vrf)
941 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
942 else
943 nh_svrf = svrf;
944
945 if (!nh_svrf) {
946 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
947 return CMD_WARNING_CONFIG_FAILED;
948 }
949
950 return static_route_leak(vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no,
951 prefix, mask_str, NULL, gate_str, ifname, flag,
952 tag_str, distance_str, label, table_str,
953 !!onlink);
954 }
955
956 DEFPY(ip_route,
957 ip_route_cmd,
958 "[no] ip route\
959 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
960 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
961 [{ \
962 tag (1-4294967295) \
963 |(1-255)$distance \
964 |vrf NAME \
965 |label WORD \
966 |table (1-4294967295) \
967 |nexthop-vrf NAME \
968 }]",
969 NO_STR IP_STR
970 "Establish static routes\n"
971 "IP destination prefix (e.g. 10.0.0.0/8)\n"
972 "IP destination prefix\n"
973 "IP destination prefix mask\n"
974 "IP gateway address\n"
975 "IP gateway interface name\n"
976 "Null interface\n"
977 "Set tag for this route\n"
978 "Tag value\n"
979 "Distance value for this route\n"
980 VRF_CMD_HELP_STR
981 MPLS_LABEL_HELPSTR
982 "Table to configure\n"
983 "The table number to configure\n"
984 VRF_CMD_HELP_STR)
985 {
986 struct static_vrf *svrf;
987 struct static_vrf *nh_svrf;
988 const char *flag = NULL;
989
990 if (table_str && vrf && !vrf_is_backend_netns()) {
991 vty_out(vty,
992 "%% table param only available when running on netns-based vrfs\n");
993 return CMD_WARNING_CONFIG_FAILED;
994 }
995
996 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
997 flag = "Null0";
998 ifname = NULL;
999 }
1000
1001 svrf = static_vty_get_unknown_vrf(vty, vrf);
1002 if (!svrf) {
1003 vty_out(vty, "%% vrf %s is not defined\n", vrf);
1004 return CMD_WARNING_CONFIG_FAILED;
1005 }
1006
1007 if (nexthop_vrf)
1008 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1009 else
1010 nh_svrf = svrf;
1011
1012 if (!nh_svrf) {
1013 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1014 return CMD_WARNING_CONFIG_FAILED;
1015 }
1016
1017 return static_route_leak(
1018 vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
1019 NULL, gate_str, ifname, flag, tag_str, distance_str, label,
1020 table_str, false);
1021 }
1022
1023 DEFPY(ip_route_vrf,
1024 ip_route_vrf_cmd,
1025 "[no] ip route\
1026 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
1027 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
1028 [{ \
1029 tag (1-4294967295) \
1030 |(1-255)$distance \
1031 |label WORD \
1032 |table (1-4294967295) \
1033 |nexthop-vrf NAME \
1034 }]",
1035 NO_STR IP_STR
1036 "Establish static routes\n"
1037 "IP destination prefix (e.g. 10.0.0.0/8)\n"
1038 "IP destination prefix\n"
1039 "IP destination prefix mask\n"
1040 "IP gateway address\n"
1041 "IP gateway interface name\n"
1042 "Null interface\n"
1043 "Set tag for this route\n"
1044 "Tag value\n"
1045 "Distance value for this route\n"
1046 MPLS_LABEL_HELPSTR
1047 "Table to configure\n"
1048 "The table number to configure\n"
1049 VRF_CMD_HELP_STR)
1050 {
1051 VTY_DECLVAR_CONTEXT(vrf, vrf);
1052 struct static_vrf *svrf = vrf->info;
1053 struct static_vrf *nh_svrf;
1054 const char *flag = NULL;
1055
1056 if (table_str && !vrf_is_backend_netns()) {
1057 vty_out(vty,
1058 "%% table param only available when running on netns-based vrfs\n");
1059 return CMD_WARNING_CONFIG_FAILED;
1060 }
1061
1062 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1063 flag = "Null0";
1064 ifname = NULL;
1065 }
1066
1067 if (nexthop_vrf)
1068 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1069 else
1070 nh_svrf = svrf;
1071
1072 if (!nh_svrf) {
1073 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1074 return CMD_WARNING_CONFIG_FAILED;
1075 }
1076
1077 return static_route_leak(
1078 vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
1079 NULL, gate_str, ifname, flag, tag_str, distance_str, label,
1080 table_str, false);
1081 }
1082
1083 DEFPY(ipv6_route_blackhole,
1084 ipv6_route_blackhole_cmd,
1085 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1086 <reject|blackhole>$flag \
1087 [{ \
1088 tag (1-4294967295) \
1089 |(1-255)$distance \
1090 |vrf NAME \
1091 |label WORD \
1092 |table (1-4294967295) \
1093 }]",
1094 NO_STR
1095 IPV6_STR
1096 "Establish static routes\n"
1097 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1098 "IPv6 source-dest route\n"
1099 "IPv6 source prefix\n"
1100 "Emit an ICMP unreachable when matched\n"
1101 "Silently discard pkts when matched\n"
1102 "Set tag for this route\n"
1103 "Tag value\n"
1104 "Distance value for this prefix\n"
1105 VRF_CMD_HELP_STR
1106 MPLS_LABEL_HELPSTR
1107 "Table to configure\n"
1108 "The table number to configure\n")
1109 {
1110 if (table_str && vrf && !vrf_is_backend_netns()) {
1111 vty_out(vty,
1112 "%% table param only available when running on netns-based vrfs\n");
1113 return CMD_WARNING_CONFIG_FAILED;
1114 }
1115
1116 return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
1117 NULL, from_str, NULL, NULL, flag, tag_str,
1118 distance_str, vrf, label, table_str);
1119 }
1120
1121 DEFPY(ipv6_route_blackhole_vrf,
1122 ipv6_route_blackhole_vrf_cmd,
1123 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1124 <reject|blackhole>$flag \
1125 [{ \
1126 tag (1-4294967295) \
1127 |(1-255)$distance \
1128 |label WORD \
1129 |table (1-4294967295) \
1130 }]",
1131 NO_STR
1132 IPV6_STR
1133 "Establish static routes\n"
1134 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1135 "IPv6 source-dest route\n"
1136 "IPv6 source prefix\n"
1137 "Emit an ICMP unreachable when matched\n"
1138 "Silently discard pkts when matched\n"
1139 "Set tag for this route\n"
1140 "Tag value\n"
1141 "Distance value for this prefix\n"
1142 MPLS_LABEL_HELPSTR
1143 "Table to configure\n"
1144 "The table number to configure\n")
1145 {
1146 VTY_DECLVAR_CONTEXT(vrf, vrf);
1147 struct static_vrf *svrf = vrf->info;
1148
1149 if (table_str && !vrf_is_backend_netns()) {
1150 vty_out(vty,
1151 "%% table param only available when running on netns-based vrfs\n");
1152 return CMD_WARNING_CONFIG_FAILED;
1153 }
1154
1155 /*
1156 * Coverity is complaining that prefix could
1157 * be dereferenced, but we know that prefix will
1158 * valid. Add an assert to make it happy
1159 */
1160 assert(prefix);
1161 return static_route_leak(
1162 vty, svrf, svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
1163 from_str, NULL, NULL, flag, tag_str, distance_str, label,
1164 table_str, false);
1165 }
1166
1167 DEFPY(ipv6_route_address_interface,
1168 ipv6_route_address_interface_cmd,
1169 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1170 X:X::X:X$gate \
1171 <INTERFACE|Null0>$ifname \
1172 [{ \
1173 tag (1-4294967295) \
1174 |(1-255)$distance \
1175 |vrf NAME \
1176 |label WORD \
1177 |table (1-4294967295) \
1178 |nexthop-vrf NAME \
1179 |onlink$onlink \
1180 }]",
1181 NO_STR
1182 IPV6_STR
1183 "Establish static routes\n"
1184 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1185 "IPv6 source-dest route\n"
1186 "IPv6 source prefix\n"
1187 "IPv6 gateway address\n"
1188 "IPv6 gateway interface name\n"
1189 "Null interface\n"
1190 "Set tag for this route\n"
1191 "Tag value\n"
1192 "Distance value for this prefix\n"
1193 VRF_CMD_HELP_STR
1194 MPLS_LABEL_HELPSTR
1195 "Table to configure\n"
1196 "The table number to configure\n"
1197 VRF_CMD_HELP_STR
1198 "Treat the nexthop as directly attached to the interface")
1199 {
1200 struct static_vrf *svrf;
1201 struct static_vrf *nh_svrf;
1202 const char *flag = NULL;
1203
1204 if (table_str && vrf && !vrf_is_backend_netns()) {
1205 vty_out(vty,
1206 "%% table param only available when running on netns-based vrfs\n");
1207 return CMD_WARNING_CONFIG_FAILED;
1208 }
1209
1210 svrf = static_vty_get_unknown_vrf(vty, vrf);
1211 if (!svrf) {
1212 vty_out(vty, "%% vrf %s is not defined\n", vrf);
1213 return CMD_WARNING_CONFIG_FAILED;
1214 }
1215
1216 if (nexthop_vrf)
1217 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1218 else
1219 nh_svrf = svrf;
1220
1221 if (!nh_svrf) {
1222 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1223 return CMD_WARNING_CONFIG_FAILED;
1224 }
1225
1226 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1227 flag = "Null0";
1228 ifname = NULL;
1229 }
1230
1231 return static_route_leak(
1232 vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
1233 from_str, gate_str, ifname, flag, tag_str, distance_str, label,
1234 table_str, !!onlink);
1235 }
1236
1237 DEFPY(ipv6_route_address_interface_vrf,
1238 ipv6_route_address_interface_vrf_cmd,
1239 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1240 X:X::X:X$gate \
1241 <INTERFACE|Null0>$ifname \
1242 [{ \
1243 tag (1-4294967295) \
1244 |(1-255)$distance \
1245 |label WORD \
1246 |table (1-4294967295) \
1247 |nexthop-vrf NAME \
1248 |onlink$onlink \
1249 }]",
1250 NO_STR
1251 IPV6_STR
1252 "Establish static routes\n"
1253 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1254 "IPv6 source-dest route\n"
1255 "IPv6 source prefix\n"
1256 "IPv6 gateway address\n"
1257 "IPv6 gateway interface name\n"
1258 "Null interface\n"
1259 "Set tag for this route\n"
1260 "Tag value\n"
1261 "Distance value for this prefix\n"
1262 MPLS_LABEL_HELPSTR
1263 "Table to configure\n"
1264 "The table number to configure\n"
1265 VRF_CMD_HELP_STR
1266 "Treat the nexthop as directly attached to the interface")
1267 {
1268 VTY_DECLVAR_CONTEXT(vrf, vrf);
1269 struct static_vrf *svrf = vrf->info;
1270 struct static_vrf *nh_svrf;
1271 const char *flag = NULL;
1272
1273 if (table_str && !vrf_is_backend_netns()) {
1274 vty_out(vty,
1275 "%% table param only available when running on netns-based vrfs\n");
1276 return CMD_WARNING_CONFIG_FAILED;
1277 }
1278
1279 if (nexthop_vrf)
1280 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1281 else
1282 nh_svrf = svrf;
1283
1284 if (!nh_svrf) {
1285 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1286 return CMD_WARNING_CONFIG_FAILED;
1287 }
1288
1289 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1290 flag = "Null0";
1291 ifname = NULL;
1292 }
1293
1294 return static_route_leak(
1295 vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
1296 from_str, gate_str, ifname, flag, tag_str, distance_str, label,
1297 table_str, !!onlink);
1298 }
1299
1300 DEFPY(ipv6_route,
1301 ipv6_route_cmd,
1302 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1303 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1304 [{ \
1305 tag (1-4294967295) \
1306 |(1-255)$distance \
1307 |vrf NAME \
1308 |label WORD \
1309 |table (1-4294967295) \
1310 |nexthop-vrf NAME \
1311 }]",
1312 NO_STR
1313 IPV6_STR
1314 "Establish static routes\n"
1315 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1316 "IPv6 source-dest route\n"
1317 "IPv6 source prefix\n"
1318 "IPv6 gateway address\n"
1319 "IPv6 gateway interface name\n"
1320 "Null interface\n"
1321 "Set tag for this route\n"
1322 "Tag value\n"
1323 "Distance value for this prefix\n"
1324 VRF_CMD_HELP_STR
1325 MPLS_LABEL_HELPSTR
1326 "Table to configure\n"
1327 "The table number to configure\n"
1328 VRF_CMD_HELP_STR)
1329 {
1330 struct static_vrf *svrf;
1331 struct static_vrf *nh_svrf;
1332 const char *flag = NULL;
1333
1334 if (table_str && vrf && !vrf_is_backend_netns()) {
1335 vty_out(vty,
1336 "%% table param only available when running on netns-based vrfs\n");
1337 return CMD_WARNING_CONFIG_FAILED;
1338 }
1339
1340 svrf = static_vty_get_unknown_vrf(vty, vrf);
1341 if (!svrf) {
1342 vty_out(vty, "%% vrf %s is not defined\n", vrf);
1343 return CMD_WARNING_CONFIG_FAILED;
1344 }
1345
1346 if (nexthop_vrf)
1347 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1348 else
1349 nh_svrf = svrf;
1350
1351 if (!nh_svrf) {
1352 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1353 return CMD_WARNING_CONFIG_FAILED;
1354 }
1355
1356 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1357 flag = "Null0";
1358 ifname = NULL;
1359 }
1360
1361 return static_route_leak(
1362 vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
1363 from_str, gate_str, ifname, flag, tag_str, distance_str, label,
1364 table_str, false);
1365 }
1366
1367 DEFPY(ipv6_route_vrf,
1368 ipv6_route_vrf_cmd,
1369 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
1370 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
1371 [{ \
1372 tag (1-4294967295) \
1373 |(1-255)$distance \
1374 |label WORD \
1375 |table (1-4294967295) \
1376 |nexthop-vrf NAME \
1377 }]",
1378 NO_STR
1379 IPV6_STR
1380 "Establish static routes\n"
1381 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1382 "IPv6 source-dest route\n"
1383 "IPv6 source prefix\n"
1384 "IPv6 gateway address\n"
1385 "IPv6 gateway interface name\n"
1386 "Null interface\n"
1387 "Set tag for this route\n"
1388 "Tag value\n"
1389 "Distance value for this prefix\n"
1390 MPLS_LABEL_HELPSTR
1391 "Table to configure\n"
1392 "The table number to configure\n"
1393 VRF_CMD_HELP_STR)
1394 {
1395 VTY_DECLVAR_CONTEXT(vrf, vrf);
1396 struct static_vrf *svrf = vrf->info;
1397 struct static_vrf *nh_svrf;
1398 const char *flag = NULL;
1399
1400 if (table_str && !vrf_is_backend_netns()) {
1401 vty_out(vty,
1402 "%% table param only available when running on netns-based vrfs\n");
1403 return CMD_WARNING_CONFIG_FAILED;
1404 }
1405
1406 if (nexthop_vrf)
1407 nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
1408 else
1409 nh_svrf = svrf;
1410
1411 if (!nh_svrf) {
1412 vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
1413 return CMD_WARNING_CONFIG_FAILED;
1414 }
1415
1416 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1417 flag = "Null0";
1418 ifname = NULL;
1419 }
1420
1421 return static_route_leak(
1422 vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
1423 from_str, gate_str, ifname, flag, tag_str, distance_str, label,
1424 table_str, false);
1425 }
1426
1427 DEFUN_NOSH (show_debugging_staticd,
1428 show_debugging_staticd_cmd,
1429 "show debugging [static]",
1430 SHOW_STR
1431 DEBUG_STR
1432 "Static Information\n")
1433 {
1434 vty_out(vty, "Static debugging status\n");
1435
1436 return CMD_SUCCESS;
1437 }
1438
1439 void static_vty_init(void)
1440 {
1441 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1442
1443 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1444 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1445 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1446 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1447 install_element(CONFIG_NODE, &ip_route_cmd);
1448 install_element(VRF_NODE, &ip_route_vrf_cmd);
1449
1450 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1451 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1452 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1453 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1454 install_element(CONFIG_NODE, &ipv6_route_cmd);
1455 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1456
1457 install_element(VIEW_NODE, &show_debugging_staticd_cmd);
1458
1459 static_list = list_new();
1460 static_list->cmp = (int (*)(void *, void *))static_list_compare;
1461 static_list->del = (void (*)(void *))static_list_delete;
1462 }