mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 15:04:05 +00:00 
			
		
		
		
	Simplify all DEFUNs by moving all logic to the northbound translation function and transforming all function parameters into a single structure. Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
		
			
				
	
	
		
			1356 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1356 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * STATICd - vty code
 | 
						|
 * Copyright (C) 2018 Cumulus Networks, Inc.
 | 
						|
 *               Donald Sharp
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the Free
 | 
						|
 * Software Foundation; either version 2 of the License, or (at your option)
 | 
						|
 * any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
						|
 * more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along
 | 
						|
 * with this program; see the file COPYING; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "command.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "vrf.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "nexthop.h"
 | 
						|
#include "table.h"
 | 
						|
#include "srcdest_table.h"
 | 
						|
#include "mpls.h"
 | 
						|
#include "northbound.h"
 | 
						|
#include "libfrr.h"
 | 
						|
#include "routing_nb.h"
 | 
						|
#include "northbound_cli.h"
 | 
						|
 | 
						|
#include "static_vrf.h"
 | 
						|
#include "static_vty.h"
 | 
						|
#include "static_routes.h"
 | 
						|
#include "static_debug.h"
 | 
						|
#include "staticd/static_vty_clippy.c"
 | 
						|
#include "static_nb.h"
 | 
						|
 | 
						|
#define STATICD_STR "Static route daemon\n"
 | 
						|
 | 
						|
/** All possible route parameters available in CLI. */
 | 
						|
struct static_route_args {
 | 
						|
	/** "no" command? */
 | 
						|
	bool delete;
 | 
						|
	/** Is VRF obtained from XPath? */
 | 
						|
	bool xpath_vrf;
 | 
						|
 | 
						|
	bool onlink;
 | 
						|
	afi_t afi;
 | 
						|
	safi_t safi;
 | 
						|
 | 
						|
	const char *vrf;
 | 
						|
	const char *nexthop_vrf;
 | 
						|
	const char *prefix;
 | 
						|
	const char *prefix_mask;
 | 
						|
	const char *source;
 | 
						|
	const char *gateway;
 | 
						|
	const char *interface_name;
 | 
						|
	const char *flag;
 | 
						|
	const char *tag;
 | 
						|
	const char *distance;
 | 
						|
	const char *label;
 | 
						|
	const char *table;
 | 
						|
	const char *color;
 | 
						|
};
 | 
						|
 | 
						|
