return "invalid";
}
-static int route_map_empty(struct route_map *map)
-{
- if (map->head == NULL && map->tail == NULL)
- return 1;
- else
- return 0;
-}
-
/* show route-map */
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
{
/* VTY related functions. */
-DEFUN (match_interface,
- match_interface_cmd,
- "match interface WORD",
- MATCH_STR
- "match first hop interface of route\n"
- "Interface name\n")
-{
- int idx_word = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_interface)
- return rmap_match_set_hook.match_interface(
- vty, index, "interface", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_interface,
- no_match_interface_cmd,
- "no match interface [WORD]",
- NO_STR
- MATCH_STR
- "Match first hop interface of route\n"
- "Interface name\n")
-{
- char *iface = (argc == 4) ? argv[3]->arg : NULL;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_interface)
- return rmap_match_set_hook.no_match_interface(
- vty, index, "interface", iface,
- RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address,
- match_ip_address_cmd,
- "match ip address <(1-199)|(1300-2699)|WORD>",
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_acl = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_address)
- return rmap_match_set_hook.match_ip_address(
- vty, index, "ip address", argv[idx_acl]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address,
- no_match_ip_address_cmd,
- "no match ip address [<(1-199)|(1300-2699)|WORD>]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_address) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_address(
- vty, index, "ip address", NULL,
- RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_address(
- vty, index, "ip address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address_prefix_list,
- match_ip_address_prefix_list_cmd,
- "match ip address prefix-list WORD",
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_address_prefix_list)
- return rmap_match_set_hook.match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address_prefix_list,
- no_match_ip_address_prefix_list_cmd,
- "no match ip address prefix-list [WORD]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
- if (argc <= idx_word)
- return rmap_match_set_hook
- .no_match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- NULL, RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_address_prefix_list(
- vty, index, "ip address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop,
- match_ip_next_hop_cmd,
- "match ip next-hop <(1-199)|(1300-2699)|WORD>",
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_acl = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop)
- return rmap_match_set_hook.match_ip_next_hop(
- vty, index, "ip next-hop", argv[idx_acl]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_next_hop,
- no_match_ip_next_hop_cmd,
- "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "IP access-list number\n"
- "IP access-list number (expanded range)\n"
- "IP Access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop", NULL,
- RMAP_EVENT_FILTER_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop_prefix_list,
- match_ip_next_hop_prefix_list_cmd,
- "match ip next-hop prefix-list WORD",
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
- return rmap_match_set_hook.match_ip_next_hop_prefix_list(
- vty, index, "ip next-hop prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ip_next_hop_prefix_list,
- no_match_ip_next_hop_prefix_list_cmd,
- "no match ip next-hop prefix-list [WORD]",
- NO_STR
- MATCH_STR
- IP_STR
- "Match next-hop address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop prefix-list", NULL,
- RMAP_EVENT_PLIST_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
- "match ip next-hop type <blackhole>",
- MATCH_STR IP_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ip_next_hop_type)
- return rmap_match_set_hook.match_ip_next_hop_type(
- vty, index, "ip next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
- "no match ip next-hop type [<blackhole>]",
- NO_STR MATCH_STR IP_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ip_next_hop) {
- if (argc <= idx_word)
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop type", NULL,
- RMAP_EVENT_MATCH_DELETED);
- return rmap_match_set_hook.no_match_ip_next_hop(
- vty, index, "ip next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address,
- match_ipv6_address_cmd,
- "match ipv6 address WORD",
- MATCH_STR
- IPV6_STR
- "Match IPv6 address of route\n"
- "IPv6 access-list name\n")
-{
- int idx_word = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_address)
- return rmap_match_set_hook.match_ipv6_address(
- vty, index, "ipv6 address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address,
- no_match_ipv6_address_cmd,
- "no match ipv6 address WORD",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match IPv6 address of route\n"
- "IPv6 access-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_address)
- return rmap_match_set_hook.no_match_ipv6_address(
- vty, index, "ipv6 address", argv[idx_word]->arg,
- RMAP_EVENT_FILTER_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address_prefix_list,
- match_ipv6_address_prefix_list_cmd,
- "match ipv6 address prefix-list WORD",
- MATCH_STR
- IPV6_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_address_prefix_list)
- return rmap_match_set_hook.match_ipv6_address_prefix_list(
- vty, index, "ipv6 address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address_prefix_list,
- no_match_ipv6_address_prefix_list_cmd,
- "no match ipv6 address prefix-list WORD",
- NO_STR
- MATCH_STR
- IPV6_STR
- "Match address of route\n"
- "Match entries of prefix-lists\n"
- "IP prefix-list name\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
- return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
- vty, index, "ipv6 address prefix-list",
- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
- return CMD_SUCCESS;
-}
-
-DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
- "match ipv6 next-hop type <blackhole>",
- MATCH_STR IPV6_STR
- "Match next-hop address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 4;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_ipv6_next_hop_type)
- return rmap_match_set_hook.match_ipv6_next_hop_type(
- vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
- "no match ipv6 next-hop type [<blackhole>]",
- NO_STR MATCH_STR IPV6_STR
- "Match address of route\n"
- "Match entries by type\n"
- "Blackhole\n")
-{
- int idx_word = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
- return rmap_match_set_hook.no_match_ipv6_next_hop_type(
- vty, index, "ipv6 next-hop type",
- (argc <= idx_word) ? NULL : argv[idx_word]->arg,
- RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-DEFUN (match_metric,
- match_metric_cmd,
- "match metric (0-4294967295)",
- MATCH_STR
- "Match metric of route\n"
- "Metric value\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_metric)
- return rmap_match_set_hook.match_metric(vty, index, "metric",
- argv[idx_number]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_metric,
- no_match_metric_cmd,
- "no match metric [(0-4294967295)]",
- NO_STR
- MATCH_STR
- "Match metric of route\n"
- "Metric value\n")
-{
- int idx_number = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_match_metric) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_match_metric(
- vty, index, "metric", NULL,
- RMAP_EVENT_MATCH_DELETED);
- return rmap_match_set_hook.no_match_metric(
- vty, index, "metric", argv[idx_number]->arg,
- RMAP_EVENT_MATCH_DELETED);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (match_tag,
- match_tag_cmd,
- "match tag (1-4294967295)",
- MATCH_STR
- "Match tag of route\n"
- "Tag value\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.match_tag)
- return rmap_match_set_hook.match_tag(vty, index, "tag",
- argv[idx_number]->arg,
- RMAP_EVENT_MATCH_ADDED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_tag,
- no_match_tag_cmd,
- "no match tag [(1-4294967295)]",
- NO_STR
- MATCH_STR
- "Match tag of route\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx = 0;
- char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
- ? argv[idx]->arg
- : NULL;
-
- if (rmap_match_set_hook.no_match_tag)
- return rmap_match_set_hook.no_match_tag(
- vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ip_nexthop,
- set_ip_nexthop_cmd,
- "set ip next-hop A.B.C.D",
- SET_STR
- IP_STR
- "Next hop address\n"
- "IP address of next hop\n")
-{
- int idx_ipv4 = 3;
- union sockunion su;
- int ret;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
- vty_out(vty, "%% Malformed nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (su.sin.sin_addr.s_addr == 0
- || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
- vty_out(vty,
- "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (rmap_match_set_hook.set_ip_nexthop)
- return rmap_match_set_hook.set_ip_nexthop(
- vty, index, "ip next-hop", argv[idx_ipv4]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ip_nexthop,
- no_set_ip_nexthop_cmd,
- "no set ip next-hop [A.B.C.D]",
- NO_STR
- SET_STR
- IP_STR
- "Next hop address\n"
- "IP address of next hop\n")
-{
- int idx = 0;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
- const char *arg = NULL;
-
- if (argv_find(argv, argc, "A.B.C.D", &idx))
- arg = argv[idx]->arg;
-
- if (rmap_match_set_hook.no_set_ip_nexthop)
- return rmap_match_set_hook.no_set_ip_nexthop(
- vty, index, "ip next-hop", arg);
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ipv6_nexthop_local,
- set_ipv6_nexthop_local_cmd,
- "set ipv6 next-hop local X:X::X:X",
- SET_STR
- IPV6_STR
- "IPv6 next-hop address\n"
- "IPv6 local address\n"
- "IPv6 address of next hop\n")
-{
- int idx_ipv6 = 4;
- struct in6_addr addr;
- int ret;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
- if (!ret) {
- vty_out(vty, "%% Malformed nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
- vty_out(vty, "%% Invalid link-local nexthop address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (rmap_match_set_hook.set_ipv6_nexthop_local)
- return rmap_match_set_hook.set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ipv6_nexthop_local,
- no_set_ipv6_nexthop_local_cmd,
- "no set ipv6 next-hop local [X:X::X:X]",
- NO_STR
- SET_STR
- IPV6_STR
- "IPv6 next-hop address\n"
- "IPv6 local address\n"
- "IPv6 address of next hop\n")
-{
- int idx_ipv6 = 5;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
- if (argc <= idx_ipv6)
- return rmap_match_set_hook.no_set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", NULL);
- return rmap_match_set_hook.no_set_ipv6_nexthop_local(
- vty, index, "ipv6 next-hop local", argv[5]->arg);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (set_metric,
- set_metric_cmd,
- "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
- SET_STR
- "Metric value for destination routing protocol\n"
- "Metric value\n"
- "Assign round trip time\n"
- "Add round trip time\n"
- "Subtract round trip time\n"
- "Add metric\n"
- "Subtract metric\n")
-{
- int idx_number = 2;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- const char *pass = (argv[idx_number]->type == RANGE_TKN)
- ? argv[idx_number]->arg
- : argv[idx_number]->text;
-
- if (rmap_match_set_hook.set_metric)
- return rmap_match_set_hook.set_metric(vty, index, "metric",
- pass);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_metric,
- no_set_metric_cmd,
- "no set metric [(0-4294967295)]",
- NO_STR
- SET_STR
- "Metric value for destination routing protocol\n"
- "Metric value\n")
-{
- int idx_number = 3;
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- if (rmap_match_set_hook.no_set_metric) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_set_metric(
- vty, index, "metric", NULL);
- return rmap_match_set_hook.no_set_metric(vty, index, "metric",
- argv[idx_number]->arg);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN (set_tag,
- set_tag_cmd,
- "set tag (1-4294967295)",
- SET_STR
- "Tag value for routing protocol\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx_number = 2;
- if (rmap_match_set_hook.set_tag)
- return rmap_match_set_hook.set_tag(vty, index, "tag",
- argv[idx_number]->arg);
- return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_tag,
- no_set_tag_cmd,
- "no set tag [(1-4294967295)]",
- NO_STR
- SET_STR
- "Tag value for routing protocol\n"
- "Tag value\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- int idx_number = 3;
- if (rmap_match_set_hook.no_set_tag) {
- if (argc <= idx_number)
- return rmap_match_set_hook.no_set_tag(vty, index, "tag",
- NULL);
- return rmap_match_set_hook.no_set_tag(vty, index, "tag",
- argv[idx_number]->arg);
- }
- return CMD_SUCCESS;
-}
-
-
-DEFUN_NOSH (route_map,
- route_map_cmd,
- "route-map WORD <deny|permit> (1-65535)",
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n"
- "Route map denies set operations\n"
- "Route map permits set operations\n"
- "Sequence to insert to/delete from existing route-map entry\n")
-{
- int idx_word = 1;
- int idx_permit_deny = 2;
- int idx_number = 3;
- struct route_map *map;
- struct route_map_index *index;
- char *endptr = NULL;
- int permit =
- argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
- unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
- const char *mapname = argv[idx_word]->arg;
-
- /* Get route map. */
- map = route_map_get(mapname);
- index = route_map_index_get(map, permit, pref);
-
- VTY_PUSH_CONTEXT(RMAP_NODE, index);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map_all,
- no_route_map_all_cmd,
- "no route-map WORD",
- NO_STR
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n")
-{
- int idx_word = 2;
- const char *mapname = argv[idx_word]->arg;
- struct route_map *map;
-
- map = route_map_lookup_by_name(mapname);
- if (map == NULL) {
- vty_out(vty, "%% Could not find route-map %s\n", mapname);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- route_map_delete(map);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map,
- no_route_map_cmd,
- "no route-map WORD <deny|permit> (1-65535)",
- NO_STR
- "Create route-map or enter route-map command mode\n"
- "Route map tag\n"
- "Route map denies set operations\n"
- "Route map permits set operations\n"
- "Sequence to insert to/delete from existing route-map entry\n")
-{
- int idx_word = 2;
- int idx_permit_deny = 3;
- int idx_number = 4;
- struct route_map *map;
- struct route_map_index *index;
- char *endptr = NULL;
- int permit = strmatch(argv[idx_permit_deny]->text, "permit")
- ? RMAP_PERMIT
- : RMAP_DENY;
- const char *prefstr = argv[idx_number]->arg;
- const char *mapname = argv[idx_word]->arg;
- unsigned long pref = strtoul(prefstr, &endptr, 10);
-
- /* Existence check. */
- map = route_map_lookup_by_name(mapname);
- if (map == NULL) {
- vty_out(vty, "%% Could not find route-map %s\n", mapname);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Lookup route map index. */
- index = route_map_index_lookup(map, permit, pref);
- if (index == NULL) {
- vty_out(vty, "%% Could not find route-map entry %s %s\n",
- mapname, prefstr);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Delete index from route map. */
- route_map_index_delete(index, 1);
-
- /* If this route rule is the last one, delete route map itself. */
- if (route_map_empty(map))
- route_map_delete(map);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_next,
- rmap_onmatch_next_cmd,
- "on-match next",
- "Exit policy on matches\n"
- "Next clause\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->type == RMAP_DENY) {
- /* Under a deny clause, match means it's finished. No
- * need to set next */
- vty_out(vty,
- "on-match next not supported under route-map deny\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- index->exitpolicy = RMAP_NEXT;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_next,
- no_rmap_onmatch_next_cmd,
- "no on-match next",
- NO_STR
- "Exit policy on matches\n"
- "Next clause\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index)
- index->exitpolicy = RMAP_EXIT;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_goto,
- rmap_onmatch_goto_cmd,
- "on-match goto (1-65535)",
- "Exit policy on matches\n"
- "Goto Clause number\n"
- "Number\n")
-{
- int idx = 0;
- char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
- : NULL;
-
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
- int d = 0;
-
- if (index) {
- if (index->type == RMAP_DENY) {
- /* Under a deny clause, match means it's finished. No
- * need to go anywhere */
- vty_out(vty,
- "on-match goto not supported under route-map deny\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (num)
- d = strtoul(num, NULL, 10);
- else
- d = index->pref + 1;
-
- if (d <= index->pref) {
- /* Can't allow you to do that, Dave */
- vty_out(vty, "can't jump backwards in route-maps\n");
- return CMD_WARNING_CONFIG_FAILED;
- } else {
- index->exitpolicy = RMAP_GOTO;
- index->nextpref = d;
- }
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_goto,
- no_rmap_onmatch_goto_cmd,
- "no on-match goto",
- NO_STR
- "Exit policy on matches\n"
- "Goto Clause number\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index)
- index->exitpolicy = RMAP_EXIT;
-
- return CMD_SUCCESS;
-}
-
-/* Cisco/GNU Zebra compatibility aliases */
-/* ALIAS_FIXME */
-DEFUN (rmap_continue,
- rmap_continue_cmd,
- "continue (1-65535)",
- "Continue on a different entry within the route-map\n"
- "Route-map entry sequence number\n")
-{
- return rmap_onmatch_goto(self, vty, argc, argv);
-}
-
-/* ALIAS_FIXME */
-DEFUN (no_rmap_continue,
- no_rmap_continue_cmd,
- "no continue [(1-65535)]",
- NO_STR
- "Continue on a different entry within the route-map\n"
- "Route-map entry sequence number\n")
-{
- return no_rmap_onmatch_goto(self, vty, argc, argv);
-}
-
static void clear_route_map_helper(struct route_map *map)
{
struct route_map_index *index;
return vty_show_unused_route_map(vty);
}
-DEFUN (rmap_call,
- rmap_call_cmd,
- "call WORD",
- "Jump to another Route-Map after match+set\n"
- "Target route-map name\n")
-{
- int idx_word = 1;
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
- const char *rmap = argv[idx_word]->arg;
-
- assert(index);
-
- /* If "call" is invoked with the same route-map name as
- * the one previously configured then, ignore the duplicate
- * configuration.
- */
- if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
- return CMD_SUCCESS;
-
- if (index->nextrm) {
- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
- index->nextrm, index->map->name);
- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
- }
- index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
-
- /* Execute event hook. */
- route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
- index->map->name);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_call,
- no_rmap_call_cmd,
- "no call",
- NO_STR
- "Jump to another Route-Map after match+set\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index->nextrm) {
- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
- index->nextrm, index->map->name);
- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
- index->nextrm = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (rmap_description,
- rmap_description_cmd,
- "description LINE...",
- "Route-map comment\n"
- "Comment describing this route-map rule\n")
-{
- int idx_line = 1;
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->description)
- XFREE(MTYPE_TMP, index->description);
- index->description = argv_concat(argv, argc, idx_line);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_description,
- no_rmap_description_cmd,
- "no description",
- NO_STR
- "Route-map comment\n")
-{
- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
- if (index) {
- if (index->description)
- XFREE(MTYPE_TMP, index->description);
- index->description = NULL;
- }
- return CMD_SUCCESS;
-}
-
DEFUN (debug_rmap,
debug_rmap_cmd,
"debug route-map",
static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
/* Configuration write function. */
-static int route_map_config_write(struct vty *vty)
-{
- struct route_map *map;
- struct route_map_index *index;
- struct route_map_rule *rule;
- int first = 1;
- int write = 0;
- struct listnode *ln;
- struct list *maplist = list_new();
-
- for (map = route_map_master.head; map; map = map->next)
- listnode_add(maplist, map);
-
- list_sort(maplist, sort_route_map);
-
- for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
- for (index = map->head; index; index = index->next) {
- if (!first)
- vty_out(vty, "!\n");
- else
- first = 0;
-
- vty_out(vty, "route-map %s %s %d\n", map->name,
- route_map_type_str(index->type), index->pref);
-
- if (index->description)
- vty_out(vty, " description %s\n",
- index->description);
-
- for (rule = index->match_list.head; rule;
- rule = rule->next)
- vty_out(vty, " match %s %s\n", rule->cmd->str,
- rule->rule_str ? rule->rule_str : "");
-
- for (rule = index->set_list.head; rule;
- rule = rule->next)
- vty_out(vty, " set %s %s\n", rule->cmd->str,
- rule->rule_str ? rule->rule_str : "");
- if (index->nextrm)
- vty_out(vty, " call %s\n", index->nextrm);
- if (index->exitpolicy == RMAP_GOTO)
- vty_out(vty, " on-match goto %d\n",
- index->nextpref);
- if (index->exitpolicy == RMAP_NEXT)
- vty_out(vty, " on-match next\n");
-
- write++;
- }
-
- list_delete(&maplist);
- return write;
-}
-
static int rmap_config_write_debug(struct vty *vty)
{
int write = 0;
return write;
}
-/* Route map node structure. */
-static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
-
/* Common route map rules */
void *route_map_rule_tag_compile(const char *arg)
route_map_master_hash = NULL;
}
-static void rmap_autocomplete(vector comps, struct cmd_token *token)
-{
- struct route_map *map;
-
- for (map = route_map_master.head; map; map = map->next)
- vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
-}
-
/* Increment the use_count counter while attaching the route map */
void route_map_counter_increment(struct route_map *map)
{
}
}
-static const struct cmd_variable_handler rmap_var_handlers[] = {
- {/* "route-map WORD" */
- .varname = "route_map",
- .completions = rmap_autocomplete},
- {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
- {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
- {.completions = NULL}};
-
/* Initialization of route map vector. */
void route_map_init(void)
{
8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
"Route Map Dep Hash");
- cmd_variable_handler_register(rmap_var_handlers);
-
rmap_debug = false;
- /* Install route map top node. */
- install_node(&rmap_node, route_map_config_write);
+ route_map_cli_init();
+ /* Install route map top node. */
install_node(&rmap_debug_node, rmap_config_write_debug);
/* Install route map commands. */
- install_default(RMAP_NODE);
- install_element(CONFIG_NODE, &route_map_cmd);
- install_element(CONFIG_NODE, &no_route_map_cmd);
- install_element(CONFIG_NODE, &no_route_map_all_cmd);
-
install_element(CONFIG_NODE, &debug_rmap_cmd);
install_element(CONFIG_NODE, &no_debug_rmap_cmd);
- /* Install the on-match stuff */
- install_element(RMAP_NODE, &route_map_cmd);
- install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
- install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
- install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
- install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
- install_element(RMAP_NODE, &rmap_continue_cmd);
- install_element(RMAP_NODE, &no_rmap_continue_cmd);
-
- /* Install the continue stuff (ALIAS of on-match). */
-
- /* Install the call stuff. */
- install_element(RMAP_NODE, &rmap_call_cmd);
- install_element(RMAP_NODE, &no_rmap_call_cmd);
-
- /* Install description commands. */
- install_element(RMAP_NODE, &rmap_description_cmd);
- install_element(RMAP_NODE, &no_rmap_description_cmd);
-
/* Install show command */
install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
install_element(ENABLE_NODE, &debug_rmap_cmd);
install_element(ENABLE_NODE, &no_debug_rmap_cmd);
-
- install_element(RMAP_NODE, &match_interface_cmd);
- install_element(RMAP_NODE, &no_match_interface_cmd);
-
- install_element(RMAP_NODE, &match_ip_address_cmd);
- install_element(RMAP_NODE, &no_match_ip_address_cmd);
-
- install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
- install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_address_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
-
- install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
- install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
-
- install_element(RMAP_NODE, &match_metric_cmd);
- install_element(RMAP_NODE, &no_match_metric_cmd);
-
- install_element(RMAP_NODE, &match_tag_cmd);
- install_element(RMAP_NODE, &no_match_tag_cmd);
-
- install_element(RMAP_NODE, &set_ip_nexthop_cmd);
- install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
-
- install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
- install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
-
- install_element(RMAP_NODE, &set_metric_cmd);
- install_element(RMAP_NODE, &no_set_metric_cmd);
-
- install_element(RMAP_NODE, &set_tag_cmd);
- install_element(RMAP_NODE, &no_set_tag_cmd);
}
--- /dev/null
+/*
+ * Route map northbound CLI implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/northbound_cli.h"
+#include "lib/routemap.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/routemap_cli_clippy.c"
+#endif /* VTYSH_EXTRACT_PL */
+
+#define ROUTE_MAP_CMD_STR \
+ "Create route-map or enter route-map command mode\n" \
+ "Route map tag\n"
+#define ROUTE_MAP_OP_CMD_STR \
+ "Route map denies set operations\n" \
+ "Route map permits set operations\n"
+#define ROUTE_MAP_SEQUENCE_CMD_STR \
+ "Sequence to insert to/delete from existing route-map entry\n"
+
+DEFPY_NOSH(
+ route_map, route_map_cmd,
+ "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ ROUTE_MAP_CMD_STR
+ ROUTE_MAP_OP_CMD_STR
+ ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+ char xpath_action[XPATH_MAXLEN + 64];
+ char xpath_index[XPATH_MAXLEN + 32];
+ char xpath[XPATH_MAXLEN];
+ int rv;
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']",
+ xpath, sequence);
+ nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index);
+ nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action);
+
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
+
+ return rv;
+}
+
+DEFPY(
+ no_route_map_all, no_route_map_all_cmd,
+ "no route-map WORD$name",
+ NO_STR
+ ROUTE_MAP_CMD_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_route_map, no_route_map_cmd,
+ "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+ NO_STR
+ ROUTE_MAP_CMD_STR
+ ROUTE_MAP_OP_CMD_STR
+ ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
+ name, sequence);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *name = yang_dnode_get_string(dnode, "../name");
+ const char *action = yang_dnode_get_string(dnode, "./action");
+ const char *sequence = yang_dnode_get_string(dnode, "./sequence");
+
+ vty_out(vty, "route-map %s %s %s\n", name, action, sequence);
+}
+
+void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, "!\n");
+}
+
+DEFPY(
+ match_interface, match_interface_cmd,
+ "match interface IFNAME",
+ MATCH_STR
+ "Match first hop interface of route\n"
+ INTERFACE_STR)
+{
+ const char *xpath = "./match-condition[condition='interface']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_interface, no_match_interface_cmd,
+ "no match interface [IFNAME]",
+ NO_STR
+ MATCH_STR
+ "Match first hop interface of route\n"
+ INTERFACE_STR)
+{
+ const char *xpath = "./match-condition[condition='interface']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_address, match_ip_address_cmd,
+ "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-address-list']";
+ char xpath_value[XPATH_MAXLEN + 32];
+ int acln = acll ? acll : aclh;
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (name) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+ } else /* if (acll || aclh) */ {
+ if ((acln >= 1 && acln <= 99)
+ || (acln >= 1300 && acln <= 1999)) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num", xpath);
+ } else {
+ /*
+ * if ((acln >= 100 && acln <= 199)
+ * || (acln >= 2000 && acln <= 2699))
+ */
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num-extended", xpath);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ acll_str ? acll_str : aclh_str);
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_address, no_match_ip_address_cmd,
+ "no match ip address [<(1-199)|(1300-2699)|WORD>]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-address-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD$name",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop, match_ip_next_hop_cmd,
+ "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+ char xpath_value[XPATH_MAXLEN + 32];
+ int acln = acll ? acll : aclh;
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (name) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+ } else /* if (acll || aclh) */ {
+ if ((acln >= 1 && acln <= 99)
+ || (acln >= 1300 && acln <= 1999)) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num", xpath);
+ } else {
+ /*
+ * if ((acln >= 100 && acln <= 199)
+ * || (acln >= 2000 && acln <= 2699))
+ */
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/access-list-num-extended", xpath);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+ acll_str ? acll_str : aclh_str);
+ }
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop, no_match_ip_next_hop_cmd,
+ "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD$name",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath =
+ "./match-condition[condition='ipv4-next-hop-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ip_next_hop_type, match_ip_next_hop_type_cmd,
+ "match ip next-hop type <blackhole>$type",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
+ "no match ip next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IP_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_address, match_ipv6_address_cmd,
+ "match ipv6 address WORD$name",
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-address-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_address, no_match_ipv6_address_cmd,
+ "no match ipv6 address [WORD]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-address-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
+ "match ipv6 address prefix-list WORD$name",
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_address_prefix_list,
+ no_match_ipv6_address_prefix_list_cmd,
+ "no match ipv6 address prefix-list [WORD]",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
+ "match ipv6 next-hop type <blackhole>$type",
+ MATCH_STR IPV6_STR
+ "Match next-hop address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
+ "no match ipv6 next-hop type [<blackhole>]",
+ NO_STR MATCH_STR IPV6_STR
+ "Match address of route\n"
+ "Match entries by type\n"
+ "Blackhole\n")
+{
+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_metric, match_metric_cmd,
+ "match metric (0-4294967295)$metric",
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ const char *xpath = "./match-condition[condition='metric']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_metric, no_match_metric_cmd,
+ "no match metric [(0-4294967295)]",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ const char *xpath = "./match-condition[condition='metric']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ match_tag, match_tag_cmd,
+ "match tag (1-4294967295)$tag",
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ const char *xpath = "./match-condition[condition='tag']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_match_tag, no_match_tag_cmd,
+ "no match tag [(1-4294967295)]",
+ NO_STR
+ MATCH_STR
+ "Match tag of route\n"
+ "Tag value\n")
+{
+ const char *xpath = "./match-condition[condition='tag']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int condition = yang_dnode_get_enum(dnode, "./condition");
+ struct lyd_node *ln;
+ const char *acl;
+
+ switch (condition) {
+ case 0: /* interface */
+ vty_out(vty, " match interface %s\n",
+ yang_dnode_get_string(dnode, "./interface"));
+ break;
+ case 1: /* ipv4-address-list */
+ case 3: /* ipv4-next-hop-list */
+ acl = NULL;
+ if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if ((ln = yang_dnode_get(dnode, "./access-list-num"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+ else if ((ln = yang_dnode_get(dnode,
+ "./access-list-num-extended"))
+ != NULL)
+ acl = yang_dnode_get_string(ln, NULL);
+
+ assert(acl);
+
+ switch (condition) {
+ case 1:
+ vty_out(vty, " match ip address %s\n", acl);
+ break;
+ case 3:
+ vty_out(vty, " match ip next-hop %s\n", acl);
+ break;
+ }
+ break;
+ case 2: /* ipv4-prefix-list */
+ vty_out(vty, " match ip address prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 4: /* ipv4-next-hop-prefix-list */
+ vty_out(vty, " match ip next-hop prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 5: /* ipv4-next-hop-type */
+ vty_out(vty, " match ip next-hop type %s\n",
+ yang_dnode_get_string(dnode, "./ipv4-next-hop-type"));
+ break;
+ case 6: /* ipv6-address-list */
+ vty_out(vty, " match ipv6 address %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 7: /* ipv6-prefix-list */
+ vty_out(vty, " match ipv6 address prefix-list %s\n",
+ yang_dnode_get_string(dnode, "./list-name"));
+ break;
+ case 8: /* ipv6-next-hop-type */
+ vty_out(vty, " match ipv6 next-hop type %s\n",
+ yang_dnode_get_string(dnode, "./ipv6-next-hop-type"));
+ break;
+ case 9: /* metric */
+ vty_out(vty, " match metric %s\n",
+ yang_dnode_get_string(dnode, "./metric"));
+ break;
+ case 10: /* tag */
+ vty_out(vty, " match tag %s\n",
+ yang_dnode_get_string(dnode, "./tag"));
+ break;
+ case 100:
+ /* NOTHING: custom field, should be handled by daemon. */
+ break;
+ }
+}
+
+DEFPY(
+ set_ip_nexthop, set_ip_nexthop_cmd,
+ "set ip next-hop A.B.C.D$addr",
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv4-next-hop']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_ip_nexthop, no_set_ip_nexthop_cmd,
+ "no set ip next-hop [A.B.C.D]",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv4-next-hop']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd,
+ "set ipv6 next-hop local X:X::X:X$addr",
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv6-next-hop']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd,
+ "no set ipv6 next-hop local [X:X::X:X]",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ const char *xpath = "./set-action[action='ipv6-next-hop']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_metric, set_metric_cmd,
+ "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n"
+ "Assign round trip time\n"
+ "Add round trip time\n"
+ "Subtract round trip time\n"
+ "Add metric\n"
+ "Subtract metric\n")
+{
+ const char *xpath = "./set-action[action='metric']";
+ char xpath_value[XPATH_MAXLEN];
+ char value[64];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (rtt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/use-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (artt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/add-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (srtt) {
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/subtract-round-trip-time", xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (ametric) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
+ xpath);
+ snprintf(value, sizeof(value), "true");
+ } else if (smetric) {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
+ xpath);
+ snprintf(value, sizeof(value), "true");
+ } else {
+ snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
+ snprintf(value, sizeof(value), "%lu", metric);
+ }
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_metric, no_set_metric_cmd,
+ "no set metric [(0-4294967295)]",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+{
+ const char *xpath = "./set-action[action='metric']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ set_tag, set_tag_cmd,
+ "set tag (1-4294967295)$tag",
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ const char *xpath = "./set-action[action='tag']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_set_tag, no_set_tag_cmd,
+ "no set tag [(1-4294967295)]",
+ NO_STR
+ SET_STR
+ "Tag value for routing protocol\n"
+ "Tag value\n")
+{
+ const char *xpath = "./set-action[action='tag']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int action = yang_dnode_get_enum(dnode, "./action");
+
+ switch (action) {
+ case 0: /* ipv4-next-hop */
+ vty_out(vty, " set ip next-hop %s\n",
+ yang_dnode_get_string(dnode, "./ipv4-address"));
+ break;
+ case 1: /* ipv6-next-hop */
+ vty_out(vty, " set ipv6 next-hop local %s\n",
+ yang_dnode_get_string(dnode, "./ipv6-address"));
+ break;
+ case 2: /* metric */
+ if (yang_dnode_get(dnode, "./use-round-trip-time")) {
+ vty_out(vty, " set metric rtt\n");
+ } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
+ vty_out(vty, " set metric +rtt\n");
+ } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
+ vty_out(vty, " set metric -rtt\n");
+ } else if (yang_dnode_get(dnode, "./add-metric")) {
+ vty_out(vty, " set metric +metric\n");
+ } else if (yang_dnode_get(dnode, "./subtract-metric")) {
+ vty_out(vty, " set metric -metric\n");
+ } else {
+ vty_out(vty, " set metric %s\n",
+ yang_dnode_get_string(dnode, "./value"));
+ }
+ break;
+ case 3: /* tag */
+ vty_out(vty, " set tag %s\n",
+ yang_dnode_get_string(dnode, "./tag"));
+ break;
+ case 100:
+ /* NOTHING: custom field, should be handled by daemon. */
+ break;
+ }
+}
+
+DEFPY(
+ rmap_onmatch_next, rmap_onmatch_next_cmd,
+ "on-match next",
+ "Exit policy on matches\n"
+ "Next clause\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_onmatch_next,
+ no_rmap_onmatch_next_cmd,
+ "no on-match next",
+ NO_STR
+ "Exit policy on matches\n"
+ "Next clause\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ rmap_onmatch_goto, rmap_onmatch_goto_cmd,
+ "on-match goto (1-65535)$rm_num",
+ "Exit policy on matches\n"
+ "Goto Clause number\n"
+ "Number\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto");
+ nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
+ "no on-match goto",
+ NO_STR
+ "Exit policy on matches\n"
+ "Goto Clause number\n")
+{
+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+/* Cisco/GNU Zebra compatibility aliases */
+ALIAS(
+ rmap_onmatch_goto, rmap_continue_cmd,
+ "continue (1-65535)$rm_num",
+ "Continue on a different entry within the route-map\n"
+ "Route-map entry sequence number\n")
+
+ALIAS(
+ no_rmap_onmatch_goto, no_rmap_continue_cmd,
+ "no continue [(1-65535)]",
+ NO_STR
+ "Continue on a different entry within the route-map\n"
+ "Route-map entry sequence number\n")
+
+void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int exit_policy = yang_dnode_get_enum(dnode, NULL);
+
+ switch (exit_policy) {
+ case 0: /* permit-or-deny */
+ /* NOTHING: default option. */
+ break;
+ case 1: /* next */
+ vty_out(vty, " on-match next\n");
+ break;
+ case 2: /* goto */
+ vty_out(vty, " on-match goto %s\n",
+ yang_dnode_get_string(dnode, "../goto-value"));
+ break;
+ }
+}
+
+DEFPY(
+ rmap_call, rmap_call_cmd,
+ "call WORD$name",
+ "Jump to another Route-Map after match+set\n"
+ "Target route-map name\n")
+{
+ nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_rmap_call, no_rmap_call_cmd,
+ "no call",
+ NO_STR
+ "Jump to another Route-Map after match+set\n")
+{
+ nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+DEFPY(
+ rmap_description, rmap_description_cmd,
+ "description LINE...",
+ "Route-map comment\n"
+ "Comment describing this route-map rule\n")
+{
+ char *desc;
+ int rv;
+
+ desc = argv_concat(argv, argc, 1);
+ nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
+ rv = nb_cli_apply_changes(vty, NULL);
+ XFREE(MTYPE_TMP, desc);
+
+ return rv;
+}
+
+DEFUN (no_rmap_description,
+ no_rmap_description_cmd,
+ "no description",
+ NO_STR
+ "Route-map comment\n")
+{
+ nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+static int route_map_config_write(struct vty *vty)
+{
+ struct lyd_node *dnode;
+ int written = 0;
+
+ dnode = yang_dnode_get(running_config->dnode,
+ "/frr-route-map:lib");
+ if (dnode) {
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ written = 1;
+ }
+
+ return written;
+}
+
+/* Route map node structure. */
+static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
+
+static void rmap_autocomplete(vector comps, struct cmd_token *token)
+{
+ struct route_map *map;
+
+ for (map = route_map_master.head; map; map = map->next)
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
+}
+
+static const struct cmd_variable_handler rmap_var_handlers[] = {
+ {.varname = "route_map", .completions = rmap_autocomplete},
+ {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
+ {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
+ {.completions = NULL}
+};
+
+void route_map_cli_init(void)
+{
+ /* Auto complete handler. */
+ cmd_variable_handler_register(rmap_var_handlers);
+
+ /* CLI commands. */
+ install_node(&rmap_node, route_map_config_write);
+ install_default(RMAP_NODE);
+ install_element(CONFIG_NODE, &route_map_cmd);
+ install_element(CONFIG_NODE, &no_route_map_cmd);
+ install_element(CONFIG_NODE, &no_route_map_all_cmd);
+
+ /* Install the on-match stuff */
+ install_element(RMAP_NODE, &route_map_cmd);
+ install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
+ install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
+ install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
+ install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
+ install_element(RMAP_NODE, &rmap_continue_cmd);
+ install_element(RMAP_NODE, &no_rmap_continue_cmd);
+
+ /* Install the call stuff. */
+ install_element(RMAP_NODE, &rmap_call_cmd);
+ install_element(RMAP_NODE, &no_rmap_call_cmd);
+
+ /* Install description commands. */
+ install_element(RMAP_NODE, &rmap_description_cmd);
+ install_element(RMAP_NODE, &no_rmap_description_cmd);
+
+ /* Install 'match' commands. */
+ install_element(RMAP_NODE, &match_interface_cmd);
+ install_element(RMAP_NODE, &no_match_interface_cmd);
+
+ install_element(RMAP_NODE, &match_ip_address_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_cmd);
+
+ install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_address_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+
+ install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
+ install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
+
+ install_element(RMAP_NODE, &match_metric_cmd);
+ install_element(RMAP_NODE, &no_match_metric_cmd);
+
+ install_element(RMAP_NODE, &match_tag_cmd);
+ install_element(RMAP_NODE, &no_match_tag_cmd);
+
+ /* Install 'set' commands. */
+ install_element(RMAP_NODE, &set_ip_nexthop_cmd);
+ install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
+
+ install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+ install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+
+ install_element(RMAP_NODE, &set_metric_cmd);
+ install_element(RMAP_NODE, &no_set_metric_cmd);
+
+ install_element(RMAP_NODE, &set_tag_cmd);
+ install_element(RMAP_NODE, &no_set_tag_cmd);
+}