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