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