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