static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
	struct prefix p, src;
 | 
						|
	struct in_addr mask;
 | 
						|
	enum static_nh_type type;
 | 
						|
	const char *bh_type;
 | 
						|
	char xpath_prefix[XPATH_MAXLEN];
 | 
						|
	char xpath_nexthop[XPATH_MAXLEN];
 | 
						|
	char xpath_mpls[XPATH_MAXLEN];
 | 
						|
	char xpath_label[XPATH_MAXLEN];
 | 
						|
	char ab_xpath[XPATH_MAXLEN];
 | 
						|
	char buf_prefix[PREFIX_STRLEN];
 | 
						|
	char buf_src_prefix[PREFIX_STRLEN] = {};
 | 
						|
	char buf_nh_type[PREFIX_STRLEN] = {};
 | 
						|
	char buf_tag[PREFIX_STRLEN];
 | 
						|
	uint8_t label_stack_id = 0;
 | 
						|
	const char *buf_gate_str;
 | 
						|
	uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
 | 
						|
	route_tag_t tag = 0;
 | 
						|
	uint32_t table_id = 0;
 | 
						|
	const struct lyd_node *dnode;
 | 
						|
	const struct lyd_node *vrf_dnode;
 | 
						|
 | 
						|
	if (args->xpath_vrf) {
 | 
						|
		vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
 | 
						|
					   VTY_CURR_XPATH);
 | 
						|
		if (vrf_dnode == NULL) {
 | 
						|
			vty_out(vty,
 | 
						|
				"%% Failed to get vrf dnode in candidate db\n");
 | 
						|
			return CMD_WARNING_CONFIG_FAILED;
 | 
						|
		}
 | 
						|
 | 
						|
		args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
 | 
						|
	} else {
 | 
						|
		if (args->vrf == NULL)
 | 
						|
			args->vrf = VRF_DEFAULT_NAME;
 | 
						|
	}
 | 
						|
	if (args->nexthop_vrf == NULL)
 | 
						|
		args->nexthop_vrf = args->vrf;
 | 
						|
 | 
						|
	if (args->interface_name &&
 | 
						|
	    !strcasecmp(args->interface_name, "Null0")) {
 | 
						|
		args->flag = "Null0";
 | 
						|
		args->interface_name = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	assert(!!str2prefix(args->prefix, &p));
 | 
						|
 | 
						|
	switch (args->afi) {
 | 
						|
	case AFI_IP:
 | 
						|
		/* Cisco like mask notation. */
 | 
						|
		if (args->prefix_mask) {
 | 
						|
			assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
 | 
						|
			       1);
 | 
						|
			p.prefixlen = ip_masklen(mask);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case AFI_IP6:
 | 
						|
		/* srcdest routing */
 | 
						|
		if (args->source)
 | 
						|
			assert(!!str2prefix(args->source, &src));
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Apply mask for given prefix. */
 | 
						|
	apply_mask(&p);
 | 
						|
	prefix2str(&p, buf_prefix, sizeof(buf_prefix));
 | 
						|
 | 
						|
	if (args->source)
 | 
						|
		prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
 | 
						|
	if (args->gateway)
 | 
						|
		buf_gate_str = args->gateway;
 | 
						|
	else
 | 
						|
		buf_gate_str = "";
 | 
						|
 | 
						|
	if (args->gateway == NULL && args->interface_name == NULL)
 | 
						|
		type = STATIC_BLACKHOLE;
 | 
						|
	else if (args->gateway && args->interface_name) {
 | 
						|
		if (args->afi == AFI_IP)
 | 
						|
			type = STATIC_IPV4_GATEWAY_IFNAME;
 | 
						|
		else
 | 
						|
			type = STATIC_IPV6_GATEWAY_IFNAME;
 | 
						|
	} else if (args->interface_name)
 | 
						|
		type = STATIC_IFNAME;
 | 
						|
	else {
 | 
						|
		if (args->afi == AFI_IP)
 | 
						|
			type = STATIC_IPV4_GATEWAY;
 | 
						|
		else
 | 
						|
			type = STATIC_IPV6_GATEWAY;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Administrative distance. */
 | 
						|
	if (args->distance)
 | 
						|
		distance = strtol(args->distance, NULL, 10);
 | 
						|
 | 
						|
	/* tag */
 | 
						|
	if (args->tag)
 | 
						|
		tag = strtoul(args->tag, NULL, 10);
 | 
						|
 | 
						|
	/* TableID */
 | 
						|
	if (args->table)
 | 
						|
		table_id = strtol(args->table, NULL, 10);
 | 
						|
 | 
						|
	static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
 | 
						|
	if (!args->delete) {
 | 
						|
		if (args->source)
 | 
						|
			snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
				 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 buf_src_prefix, table_id, buf_nh_type,
 | 
						|
				 args->nexthop_vrf, buf_gate_str,
 | 
						|
				 args->interface_name);
 | 
						|
		else
 | 
						|
			snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
				 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 table_id, buf_nh_type, args->nexthop_vrf,
 | 
						|
				 buf_gate_str, args->interface_name);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * If there's already the same nexthop but with a different
 | 
						|
		 * distance, then remove it for the replacement.
 | 
						|
		 */
 | 
						|
		dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
 | 
						|
		if (dnode) {
 | 
						|
			dnode = yang_get_subtree_with_no_sibling(dnode);
 | 
						|
			assert(dnode);
 | 
						|
			yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
 | 
						|
 | 
						|
			nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY,
 | 
						|
					      NULL);
 | 
						|
		}
 | 
						|
 | 
						|
		/* route + path procesing */
 | 
						|
		if (args->source)
 | 
						|
			snprintf(xpath_prefix, sizeof(xpath_prefix),
 | 
						|
				 FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 buf_src_prefix, table_id, distance);
 | 
						|
		else
 | 
						|
			snprintf(xpath_prefix, sizeof(xpath_prefix),
 | 
						|
				 FRR_STATIC_ROUTE_INFO_KEY_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 table_id, distance);
 | 
						|
 | 
						|
		nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
 | 
						|
 | 
						|
		/* Tag processing */
 | 
						|
		snprintf(buf_tag, sizeof(buf_tag), "%u", tag);
 | 
						|
		strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
 | 
						|
		strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TAG_XPATH,
 | 
						|
			sizeof(ab_xpath));
 | 
						|
		nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
 | 
						|
 | 
						|
		/* nexthop processing */
 | 
						|
 | 
						|
		snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
			 FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
 | 
						|
			 args->nexthop_vrf, buf_gate_str, args->interface_name);
 | 
						|
		strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
 | 
						|
		strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
 | 
						|
		nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
 | 
						|
 | 
						|
		if (type == STATIC_BLACKHOLE) {
 | 
						|
			strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
 | 
						|
			strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_BH_XPATH,
 | 
						|
				sizeof(ab_xpath));
 | 
						|
 | 
						|
			/* Route flags */
 | 
						|
			if (args->flag) {
 | 
						|
				switch (args->flag[0]) {
 | 
						|
				case 'r':
 | 
						|
					bh_type = "reject";
 | 
						|
					break;
 | 
						|
				case 'b':
 | 
						|
					bh_type = "unspec";
 | 
						|
					break;
 | 
						|
				case 'N':
 | 
						|
					bh_type = "null";
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					bh_type = NULL;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				nb_cli_enqueue_change(vty, ab_xpath,
 | 
						|
						      NB_OP_MODIFY, bh_type);
 | 
						|
			} else {
 | 
						|
				nb_cli_enqueue_change(vty, ab_xpath,
 | 
						|
						      NB_OP_MODIFY, "null");
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (type == STATIC_IPV4_GATEWAY_IFNAME
 | 
						|
		    || type == STATIC_IPV6_GATEWAY_IFNAME) {
 | 
						|
			strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
 | 
						|
			strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
 | 
						|
				sizeof(ab_xpath));
 | 
						|
 | 
						|
			if (args->onlink)
 | 
						|
				nb_cli_enqueue_change(vty, ab_xpath,
 | 
						|
						      NB_OP_MODIFY, "true");
 | 
						|
			else
 | 
						|
				nb_cli_enqueue_change(vty, ab_xpath,
 | 
						|
						      NB_OP_MODIFY, "false");
 | 
						|
		}
 | 
						|
		if (type == STATIC_IPV4_GATEWAY
 | 
						|
		    || type == STATIC_IPV6_GATEWAY
 | 
						|
		    || type == STATIC_IPV4_GATEWAY_IFNAME
 | 
						|
		    || type == STATIC_IPV6_GATEWAY_IFNAME) {
 | 
						|
			strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
 | 
						|
			strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
 | 
						|
				sizeof(ab_xpath));
 | 
						|
			if (args->color)
 | 
						|
				nb_cli_enqueue_change(vty, ab_xpath,
 | 
						|
						      NB_OP_MODIFY,
 | 
						|
						      args->color);
 | 
						|
		}
 | 
						|
		if (args->label) {
 | 
						|
			/* copy of label string (start) */
 | 
						|
			char *ostr;
 | 
						|
			/* pointer to next segment */
 | 
						|
			char *nump;
 | 
						|
 | 
						|
			strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
 | 
						|
			strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
 | 
						|
				sizeof(xpath_mpls));
 | 
						|
 | 
						|
			nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
 | 
						|
					      NULL);
 | 
						|
 | 
						|
			ostr = XSTRDUP(MTYPE_TMP, args->label);
 | 
						|
			while ((nump = strsep(&ostr, "/")) != NULL) {
 | 
						|
				snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
					 FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
 | 
						|
					 label_stack_id);
 | 
						|
				strlcpy(xpath_label, xpath_mpls,
 | 
						|
					sizeof(xpath_label));
 | 
						|
				strlcat(xpath_label, ab_xpath,
 | 
						|
					sizeof(xpath_label));
 | 
						|
				nb_cli_enqueue_change(vty, xpath_label,
 | 
						|
						      NB_OP_MODIFY, nump);
 | 
						|
				label_stack_id++;
 | 
						|
			}
 | 
						|
			XFREE(MTYPE_TMP, ostr);
 | 
						|
		} else {
 | 
						|
			strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
 | 
						|
			strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
 | 
						|
				sizeof(xpath_mpls));
 | 
						|
			nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
 | 
						|
					      NULL);
 | 
						|
		}
 | 
						|
		ret = nb_cli_apply_changes(vty, xpath_prefix);
 | 
						|
	} else {
 | 
						|
		if (args->source)
 | 
						|
			snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
				 FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 buf_src_prefix, table_id, buf_nh_type,
 | 
						|
				 args->nexthop_vrf, buf_gate_str,
 | 
						|
				 args->interface_name);
 | 
						|
		else
 | 
						|
			snprintf(ab_xpath, sizeof(ab_xpath),
 | 
						|
				 FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
 | 
						|
				 "frr-staticd:staticd", "staticd", args->vrf,
 | 
						|
				 buf_prefix,
 | 
						|
				 yang_afi_safi_value2identity(args->afi,
 | 
						|
							      args->safi),
 | 
						|
				 table_id, buf_nh_type, args->nexthop_vrf,
 | 
						|
				 buf_gate_str, args->interface_name);
 | 
						|
 | 
						|
		dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
 | 
						|
		if (!dnode) {
 | 
						|
			vty_out(vty,
 | 
						|
				"%% Refusing to remove a non-existent route\n");
 | 
						|
			return CMD_SUCCESS;
 | 
						|
		}
 | 
						|
 | 
						|
		dnode = yang_get_subtree_with_no_sibling(dnode);
 | 
						|
		assert(dnode);
 | 
						|
		yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
 | 
						|
 | 
						|
		nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
 | 
						|
		ret = nb_cli_apply_changes(vty, ab_xpath);
 | 
						|
	}
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* Static unicast routes for multicast RPF lookup. */
 | 
						|
