lib: convert if_rmap to YANG northbound

- 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>
This commit is contained in:
Christian Hopps 2023-04-09 05:02:51 -04:00
parent 2eb4471114
commit efa2ca6ef0
5 changed files with 236 additions and 133 deletions

View 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;
struct if_rmap *if_rmap = if_rmap_get(ctx, ifname);
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;
return;
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;
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_IN]);
}
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;
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;
char xpath[XPATH_MAXLEN];
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;
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 CMD_SUCCESS;
return nb_cli_apply_changes(vty, NULL);
}
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(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)
{
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);
const char *dir = in ? "in" : "out";
const char *other_dir = in ? "out" : "in";
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;
}
return if_route_map_handler(vty, false, dir, other_dir, ifname,
route_map);
}
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;
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)
{
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);
}
/*
* 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);
}

View 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

View 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 \

80
yang/frr-if-rmap.yang Normal file
View File

@ -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";
}
}
}
}
}

View 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