]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: convert if_rmap to YANG northbound
authorChristian Hopps <chopps@labn.net>
Sun, 9 Apr 2023 09:02:51 +0000 (05:02 -0400)
committerChristian Hopps <chopps@labn.net>
Tue, 11 Apr 2023 19:27:05 +0000 (15:27 -0400)
- nice correspondence between new YANG grouping and shared library code.
- fixes bug with RIPNG use, certainly didn't work before.
- removes rip header from shared library code
- still has uses RIP_NODE/RIPNG_NODE as required by CLI foo.

Signed-off-by: Christian Hopps <chopps@labn.net>
lib/if_rmap.c
lib/if_rmap.h
lib/subdir.am
yang/frr-if-rmap.yang [new file with mode: 0644]
yang/subdir.am

index ae9c107187f5cc1489b239da2b5d50206ea8c65e..5895924a5e90072e554624e84ea42ad6392263a0 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* route-map for interface.
  * Copyright (C) 1999 Kunihiro Ishiguro
+ * Copyright (C) 2023 LabN Consulting, L.L.C.
  */
 
 #include <zebra.h>
@@ -10,7 +11,9 @@
 #include "memory.h"
 #include "if.h"
 #include "if_rmap.h"
-#include "ripd/ripd.h"
+#include "northbound_cli.h"
+
+#include "lib/if_rmap_clippy.c"
 
 DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container");
 DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME,
@@ -18,8 +21,6 @@ DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME,
 DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map");
 DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name");
 
-static struct list *if_rmap_ctx_list;
-
 static struct if_rmap *if_rmap_new(void)
 {
        struct if_rmap *new;
@@ -31,7 +32,9 @@ static struct if_rmap *if_rmap_new(void)
 
 static void if_rmap_free(struct if_rmap *if_rmap)
 {
-       XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname);
+       char *no_const_ifname = (char *)if_rmap->ifname;
+
+       XFREE(MTYPE_IF_RMAP_NAME, no_const_ifname);
 
        XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
        XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
@@ -41,16 +44,11 @@ static void if_rmap_free(struct if_rmap *if_rmap)
 
 struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, const char *ifname)
 {
-       struct if_rmap key;
+       struct if_rmap key = {.ifname = ifname};
        struct if_rmap *if_rmap;
 
-       /* temporary copy */
-       key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL;
-
        if_rmap = hash_lookup(ctx->ifrmaphash, &key);
 
-       XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
-
        return if_rmap;
 }
 
@@ -80,16 +78,11 @@ static void *if_rmap_hash_alloc(void *arg)
 
 static struct if_rmap *if_rmap_get(struct if_rmap_ctx *ctx, const char *ifname)
 {
-       struct if_rmap key;
+       struct if_rmap key = {.ifname = ifname};
        struct if_rmap *ret;
 
-       /* temporary copy */
-       key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL;
-
        ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc);
 
-       XFREE(MTYPE_IF_RMAP_NAME, key.ifname);
-
        return ret;
 }
 
@@ -108,58 +101,32 @@ static bool if_rmap_hash_cmp(const void *arg1, const void *arg2)
        return strcmp(if_rmap1->ifname, if_rmap2->ifname) == 0;
 }
 
-static struct if_rmap *if_rmap_set(struct if_rmap_ctx *ctx,
-                                  const char *ifname, enum if_rmap_type type,
-                                  const char *routemap_name)
+static void if_rmap_set(struct if_rmap_ctx *ctx, const char *ifname,
+                       enum if_rmap_type type, const char *routemap_name)
 {
-       struct if_rmap *if_rmap;
-
-       if_rmap = if_rmap_get(ctx, ifname);
+       struct if_rmap *if_rmap = if_rmap_get(ctx, ifname);
 
-       if (type == IF_RMAP_IN) {
-               XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
-               if_rmap->routemap[IF_RMAP_IN] =
-                       XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name);
-       }
-       if (type == IF_RMAP_OUT) {
-               XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
-               if_rmap->routemap[IF_RMAP_OUT] =
-                       XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name);
-       }
+       assert(type == IF_RMAP_IN || type == IF_RMAP_OUT);
+       XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[type]);
+       if_rmap->routemap[type] = XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name);
 
        if (ctx->if_rmap_add_hook)
                (ctx->if_rmap_add_hook)(ctx, if_rmap);
-
-       return if_rmap;
 }
 