DEFPY_YANG (ip_mroute_dist,
 | 
						|
       ip_mroute_dist_cmd,
 | 
						|
       "[no] ip mroute A.B.C.D/M$prefix <A.B.C.D$gate|INTERFACE$ifname> [(1-255)$distance]",
 | 
						|
       NO_STR
 | 
						|
       IP_STR
 | 
						|
       "Configure static unicast route into MRIB for multicast RPF lookup\n"
 | 
						|
       "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
       "Nexthop address\n"
 | 
						|
       "Nexthop interface name\n"
 | 
						|
       "Distance\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_MULTICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.distance = distance_str,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
/* Static route configuration.  */
 | 
						|
DEFPY_YANG(ip_route_blackhole,
 | 
						|
      ip_route_blackhole_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask>                        \
 | 
						|
	<reject|blackhole>$flag                                               \
 | 
						|
	[{                                                                    \
 | 
						|
	  tag (1-4294967295)                                                  \
 | 
						|
	  |(1-255)$distance                                                   \
 | 
						|
	  |vrf NAME                                                           \
 | 
						|
	  |label WORD                                                         \
 | 
						|
          |table (1-4294967295)                                               \
 | 
						|
          }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "Emit an ICMP unreachable when matched\n"
 | 
						|
      "Silently discard pkts when matched\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.flag = flag,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.vrf = vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ip_route_blackhole_vrf,
 | 
						|
      ip_route_blackhole_vrf_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask>                        \
 | 
						|
	<reject|blackhole>$flag                                               \
 | 
						|
	[{                                                                    \
 | 
						|
	  tag (1-4294967295)                                                  \
 | 
						|
	  |(1-255)$distance                                                   \
 | 
						|
	  |label WORD                                                         \
 | 
						|
	  |table (1-4294967295)                                               \
 | 
						|
          }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "Emit an ICMP unreachable when matched\n"
 | 
						|
      "Silently discard pkts when matched\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.flag = flag,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.xpath_vrf = true,
 | 
						|
	};
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Coverity is complaining that prefix could
 | 
						|
	 * be dereferenced, but we know that prefix will
 | 
						|
	 * valid.  Add an assert to make it happy
 | 
						|
	 */
 | 
						|
	assert(args.prefix);
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ip_route_address_interface,
 | 
						|
      ip_route_address_interface_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
 | 
						|
	A.B.C.D$gate                                   \
 | 
						|
	<INTERFACE|Null0>$ifname                       \
 | 
						|
	[{                                             \
 | 
						|
	  tag (1-4294967295)                           \
 | 
						|
	  |(1-255)$distance                            \
 | 
						|
	  |vrf NAME                                    \
 | 
						|
	  |label WORD                                  \
 | 
						|
	  |table (1-4294967295)                        \
 | 
						|
	  |nexthop-vrf NAME                            \
 | 
						|
	  |onlink$onlink                               \
 | 
						|
	  |color (1-4294967295)                        \
 | 
						|
          }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "IP gateway address\n"
 | 
						|
      "IP gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "Treat the nexthop as directly attached to the interface\n"
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.onlink = !!onlink,
 | 
						|
		.vrf = vrf,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ip_route_address_interface_vrf,
 | 
						|
      ip_route_address_interface_vrf_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
 | 
						|
	A.B.C.D$gate                                   \
 | 
						|
	<INTERFACE|Null0>$ifname                       \
 | 
						|
	[{                                             \
 | 
						|
	  tag (1-4294967295)                           \
 | 
						|
	  |(1-255)$distance                            \
 | 
						|
	  |label WORD                                  \
 | 
						|
	  |table (1-4294967295)                        \
 | 
						|
	  |nexthop-vrf NAME                            \
 | 
						|
	  |onlink$onlink                               \
 | 
						|
	  |color (1-4294967295)                        \
 | 
						|
	  }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "IP gateway address\n"
 | 
						|
      "IP gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "Treat the nexthop as directly attached to the interface\n"
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.onlink = !!onlink,
 | 
						|
		.xpath_vrf = true,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ip_route,
 | 
						|
      ip_route_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
 | 
						|
	<A.B.C.D$gate|<INTERFACE|Null0>$ifname>        \
 | 
						|
	[{                                             \
 | 
						|
	  tag (1-4294967295)                           \
 | 
						|
	  |(1-255)$distance                            \
 | 
						|
	  |vrf NAME                                    \
 | 
						|
	  |label WORD                                  \
 | 
						|
	  |table (1-4294967295)                        \
 | 
						|
	  |nexthop-vrf NAME                            \
 | 
						|
	  |color (1-4294967295)                        \
 | 
						|
          }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "IP gateway address\n"
 | 
						|
      "IP gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.vrf = vrf,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ip_route_vrf,
 | 
						|
      ip_route_vrf_cmd,
 | 
						|
      "[no] ip route\
 | 
						|
	<A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
 | 
						|
	<A.B.C.D$gate|<INTERFACE|Null0>$ifname>        \
 | 
						|
	[{                                             \
 | 
						|
	  tag (1-4294967295)                           \
 | 
						|
	  |(1-255)$distance                            \
 | 
						|
	  |label WORD                                  \
 | 
						|
	  |table (1-4294967295)                        \
 | 
						|
	  |nexthop-vrf NAME                            \
 | 
						|
	  |color (1-4294967295)                        \
 | 
						|
          }]",
 | 
						|
      NO_STR IP_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IP destination prefix (e.g. 10.0.0.0/8)\n"
 | 
						|
      "IP destination prefix\n"
 | 
						|
      "IP destination prefix mask\n"
 | 
						|
      "IP gateway address\n"
 | 
						|
      "IP gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this route\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix,
 | 
						|
		.prefix_mask = mask_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.xpath_vrf = true,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route_blackhole,
 | 
						|
      ipv6_route_blackhole_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          <reject|blackhole>$flag                          \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |vrf NAME                                      \
 | 
						|
            |label WORD                                    \
 | 
						|
            |table (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "Emit an ICMP unreachable when matched\n"
 | 
						|
      "Silently discard pkts when matched\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.flag = flag,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.vrf = vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route_blackhole_vrf,
 | 
						|
      ipv6_route_blackhole_vrf_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          <reject|blackhole>$flag                          \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |label WORD                                    \
 | 
						|
            |table (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "Emit an ICMP unreachable when matched\n"
 | 
						|
      "Silently discard pkts when matched\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.flag = flag,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.xpath_vrf = true,
 | 
						|
	};
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Coverity is complaining that prefix could
 | 
						|
	 * be dereferenced, but we know that prefix will
 | 
						|
	 * valid.  Add an assert to make it happy
 | 
						|
	 */
 | 
						|
	assert(args.prefix);
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route_address_interface,
 | 
						|
      ipv6_route_address_interface_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          X:X::X:X$gate                                    \
 | 
						|
          <INTERFACE|Null0>$ifname                         \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |vrf NAME                                      \
 | 
						|
            |label WORD                                    \
 | 
						|
	    |table (1-4294967295)                          \
 | 
						|
            |nexthop-vrf NAME                              \
 | 
						|
	    |onlink$onlink                                 \
 | 
						|
	    |color (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "IPv6 gateway address\n"
 | 
						|
      "IPv6 gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "Treat the nexthop as directly attached to the interface\n"
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.onlink = !!onlink,
 | 
						|
		.vrf = vrf,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route_address_interface_vrf,
 | 
						|
      ipv6_route_address_interface_vrf_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          X:X::X:X$gate                                    \
 | 
						|
          <INTERFACE|Null0>$ifname                         \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |label WORD                                    \
 | 
						|
	    |table (1-4294967295)                          \
 | 
						|
            |nexthop-vrf NAME                              \
 | 
						|
	    |onlink$onlink                                 \
 | 
						|
	    |color (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "IPv6 gateway address\n"
 | 
						|
      "IPv6 gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "Treat the nexthop as directly attached to the interface\n"
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.onlink = !!onlink,
 | 
						|
		.xpath_vrf = true,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route,
 | 
						|
      ipv6_route_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          <X:X::X:X$gate|<INTERFACE|Null0>$ifname>         \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |vrf NAME                                      \
 | 
						|
            |label WORD                                    \
 | 
						|
	    |table (1-4294967295)                          \
 | 
						|
            |nexthop-vrf NAME                              \
 | 
						|
            |color (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "IPv6 gateway address\n"
 | 
						|
      "IPv6 gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.vrf = vrf,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(ipv6_route_vrf,
 | 
						|
      ipv6_route_vrf_cmd,
 | 
						|
      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
 | 
						|
          <X:X::X:X$gate|<INTERFACE|Null0>$ifname>                 \
 | 
						|
          [{                                               \
 | 
						|
            tag (1-4294967295)                             \
 | 
						|
            |(1-255)$distance                              \
 | 
						|
            |label WORD                                    \
 | 
						|
	    |table (1-4294967295)                          \
 | 
						|
            |nexthop-vrf NAME                              \
 | 
						|
	    |color (1-4294967295)                          \
 | 
						|
          }]",
 | 
						|
      NO_STR
 | 
						|
      IPV6_STR
 | 
						|
      "Establish static routes\n"
 | 
						|
      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
 | 
						|
      "IPv6 source-dest route\n"
 | 
						|
      "IPv6 source prefix\n"
 | 
						|
      "IPv6 gateway address\n"
 | 
						|
      "IPv6 gateway interface name\n"
 | 
						|
      "Null interface\n"
 | 
						|
      "Set tag for this route\n"
 | 
						|
      "Tag value\n"
 | 
						|
      "Distance value for this prefix\n"
 | 
						|
      MPLS_LABEL_HELPSTR
 | 
						|
      "Table to configure\n"
 | 
						|
      "The table number to configure\n"
 | 
						|
      VRF_CMD_HELP_STR
 | 
						|
      "SR-TE color\n"
 | 
						|
      "The SR-TE color to configure\n")
 | 
						|
{
 | 
						|
	struct static_route_args args = {
 | 
						|
		.delete = !!no,
 | 
						|
		.afi = AFI_IP6,
 | 
						|
		.safi = SAFI_UNICAST,
 | 
						|
		.prefix = prefix_str,
 | 
						|
		.source = from_str,
 | 
						|
		.gateway = gate_str,
 | 
						|
		.interface_name = ifname,
 | 
						|
		.tag = tag_str,
 | 
						|
		.distance = distance_str,
 | 
						|
		.label = label,
 | 
						|
		.table = table_str,
 | 
						|
		.color = color_str,
 | 
						|
		.xpath_vrf = true,
 | 
						|
		.nexthop_vrf = nexthop_vrf,
 | 
						|
	};
 | 
						|
 | 
						|
	return static_route_nb_run(vty, &args);
 | 
						|
}
 | 
						|
 | 
						|
void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
 | 
						|
		     bool show_defaults)
 | 
						|
{
 | 
						|
	const char *vrf;
 | 
						|
 | 
						|
	vrf = yang_dnode_get_string(dnode, "../vrf");
 | 
						|
	if (strcmp(vrf, VRF_DEFAULT_NAME))
 | 
						|
		vty_out(vty, "vrf %s\n", vrf);
 | 
						|
}
 | 
						|
 | 
						|
void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode)
 | 
						|
{
 | 
						|
	const char *vrf;
 | 
						|
 | 
						|
	vrf = yang_dnode_get_string(dnode, "../vrf");
 | 
						|
	if (strcmp(vrf, VRF_DEFAULT_NAME))
 | 
						|
		vty_out(vty, "exit-vrf\n");
 | 
						|
}
 | 
						|
 | 
						|
struct mpls_label_iter {
 | 
						|
	struct vty *vty;
 | 
						|
	bool first;
 | 
						|
};
 | 
						|
 | 
						|
static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg)
 | 
						|
{
 | 
						|
	struct mpls_label_iter *iter = arg;
 | 
						|
 | 
						|
	if (yang_dnode_exists(dnode, "./label")) {
 | 
						|
		if (iter->first)
 | 
						|
			vty_out(iter->vty, " label %s",
 | 
						|
				yang_dnode_get_string(dnode, "./label"));
 | 
						|
		else
 | 
						|
			vty_out(iter->vty, "/%s",
 | 
						|
				yang_dnode_get_string(dnode, "./label"));
 | 
						|
		iter->first = false;
 | 
						|
	}
 | 
						|
 | 
						|
	return YANG_ITER_CONTINUE;
 | 
						|
}
 | 
						|
 | 
						|
static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route,
 | 
						|
			     const struct lyd_node *src,
 | 
						|
			     const struct lyd_node *path,
 | 
						|
			     const struct lyd_node *nexthop, bool show_defaults)
 | 
						|
{
 | 
						|
	const char *vrf;
 | 
						|
	const char *afi_safi;
 | 
						|
	afi_t afi;
 | 
						|
	safi_t safi;
 | 
						|
	enum static_nh_type nh_type;
 | 
						|
	enum static_blackhole_type bh_type;
 | 
						|
	uint32_t tag;
 | 
						|
	uint8_t distance;
 | 
						|
	struct mpls_label_iter iter;
 | 
						|
	const char *nexthop_vrf;
 | 
						|
	uint32_t table_id;
 | 
						|
	bool onlink;
 | 
						|
 | 
						|
	vrf = yang_dnode_get_string(route, "../../vrf");
 | 
						|
 | 
						|
	afi_safi = yang_dnode_get_string(route, "./afi-safi");
 | 
						|
	yang_afi_safi_identity2value(afi_safi, &afi, &safi);
 | 
						|
 | 
						|
	if (afi == AFI_IP)
 | 
						|
		vty_out(vty, "%sip",
 | 
						|
			strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
 | 
						|
	else
 | 
						|
		vty_out(vty, "%sipv6",
 | 
						|
			strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
 | 
						|
 | 
						|
	if (safi == SAFI_UNICAST)
 | 
						|
		vty_out(vty, " route");
 | 
						|
	else
 | 
						|
		vty_out(vty, " mroute");
 | 
						|
 | 
						|
	vty_out(vty, " %s", yang_dnode_get_string(route, "./prefix"));
 | 
						|
 | 
						|
	if (src)
 | 
						|
		vty_out(vty, " from %s",
 | 
						|
			yang_dnode_get_string(src, "./src-prefix"));
 | 
						|
 | 
						|
	nh_type = yang_dnode_get_enum(nexthop, "./nh-type");
 | 
						|
	switch (nh_type) {
 | 
						|
	case STATIC_IFNAME:
 | 
						|
		vty_out(vty, " %s",
 | 
						|
			yang_dnode_get_string(nexthop, "./interface"));
 | 
						|
		break;
 | 
						|
	case STATIC_IPV4_GATEWAY:
 | 
						|
	case STATIC_IPV6_GATEWAY:
 | 
						|
		vty_out(vty, " %s",
 | 
						|
			yang_dnode_get_string(nexthop, "./gateway"));
 | 
						|
		break;
 | 
						|
	case STATIC_IPV4_GATEWAY_IFNAME:
 | 
						|
	case STATIC_IPV6_GATEWAY_IFNAME:
 | 
						|
		vty_out(vty, " %s",
 | 
						|
			yang_dnode_get_string(nexthop, "./gateway"));
 | 
						|
		vty_out(vty, " %s",
 | 
						|
			yang_dnode_get_string(nexthop, "./interface"));
 | 
						|
		break;
 | 
						|
	case STATIC_BLACKHOLE:
 | 
						|
		bh_type = yang_dnode_get_enum(nexthop, "./bh-type");
 | 
						|
		switch (bh_type) {
 | 
						|
		case STATIC_BLACKHOLE_DROP:
 | 
						|
			vty_out(vty, " blackhole");
 | 
						|
			break;
 | 
						|
		case STATIC_BLACKHOLE_NULL:
 | 
						|
			vty_out(vty, " Null0");
 | 
						|
			break;
 | 
						|
		case STATIC_BLACKHOLE_REJECT:
 | 
						|
			vty_out(vty, " reject");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (yang_dnode_exists(path, "./tag")) {
 | 
						|
		tag = yang_dnode_get_uint32(path, "./tag");
 | 
						|
		if (tag != 0 || show_defaults)
 | 
						|
			vty_out(vty, " tag %" PRIu32, tag);
 | 
						|
	}
 | 
						|
 | 
						|
	distance = yang_dnode_get_uint8(path, "./distance");
 | 
						|
	if (distance != ZEBRA_STATIC_DISTANCE_DEFAULT || show_defaults)
 | 
						|
		vty_out(vty, " %" PRIu8, distance);
 | 
						|
 | 
						|
	iter.vty = vty;
 | 
						|
	iter.first = true;
 | 
						|
	yang_dnode_iterate(mpls_label_iter_cb, &iter, nexthop,
 | 
						|
			   "./mpls-label-stack/entry");
 | 
						|
 | 
						|
	nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf");
 | 
						|
	if (strcmp(vrf, nexthop_vrf))
 | 
						|
		vty_out(vty, " nexthop-vrf %s", nexthop_vrf);
 | 
						|
 | 
						|
	table_id = yang_dnode_get_uint32(path, "./table-id");
 | 
						|
	if (table_id || show_defaults)
 | 
						|
		vty_out(vty, " table %" PRIu32, table_id);
 | 
						|
 | 
						|
	if (yang_dnode_exists(nexthop, "./onlink")) {
 | 
						|
		onlink = yang_dnode_get_bool(nexthop, "./onlink");
 | 
						|
		if (onlink)
 | 
						|
			vty_out(vty, " onlink");
 | 
						|
	}
 | 
						|
 | 
						|
	if (yang_dnode_exists(nexthop, "./srte-color"))
 | 
						|
		vty_out(vty, " color %s",
 | 
						|
			yang_dnode_get_string(nexthop, "./srte-color"));
 | 
						|
 | 
						|
	vty_out(vty, "\n");
 | 
						|
}
 | 
						|
 | 
						|
void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
 | 
						|
			     bool show_defaults)
 | 
						|
{
 | 
						|
	const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
 | 
						|
	const struct lyd_node *route =
 | 
						|
		yang_dnode_get_parent(path, "route-list");
 | 
						|
 | 
						|
	nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults);
 | 
						|
}
 | 
						|
 | 
						|
void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode,
 | 
						|
				 bool show_defaults)
 | 
						|
{
 | 
						|
	const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
 | 
						|
	const struct lyd_node *src = yang_dnode_get_parent(path, "src-list");
 | 
						|
	const struct lyd_node *route = yang_dnode_get_parent(src, "route-list");
 | 
						|
 | 
						|
	nexthop_cli_show(vty, route, src, path, dnode, show_defaults);
 | 
						|
}
 | 
						|
 | 
						|
int static_nexthop_cli_cmp(const struct lyd_node *dnode1,
 | 
						|
			   const struct lyd_node *dnode2)
 | 
						|
{
 | 
						|
	enum static_nh_type nh_type1, nh_type2;
 | 
						|
	struct prefix prefix1, prefix2;
 | 
						|
	int ret = 0;
 | 
						|
 | 
						|
	nh_type1 = yang_dnode_get_enum(dnode1, "./nh-type");
 | 
						|
	nh_type2 = yang_dnode_get_enum(dnode2, "./nh-type");
 | 
						|
 | 
						|
	if (nh_type1 != nh_type2)
 | 
						|
		return (int)nh_type1 - (int)nh_type2;
 | 
						|
 | 
						|
	switch (nh_type1) {
 | 
						|
	case STATIC_IFNAME:
 | 
						|
		ret = if_cmp_name_func(
 | 
						|
			yang_dnode_get_string(dnode1, "./interface"),
 | 
						|
			yang_dnode_get_string(dnode2, "./interface"));
 | 
						|
		break;
 | 
						|
	case STATIC_IPV4_GATEWAY:
 | 
						|
	case STATIC_IPV6_GATEWAY:
 | 
						|
		yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
 | 
						|
		yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
 | 
						|
		ret = prefix_cmp(&prefix1, &prefix2);
 | 
						|
		break;
 | 
						|
	case STATIC_IPV4_GATEWAY_IFNAME:
 | 
						|
	case STATIC_IPV6_GATEWAY_IFNAME:
 | 
						|
		yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
 | 
						|
		yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
 | 
						|
		ret = prefix_cmp(&prefix1, &prefix2);
 | 
						|
		if (!ret)
 | 
						|
			ret = if_cmp_name_func(
 | 
						|
				yang_dnode_get_string(dnode1, "./interface"),
 | 
						|
				yang_dnode_get_string(dnode2, "./interface"));
 | 
						|
		break;
 | 
						|
	case STATIC_BLACKHOLE:
 | 
						|
		/* There's only one blackhole nexthop per route */
 | 
						|
		ret = 0;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
 | 
						|
	return if_cmp_name_func(yang_dnode_get_string(dnode1, "./vrf"),
 | 
						|
				yang_dnode_get_string(dnode2, "./vrf"));
 | 
						|
}
 | 
						|
 | 
						|
int static_route_list_cli_cmp(const struct lyd_node *dnode1,
 | 
						|
			      const struct lyd_node *dnode2)
 | 
						|
{
 | 
						|
	const char *afi_safi1, *afi_safi2;
 | 
						|
	afi_t afi1, afi2;
 | 
						|
	safi_t safi1, safi2;
 | 
						|
	struct prefix prefix1, prefix2;
 | 
						|
 | 
						|
	afi_safi1 = yang_dnode_get_string(dnode1, "./afi-safi");
 | 
						|
	yang_afi_safi_identity2value(afi_safi1, &afi1, &safi1);
 | 
						|
 | 
						|
	afi_safi2 = yang_dnode_get_string(dnode2, "./afi-safi");
 | 
						|
	yang_afi_safi_identity2value(afi_safi2, &afi2, &safi2);
 | 
						|
 | 
						|
	if (afi1 != afi2)
 | 
						|
		return (int)afi1 - (int)afi2;
 | 
						|
 | 
						|
	if (safi1 != safi2)
 | 
						|
		return (int)safi1 - (int)safi2;
 | 
						|
 | 
						|
	yang_dnode_get_prefix(&prefix1, dnode1, "./prefix");
 | 
						|
	yang_dnode_get_prefix(&prefix2, dnode2, "./prefix");
 | 
						|
 | 
						|
	return prefix_cmp(&prefix1, &prefix2);
 | 
						|
}
 | 
						|
 | 
						|
int static_src_list_cli_cmp(const struct lyd_node *dnode1,
 | 
						|
			    const struct lyd_node *dnode2)
 | 
						|
{
 | 
						|
	struct prefix prefix1, prefix2;
 | 
						|
 | 
						|
	yang_dnode_get_prefix(&prefix1, dnode1, "./src-prefix");
 | 
						|
	yang_dnode_get_prefix(&prefix2, dnode2, "./src-prefix");
 | 
						|
 | 
						|
	return prefix_cmp(&prefix1, &prefix2);
 | 
						|
}
 | 
						|
 | 
						|
int static_path_list_cli_cmp(const struct lyd_node *dnode1,
 | 
						|
			     const struct lyd_node *dnode2)
 | 
						|
{
 | 
						|
	uint32_t table_id1, table_id2;
 | 
						|
	uint8_t distance1, distance2;
 | 
						|
 | 
						|
	table_id1 = yang_dnode_get_uint32(dnode1, "./table-id");
 | 
						|
	table_id2 = yang_dnode_get_uint32(dnode2, "./table-id");
 | 
						|
 | 
						|
	if (table_id1 != table_id2)
 | 
						|
		return (int)table_id1 - (int)table_id2;
 | 
						|
 | 
						|
	distance1 = yang_dnode_get_uint8(dnode1, "./distance");
 | 
						|
	distance2 = yang_dnode_get_uint8(dnode2, "./distance");
 | 
						|
 | 
						|
	return (int)distance1 - (int)distance2;
 | 
						|
}
 | 
						|
 | 
						|
DEFPY_YANG(debug_staticd, debug_staticd_cmd,
 | 
						|
	   "[no] debug static [{events$events|route$route}]",
 | 
						|
	   NO_STR DEBUG_STR STATICD_STR
 | 
						|
	   "Debug events\n"
 | 
						|
	   "Debug route\n")
 | 
						|
{
 | 
						|
	/* If no specific category, change all */
 | 
						|
	if (strmatch(argv[argc - 1]->text, "static"))
 | 
						|
		static_debug_set(vty->node, !no, true, true);
 | 
						|
	else
 | 
						|
		static_debug_set(vty->node, !no, !!events, !!route);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN_NOSH (show_debugging_static,
 | 
						|
	    show_debugging_static_cmd,
 | 
						|
	    "show debugging [static]",
 | 
						|
	    SHOW_STR
 | 
						|
	    DEBUG_STR
 | 
						|
	    "Static Information\n")
 | 
						|
{
 | 
						|
	vty_out(vty, "Staticd debugging status\n");
 | 
						|
 | 
						|
	static_debug_status_write(vty);
 | 
						|
 | 
						|
	cmd_show_lib_debugs(vty);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static struct cmd_node debug_node = {
 | 
						|
	.name = "debug",
 | 
						|
	.node = DEBUG_NODE,
 | 
						|
	.prompt = "",
 | 
						|
	.config_write = static_config_write_debug,
 | 
						|
};
 | 
						|
 | 
						|
void static_vty_init(void)
 | 
						|
{
 | 
						|
	install_node(&debug_node);
 | 
						|
 | 
						|
	install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
 | 
						|
 | 
						|
	install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
 | 
						|
	install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
 | 
						|
	install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
 | 
						|
	install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
 | 
						|
	install_element(CONFIG_NODE, &ip_route_cmd);
 | 
						|
	install_element(VRF_NODE, &ip_route_vrf_cmd);
 | 
						|
 | 
						|
	install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
 | 
						|
	install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
 | 
						|
	install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
 | 
						|
	install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
 | 
						|
	install_element(CONFIG_NODE, &ipv6_route_cmd);
 | 
						|
	install_element(VRF_NODE, &ipv6_route_vrf_cmd);
 | 
						|
 | 
						|
	install_element(ENABLE_NODE, &show_debugging_static_cmd);
 | 
						|
	install_element(ENABLE_NODE, &debug_staticd_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_staticd_cmd);
 | 
						|
}
 |