]> git.proxmox.com Git - mirror_frr.git/blame - staticd/static_vty.c
Merge pull request #6237 from ton31337/fix/show_hostname_in_bgp
[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"
31ddf3b7 35#include "static_debug.h"
7e24fdf3
DS
36#ifndef VTYSH_EXTRACT_PL
37#include "staticd/static_vty_clippy.c"
38#endif
31ddf3b7
MS
39
40#define STATICD_STR "Static route daemon\n"
41
7e24fdf3
DS
42static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
43 const char *vrf_name)
44{
45 struct static_vrf *svrf;
46 struct vrf *vrf;
47
48 svrf = static_vrf_lookup_by_name(vrf_name);
49
50 if (svrf)
51 return svrf;
52
53 vrf = vrf_get(VRF_UNKNOWN, vrf_name);
54 if (!vrf) {
55 vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
56 return NULL;
57 }
58 svrf = vrf->info;
59 if (!svrf) {
60 vty_out(vty, "%% Could not create vrf-info %s\n",
61 vrf_name);
62 return NULL;
63 }
64 /* Mark as having FRR configuration */
65 vrf_set_user_cfged(vrf);
66
67 return svrf;
68}
69
70struct static_hold_route {
71 char *vrf_name;
72 char *nhvrf_name;
73 afi_t afi;
74 safi_t safi;
75 char *dest_str;
76 char *mask_str;
77 char *src_str;
78 char *gate_str;
79 char *ifname;
80 char *flag_str;
81 char *tag_str;
82 char *distance_str;
83 char *label_str;
84 char *table_str;
02dc8ba3 85 bool onlink;
7e24fdf3
DS
86
87 /* processed & masked destination, used for config display */
88 struct prefix dest;
89};
90
91static struct list *static_list;
92
93static int static_list_compare_helper(const char *s1, const char *s2)
94{
4f4060f6
DL
95 /* extra (!s1 && !s2) to keep SA happy */
96 if (s1 == s2 || (!s1 && !s2))
7e24fdf3
DS
97 return 0;
98
99 if (!s1 && s2)
100 return -1;
101
102 if (s1 && !s2)
103 return 1;
104
105 return strcmp(s1, s2);
106}
107
108static void static_list_delete(struct static_hold_route *shr)
109{
0a22ddfb
QY
110 XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
111 XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
112 XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
113 XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
114 XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
115 XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
116 XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
117 XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
118 XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
119 XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
120 XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
121 XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
7e24fdf3
DS
122
123 XFREE(MTYPE_STATIC_ROUTE, shr);
124}
125
126static int static_list_compare(void *arg1, void *arg2)
127{
128 struct static_hold_route *shr1 = arg1;
129 struct static_hold_route *shr2 = arg2;
130 int ret;
131
132 ret = strcmp(shr1->vrf_name, shr2->vrf_name);
133 if (ret)
134 return ret;
135
136 ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
137 if (ret)
138 return ret;
139
140 ret = shr1->afi - shr2->afi;
141 if (ret)
142 return ret;
143
144 ret = shr1->safi - shr2->safi;
145 if (ret)
146 return ret;
147
148 ret = prefix_cmp(&shr1->dest, &shr2->dest);
149 if (ret)
150 return ret;
151
152 ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
153 if (ret)
154 return ret;
155
156 ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
157 if (ret)
158 return ret;
159
160 ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
161 if (ret)
162 return ret;
163
164 ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
165 if (ret)
166 return ret;
167
168 ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
169 if (ret)
170 return ret;
171
172 ret = static_list_compare_helper(shr1->distance_str,
173 shr2->distance_str);
174 if (ret)
175 return ret;
176
177 ret = static_list_compare_helper(shr1->table_str,
178 shr2->table_str);
179 if (ret)
180 return ret;
181
182 return static_list_compare_helper(shr1->label_str, shr2->label_str);
183}
184
185
186/* General function for static route. */
187static int zebra_static_route_holdem(
188 struct static_vrf *svrf, struct static_vrf *nh_svrf, afi_t afi,
189 safi_t safi, const char *negate, struct prefix *dest,
190 const char *dest_str, const char *mask_str, const char *src_str,
191 const char *gate_str, const char *ifname, const char *flag_str,
192 const char *tag_str, const char *distance_str, const char *label_str,
7f1a170f 193 const char *table_str, bool onlink)
7e24fdf3
DS
194{
195 struct static_hold_route *shr, *lookup;
196 struct listnode *node;
197
198 zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
199 dest_str);
200
201 shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
202 shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, svrf->vrf->name);
203 shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_svrf->vrf->name);
204 shr->afi = afi;
205 shr->safi = safi;
7f1a170f 206 shr->onlink = onlink;
7e24fdf3
DS
207 if (dest)
208 prefix_copy(&shr->dest, dest);
209 if (dest_str)
210 shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
211 if (mask_str)
212 shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
213 if (src_str)
214 shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
215 if (gate_str)
216 shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
217 if (ifname)
218 shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
219 if (flag_str)
220 shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
221 if (tag_str)
222 shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
223 if (distance_str)
224 shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
225 if (label_str)
226 shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
227 if (table_str)
228 shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str);
229
230 for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
231 if (static_list_compare(shr, lookup) == 0)
232 break;
233 }
234
235 if (lookup) {
236 if (negate) {
237 listnode_delete(static_list, lookup);
238 static_list_delete(shr);
239 static_list_delete(lookup);
240
241 return CMD_SUCCESS;
242 }
243
244 /*
245 * If a person enters the same line again
246 * we need to silently accept it
247 */
248 goto shr_cleanup;
249 }
250
251 if (!negate) {
252 listnode_add_sort(static_list, shr);
253 return CMD_SUCCESS;
254 }
255
256 shr_cleanup:
257 XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
258 XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
259 XFREE(MTYPE_STATIC_ROUTE, shr);
260
261 return CMD_SUCCESS;
262}
263
264static int static_route_leak(
265 struct vty *vty, struct static_vrf *svrf, struct static_vrf *nh_svrf,
266 afi_t afi, safi_t safi, const char *negate, const char *dest_str,
267 const char *mask_str, const char *src_str, const char *gate_str,
268 const char *ifname, const char *flag_str, const char *tag_str,
02dc8ba3
QY
269 const char *distance_str, const char *label_str, const char *table_str,
270 bool onlink)
7e24fdf3
DS
271{
272 int ret;
273 uint8_t distance;
274 struct prefix p, src;
275 struct prefix_ipv6 *src_p = NULL;
276 union g_addr gate;
277 union g_addr *gatep = NULL;
278 struct in_addr mask;
279 enum static_blackhole_type bh_type = 0;
280 route_tag_t tag = 0;
281 uint8_t type;
282 struct static_nh_label snh_label;
283 uint32_t table_id = 0;
284
285 ret = str2prefix(dest_str, &p);
286 if (ret <= 0) {
287 if (vty)
288 vty_out(vty, "%% Malformed address\n");
289 else
15569c58
DA
290 zlog_warn("%s: Malformed address: %s", __func__,
291 dest_str);
7e24fdf3
DS
292 return CMD_WARNING_CONFIG_FAILED;
293 }
294
295 switch (afi) {
296 case AFI_IP:
297 /* Cisco like mask notation. */
298 if (mask_str) {
299 ret = inet_aton(mask_str, &mask);
300 if (ret == 0) {
301 if (vty)
302 vty_out(vty, "%% Malformed address\n");
303 else
304 zlog_warn("%s: Malformed address: %s",
15569c58 305 __func__, mask_str);
7e24fdf3
DS
306 return CMD_WARNING_CONFIG_FAILED;
307 }
308 p.prefixlen = ip_masklen(mask);
309 }
310 break;
311 case AFI_IP6:
312 /* srcdest routing */
313 if (src_str) {
314 ret = str2prefix(src_str, &src);
315 if (ret <= 0 || src.family != AF_INET6) {
316 if (vty)
317 vty_out(vty,
318 "%% Malformed source address\n");
319 else
320 zlog_warn(
8d5cbee9 321 "%s: Malformed source address: %s",
15569c58 322 __func__, src_str);
7e24fdf3
DS
323 return CMD_WARNING_CONFIG_FAILED;
324 }
325 src_p = (struct prefix_ipv6 *)&src;
326 }
327 break;
328 default:
329 break;
330 }
331
332 /* Apply mask for given prefix. */
333 apply_mask(&p);
334
335 if (svrf->vrf->vrf_id == VRF_UNKNOWN
336 || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) {
337 vrf_set_user_cfged(svrf->vrf);
338 return zebra_static_route_holdem(
339 svrf, nh_svrf, afi, safi, negate, &p, dest_str,
340 mask_str, src_str, gate_str, ifname, flag_str, tag_str,
7f1a170f 341 distance_str, label_str, table_str, onlink);
7e24fdf3
DS
342 }
343
344 if (table_str) {
345 /* table configured. check consistent with vrf config
346 */
347 if (svrf->vrf->data.l.table_id != RT_TABLE_MAIN) {
348 if (vty)
349 vty_out(vty,
350 "%% Table %s overlaps vrf table %u\n",
351 table_str, svrf->vrf->data.l.table_id);
352 else
15569c58
DA
353 zlog_warn("%s: Table %s overlaps vrf table %u",
354 __func__, table_str,
355 svrf->vrf->data.l.table_id);
7e24fdf3
DS
356 return CMD_WARNING_CONFIG_FAILED;
357 }
358 }
359
360 /* Administrative distance. */
361 if (distance_str)
362 distance = atoi(distance_str);
363 else
364 distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
365
366 /* tag */
367 if (tag_str)
368 tag = strtoul(tag_str, NULL, 10);
369
370 /* Labels */
371 memset(&snh_label, 0, sizeof(struct static_nh_label));
372 if (label_str) {
373 if (!mpls_enabled) {
374 if (vty)
375 vty_out(vty,
376 "%% MPLS not turned on in kernel, ignoring command\n");
377 else
378 zlog_warn(
379 "%s: MPLS not turned on in kernel ignoring static route to %s",
15569c58 380 __func__, dest_str);
7e24fdf3
DS
381 return CMD_WARNING_CONFIG_FAILED;
382 }
383 int rc = mpls_str2label(label_str, &snh_label.num_labels,
384 snh_label.label);
385 if (rc < 0) {
386 switch (rc) {
387 case -1:
388 if (vty)
389 vty_out(vty, "%% Malformed label(s)\n");
390 else
391 zlog_warn(
392 "%s: Malformed labels specified for route %s",
15569c58 393 __func__, dest_str);
7e24fdf3
DS
394 break;
395 case -2:
396 if (vty)
397 vty_out(vty,
398 "%% Cannot use reserved label(s) (%d-%d)\n",
399 MPLS_LABEL_RESERVED_MIN,
400 MPLS_LABEL_RESERVED_MAX);
401 else
402 zlog_warn(
403 "%s: Cannot use reserved labels (%d-%d) for %s",
15569c58 404 __func__,
7e24fdf3
DS
405 MPLS_LABEL_RESERVED_MIN,
406 MPLS_LABEL_RESERVED_MAX,
407 dest_str);
408 break;
409 case -3:
410 if (vty)
411 vty_out(vty,
412 "%% Too many labels. Enter %d or fewer\n",
413 MPLS_MAX_LABELS);
414 else
415 zlog_warn(
416 "%s: Too many labels, Enter %d or fewer for %s",
15569c58
DA
417 __func__, MPLS_MAX_LABELS,
418 dest_str);
7e24fdf3
DS
419 break;
420 }
421 return CMD_WARNING_CONFIG_FAILED;
422 }
423 }
424
425 /* TableID */
426 if (table_str)
427 table_id = atol(table_str);
428
429 /* Null0 static route. */
430 if (ifname != NULL) {
38aac4a8
QY
431 if (strcasecmp(ifname, "Null0") == 0
432 || strcasecmp(ifname, "reject") == 0
433 || strcasecmp(ifname, "blackhole") == 0) {
7e24fdf3
DS
434 if (vty)
435 vty_out(vty,
a88be399 436 "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n");
7e24fdf3
DS
437 else
438 zlog_warn(
8751e3bc 439 "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)",
15569c58 440 __func__, dest_str);
7e24fdf3
DS
441 return CMD_WARNING_CONFIG_FAILED;
442 }
443 }
444
445 /* Route flags */
446 if (flag_str) {
447 switch (flag_str[0]) {
448 case 'r':
449 bh_type = STATIC_BLACKHOLE_REJECT;
450 break;
451 case 'b':
452 bh_type = STATIC_BLACKHOLE_DROP;
453 break;
454 case 'N':
455 bh_type = STATIC_BLACKHOLE_NULL;
456 break;
457 default:
458 if (vty)
459 vty_out(vty, "%% Malformed flag %s \n",
460 flag_str);
461 else
462 zlog_warn("%s: Malformed flag %s for %s",
15569c58 463 __func__, flag_str, dest_str);
7e24fdf3
DS
464 return CMD_WARNING_CONFIG_FAILED;
465 }
466 }
467
468 if (gate_str) {
469 if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
470 if (vty)
471 vty_out(vty,
472 "%% Malformed nexthop address %s\n",
473 gate_str);
474 else
475 zlog_warn(
476 "%s: Malformed nexthop address %s for %s",
15569c58 477 __func__, gate_str, dest_str);
7e24fdf3
DS
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",
5e81f5dd 594 __func__, shr->dest_str);
7e24fdf3
DS
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 869 VRF_CMD_HELP_STR
92ae10e6 870 "Treat the nexthop as directly attached to the interface\n")
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 937 VRF_CMD_HELP_STR
92ae10e6 938 "Treat the nexthop as directly attached to the interface\n")
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 1213 VRF_CMD_HELP_STR
92ae10e6 1214 "Treat the nexthop as directly attached to the interface\n")
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 1281 VRF_CMD_HELP_STR
92ae10e6 1282 "Treat the nexthop as directly attached to the interface\n")
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 1441}
31ddf3b7
MS
1442DEFPY(debug_staticd,
1443 debug_staticd_cmd,
1444 "[no] debug static [{events$events}]",
1445 NO_STR
1446 DEBUG_STR
1447 STATICD_STR
1448 "Debug events\n")
1449{
1450 /* If no specific category, change all */
1451 if (strmatch(argv[argc - 1]->text, "static"))
1452 static_debug_set(vty->node, !no, true);
1453 else
1454 static_debug_set(vty->node, !no, !!events);
7e24fdf3 1455
31ddf3b7
MS
1456 return CMD_SUCCESS;
1457}
1458
1459DEFUN_NOSH (show_debugging_static,
1460 show_debugging_static_cmd,
e60b527e
DS
1461 "show debugging [static]",
1462 SHOW_STR
1463 DEBUG_STR
1464 "Static Information\n")
1465{
31ddf3b7
MS
1466 vty_out(vty, "Staticd debugging status\n");
1467
1468 static_debug_status_write(vty);
e60b527e
DS
1469
1470 return CMD_SUCCESS;
1471}
1472
31ddf3b7
MS
1473static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
1474
7e24fdf3
DS
1475void static_vty_init(void)
1476{
31ddf3b7
MS
1477 install_node(&debug_node, static_config_write_debug);
1478
7e24fdf3
DS
1479 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1480
1481 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1482 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1483 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1484 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1485 install_element(CONFIG_NODE, &ip_route_cmd);
1486 install_element(VRF_NODE, &ip_route_vrf_cmd);
1487
1488 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1489 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1490 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1491 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1492 install_element(CONFIG_NODE, &ipv6_route_cmd);
1493 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1494
31ddf3b7
MS
1495 install_element(VIEW_NODE, &show_debugging_static_cmd);
1496 install_element(VIEW_NODE, &debug_staticd_cmd);
1497 install_element(CONFIG_NODE, &debug_staticd_cmd);
e60b527e 1498
7e24fdf3
DS
1499 static_list = list_new();
1500 static_list->cmp = (int (*)(void *, void *))static_list_compare;
1501 static_list->del = (void (*)(void *))static_list_delete;
1502}