-static int if_rmap_unset(struct if_rmap_ctx *ctx,
-                        const char *ifname, enum if_rmap_type type,
-                        const char *routemap_name)
+static void if_rmap_unset(struct if_rmap_ctx *ctx, const char *ifname,
+                         enum if_rmap_type type)
 {
-       struct if_rmap *if_rmap;
+       struct if_rmap *if_rmap = if_rmap_lookup(ctx, ifname);
 
-       if_rmap = if_rmap_lookup(ctx, ifname);
        if (!if_rmap)
-               return 0;
-
-       if (type == IF_RMAP_IN) {
-               if (!if_rmap->routemap[IF_RMAP_IN])
-                       return 0;
-               if (strcmp(if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0)
-                       return 0;
-
-               XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
-       }
+               return;
 
-       if (type == IF_RMAP_OUT) {
-               if (!if_rmap->routemap[IF_RMAP_OUT])
-                       return 0;
-               if (strcmp(if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0)
-                       return 0;
+       assert(type == IF_RMAP_IN || type == IF_RMAP_OUT);
+       if (!if_rmap->routemap[type])
+               return;
 
-               XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
-       }
+       XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[type]);
 
        if (ctx->if_rmap_delete_hook)
                ctx->if_rmap_delete_hook(ctx, if_rmap);
@@ -169,80 +136,131 @@ static int if_rmap_unset(struct if_rmap_ctx *ctx,
                hash_release(ctx->ifrmaphash, if_rmap);
                if_rmap_free(if_rmap);
        }
-
-       return 1;
 }
 
-DEFUN (if_rmap,
-       if_rmap_cmd,
-       "route-map RMAP_NAME <in|out> IFNAME",
-       "Route map set\n"
-       "Route map name\n"
-       "Route map set for input filtering\n"
-       "Route map set for output filtering\n"
-       "Route map interface name\n")
+static int if_route_map_handler(struct vty *vty, bool no, const char *dir,
+                               const char *other_dir, const char *ifname,
+                               const char *route_map)
 {
-       int idx_rmap_name = 1;
-       int idx_in_out = 2;
-       int idx_ifname = 3;
-       enum if_rmap_type type;
-       struct if_rmap_ctx *ctx;
+       enum nb_operation op = no ? NB_OP_DESTROY : NB_OP_MODIFY;
        const struct lyd_node *dnode;
-       struct rip *rip;
-
-       dnode = yang_dnode_get(running_config->dnode, VTY_CURR_XPATH);
-       rip = nb_running_get_entry(dnode, NULL, true);
-       ctx = rip->if_rmap_ctx;
-
-       if (strncmp(argv[idx_in_out]->text, "in", 1) == 0)
-               type = IF_RMAP_IN;
-       else if (strncmp(argv[idx_in_out]->text, "out", 1) == 0)
-               type = IF_RMAP_OUT;
-       else {
-               vty_out(vty, "route-map direction must be [in|out]\n");
-               return CMD_WARNING_CONFIG_FAILED;
+       char xpath[XPATH_MAXLEN];
+
+       if (!no) {
+               snprintf(
+                       xpath, sizeof(xpath),
+                       "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
+                       ifname, dir);
+       } else {
+               /*
+                * If we are deleting the last policy for this interface,
+                * (i.e., no `in` or `out` policy). delete the interface list
+                * node instead.
+                */
+               dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                      VTY_CURR_XPATH);
+               if (yang_dnode_existsf(
+                           dnode,
+                           "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
+                           ifname, other_dir)) {
+                       snprintf(
+                               xpath, sizeof(xpath),
+                               "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
+                               ifname, dir);
+               } else {
+                       /* both dir will be empty so delete the list node */
+                       snprintf(xpath, sizeof(xpath),
+                                "./if-route-maps/if-route-map[interface='%s']",
+                                ifname);
+               }
        }
+       nb_cli_enqueue_change(vty, xpath, op, route_map);
 
-       if_rmap_set(ctx, argv[idx_ifname]->arg,
-                   type, argv[idx_rmap_name]->arg);
+       return nb_cli_apply_changes(vty, NULL);
+}
 
-       return CMD_SUCCESS;
+DEFPY_YANG(if_ipv4_route_map, if_ipv4_route_map_cmd,
+          "route-map ROUTE-MAP <in$in|out> IFNAME",
+          "Route map set\n"
+          "Route map name\n"
+          "Route map set for input filtering\n"
+          "Route map set for output filtering\n" INTERFACE_STR)
+{
+       const char *dir = in ? "in" : "out";
+       const char *other_dir = in ? "out" : "in";
+
+       return if_route_map_handler(vty, false, dir, other_dir, ifname,
+                                   route_map);
 }
 
-DEFUN (no_if_rmap,
-       no_if_rmap_cmd,
-       "no route-map ROUTEMAP_NAME <in|out> IFNAME",
-       NO_STR
-       "Route map unset\n"
-       "Route map name\n"
-       "Route map for input filtering\n"
-       "Route map for output filtering\n"
-       "Route map interface name\n")
+DEFPY_YANG(no_if_ipv4_route_map, no_if_ipv4_route_map_cmd,
+          "no route-map [ROUTE-MAP] <in$in|out> IFNAME",
+          NO_STR
+          "Route map set\n"
+          "Route map name\n"
+          "Route map set for input filtering\n"
+          "Route map set for output filtering\n" INTERFACE_STR)
 {
-       int idx_routemap_name = 2;
-       int idx_in_out = 3;
-       int idx_ifname = 4;
-       int ret;
-       enum if_rmap_type type;
-       struct if_rmap_ctx *ctx =
-               (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list);
-
-       if (strncmp(argv[idx_in_out]->arg, "i", 1) == 0)
-               type = IF_RMAP_IN;
-       else if (strncmp(argv[idx_in_out]->arg, "o", 1) == 0)
-               type = IF_RMAP_OUT;
-       else {
-               vty_out(vty, "route-map direction must be [in|out]\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       const char *dir = in ? "in" : "out";
+       const char *other_dir = in ? "out" : "in";
 
-       ret = if_rmap_unset(ctx, argv[idx_ifname]->arg, type,
-                           argv[idx_routemap_name]->arg);
-       if (!ret) {
-               vty_out(vty, "route-map doesn't exist\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       return CMD_SUCCESS;
+       return if_route_map_handler(vty, true, dir, other_dir, ifname,
+                                   route_map);
+}
+
+/*
+ * CLI infra requires new handlers for ripngd
+ */
+DEFPY_YANG(if_ipv6_route_map, if_ipv6_route_map_cmd,
+          "route-map ROUTE-MAP <in$in|out> IFNAME",
+          "Route map set\n"
+          "Route map name\n"
+          "Route map set for input filtering\n"
+          "Route map set for output filtering\n" INTERFACE_STR)
+{
+       const char *dir = in ? "in" : "out";
+       const char *other_dir = in ? "out" : "in";
+
+       return if_route_map_handler(vty, false, dir, other_dir, ifname,
+                                   route_map);
+}
+
+DEFPY_YANG(no_if_ipv6_route_map, no_if_ipv6_route_map_cmd,
+          "no route-map [ROUTE-MAP] <in$in|out> IFNAME",
+          NO_STR
+          "Route map set\n"
+          "Route map name\n"
+          "Route map set for input filtering\n"
+          "Route map set for output filtering\n" INTERFACE_STR)
+{
+       const char *dir = in ? "in" : "out";
+       const char *other_dir = in ? "out" : "in";
+
+       return if_route_map_handler(vty, true, dir, other_dir, ifname,
+                                   route_map);
+}
+
+
+void if_rmap_yang_modify_cb(struct if_rmap_ctx *ctx,
+                           const struct lyd_node *dnode,
+                           enum if_rmap_type type, bool del)
+{
+
+       const char *mapname = yang_dnode_get_string(dnode, NULL);
+       const char *ifname = yang_dnode_get_string(dnode, "../interface");
+
+       if (del)
+               if_rmap_unset(ctx, ifname, type);
+       else
+               if_rmap_set(ctx, ifname, type, mapname);
+}
+
+void if_rmap_yang_destroy_cb(struct if_rmap_ctx *ctx,
+                            const struct lyd_node *dnode)
+{
+       const char *ifname = yang_dnode_get_string(dnode, "interface");
+       if_rmap_unset(ctx, ifname, IF_RMAP_IN);
+       if_rmap_unset(ctx, ifname, IF_RMAP_OUT);
 }
 
 
@@ -279,10 +297,8 @@ int config_write_if_rmap(struct vty *vty, struct if_rmap_ctx *ctx)
 
 void if_rmap_ctx_delete(struct if_rmap_ctx *ctx)
 {
-       listnode_delete(if_rmap_ctx_list, ctx);
        hash_clean_and_free(&ctx->ifrmaphash, (void (*)(void *))if_rmap_free);
-       if (ctx->name)
-               XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx->name);
+       XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx->name);
        XFREE(MTYPE_IF_RMAP_CTX, ctx);
 }
 
@@ -297,25 +313,20 @@ struct if_rmap_ctx *if_rmap_ctx_create(const char *name)
        ctx->ifrmaphash =
                hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp,
                                 "Interface Route-Map Hash");
-       if (!if_rmap_ctx_list)
-               if_rmap_ctx_list = list_new();
-       listnode_add(if_rmap_ctx_list, ctx);
        return ctx;
 }
 
 void if_rmap_init(int node)
 {
-       if (node == RIPNG_NODE) {
-       } else if (node == RIP_NODE) {
-               install_element(RIP_NODE, &if_rmap_cmd);
-               install_element(RIP_NODE, &no_if_rmap_cmd);
+       if (node == RIP_NODE) {
+               install_element(RIP_NODE, &if_ipv4_route_map_cmd);
+               install_element(RIP_NODE, &no_if_ipv4_route_map_cmd);
+       } else if (node == RIPNG_NODE) {
+               install_element(RIPNG_NODE, &if_ipv6_route_map_cmd);
+               install_element(RIPNG_NODE, &no_if_ipv6_route_map_cmd);
        }
-       if_rmap_ctx_list = list_new();
 }
 
 void if_rmap_terminate(void)
 {
-       if (!if_rmap_ctx_list)
-               return;
-       list_delete(&if_rmap_ctx_list);
 }
index 3bdbc2a3b2cd1b7282ec93c2fbd005f96de7a7d1..6f5fb578f00267a9d913c78203ddb3c35f8499a9 100644 (file)
@@ -6,15 +6,20 @@
 #ifndef _ZEBRA_IF_RMAP_H
 #define _ZEBRA_IF_RMAP_H
 
+#include "typesafe.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+struct lyd_node;
+struct vty;
+
 enum if_rmap_type { IF_RMAP_IN, IF_RMAP_OUT, IF_RMAP_MAX };
 
 struct if_rmap {
        /* Name of the interface. */
-       char *ifname;
+       const char *ifname;
 
        char *routemap[IF_RMAP_MAX];
 };
@@ -45,6 +50,11 @@ void if_rmap_hook_delete(struct if_rmap_ctx *ctx,
                                      struct if_rmap *));
 extern struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx,
                                      const char *ifname);
