]> git.proxmox.com Git - mirror_frr.git/blame - staticd/static_vty.c
Merge pull request #6886 from opensourcerouting/grpc-doc
[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"
88fa5104 30#include "northbound.h"
31#include "libfrr.h"
32#include "routing_nb.h"
33#include "northbound_cli.h"
7e24fdf3
DS
34
35#include "static_vrf.h"
36#include "static_memory.h"
37#include "static_vty.h"
38#include "static_routes.h"
31ddf3b7 39#include "static_debug.h"
7e24fdf3
DS
40#ifndef VTYSH_EXTRACT_PL
41#include "staticd/static_vty_clippy.c"
42#endif
88fa5104 43#include "static_nb.h"
31ddf3b7
MS
44
45#define STATICD_STR "Static route daemon\n"
46
88fa5104 47static int static_route_leak(struct vty *vty, const char *svrf,
48 const char *nh_svrf, afi_t afi, safi_t safi,
49 const char *negate, const char *dest_str,
50 const char *mask_str, const char *src_str,
51 const char *gate_str, const char *ifname,
52 const char *flag_str, const char *tag_str,
53 const char *distance_str, const char *label_str,
54 const char *table_str, bool onlink)
7e24fdf3 55{
7e24fdf3 56 int ret;
7e24fdf3 57 struct prefix p, src;
7e24fdf3 58 struct in_addr mask;
7e24fdf3 59 uint8_t type;
88fa5104 60 const char *bh_type;
61 char xpath_prefix[XPATH_MAXLEN];
62 char xpath_nexthop[XPATH_MAXLEN];
63 char xpath_mpls[XPATH_MAXLEN];
64 char xpath_label[XPATH_MAXLEN];
65 char ab_xpath[XPATH_MAXLEN];
66 char buf_prefix[PREFIX_STRLEN];
67 char buf_src_prefix[PREFIX_STRLEN];
68 char buf_nh_type[PREFIX_STRLEN];
69 char buf_tag[PREFIX_STRLEN];
70 char buf_tableid[PREFIX_STRLEN];
71 uint8_t label_stack_id = 0;
72 const char *buf_gate_str;
73 uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
74 route_tag_t tag = 0;
7e24fdf3 75 uint32_t table_id = 0;
88fa5104 76 const struct lyd_node *dnode;
77
78 memset(buf_src_prefix, 0, PREFIX_STRLEN);
79 memset(buf_nh_type, 0, PREFIX_STRLEN);
7e24fdf3
DS
80
81 ret = str2prefix(dest_str, &p);
82 if (ret <= 0) {
83 if (vty)
84 vty_out(vty, "%% Malformed address\n");
85 else
15569c58
DA
86 zlog_warn("%s: Malformed address: %s", __func__,
87 dest_str);
7e24fdf3
DS
88 return CMD_WARNING_CONFIG_FAILED;
89 }
90
91 switch (afi) {
92 case AFI_IP:
93 /* Cisco like mask notation. */
94 if (mask_str) {
95 ret = inet_aton(mask_str, &mask);
96 if (ret == 0) {
97 if (vty)
98 vty_out(vty, "%% Malformed address\n");
99 else
100 zlog_warn("%s: Malformed address: %s",
15569c58 101 __func__, mask_str);
7e24fdf3
DS
102 return CMD_WARNING_CONFIG_FAILED;
103 }
104 p.prefixlen = ip_masklen(mask);
105 }
106 break;
107 case AFI_IP6:
108 /* srcdest routing */
109 if (src_str) {
110 ret = str2prefix(src_str, &src);
111 if (ret <= 0 || src.family != AF_INET6) {
112 if (vty)
113 vty_out(vty,
114 "%% Malformed source address\n");
115 else
116 zlog_warn(
8d5cbee9 117 "%s: Malformed source address: %s",
15569c58 118 __func__, src_str);
7e24fdf3
DS
119 return CMD_WARNING_CONFIG_FAILED;
120 }
7e24fdf3
DS
121 }
122 break;
123 default:
124 break;
125 }
126
127 /* Apply mask for given prefix. */
128 apply_mask(&p);
129
88fa5104 130 prefix2str(&p, buf_prefix, sizeof(buf_prefix));
7e24fdf3 131
88fa5104 132 if (src_str)
133 prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
134 if (gate_str)
135 buf_gate_str = gate_str;
136 else
137 buf_gate_str = "";
138
139 if (gate_str == NULL && ifname == NULL)
140 type = STATIC_BLACKHOLE;
141 else if (gate_str && ifname) {
142 if (afi == AFI_IP)
143 type = STATIC_IPV4_GATEWAY_IFNAME;
144 else
145 type = STATIC_IPV6_GATEWAY_IFNAME;
146 } else if (ifname)
147 type = STATIC_IFNAME;
148 else {
149 if (afi == AFI_IP)
150 type = STATIC_IPV4_GATEWAY;
151 else
152 type = STATIC_IPV6_GATEWAY;
7e24fdf3
DS
153 }
154
155 /* Administrative distance. */
156 if (distance_str)
157 distance = atoi(distance_str);
158 else
159 distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
160
161 /* tag */
162 if (tag_str)
163 tag = strtoul(tag_str, NULL, 10);
164
7e24fdf3
DS
165 /* TableID */
166 if (table_str)
167 table_id = atol(table_str);
168
88fa5104 169 static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN);
170 if (!negate) {
171 /* route + path procesing */
172 if (src_str)
173 snprintf(xpath_prefix, sizeof(xpath_prefix),
174 FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
175 "frr-staticd:staticd", "staticd", svrf,
176 buf_prefix,
314825ff 177 yang_afi_safi_value2identity(afi, safi),
88fa5104 178 buf_src_prefix, distance);
179 else
180 snprintf(xpath_prefix, sizeof(xpath_prefix),
181 FRR_STATIC_ROUTE_INFO_KEY_XPATH,
182 "frr-staticd:staticd", "staticd", svrf,
183 buf_prefix,
314825ff 184 yang_afi_safi_value2identity(afi, safi),
88fa5104 185 distance);
186
187 nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
188
189 /* Tag processing */
190 snprintf(buf_tag, sizeof(buf_tag), "%u", tag);
191 strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
192 strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TAG_XPATH,
193 sizeof(ab_xpath));
194 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
195
196 /* Table-Id processing */
197 snprintf(buf_tableid, sizeof(buf_tableid), "%u", table_id);
198 strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
199 strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TABLEID_XPATH,
200 sizeof(ab_xpath));
201 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tableid);
202 /* nexthop processing */
203
204 snprintf(ab_xpath, sizeof(ab_xpath),
205 FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf,
206 buf_gate_str, ifname);
207 strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
208 strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
209 nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
210
211 if (type == STATIC_BLACKHOLE) {
212 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
213 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_BH_XPATH,
214 sizeof(ab_xpath));
215
216 /* Route flags */
217 if (flag_str) {
218 switch (flag_str[0]) {
219 case 'r':
220 bh_type = "reject";
221 break;
222 case 'b':
223 bh_type = "unspec";
224 break;
225 case 'N':
226 bh_type = "null";
227 break;
228 default:
229 bh_type = NULL;
230 break;
231 }
232 nb_cli_enqueue_change(vty, ab_xpath,
233 NB_OP_MODIFY, bh_type);
234 } else {
235 nb_cli_enqueue_change(vty, ab_xpath,
236 NB_OP_MODIFY, "null");
237 }
7e24fdf3 238 }
88fa5104 239 if (type == STATIC_IPV4_GATEWAY_IFNAME
240 || type == STATIC_IPV6_GATEWAY_IFNAME) {
241 strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
242 strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
243 sizeof(ab_xpath));
244
245 if (onlink)
246 nb_cli_enqueue_change(vty, ab_xpath,
247 NB_OP_MODIFY, "true");
7e24fdf3 248 else
88fa5104 249 nb_cli_enqueue_change(vty, ab_xpath,
250 NB_OP_MODIFY, "false");
7e24fdf3 251 }
88fa5104 252 if (label_str) {
253 /* copy of label string (start) */
254 char *ostr;
255 /* pointer to next segment */
256 char *nump;
257
258 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
259 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
260 sizeof(xpath_mpls));
261
262 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
263 NULL);
264
265 ostr = XSTRDUP(MTYPE_TMP, label_str);
266 while ((nump = strsep(&ostr, "/")) != NULL) {
267 snprintf(ab_xpath, sizeof(ab_xpath),
268 FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
269 label_stack_id);
270 strlcpy(xpath_label, xpath_mpls,
271 sizeof(xpath_label));
272 strlcat(xpath_label, ab_xpath,
273 sizeof(xpath_label));
274 nb_cli_enqueue_change(vty, xpath_label,
275 NB_OP_MODIFY, nump);
276 label_stack_id++;
277 }
278 XFREE(MTYPE_TMP, ostr);
279 } else {
280 strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
281 strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
282 sizeof(xpath_mpls));
283 nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
284 NULL);
b1ab2876 285 }
88fa5104 286 ret = nb_cli_apply_changes(vty, xpath_prefix);
7e24fdf3 287 } else {
88fa5104 288 if (src_str)
289 snprintf(ab_xpath, sizeof(ab_xpath),
290 FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH,
291 "frr-staticd:staticd", "staticd", svrf,
292 buf_prefix,
314825ff 293 yang_afi_safi_value2identity(afi, safi),
88fa5104 294 buf_src_prefix, distance, buf_nh_type, nh_svrf,
295 buf_gate_str, ifname);
296 else
297 snprintf(ab_xpath, sizeof(ab_xpath),
298 FRR_DEL_S_ROUTE_NH_KEY_XPATH,
299 "frr-staticd:staticd", "staticd", svrf,
300 buf_prefix,
314825ff 301 yang_afi_safi_value2identity(afi, safi),
88fa5104 302 distance, buf_nh_type, nh_svrf, buf_gate_str,
303 ifname);
304
305 dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
306 if (!dnode)
307 return ret;
308
309 dnode = yang_get_subtree_with_no_sibling(dnode);
310 assert(dnode);
311 yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
312
313 nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
314 ret = nb_cli_apply_changes(vty, ab_xpath);
7e24fdf3
DS
315 }
316
88fa5104 317 return ret;
7e24fdf3 318}
7e24fdf3
DS
319static int static_route(struct vty *vty, afi_t afi, safi_t safi,
320 const char *negate, const char *dest_str,
321 const char *mask_str, const char *src_str,
322 const char *gate_str, const char *ifname,
323 const char *flag_str, const char *tag_str,
324 const char *distance_str, const char *vrf_name,
325 const char *label_str, const char *table_str)
326{
88fa5104 327 if (!vrf_name)
328 vrf_name = VRF_DEFAULT_NAME;
7e24fdf3 329
88fa5104 330 return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
331 dest_str, mask_str, src_str, gate_str, ifname,
332 flag_str, tag_str, distance_str, label_str,
333 table_str, false);
7e24fdf3
DS
334}
335
336/* Write static route configuration. */
337int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
338 safi_t safi, const char *cmd)
339{
7e24fdf3
DS
340 char spacing[100];
341 struct route_node *rn;
88fa5104 342 struct static_nexthop *nh;
343 struct static_path *pn;
7e24fdf3 344 struct route_table *stable;
88fa5104 345 struct static_route_info *si;
7e24fdf3
DS
346 char buf[SRCDEST2STR_BUFFER];
347 int write = 0;
88fa5104 348 struct stable_info *info;
7e24fdf3
DS
349
350 stable = svrf->stable[afi][safi];
351 if (stable == NULL)
352 return write;
353
772270f3
QY
354 snprintf(spacing, sizeof(spacing), "%s%s",
355 (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", cmd);
7e24fdf3 356
88fa5104 357 for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
358 si = static_route_info_from_rnode(rn);
359 if (!si)
7e24fdf3 360 continue;
88fa5104 361 info = static_get_stable_info(rn);
362 frr_each(static_path_list, &si->path_list, pn) {
363 frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
364 vty_out(vty, "%s %s", spacing,
365 srcdest_rnode2str(rn, buf,
366 sizeof(buf)));
367
368 switch (nh->type) {
369 case STATIC_IPV4_GATEWAY:
370 vty_out(vty, " %s",
371 inet_ntoa(nh->addr.ipv4));
7e24fdf3 372 break;
88fa5104 373 case STATIC_IPV6_GATEWAY:
374 vty_out(vty, " %s",
375 inet_ntop(AF_INET6,
376 &nh->addr.ipv6, buf,
377 sizeof(buf)));
7e24fdf3 378 break;
88fa5104 379 case STATIC_IFNAME:
380 vty_out(vty, " %s", nh->ifname);
381 break;
382 case STATIC_BLACKHOLE:
383 switch (nh->bh_type) {
384 case STATIC_BLACKHOLE_DROP:
385 vty_out(vty, " blackhole");
386 break;
387 case STATIC_BLACKHOLE_NULL:
388 vty_out(vty, " Null0");
389 break;
390 case STATIC_BLACKHOLE_REJECT:
391 vty_out(vty, " reject");
392 break;
393 }
394 break;
395 case STATIC_IPV4_GATEWAY_IFNAME:
396 vty_out(vty, " %s %s",
397 inet_ntop(AF_INET,
398 &nh->addr.ipv4, buf,
399 sizeof(buf)),
400 nh->ifname);
401 break;
402 case STATIC_IPV6_GATEWAY_IFNAME:
403 vty_out(vty, " %s %s",
404 inet_ntop(AF_INET6,
405 &nh->addr.ipv6, buf,
406 sizeof(buf)),
407 nh->ifname);
7e24fdf3
DS
408 break;
409 }
7e24fdf3 410
88fa5104 411 if (pn->tag)
412 vty_out(vty, " tag %" ROUTE_TAG_PRI,
413 pn->tag);
414
415 if (pn->distance
416 != ZEBRA_STATIC_DISTANCE_DEFAULT)
417 vty_out(vty, " %u", pn->distance);
418
419 /* Label information */
420 if (nh->snh_label.num_labels)
421 vty_out(vty, " label %s",
422 mpls_label2str(
423 nh->snh_label
424 .num_labels,
425 nh->snh_label.label,
426 buf, sizeof(buf), 0));
427
428 if (nh->nh_vrf_id != GET_STABLE_VRF_ID(info))
429 vty_out(vty, " nexthop-vrf %s",
430 nh->nh_vrfname);
431
432 /*
433 * table ID from VRF overrides
434 * configured
435 */
436 if (pn->table_id
437 && svrf->vrf->data.l.table_id
438 == RT_TABLE_MAIN)
439 vty_out(vty, " table %u", pn->table_id);
440
441 if (nh->onlink)
442 vty_out(vty, " onlink");
443
444 vty_out(vty, "\n");
445
446 write = 1;
447 }
7e24fdf3 448 }
88fa5104 449 }
7e24fdf3
DS
450 return write;
451}
452
453/* Static unicast routes for multicast RPF lookup. */
ca77b518 454DEFPY_YANG (ip_mroute_dist,
7e24fdf3
DS
455 ip_mroute_dist_cmd,
456 "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
457 NO_STR
458 IP_STR
459 "Configure static unicast route into MRIB for multicast RPF lookup\n"
460 "IP destination prefix (e.g. 10.0.0.0/8)\n"
461 "Nexthop address\n"
462 "Nexthop interface name\n"
463 "Distance\n")
464{
465 return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
466 NULL, NULL, gate_str, ifname, NULL, NULL,
467 distance_str, NULL, NULL, NULL);
468}
469
470/* Static route configuration. */
ca77b518 471DEFPY_YANG(ip_route_blackhole,
7e24fdf3
DS
472 ip_route_blackhole_cmd,
473 "[no] ip route\
474 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
475 <reject|blackhole>$flag \
476 [{ \
477 tag (1-4294967295) \
478 |(1-255)$distance \
479 |vrf NAME \
480 |label WORD \
481 |table (1-4294967295) \
482 }]",
483 NO_STR IP_STR
484 "Establish static routes\n"
485 "IP destination prefix (e.g. 10.0.0.0/8)\n"
486 "IP destination prefix\n"
487 "IP destination prefix mask\n"
488 "Emit an ICMP unreachable when matched\n"
489 "Silently discard pkts when matched\n"
490 "Set tag for this route\n"
491 "Tag value\n"
492 "Distance value for this route\n"
493 VRF_CMD_HELP_STR
494 MPLS_LABEL_HELPSTR
495 "Table to configure\n"
496 "The table number to configure\n")
497{
81bd033c 498 if (table_str && vrf && !vrf_is_backend_netns()) {
7e24fdf3
DS
499 vty_out(vty,
500 "%% table param only available when running on netns-based vrfs\n");
501 return CMD_WARNING_CONFIG_FAILED;
502 }
503
504 return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
505 mask_str, NULL, NULL, NULL, flag, tag_str,
506 distance_str, vrf, label, table_str);
507}
508
ca77b518 509DEFPY_YANG(ip_route_blackhole_vrf,
7e24fdf3
DS
510 ip_route_blackhole_vrf_cmd,
511 "[no] ip route\
512 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
513 <reject|blackhole>$flag \
514 [{ \
515 tag (1-4294967295) \
516 |(1-255)$distance \
517 |label WORD \
518 |table (1-4294967295) \
519 }]",
520 NO_STR IP_STR
521 "Establish static routes\n"
522 "IP destination prefix (e.g. 10.0.0.0/8)\n"
523 "IP destination prefix\n"
524 "IP destination prefix mask\n"
525 "Emit an ICMP unreachable when matched\n"
526 "Silently discard pkts when matched\n"
527 "Set tag for this route\n"
528 "Tag value\n"
529 "Distance value for this route\n"
530 MPLS_LABEL_HELPSTR
531 "Table to configure\n"
532 "The table number to configure\n")
533{
88fa5104 534 const struct lyd_node *vrf_dnode;
535 const char *vrfname;
7e24fdf3 536
88fa5104 537 vrf_dnode =
538 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
539 if (!vrf_dnode) {
540 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
541 return CMD_WARNING_CONFIG_FAILED;
542 }
88fa5104 543 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7e24fdf3
DS
544 /*
545 * Coverity is complaining that prefix could
546 * be dereferenced, but we know that prefix will
547 * valid. Add an assert to make it happy
548 */
549 assert(prefix);
88fa5104 550 return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
551 no, prefix, mask_str, NULL, NULL, NULL, flag,
02dc8ba3
QY
552 tag_str, distance_str, label, table_str,
553 false);
7e24fdf3
DS
554}
555
ca77b518 556DEFPY_YANG(ip_route_address_interface,
7e24fdf3
DS
557 ip_route_address_interface_cmd,
558 "[no] ip route\
559 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
560 A.B.C.D$gate \
54a3d7cb 561 <INTERFACE|Null0>$ifname \
7e24fdf3
DS
562 [{ \
563 tag (1-4294967295) \
564 |(1-255)$distance \
565 |vrf NAME \
566 |label WORD \
567 |table (1-4294967295) \
568 |nexthop-vrf NAME \
02dc8ba3 569 |onlink$onlink \
7e24fdf3
DS
570 }]",
571 NO_STR IP_STR
572 "Establish static routes\n"
573 "IP destination prefix (e.g. 10.0.0.0/8)\n"
574 "IP destination prefix\n"
575 "IP destination prefix mask\n"
576 "IP gateway address\n"
54a3d7cb
QY
577 "IP gateway interface name\n"
578 "Null interface\n"
7e24fdf3
DS
579 "Set tag for this route\n"
580 "Tag value\n"
581 "Distance value for this route\n"
582 VRF_CMD_HELP_STR
583 MPLS_LABEL_HELPSTR
584 "Table to configure\n"
585 "The table number to configure\n"
02dc8ba3 586 VRF_CMD_HELP_STR
92ae10e6 587 "Treat the nexthop as directly attached to the interface\n")
7e24fdf3 588{
88fa5104 589 const char *nh_vrf;
7e24fdf3
DS
590 const char *flag = NULL;
591
592 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
593 flag = "Null0";
594 ifname = NULL;
595 }
88fa5104 596 if (!vrf)
597 vrf = VRF_DEFAULT_NAME;
7e24fdf3
DS
598
599 if (nexthop_vrf)
88fa5104 600 nh_vrf = nexthop_vrf;
7e24fdf3 601 else
88fa5104 602 nh_vrf = vrf;
7e24fdf3 603
88fa5104 604 return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
02dc8ba3
QY
605 prefix, mask_str, NULL, gate_str, ifname, flag,
606 tag_str, distance_str, label, table_str,
607 !!onlink);
7e24fdf3
DS
608}
609
ca77b518 610DEFPY_YANG(ip_route_address_interface_vrf,
7e24fdf3
DS
611 ip_route_address_interface_vrf_cmd,
612 "[no] ip route\
613 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
614 A.B.C.D$gate \
54a3d7cb 615 <INTERFACE|Null0>$ifname \
7e24fdf3
DS
616 [{ \
617 tag (1-4294967295) \
618 |(1-255)$distance \
619 |label WORD \
620 |table (1-4294967295) \
621 |nexthop-vrf NAME \
02dc8ba3 622 |onlink$onlink \
7e24fdf3
DS
623 }]",
624 NO_STR IP_STR
625 "Establish static routes\n"
626 "IP destination prefix (e.g. 10.0.0.0/8)\n"
627 "IP destination prefix\n"
628 "IP destination prefix mask\n"
629 "IP gateway address\n"
54a3d7cb
QY
630 "IP gateway interface name\n"
631 "Null interface\n"
7e24fdf3
DS
632 "Set tag for this route\n"
633 "Tag value\n"
634 "Distance value for this route\n"
635 MPLS_LABEL_HELPSTR
636 "Table to configure\n"
637 "The table number to configure\n"
02dc8ba3 638 VRF_CMD_HELP_STR
92ae10e6 639 "Treat the nexthop as directly attached to the interface\n")
7e24fdf3 640{
88fa5104 641 const char *nh_vrf;
7e24fdf3 642 const char *flag = NULL;
88fa5104 643 const struct lyd_node *vrf_dnode;
644 const char *vrfname;
7e24fdf3 645
88fa5104 646 vrf_dnode =
647 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
648 if (!vrf_dnode) {
649 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
650 return CMD_WARNING_CONFIG_FAILED;
651 }
88fa5104 652 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7e24fdf3
DS
653
654 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
655 flag = "Null0";
656 ifname = NULL;
657 }
7e24fdf3 658 if (nexthop_vrf)
88fa5104 659 nh_vrf = nexthop_vrf;
7e24fdf3 660 else
88fa5104 661 nh_vrf = vrfname;
7e24fdf3 662
88fa5104 663 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
02dc8ba3
QY
664 prefix, mask_str, NULL, gate_str, ifname, flag,
665 tag_str, distance_str, label, table_str,
666 !!onlink);
7e24fdf3
DS
667}
668
ca77b518 669DEFPY_YANG(ip_route,
7e24fdf3
DS
670 ip_route_cmd,
671 "[no] ip route\
672 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
54a3d7cb 673 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
7e24fdf3
DS
674 [{ \
675 tag (1-4294967295) \
676 |(1-255)$distance \
677 |vrf NAME \
678 |label WORD \
679 |table (1-4294967295) \
680 |nexthop-vrf NAME \
681 }]",
682 NO_STR IP_STR
683 "Establish static routes\n"
684 "IP destination prefix (e.g. 10.0.0.0/8)\n"
685 "IP destination prefix\n"
686 "IP destination prefix mask\n"
687 "IP gateway address\n"
688 "IP gateway interface name\n"
54a3d7cb 689 "Null interface\n"
7e24fdf3
DS
690 "Set tag for this route\n"
691 "Tag value\n"
692 "Distance value for this route\n"
693 VRF_CMD_HELP_STR
694 MPLS_LABEL_HELPSTR
695 "Table to configure\n"
696 "The table number to configure\n"
697 VRF_CMD_HELP_STR)
698{
88fa5104 699 const char *nh_vrf;
7e24fdf3
DS
700 const char *flag = NULL;
701
7e24fdf3
DS
702 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
703 flag = "Null0";
704 ifname = NULL;
705 }
706
88fa5104 707 if (!vrf)
708 vrf = VRF_DEFAULT_NAME;
7e24fdf3
DS
709
710 if (nexthop_vrf)
88fa5104 711 nh_vrf = nexthop_vrf;
7e24fdf3 712 else
88fa5104 713 nh_vrf = vrf;
7e24fdf3 714
88fa5104 715 return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
716 prefix, mask_str, NULL, gate_str, ifname, flag,
717 tag_str, distance_str, label, table_str,
718 false);
7e24fdf3
DS
719}
720
ca77b518 721DEFPY_YANG(ip_route_vrf,
7e24fdf3
DS
722 ip_route_vrf_cmd,
723 "[no] ip route\
724 <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
54a3d7cb 725 <A.B.C.D$gate|<INTERFACE|Null0>$ifname> \
7e24fdf3
DS
726 [{ \
727 tag (1-4294967295) \
728 |(1-255)$distance \
729 |label WORD \
730 |table (1-4294967295) \
731 |nexthop-vrf NAME \
732 }]",
733 NO_STR IP_STR
734 "Establish static routes\n"
735 "IP destination prefix (e.g. 10.0.0.0/8)\n"
736 "IP destination prefix\n"
737 "IP destination prefix mask\n"
738 "IP gateway address\n"
739 "IP gateway interface name\n"
54a3d7cb 740 "Null interface\n"
7e24fdf3
DS
741 "Set tag for this route\n"
742 "Tag value\n"
743 "Distance value for this route\n"
744 MPLS_LABEL_HELPSTR
745 "Table to configure\n"
746 "The table number to configure\n"
747 VRF_CMD_HELP_STR)
748{
88fa5104 749 const char *nh_vrf;
51c4ed0a 750 const char *flag = NULL;
88fa5104 751 const struct lyd_node *vrf_dnode;
752 const char *vrfname;
7e24fdf3 753
88fa5104 754 vrf_dnode =
755 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
756 if (!vrf_dnode) {
757 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
758 return CMD_WARNING_CONFIG_FAILED;
759 }
760
88fa5104 761 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
762
7e24fdf3
DS
763 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
764 flag = "Null0";
765 ifname = NULL;
766 }
7e24fdf3 767 if (nexthop_vrf)
88fa5104 768 nh_vrf = nexthop_vrf;
7e24fdf3 769 else
88fa5104 770 nh_vrf = vrfname;
7e24fdf3 771
88fa5104 772 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
773 prefix, mask_str, NULL, gate_str, ifname, flag,
774 tag_str, distance_str, label, table_str,
775 false);
7e24fdf3
DS
776}
777
ca77b518 778DEFPY_YANG(ipv6_route_blackhole,
7e24fdf3
DS
779 ipv6_route_blackhole_cmd,
780 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
54a3d7cb 781 <reject|blackhole>$flag \
7e24fdf3
DS
782 [{ \
783 tag (1-4294967295) \
784 |(1-255)$distance \
785 |vrf NAME \
786 |label WORD \
787 |table (1-4294967295) \
788 }]",
789 NO_STR
790 IPV6_STR
791 "Establish static routes\n"
792 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
793 "IPv6 source-dest route\n"
794 "IPv6 source prefix\n"
7e24fdf3
DS
795 "Emit an ICMP unreachable when matched\n"
796 "Silently discard pkts when matched\n"
797 "Set tag for this route\n"
798 "Tag value\n"
799 "Distance value for this prefix\n"
800 VRF_CMD_HELP_STR
801 MPLS_LABEL_HELPSTR
802 "Table to configure\n"
803 "The table number to configure\n")
804{
81bd033c 805 if (table_str && vrf && !vrf_is_backend_netns()) {
7e24fdf3
DS
806 vty_out(vty,
807 "%% table param only available when running on netns-based vrfs\n");
808 return CMD_WARNING_CONFIG_FAILED;
809 }
810
811 return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
812 NULL, from_str, NULL, NULL, flag, tag_str,
813 distance_str, vrf, label, table_str);
814}
815
ca77b518 816DEFPY_YANG(ipv6_route_blackhole_vrf,
7e24fdf3
DS
817 ipv6_route_blackhole_vrf_cmd,
818 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
54a3d7cb 819 <reject|blackhole>$flag \
7e24fdf3
DS
820 [{ \
821 tag (1-4294967295) \
822 |(1-255)$distance \
823 |label WORD \
824 |table (1-4294967295) \
825 }]",
826 NO_STR
827 IPV6_STR
828 "Establish static routes\n"
829 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
830 "IPv6 source-dest route\n"
831 "IPv6 source prefix\n"
7e24fdf3
DS
832 "Emit an ICMP unreachable when matched\n"
833 "Silently discard pkts when matched\n"
834 "Set tag for this route\n"
835 "Tag value\n"
836 "Distance value for this prefix\n"
837 MPLS_LABEL_HELPSTR
838 "Table to configure\n"
839 "The table number to configure\n")
840{
88fa5104 841 const struct lyd_node *vrf_dnode;
842 const char *vrfname;
7e24fdf3 843
88fa5104 844 vrf_dnode =
845 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
846 if (!vrf_dnode) {
847 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
848 return CMD_WARNING_CONFIG_FAILED;
849 }
88fa5104 850 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7e24fdf3
DS
851
852 /*
853 * Coverity is complaining that prefix could
854 * be dereferenced, but we know that prefix will
855 * valid. Add an assert to make it happy
856 */
857 assert(prefix);
88fa5104 858
859 return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
860 no, prefix_str, NULL, from_str, NULL, NULL,
861 flag, tag_str, distance_str, label, table_str,
862 false);
7e24fdf3
DS
863}
864
ca77b518 865DEFPY_YANG(ipv6_route_address_interface,
7e24fdf3
DS
866 ipv6_route_address_interface_cmd,
867 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
868 X:X::X:X$gate \
54a3d7cb 869 <INTERFACE|Null0>$ifname \
7e24fdf3
DS
870 [{ \
871 tag (1-4294967295) \
872 |(1-255)$distance \
873 |vrf NAME \
874 |label WORD \
875 |table (1-4294967295) \
876 |nexthop-vrf NAME \
02dc8ba3 877 |onlink$onlink \
7e24fdf3
DS
878 }]",
879 NO_STR
880 IPV6_STR
881 "Establish static routes\n"
882 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
883 "IPv6 source-dest route\n"
884 "IPv6 source prefix\n"
885 "IPv6 gateway address\n"
886 "IPv6 gateway interface name\n"
54a3d7cb 887 "Null interface\n"
7e24fdf3
DS
888 "Set tag for this route\n"
889 "Tag value\n"
890 "Distance value for this prefix\n"
891 VRF_CMD_HELP_STR
892 MPLS_LABEL_HELPSTR
893 "Table to configure\n"
894 "The table number to configure\n"
02dc8ba3 895 VRF_CMD_HELP_STR
92ae10e6 896 "Treat the nexthop as directly attached to the interface\n")
7e24fdf3 897{
88fa5104 898 const char *nh_vrf;
c66861af 899 const char *flag = NULL;
7e24fdf3 900
88fa5104 901 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
902 flag = "Null0";
903 ifname = NULL;
7e24fdf3
DS
904 }
905
88fa5104 906 if (!vrf)
907 vrf = VRF_DEFAULT_NAME;
7e24fdf3
DS
908
909 if (nexthop_vrf)
88fa5104 910 nh_vrf = nexthop_vrf;
7e24fdf3 911 else
88fa5104 912 nh_vrf = vrf;
7e24fdf3 913
88fa5104 914 return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
915 prefix_str, NULL, from_str, gate_str, ifname,
916 flag, tag_str, distance_str, label, table_str,
917 !!onlink);
7e24fdf3
DS
918}
919
ca77b518 920DEFPY_YANG(ipv6_route_address_interface_vrf,
7e24fdf3
DS
921 ipv6_route_address_interface_vrf_cmd,
922 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
923 X:X::X:X$gate \
54a3d7cb 924 <INTERFACE|Null0>$ifname \
7e24fdf3
DS
925 [{ \
926 tag (1-4294967295) \
927 |(1-255)$distance \
928 |label WORD \
929 |table (1-4294967295) \
930 |nexthop-vrf NAME \
02dc8ba3 931 |onlink$onlink \
7e24fdf3
DS
932 }]",
933 NO_STR
934 IPV6_STR
935 "Establish static routes\n"
936 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
937 "IPv6 source-dest route\n"
938 "IPv6 source prefix\n"
939 "IPv6 gateway address\n"
940 "IPv6 gateway interface name\n"
54a3d7cb 941 "Null interface\n"
7e24fdf3
DS
942 "Set tag for this route\n"
943 "Tag value\n"
944 "Distance value for this prefix\n"
945 MPLS_LABEL_HELPSTR
946 "Table to configure\n"
947 "The table number to configure\n"
02dc8ba3 948 VRF_CMD_HELP_STR
92ae10e6 949 "Treat the nexthop as directly attached to the interface\n")
7e24fdf3 950{
88fa5104 951 const char *nh_vrf;
c66861af 952 const char *flag = NULL;
88fa5104 953 const struct lyd_node *vrf_dnode;
954 const char *vrfname;
7e24fdf3 955
88fa5104 956 vrf_dnode =
957 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
958 if (!vrf_dnode) {
959 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
960 return CMD_WARNING_CONFIG_FAILED;
961 }
88fa5104 962 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7e24fdf3
DS
963
964 if (nexthop_vrf)
88fa5104 965 nh_vrf = nexthop_vrf;
7e24fdf3 966 else
88fa5104 967 nh_vrf = vrfname;
7e24fdf3 968
54a3d7cb
QY
969 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
970 flag = "Null0";
971 ifname = NULL;
972 }
88fa5104 973 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
974 no, prefix_str, NULL, from_str, gate_str,
975 ifname, flag, tag_str, distance_str, label,
976 table_str, !!onlink);
7e24fdf3
DS
977}
978
ca77b518 979DEFPY_YANG(ipv6_route,
7e24fdf3
DS
980 ipv6_route_cmd,
981 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
54a3d7cb 982 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
7e24fdf3
DS
983 [{ \
984 tag (1-4294967295) \
985 |(1-255)$distance \
986 |vrf NAME \
987 |label WORD \
988 |table (1-4294967295) \
989 |nexthop-vrf NAME \
990 }]",
991 NO_STR
992 IPV6_STR
993 "Establish static routes\n"
994 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
995 "IPv6 source-dest route\n"
996 "IPv6 source prefix\n"
997 "IPv6 gateway address\n"
998 "IPv6 gateway interface name\n"
54a3d7cb 999 "Null interface\n"
7e24fdf3
DS
1000 "Set tag for this route\n"
1001 "Tag value\n"
1002 "Distance value for this prefix\n"
1003 VRF_CMD_HELP_STR
1004 MPLS_LABEL_HELPSTR
1005 "Table to configure\n"
1006 "The table number to configure\n"
1007 VRF_CMD_HELP_STR)
1008{
88fa5104 1009 const char *nh_vrf;
c66861af 1010 const char *flag = NULL;
7e24fdf3 1011
88fa5104 1012 if (!vrf)
1013 vrf = VRF_DEFAULT_NAME;
7e24fdf3
DS
1014
1015 if (nexthop_vrf)
88fa5104 1016 nh_vrf = nexthop_vrf;
7e24fdf3 1017 else
88fa5104 1018 nh_vrf = vrf;
7e24fdf3 1019
54a3d7cb
QY
1020 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1021 flag = "Null0";
1022 ifname = NULL;
1023 }
88fa5104 1024 return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
1025 prefix_str, NULL, from_str, gate_str, ifname,
1026 flag, tag_str, distance_str, label, table_str,
1027 false);
7e24fdf3
DS
1028}
1029
ca77b518 1030DEFPY_YANG(ipv6_route_vrf,
7e24fdf3
DS
1031 ipv6_route_vrf_cmd,
1032 "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
54a3d7cb 1033 <X:X::X:X$gate|<INTERFACE|Null0>$ifname> \
7e24fdf3
DS
1034 [{ \
1035 tag (1-4294967295) \
1036 |(1-255)$distance \
1037 |label WORD \
1038 |table (1-4294967295) \
1039 |nexthop-vrf NAME \
1040 }]",
1041 NO_STR
1042 IPV6_STR
1043 "Establish static routes\n"
1044 "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
1045 "IPv6 source-dest route\n"
1046 "IPv6 source prefix\n"
1047 "IPv6 gateway address\n"
1048 "IPv6 gateway interface name\n"
54a3d7cb 1049 "Null interface\n"
7e24fdf3
DS
1050 "Set tag for this route\n"
1051 "Tag value\n"
1052 "Distance value for this prefix\n"
1053 MPLS_LABEL_HELPSTR
1054 "Table to configure\n"
1055 "The table number to configure\n"
1056 VRF_CMD_HELP_STR)
1057{
88fa5104 1058 const char *nh_vrf;
c66861af 1059 const char *flag = NULL;
88fa5104 1060 const struct lyd_node *vrf_dnode;
1061 const char *vrfname;
7e24fdf3 1062
88fa5104 1063 vrf_dnode =
1064 yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
1065 if (!vrf_dnode) {
1066 vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
7e24fdf3
DS
1067 return CMD_WARNING_CONFIG_FAILED;
1068 }
88fa5104 1069 vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7e24fdf3
DS
1070
1071 if (nexthop_vrf)
88fa5104 1072 nh_vrf = nexthop_vrf;
7e24fdf3 1073 else
88fa5104 1074 nh_vrf = vrfname;
7e24fdf3 1075
54a3d7cb
QY
1076 if (ifname && !strncasecmp(ifname, "Null0", 5)) {
1077 flag = "Null0";
1078 ifname = NULL;
1079 }
88fa5104 1080 return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
1081 no, prefix_str, NULL, from_str, gate_str,
1082 ifname, flag, tag_str, distance_str, label,
1083 table_str, false);
7e24fdf3 1084}
ca77b518 1085DEFPY_YANG(debug_staticd,
31ddf3b7
MS
1086 debug_staticd_cmd,
1087 "[no] debug static [{events$events}]",
1088 NO_STR
1089 DEBUG_STR
1090 STATICD_STR
1091 "Debug events\n")
1092{
1093 /* If no specific category, change all */
1094 if (strmatch(argv[argc - 1]->text, "static"))
1095 static_debug_set(vty->node, !no, true);
1096 else
1097 static_debug_set(vty->node, !no, !!events);
7e24fdf3 1098
31ddf3b7
MS
1099 return CMD_SUCCESS;
1100}
1101
1102DEFUN_NOSH (show_debugging_static,
1103 show_debugging_static_cmd,
e60b527e
DS
1104 "show debugging [static]",
1105 SHOW_STR
1106 DEBUG_STR
1107 "Static Information\n")
1108{
31ddf3b7
MS
1109 vty_out(vty, "Staticd debugging status\n");
1110
1111 static_debug_status_write(vty);
e60b527e
DS
1112
1113 return CMD_SUCCESS;
1114}
1115
62b346ee 1116static struct cmd_node debug_node = {
f4b8291f 1117 .name = "debug",
62b346ee
DL
1118 .node = DEBUG_NODE,
1119 .prompt = "",
612c2c15 1120 .config_write = static_config_write_debug,
62b346ee 1121};
31ddf3b7 1122
7e24fdf3
DS
1123void static_vty_init(void)
1124{
612c2c15 1125 install_node(&debug_node);
31ddf3b7 1126
7e24fdf3
DS
1127 install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
1128
1129 install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
1130 install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
1131 install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
1132 install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
1133 install_element(CONFIG_NODE, &ip_route_cmd);
1134 install_element(VRF_NODE, &ip_route_vrf_cmd);
1135
1136 install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
1137 install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
1138 install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
1139 install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
1140 install_element(CONFIG_NODE, &ipv6_route_cmd);
1141 install_element(VRF_NODE, &ipv6_route_vrf_cmd);
1142
31ddf3b7
MS
1143 install_element(VIEW_NODE, &show_debugging_static_cmd);
1144 install_element(VIEW_NODE, &debug_staticd_cmd);
1145 install_element(CONFIG_NODE, &debug_staticd_cmd);
7e24fdf3 1146}