]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: implement new route map CLI
authorRafael Zalamena <rzalamena@opensourcerouting.org>
Mon, 30 Sep 2019 18:01:46 +0000 (15:01 -0300)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Tue, 4 Feb 2020 17:05:43 +0000 (14:05 -0300)
Use the northbound back-end instead of the old route map CLI.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
lib/routemap.c
lib/routemap.h
lib/routemap_cli.c [new file with mode: 0644]
lib/routemap_northbound.c
lib/subdir.am
vtysh/extract.pl.in

index a8feebd3138ed495f0f5c66fd40cb81e48a80f9a..e07ad0812333b892839d81fd78a12267a399d6e9 100644 (file)
@@ -759,14 +759,6 @@ static const char *route_map_result_str(route_map_result_t res)
        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)
 {
@@ -2010,871 +2002,6 @@ void route_map_notify_dependencies(const char *affected_name,
 
 
 /* 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;
@@ -2937,89 +2064,6 @@ DEFUN (rmap_show_unused,
        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",
@@ -3045,59 +2089,6 @@ DEFUN (no_debug_rmap,
 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;
@@ -3110,9 +2101,6 @@ static int rmap_config_write_debug(struct vty *vty)
        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)
@@ -3171,14 +2159,6 @@ void route_map_finish(void)
        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)
 {
@@ -3196,14 +2176,6 @@ void route_map_counter_decrement(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)
 {
@@ -3221,43 +2193,17 @@ 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);
 
@@ -3266,49 +2212,4 @@ void route_map_init(void)
 
        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);
 }
index d9e7f73f815e3902db8c5b19ae467a8c22d5fef1..70e150c9812bc457be8a7af086a1d6a46232e220 100644 (file)
@@ -666,8 +666,27 @@ int lib_route_map_entry_match_destroy(enum nb_event event,
                                      const struct lyd_node *dnode);
 int lib_route_map_entry_set_destroy(enum nb_event event,
                                    const struct lyd_node *dnode);
+
 extern const struct frr_yang_module_info frr_route_map_info;
 
+/* routemap_cli.c */
+extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void route_map_instance_show_end(struct vty *vty,
+                                       struct lyd_node *dnode);
+extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+                                 bool show_defaults);
+extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults);
+extern void route_map_description_show(struct vty *vty,
+                                      struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void route_map_cli_init(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
new file mode 100644 (file)
index 0000000..987693c
--- /dev/null
@@ -0,0 +1,1075 @@
+/*
+ * 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);
+}
index 02eb756334452605909e75e2298513350054d2cb..b9ac01e8653d297bffddf3b36d84128c8d547fd7 100644 (file)
@@ -1218,6 +1218,8 @@ const struct frr_yang_module_info frr_route_map_info = {
                        .cbs = {
                                .create = lib_route_map_entry_create,
                                .destroy = lib_route_map_entry_destroy,
+                               .cli_show = route_map_instance_show,
+                               .cli_show_end = route_map_instance_show_end,
                        }
                },
                {
@@ -1225,6 +1227,7 @@ const struct frr_yang_module_info frr_route_map_info = {
                        .cbs = {
                                .modify = lib_route_map_entry_description_modify,
                                .destroy = lib_route_map_entry_description_destroy,
+                               .cli_show = route_map_description_show,
                        }
                },
                {
@@ -1238,12 +1241,14 @@ const struct frr_yang_module_info frr_route_map_info = {
                        .cbs = {
                                .modify = lib_route_map_entry_call_modify,
                                .destroy = lib_route_map_entry_call_destroy,
+                               .cli_show = route_map_call_show,
                        }
                },
                {
                        .xpath = "/frr-route-map:lib/route-map/entry/exit-policy",
                        .cbs = {
                                .modify = lib_route_map_entry_exit_policy_modify,
+                               .cli_show = route_map_exit_policy_show,
                        }
                },
                {
@@ -1258,6 +1263,7 @@ const struct frr_yang_module_info frr_route_map_info = {
                        .cbs = {
                                .create = lib_route_map_entry_match_condition_create,
                                .destroy = lib_route_map_entry_match_condition_destroy,
+                               .cli_show = route_map_condition_show,
                        }
                },
                {
@@ -1321,6 +1327,7 @@ const struct frr_yang_module_info frr_route_map_info = {
                        .cbs = {
                                .create = lib_route_map_entry_set_action_create,
                                .destroy = lib_route_map_entry_set_action_destroy,
+                               .cli_show = route_map_action_show,
                        }
                },
                {
index 94b3d933ac95a0b2cdf64f4c27215f9ca66c32b1..ffac721256430911599cba04426033b7c3f81707 100644 (file)
@@ -71,6 +71,7 @@ lib_libfrr_la_SOURCES = \
        lib/qobj.c \
        lib/ringbuf.c \
        lib/routemap.c \
+       lib/routemap_cli.c \
        lib/routemap_northbound.c \
        lib/sbuf.c \
        lib/seqlock.c \
@@ -122,6 +123,7 @@ vtysh_scan += \
        $(top_srcdir)/lib/nexthop_group.c \
        $(top_srcdir)/lib/plist.c \
        $(top_srcdir)/lib/routemap.c \
+       $(top_srcdir)/lib/routemap_cli.c \
        $(top_srcdir)/lib/vrf.c \
        $(top_srcdir)/lib/vty.c \
        # end
@@ -141,6 +143,8 @@ lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
 lib/nexthop_group.lo: lib/nexthop_group_clippy.c
 lib/northbound_cli_clippy.c: $(CLIPPY_DEPS)
 lib/northbound_cli.lo: lib/northbound_cli_clippy.c
+lib/routemap_cli_clippy.c: $(CLIPPY_DEPS)
+lib/routemap_cli.lo: lib/routemap_cli_clippy.c
 lib/vty_clippy.c: $(CLIPPY_DEPS)
 lib/vty.lo: lib/vty_clippy.c
 lib/log_vty_clippy.c: $(CLIPPY_DEPS)
index 13413888bf5e6be7b8c2b154895c06b3ee14cee5..b7ac0abe02c0160027d92a6af760952471251497 100755 (executable)
@@ -87,7 +87,7 @@ sub scan_file {
         if ($file =~ /lib\/keychain\.c$/) {
             $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
         }
-        elsif ($file =~ /lib\/routemap\.c$/) {
+        elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) {
             $protocol = "VTYSH_RMAP";
         }
         elsif ($file =~ /lib\/vrf\.c$/) {