+extern void if_rmap_yang_modify_cb(struct if_rmap_ctx *ctx,
+                                  const struct lyd_node *dnode,
+                                  enum if_rmap_type type, bool del);
+extern void if_rmap_yang_destroy_cb(struct if_rmap_ctx *ctx,
+                                   const struct lyd_node *dnode);
 extern int config_write_if_rmap(struct vty *, struct if_rmap_ctx *ctx);
 
 #ifdef __cplusplus
index 83eecbee577638db4a788202fa6d6f1520248bed..dcc58b31ae3ee59ebe675563292afaf1cf7b0f2e 100644 (file)
@@ -174,6 +174,7 @@ clippy_scan += \
        lib/affinitymap_cli.c \
        lib/if.c \
        lib/filter_cli.c \
+       lib/if_rmap.c \
        lib/log_vty.c \
        lib/nexthop_group.c \
        lib/northbound_cli.c \
diff --git a/yang/frr-if-rmap.yang b/yang/frr-if-rmap.yang
new file mode 100644 (file)
index 0000000..0fa2c5e
--- /dev/null
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: BSD-2-Clause
+module frr-if-rmap {
+  yang-version 1.1;
+  namespace "http://frrouting.org/yang/frr-if-rmap";
+  prefix frr-if-map;
+
+  import frr-interface {
+    prefix frr-interface;
+  }
+
+  import frr-route-map {
+    prefix frr-route-map;
+  }
+
+  organization
+    "FRRouting";
+  contact
+    "FRR Users List:       <mailto:frog@lists.frrouting.org>
+     FRR Development List: <mailto:dev@lists.frrouting.org>";
+  description
+    "This module defines route map settings
+
+     Copyright 2023 LabN Consulting L.L.C
+
+     Redistribution and use in source and binary forms, with or without
+     modification, are permitted provided that the following conditions
+     are met:
+
+     1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+     \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+  revision 2023-04-09 {
+    description
+      "Initial revision";
+    reference "FRRouting";
+  }
+
+  grouping if-route-maps-group {
+    description "Grouping for interface route maps";
+
+    container if-route-maps {
+      description "Collection of interface route-maps";
+
+      list if-route-map {
+        must "in-route-map or out-route-map";
+        key "interface";
+        description "Collection of route-maps for an interface";
+
+        leaf "interface" {
+          type frr-interface:interface-ref;
+          description "The interface the route maps are associated with";
+        }
+        leaf "in-route-map" {
+          type frr-route-map:route-map-name;
+          description "Name of the ingress route map";
+        }
+        leaf "out-route-map" {
+          type frr-route-map:route-map-name;
+          description "Name of the egress route map";
+        }
+      }
+    }
+  }
+}
index 82a6a01474a46a1906c980c5a4e2a9c35b00f4b1..eb17c38dbc01796ff02c4fdab4d87ea12e8345f9 100644 (file)
@@ -24,6 +24,7 @@ dist_yangmodels_DATA += yang/frr-filter.yang
 dist_yangmodels_DATA += yang/frr-module-translator.yang
 dist_yangmodels_DATA += yang/frr-nexthop.yang
 dist_yangmodels_DATA += yang/frr-test-module.yang
+dist_yangmodels_DATA += yang/frr-if-rmap.yang
 dist_yangmodels_DATA += yang/frr-interface.yang
 dist_yangmodels_DATA += yang/frr-route-map.yang
 dist_yangmodels_DATA += yang/frr-zebra-route-map.yang