Merge pull request #15185 from LabNConsulting/chopps/distlist

add northbound support to distribute-list code.
This commit is contained in:
Igor Ryzhov 2024-01-22 16:52:45 +02:00 committed by GitHub
commit 22d1ad786f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 543 additions and 170 deletions

View File

@ -710,7 +710,7 @@ DEFUN (babel_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_parser(prefix, true, argv[2 + prefix]->text, return distribute_list_parser(NULL, prefix, true, argv[2 + prefix]->text,
argv[1 + prefix]->arg, ifname); argv[1 + prefix]->arg, ifname);
} }
@ -731,7 +731,7 @@ DEFUN (babel_no_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_no_parser(vty, prefix, true, return distribute_list_no_parser(NULL, vty, prefix, true,
argv[3 + prefix]->text, argv[3 + prefix]->text,
argv[2 + prefix]->arg, ifname); argv[2 + prefix]->arg, ifname);
} }
@ -753,7 +753,8 @@ DEFUN (babel_ipv6_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_parser(prefix, false, argv[3 + prefix]->text, return distribute_list_parser(NULL, prefix, false,
argv[3 + prefix]->text,
argv[2 + prefix]->arg, ifname); argv[2 + prefix]->arg, ifname);
} }
@ -775,7 +776,7 @@ DEFUN (babel_no_ipv6_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_no_parser(vty, prefix, false, return distribute_list_no_parser(NULL, vty, prefix, false,
argv[4 + prefix]->text, argv[4 + prefix]->text,
argv[3 + prefix]->arg, ifname); argv[3 + prefix]->arg, ifname);
} }

View File

@ -1123,7 +1123,7 @@ DEFUN (eigrp_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_parser(prefix, true, argv[2 + prefix]->text, return distribute_list_parser(NULL, prefix, true, argv[2 + prefix]->text,
argv[1 + prefix]->arg, ifname); argv[1 + prefix]->arg, ifname);
} }
@ -1144,14 +1144,14 @@ DEFUN (eigrp_no_distribute_list,
if (argv[argc - 1]->type == VARIABLE_TKN) if (argv[argc - 1]->type == VARIABLE_TKN)
ifname = argv[argc - 1]->arg; ifname = argv[argc - 1]->arg;
return distribute_list_no_parser(vty, prefix, true, return distribute_list_no_parser(NULL, vty, prefix, true,
argv[3 + prefix]->text, argv[3 + prefix]->text,
argv[2 + prefix]->arg, ifname); argv[2 + prefix]->arg, ifname);
} }
/* Route-map init */ /* Route-map init */
void eigrp_route_map_init() void eigrp_route_map_init(void)
{ {
route_map_init(); route_map_init();
route_map_init_vty(); route_map_init_vty();

View File

@ -244,11 +244,13 @@ static enum distribute_type distribute_direction(const char *dir, bool v4)
__builtin_unreachable(); __builtin_unreachable();
} }
int distribute_list_parser(bool prefix, bool v4, const char *dir, int distribute_list_parser(struct distribute_ctx *ctx, bool prefix, bool v4,
const char *list, const char *ifname) const char *dir, const char *list, const char *ifname)
{ {
enum distribute_type type = distribute_direction(dir, v4); enum distribute_type type = distribute_direction(dir, v4);
struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
if (!ctx)
ctx = listnode_head(dist_ctx_list);
void (*distfn)(struct distribute_ctx *, const char *, void (*distfn)(struct distribute_ctx *, const char *,
enum distribute_type, const char *) = enum distribute_type, const char *) =
@ -259,14 +261,17 @@ int distribute_list_parser(bool prefix, bool v4, const char *dir,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
const char *dir, const char *list, int distribute_list_no_parser(struct distribute_ctx *ctx, struct vty *vty,
const char *ifname) bool prefix, bool v4, const char *dir,
const char *list, const char *ifname)
{ {
enum distribute_type type = distribute_direction(dir, v4); enum distribute_type type = distribute_direction(dir, v4);
struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
int ret; int ret;
if (!ctx)
ctx = listnode_head(dist_ctx_list);
int (*distfn)(struct distribute_ctx *, const char *, int (*distfn)(struct distribute_ctx *, const char *,
enum distribute_type, const char *) = enum distribute_type, const char *) =
prefix ? &distribute_list_prefix_unset : &distribute_list_unset; prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
@ -274,7 +279,8 @@ int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
ret = distfn(ctx, ifname, type, list); ret = distfn(ctx, ifname, type, list);
if (!ret) { if (!ret) {
vty_out(vty, "distribute list doesn't exist\n"); if (vty)
vty_out(vty, "distribute list doesn't exist\n");
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
@ -443,6 +449,125 @@ int config_write_distribute(struct vty *vty,
return write; return write;
} }
/* ---------- */
/* Northbound */
/* ---------- */
int group_distribute_list_create_helper(
struct nb_cb_create_args *args, struct distribute_ctx *ctx)
{
nb_running_set_entry(args->dnode, ctx);
return NB_OK;
}
/*
* XPath: /frr-ripd:ripd/instance/distribute-lists/distribute-list/{in,out}/{access,prefix}-list
*/
int group_distribute_list_destroy(struct nb_cb_destroy_args *args)
{
nb_running_unset_entry(args->dnode);
return NB_OK;
}
static int distribute_list_leaf_update(const struct lyd_node *dnode,
int ip_version, bool no)
{
struct distribute_ctx *ctx;
struct lyd_node *dir_node = lyd_parent(dnode);
struct lyd_node_inner *list_node = dir_node->parent;
struct lyd_node *intf_key = list_node->child;
bool ipv4 = ip_version == 4 ? true : false;
bool prefix;
ctx = nb_running_get_entry_non_rec(&list_node->node, NULL, false);
prefix = dnode->schema->name[0] == 'p' ? true : false;
if (no)
distribute_list_no_parser(ctx, NULL, prefix, ipv4,
dir_node->schema->name,
lyd_get_value(dnode),
lyd_get_value(intf_key));
else
distribute_list_parser(ctx, prefix, ipv4,
dir_node->schema->name,
lyd_get_value(dnode),
lyd_get_value(intf_key));
return NB_OK;
}
static int distribute_list_leaf_modify(struct nb_cb_modify_args *args,
int ip_version)
{
if (args->event != NB_EV_APPLY)
return NB_OK;
return distribute_list_leaf_update(args->dnode, ip_version, false);
}
static int distribute_list_leaf_destroy(struct nb_cb_destroy_args *args,
int ip_version)
{
if (args->event != NB_EV_APPLY)
return NB_OK;
return distribute_list_leaf_update(args->dnode, ip_version, true);
}
int group_distribute_list_ipv4_modify(struct nb_cb_modify_args *args)
{
return distribute_list_leaf_modify(args, 4);
}
int group_distribute_list_ipv4_destroy(struct nb_cb_destroy_args *args)
{
return distribute_list_leaf_destroy(args, 4);
}
int group_distribute_list_ipv6_modify(struct nb_cb_modify_args *args)
{
return distribute_list_leaf_modify(args, 6);
}
int group_distribute_list_ipv6_destroy(struct nb_cb_destroy_args *args)
{
return distribute_list_leaf_destroy(args, 6);
}
static int distribute_list_leaf_cli_show(struct vty *vty,
const struct lyd_node *dnode,
int ip_version)
{
struct lyd_node *dir_node = lyd_parent(dnode);
struct lyd_node_inner *list_node = dir_node->parent;
struct lyd_node *intf_key = list_node->child;
bool ipv6 = ip_version == 6 ? true : false;
bool prefix;
prefix = dnode->schema->name[0] == 'p' ? true : false;
vty_out(vty,
" %sdistribute-list %s%s %s %s\n",
ipv6 ? "ipv6 " : "",
prefix ? "prefix " : "",
lyd_get_value(dnode),
dir_node->schema->name,
lyd_get_value(intf_key));
return NB_OK;
}
void group_distribute_list_ipv4_cli_show(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
distribute_list_leaf_cli_show(vty, dnode, 4);
}
void group_distribute_list_ipv6_cli_show(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
distribute_list_leaf_cli_show(vty, dnode, 6);
}
/* ------------- */
/* Setup/Cleanup */
/* ------------- */
void distribute_list_delete(struct distribute_ctx **ctx) void distribute_list_delete(struct distribute_ctx **ctx)
{ {
hash_clean_and_free(&(*ctx)->disthash, hash_clean_and_free(&(*ctx)->disthash,

View File

@ -9,6 +9,7 @@
#include <zebra.h> #include <zebra.h>
#include "if.h" #include "if.h"
#include "filter.h" #include "filter.h"
#include "northbound.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -69,11 +70,43 @@ extern enum filter_type distribute_apply_in(struct interface *,
extern enum filter_type distribute_apply_out(struct interface *, extern enum filter_type distribute_apply_out(struct interface *,
struct prefix *); struct prefix *);
extern int distribute_list_parser(bool prefix, bool v4, const char *dir, extern int distribute_list_parser(struct distribute_ctx *ctx, bool prefix,
const char *list, const char *ifname); bool v4, const char *dir, const char *list,
extern int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4, const char *ifname);
extern int distribute_list_no_parser(struct distribute_ctx *ctx,
struct vty *vty, bool prefix, bool v4,
const char *dir, const char *list, const char *dir, const char *list,
const char *ifname); const char *ifname);
/*
* Northbound
*/
/*
* Define your own create callback and then call thes helper with your
* distribute list context when a list entry is created. Additionally, plug the
* destroy callback into the frr_module_yang_info struct, or call it if you have
* your own callback destroy function.
*/
extern int group_distribute_list_create_helper(struct nb_cb_create_args *args,
struct distribute_ctx *ctx);
extern int group_distribute_list_destroy(struct nb_cb_destroy_args *args);
/*
* Plug 3 of these handlers in for your distribute-list for all the northbound
* distribute_list leaf callbacks. If you need multi-protocol then use the
* grouping twice under 2 different containers.
*/
extern int group_distribute_list_ipv4_modify(struct nb_cb_modify_args *args);
extern int group_distribute_list_ipv4_destroy(struct nb_cb_destroy_args *args);
extern void group_distribute_list_ipv4_cli_show(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
extern int group_distribute_list_ipv6_modify(struct nb_cb_modify_args *args);
extern int group_distribute_list_ipv6_destroy(struct nb_cb_destroy_args *args);
extern void group_distribute_list_ipv6_cli_show(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1128,46 +1128,59 @@ DEFPY_YANG (clear_ip_rip,
return ret; return ret;
} }
DEFUN (rip_distribute_list, DEFPY_YANG(
rip_distribute_list_cmd, rip_distribute_list, rip_distribute_list_cmd,
"distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "distribute-list [prefix]$prefix ACCESSLIST4_NAME$name <in|out>$dir [WORD$ifname]",
"Filter networks in routing updates\n" "Filter networks in routing updates\n"
"Specify a prefix\n" "Specify a prefix list\n"
"Access-list name\n" "access-list or prefix-list name\n"
"Filter incoming routing updates\n" "Filter incoming routing updates\n"
"Filter outgoing routing updates\n" "Filter outgoing routing updates\n"
"Interface name\n") "Interface name\n")
{ {
const char *ifname = NULL; char xpath[XPATH_MAXLEN];
int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
if (argv[argc - 1]->type == VARIABLE_TKN) snprintf(xpath, sizeof(xpath),
ifname = argv[argc - 1]->arg; "./distribute-list[interface='%s']/%s/%s-list",
ifname ? ifname : "", dir, prefix ? "prefix" : "access");
return distribute_list_parser(prefix, true, argv[2 + prefix]->text, /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */
argv[1 + prefix]->arg, ifname); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
} }
DEFUN (rip_no_distribute_list, DEFPY_YANG(no_rip_distribute_list,
rip_no_distribute_list_cmd, no_rip_distribute_list_cmd,
"no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "no distribute-list [prefix]$prefix [ACCESSLIST4_NAME$name] <in|out>$dir [WORD$ifname]",
NO_STR NO_STR
"Filter networks in routing updates\n" "Filter networks in routing updates\n"
"Specify a prefix\n" "Specify a prefix list\n"
"Access-list name\n" "access-list or prefix-list name\n"
"Filter incoming routing updates\n" "Filter incoming routing updates\n"
"Filter outgoing routing updates\n" "Filter outgoing routing updates\n"
"Interface name\n") "Interface name\n")
{ {
const char *ifname = NULL; const struct lyd_node *value_node;
int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; char xpath[XPATH_MAXLEN];
if (argv[argc - 1]->type == VARIABLE_TKN) snprintf(xpath, sizeof(xpath),
ifname = argv[argc - 1]->arg; "./distribute-list[interface='%s']/%s/%s-list",
ifname ? ifname : "", dir, prefix ? "prefix" : "access");
return distribute_list_no_parser(vty, prefix, true, /*
argv[3 + prefix]->text, * See if the user has specified specific list so check it exists.
argv[2 + prefix]->arg, ifname); *
* NOTE: Other FRR CLI commands do not do this sort of verification and
* there may be an official decision not to.
*/
if (name) {
value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s",
VTY_CURR_XPATH, xpath);
if (!value_node || strcmp(name, lyd_get_value(value_node))) {
vty_out(vty, "distribute list doesn't exist\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
} }
void rip_cli_init(void) void rip_cli_init(void)
@ -1176,7 +1189,7 @@ void rip_cli_init(void)
install_element(CONFIG_NODE, &no_router_rip_cmd); install_element(CONFIG_NODE, &no_router_rip_cmd);
install_element(RIP_NODE, &rip_distribute_list_cmd); install_element(RIP_NODE, &rip_distribute_list_cmd);
install_element(RIP_NODE, &rip_no_distribute_list_cmd); install_element(RIP_NODE, &no_rip_distribute_list_cmd);
install_element(RIP_NODE, &rip_allow_ecmp_cmd); install_element(RIP_NODE, &rip_allow_ecmp_cmd);
install_element(RIP_NODE, &no_rip_allow_ecmp_cmd); install_element(RIP_NODE, &no_rip_allow_ecmp_cmd);

View File

@ -6,11 +6,12 @@
#include <zebra.h> #include <zebra.h>
#include "northbound.h" #include "distribute.h"
#include "if_rmap.h"
#include "libfrr.h" #include "libfrr.h"
#include "northbound.h"
#include "ripd/rip_nb.h" #include "ripd/rip_nb.h"
#include "lib/if_rmap.h"
/* clang-format off */ /* clang-format off */
const struct frr_yang_module_info frr_ripd_info = { const struct frr_yang_module_info frr_ripd_info = {
@ -143,6 +144,45 @@ const struct frr_yang_module_info frr_ripd_info = {
.destroy = ripd_instance_non_passive_interface_destroy, .destroy = ripd_instance_non_passive_interface_destroy,
}, },
}, },
{
.xpath = "/frr-ripd:ripd/instance/distribute-list",
.cbs = {
.create = ripd_instance_distribute_list_create,
.destroy = group_distribute_list_destroy,
}
},
{
.xpath = "/frr-ripd:ripd/instance/distribute-list/in/access-list",
.cbs = {
.modify = group_distribute_list_ipv4_modify,
.destroy = group_distribute_list_ipv4_destroy,
.cli_show = group_distribute_list_ipv4_cli_show,
}
},
{
.xpath = "/frr-ripd:ripd/instance/distribute-list/out/access-list",
.cbs = {
.modify = group_distribute_list_ipv4_modify,
.destroy = group_distribute_list_ipv4_destroy,
.cli_show = group_distribute_list_ipv4_cli_show,
}
},
{
.xpath = "/frr-ripd:ripd/instance/distribute-list/in/prefix-list",
.cbs = {
.modify = group_distribute_list_ipv4_modify,
.destroy = group_distribute_list_ipv4_destroy,
.cli_show = group_distribute_list_ipv4_cli_show,
}
},
{
.xpath = "/frr-ripd:ripd/instance/distribute-list/out/prefix-list",
.cbs = {
.modify = group_distribute_list_ipv4_modify,
.destroy = group_distribute_list_ipv4_destroy,
.cli_show = group_distribute_list_ipv4_cli_show,
}
},
{ {
.xpath = "/frr-ripd:ripd/instance/redistribute", .xpath = "/frr-ripd:ripd/instance/redistribute",
.cbs = { .cbs = {

View File

@ -7,6 +7,8 @@
#ifndef _FRR_RIP_NB_H_ #ifndef _FRR_RIP_NB_H_
#define _FRR_RIP_NB_H_ #define _FRR_RIP_NB_H_
#include "northbound.h"
extern const struct frr_yang_module_info frr_ripd_info; extern const struct frr_yang_module_info frr_ripd_info;
/* Mandatory callbacks. */ /* Mandatory callbacks. */
@ -45,6 +47,8 @@ int ripd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args);
int ripd_instance_non_passive_interface_create(struct nb_cb_create_args *args); int ripd_instance_non_passive_interface_create(struct nb_cb_create_args *args);
int ripd_instance_non_passive_interface_destroy( int ripd_instance_non_passive_interface_destroy(
struct nb_cb_destroy_args *args); struct nb_cb_destroy_args *args);
int ripd_instance_distribute_list_create(struct nb_cb_create_args *args);
int ripd_instance_distribute_list_destroy(struct nb_cb_destroy_args *args);
int ripd_instance_redistribute_create(struct nb_cb_create_args *args); int ripd_instance_redistribute_create(struct nb_cb_create_args *args);
int ripd_instance_redistribute_destroy(struct nb_cb_destroy_args *args); int ripd_instance_redistribute_destroy(struct nb_cb_destroy_args *args);
int ripd_instance_redistribute_route_map_modify(struct nb_cb_modify_args *args); int ripd_instance_redistribute_route_map_modify(struct nb_cb_modify_args *args);

View File

@ -548,6 +548,23 @@ int ripd_instance_non_passive_interface_destroy(struct nb_cb_destroy_args *args)
return rip_passive_nondefault_unset(rip, ifname); return rip_passive_nondefault_unset(rip, ifname);
} }
/*
* XPath: /frr-ripd:ripd/instance/distribute-list
*/
int ripd_instance_distribute_list_create(struct nb_cb_create_args *args)
{
struct rip *rip;
if (args->event != NB_EV_APPLY)
return NB_OK;
rip = nb_running_get_entry(args->dnode, NULL, true);
group_distribute_list_create_helper(args, rip->distribute_ctx);
return NB_OK;
}
/* /*
* XPath: /frr-ripd:ripd/instance/redistribute * XPath: /frr-ripd:ripd/instance/redistribute
*/ */

View File

@ -3271,9 +3271,6 @@ static int config_write_rip(struct vty *vty)
nb_cli_show_dnode_cmds(vty, dnode, false); nb_cli_show_dnode_cmds(vty, dnode, false);
/* Distribute configuration. */
config_write_distribute(vty, rip->distribute_ctx);
vty_out(vty, "exit\n"); vty_out(vty, "exit\n");
write = 1; write = 1;

View File

@ -516,48 +516,59 @@ DEFPY_YANG (clear_ipv6_rip,
return ret; return ret;
} }
DEFUN (ripng_ipv6_distribute_list, DEFPY_YANG(
ripng_ipv6_distribute_list_cmd, ripng_ipv6_distribute_list, ripng_ipv6_distribute_list_cmd,
"ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "ipv6 distribute-list [prefix]$prefix ACCESSLIST4_NAME$name <in|out>$dir [WORD$ifname]",
"IPv6\n" "Filter networks in routing updates\n"
"Filter networks in routing updates\n" "Specify a prefix list\n"
"Specify a prefix\n" "access-list or prefix-list name\n"
"Access-list name\n" "Filter incoming routing updates\n"
"Filter incoming routing updates\n" "Filter outgoing routing updates\n"
"Filter outgoing routing updates\n" "Interface name\n")
"Interface name\n")
{ {
const char *ifname = NULL; char xpath[XPATH_MAXLEN];
int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
if (argv[argc - 1]->type == VARIABLE_TKN) snprintf(xpath, sizeof(xpath),
ifname = argv[argc - 1]->arg; "./distribute-list[interface='%s']/%s/%s-list",
ifname ? ifname : "", dir, prefix ? "prefix" : "access");
return distribute_list_parser(prefix, false, argv[3 + prefix]->text, /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */
argv[2 + prefix]->arg, ifname); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name);
return nb_cli_apply_changes(vty, NULL);
} }
DEFUN (ripng_no_ipv6_distribute_list, DEFPY_YANG(no_ripng_ipv6_distribute_list,
ripng_no_ipv6_distribute_list_cmd, no_ripng_ipv6_distribute_list_cmd,
"no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "no ipv6 distribute-list [prefix]$prefix [ACCESSLIST4_NAME$name] <in|out>$dir [WORD$ifname]",
NO_STR NO_STR
"IPv6\n" "Filter networks in routing updates\n"
"Filter networks in routing updates\n" "Specify a prefix list\n"
"Specify a prefix\n" "access-list or prefix-list name\n"
"Access-list name\n" "Filter incoming routing updates\n"
"Filter incoming routing updates\n" "Filter outgoing routing updates\n"
"Filter outgoing routing updates\n" "Interface name\n")
"Interface name\n")
{ {
const char *ifname = NULL; const struct lyd_node *value_node;
int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0; char xpath[XPATH_MAXLEN];
if (argv[argc - 1]->type == VARIABLE_TKN) snprintf(xpath, sizeof(xpath),
ifname = argv[argc - 1]->arg; "./distribute-list[interface='%s']/%s/%s-list",
ifname ? ifname : "", dir, prefix ? "prefix" : "access");
return distribute_list_no_parser(vty, prefix, false, /*
argv[4 + prefix]->text, * See if the user has specified specific list so check it exists.
argv[3 + prefix]->arg, ifname); *
* NOTE: Other FRR CLI commands do not do this sort of verification and
* there may be an official decision not to.
*/
if (name) {
value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s",
VTY_CURR_XPATH, xpath);
if (!value_node || strcmp(name, lyd_get_value(value_node))) {
vty_out(vty, "distribute list doesn't exist\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
} }
void ripng_cli_init(void) void ripng_cli_init(void)
@ -566,7 +577,7 @@ void ripng_cli_init(void)
install_element(CONFIG_NODE, &no_router_ripng_cmd); install_element(CONFIG_NODE, &no_router_ripng_cmd);
install_element(RIPNG_NODE, &ripng_ipv6_distribute_list_cmd); install_element(RIPNG_NODE, &ripng_ipv6_distribute_list_cmd);
install_element(RIPNG_NODE, &ripng_no_ipv6_distribute_list_cmd); install_element(RIPNG_NODE, &no_ripng_ipv6_distribute_list_cmd);
install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd);
install_element(RIPNG_NODE, &no_ripng_allow_ecmp_cmd); install_element(RIPNG_NODE, &no_ripng_allow_ecmp_cmd);

View File

@ -6,11 +6,12 @@
#include <zebra.h> #include <zebra.h>
#include "northbound.h" #include "distribute.h"
#include "if_rmap.h"
#include "libfrr.h" #include "libfrr.h"
#include "northbound.h"
#include "ripngd/ripng_nb.h" #include "ripngd/ripng_nb.h"
#include "lib/if_rmap.h"
/* clang-format off */ /* clang-format off */
const struct frr_yang_module_info frr_ripngd_info = { const struct frr_yang_module_info frr_ripngd_info = {
@ -92,6 +93,45 @@ const struct frr_yang_module_info frr_ripngd_info = {
.destroy = ripngd_instance_passive_interface_destroy, .destroy = ripngd_instance_passive_interface_destroy,
}, },
}, },
{
.xpath = "/frr-ripngd:ripngd/instance/distribute-list",
.cbs = {
.create = ripngd_instance_distribute_list_create,
.destroy = group_distribute_list_destroy,
}
},
{
.xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/access-list",
.cbs = {
.modify = group_distribute_list_ipv6_modify,
.destroy = group_distribute_list_ipv6_destroy,
.cli_show = group_distribute_list_ipv6_cli_show,
}
},
{
.xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/access-list",
.cbs = {
.modify = group_distribute_list_ipv6_modify,
.destroy = group_distribute_list_ipv6_destroy,
.cli_show = group_distribute_list_ipv6_cli_show,
}
},
{
.xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/prefix-list",
.cbs = {
.modify = group_distribute_list_ipv6_modify,
.destroy = group_distribute_list_ipv6_destroy,
.cli_show = group_distribute_list_ipv6_cli_show,
}
},
{
.xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/prefix-list",
.cbs = {
.modify = group_distribute_list_ipv6_modify,
.destroy = group_distribute_list_ipv6_destroy,
.cli_show = group_distribute_list_ipv6_cli_show,
}
},
{ {
.xpath = "/frr-ripngd:ripngd/instance/redistribute", .xpath = "/frr-ripngd:ripngd/instance/redistribute",
.cbs = { .cbs = {

View File

@ -7,6 +7,8 @@
#ifndef _FRR_RIPNG_NB_H_ #ifndef _FRR_RIPNG_NB_H_
#define _FRR_RIPNG_NB_H_ #define _FRR_RIPNG_NB_H_
#include "northbound.h"
extern const struct frr_yang_module_info frr_ripngd_info; extern const struct frr_yang_module_info frr_ripngd_info;
/* Mandatory callbacks. */ /* Mandatory callbacks. */
@ -30,6 +32,8 @@ int ripngd_instance_offset_list_access_list_modify(
int ripngd_instance_offset_list_metric_modify(struct nb_cb_modify_args *args); int ripngd_instance_offset_list_metric_modify(struct nb_cb_modify_args *args);
int ripngd_instance_passive_interface_create(struct nb_cb_create_args *args); int ripngd_instance_passive_interface_create(struct nb_cb_create_args *args);
int ripngd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args); int ripngd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args);
int ripngd_instance_distribute_list_create(struct nb_cb_create_args *args);
int ripngd_instance_distribute_list_destroy(struct nb_cb_destroy_args *args);
int ripngd_instance_redistribute_create(struct nb_cb_create_args *args); int ripngd_instance_redistribute_create(struct nb_cb_create_args *args);
int ripngd_instance_redistribute_destroy(struct nb_cb_destroy_args *args); int ripngd_instance_redistribute_destroy(struct nb_cb_destroy_args *args);
int ripngd_instance_redistribute_route_map_modify( int ripngd_instance_redistribute_route_map_modify(

View File

@ -368,6 +368,22 @@ int ripngd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args)
return ripng_passive_interface_unset(ripng, ifname); return ripng_passive_interface_unset(ripng, ifname);
} }
/*
* XPath: /frr-ripng:ripng/instance/distribute-list
*/
int ripngd_instance_distribute_list_create(struct nb_cb_create_args *args)
{
struct ripng *ripng;
if (args->event != NB_EV_APPLY)
return NB_OK;
ripng = nb_running_get_entry(args->dnode, NULL, true);
group_distribute_list_create_helper(args, ripng->distribute_ctx);
return NB_OK;
}
/* /*
* XPath: /frr-ripngd:ripngd/instance/redistribute * XPath: /frr-ripngd:ripngd/instance/redistribute
*/ */

View File

@ -2286,8 +2286,6 @@ static int ripng_config_write(struct vty *vty)
nb_cli_show_dnode_cmds(vty, dnode, false); nb_cli_show_dnode_cmds(vty, dnode, false);
config_write_distribute(vty, ripng->distribute_ctx);
vty_out(vty, "exit\n"); vty_out(vty, "exit\n");
write = 1; write = 1;

View File

@ -10,6 +10,9 @@ module frr-filter {
import ietf-yang-types { import ietf-yang-types {
prefix yang; prefix yang;
} }
import frr-interface {
prefix frr-interface;
}
organization "FRRouting"; organization "FRRouting";
contact contact
@ -45,35 +48,95 @@ module frr-filter {
revision 2019-07-04 { revision 2019-07-04 {
description "Initial revision"; description "Initial revision";
reference "FRRouting";
} }
/* /*
* Types. * Types.
*/ */
typedef access-list-name { typedef access-list-name {
description "Access list name formatting";
type string { type string {
length 1..128; length 1..128;
} }
description "Access list name formatting";
} }
typedef access-list-sequence { typedef access-list-sequence {
description "Access list sequence number";
type uint32 { type uint32 {
range "1..4294967295"; range "1..4294967295";
} }
description "Access list sequence number";
} }
typedef access-list-action { typedef access-list-action {
description "Access list return action on match";
type enumeration { type enumeration {
enum deny { enum deny {
description "Deny an entry";
value 0; value 0;
description "Deny an entry";
} }
enum permit { enum permit {
description "Accept an entry";
value 1; value 1;
description "Accept an entry";
}
}
description "Access list return action on match";
}
typedef access-list-ref {
type leafref {
path "/frr-filter:lib/frr-filter:access-list/frr-filter:name";
require-instance false;
}
description "IPv4 or IPv6 access list reference";
}
typedef prefix-list-ref {
type leafref {
path "/frr-filter:lib/frr-filter:prefix-list/frr-filter:name";
require-instance false;
}
description "IPv4 or IPv6 prefix list reference";
}
/*
* Grouping.
*/
grouping distribute-list-group {
description "Distribute list grouping";
list distribute-list {
key "interface";
description "Distribute list configuration";
leaf interface {
type union {
type frr-interface:interface-ref;
type empty;
}
description
"Interface to attach list to or empty for global.";
}
container in {
description "Inbound filter list";
leaf access-list {
type access-list-ref;
description "inbound access list";
}
leaf prefix-list {
type prefix-list-ref;
description "inbound prefix list";
}
}
container out {
description "Outbound filter list";
leaf access-list {
type access-list-ref;
description "outbound access list";
}
leaf prefix-list {
type prefix-list-ref;
description "outbound prefix list";
}
} }
} }
} }
@ -82,77 +145,74 @@ module frr-filter {
* Configuration data. * Configuration data.
*/ */
container lib { container lib {
description "Filter library";
list access-list { list access-list {
key "type name";
description "Access list instance"; description "Access list instance";
key "type name";
leaf type { leaf type {
description "Access list content type";
type enumeration { type enumeration {
enum ipv4 { enum ipv4 {
description "Internet Protocol address version 4"; value 0;
value 0; description "Internet Protocol address version 4";
} }
enum ipv6 { enum ipv6 {
description "Internet Protocol address version 6"; value 1;
value 1; description "Internet Protocol address version 6";
} }
enum mac { enum mac {
description "Media Access Control address";
value 2; value 2;
description "Media Access Control address";
} }
} }
description "Access list content type";
} }
leaf name { leaf name {
description "Access list name";
type access-list-name; type access-list-name;
description "Access list name";
} }
leaf remark { leaf remark {
description "Access list remark";
type string; type string;
description "Access list remark";
} }
list entry { list entry {
description "Access list entry";
key "sequence"; key "sequence";
description "Access list entry";
leaf sequence { leaf sequence {
description "Access list sequence value";
type access-list-sequence; type access-list-sequence;
description "Access list sequence value";
} }
leaf action { leaf action {
description "Access list action on match";
type access-list-action; type access-list-action;
mandatory true; mandatory true;
description "Access list action on match";
} }
choice value { choice value {
description "Access list value to match";
mandatory true; mandatory true;
description "Access list value to match";
case ipv4-prefix { case ipv4-prefix {
when "../type = 'ipv4'"; when "../type = 'ipv4'";
choice style { choice style {
description "Access list entry style selection: zebra or cisco.";
mandatory true; mandatory true;
description "Access list entry style selection: zebra or cisco.";
case zebra { case zebra {
leaf ipv4-prefix { leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix; type inet:ipv4-prefix;
mandatory true; mandatory true;
description "Configure IPv4 prefix to match";
} }
leaf ipv4-exact-match { leaf ipv4-exact-match {
description "Exact match of prefix";
type boolean; type boolean;
default false; default false;
description "Exact match of prefix";
} }
} }
case cisco { case cisco {
@ -160,19 +220,20 @@ module frr-filter {
description "Source value to match"; description "Source value to match";
leaf host { leaf host {
description "Host to match";
type inet:ipv4-address; type inet:ipv4-address;
description "Host to match";
} }
container network { container network {
description "Network to match";
leaf address { leaf address {
type inet:ipv4-address;
mandatory true; mandatory true;
description "Network address part."; description "Network address part.";
type inet:ipv4-address;
} }
leaf mask { leaf mask {
type inet:ipv4-address;
mandatory true; mandatory true;
description "Network mask/wildcard part."; description "Network mask/wildcard part.";
type inet:ipv4-address;
} }
} }
leaf source-any { leaf source-any {
@ -180,8 +241,8 @@ module frr-filter {
* Was `any`, however it conflicts with `any` leaf * Was `any`, however it conflicts with `any` leaf
* outside this choice. * outside this choice.
*/ */
description "Match any";
type empty; type empty;
description "Match any";
} }
} }
@ -189,24 +250,25 @@ module frr-filter {
description "Destination value to match"; description "Destination value to match";
leaf destination-host { leaf destination-host {
description "Host to match";
type inet:ipv4-address; type inet:ipv4-address;
description "Host to match";
} }
container destination-network { container destination-network {
description "Destination network to match";
leaf address { leaf address {
type inet:ipv4-address;
mandatory true; mandatory true;
description "Network address part."; description "Network address part.";
type inet:ipv4-address;
} }
leaf mask { leaf mask {
type inet:ipv4-address;
mandatory true; mandatory true;
description "Network mask/wildcard part."; description "Network mask/wildcard part.";
type inet:ipv4-address;
} }
} }
leaf destination-any { leaf destination-any {
description "Match any";
type empty; type empty;
description "Match any";
} }
} }
} }
@ -216,29 +278,29 @@ module frr-filter {
when "../type = 'ipv6'"; when "../type = 'ipv6'";
leaf ipv6-prefix { leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix; type inet:ipv6-prefix;
mandatory true; mandatory true;
description "Configure IPv6 prefix to match";
} }
leaf ipv6-exact-match { leaf ipv6-exact-match {
description "Exact match of prefix";
type boolean; type boolean;
default false; default false;
description "Exact match of prefix";
} }
} }
case mac { case mac {
when "../type = 'mac'"; when "../type = 'mac'";
leaf mac { leaf mac {
description "Configure MAC address to match";
type yang:mac-address; type yang:mac-address;
description "Configure MAC address to match";
} }
} }
case any { case any {
leaf any { leaf any {
description "Match anything";
type empty; type empty;
description "Match anything";
} }
} }
} }
@ -246,108 +308,104 @@ module frr-filter {
} }
list prefix-list { list prefix-list {
description "Prefix list instance";
key "type name"; key "type name";
description "Prefix list instance";
leaf type { leaf type {
description "Prefix list type";
type enumeration { type enumeration {
enum ipv4 { enum ipv4 {
description "Internet Protocol address version 4";
value 0; value 0;
description "Internet Protocol address version 4";
} }
enum ipv6 { enum ipv6 {
description "Internet Protocol address version 6";
value 1; value 1;
description "Internet Protocol address version 6";
} }
} }
description "Prefix list type";
} }
leaf name { leaf name {
description "Prefix list name";
type access-list-name; type access-list-name;
description "Prefix list name";
} }
leaf remark { leaf remark {
description "Prefix list user description";
type string; type string;
description "Prefix list user description";
} }
list entry { list entry {
description "Prefix list entry";
key "sequence"; key "sequence";
description "Prefix list entry";
leaf sequence { leaf sequence {
description "Prefix list sequence value";
type access-list-sequence; type access-list-sequence;
description "Prefix list sequence value";
} }
leaf action { leaf action {
description "Prefix list action on match";
type access-list-action; type access-list-action;
mandatory true; mandatory true;
description "Prefix list action on match";
} }
choice value { choice value {
description "Prefix list value to match";
mandatory true; mandatory true;
description "Prefix list value to match";
case ipv4-prefix { case ipv4-prefix {
leaf ipv4-prefix { leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix; type inet:ipv4-prefix;
mandatory true; mandatory true;
description "Configure IPv4 prefix to match";
} }
leaf ipv4-prefix-length-greater-or-equal { leaf ipv4-prefix-length-greater-or-equal {
type uint8 {
range "0..32";
}
description description
"Specifies if matching prefixes with length greater than "Specifies if matching prefixes with length greater than
or equal to value"; or equal to value";
type uint8 {
range "0..32";
}
} }
leaf ipv4-prefix-length-lesser-or-equal { leaf ipv4-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 { type uint8 {
range "0..32"; range "0..32";
} }
description
"Specifies if matching prefixes with length lesser than
or equal to value";
} }
} }
case ipv6-prefix { case ipv6-prefix {
leaf ipv6-prefix { leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix; type inet:ipv6-prefix;
mandatory true; mandatory true;
description "Configure IPv6 prefix to match";
} }
leaf ipv6-prefix-length-greater-or-equal { leaf ipv6-prefix-length-greater-or-equal {
type uint8 {
range "0..128";
}
description description
"Specifies if matching prefixes with length greater than "Specifies if matching prefixes with length greater than
or equal to value"; or equal to value";
type uint8 {
range "0..128";
}
} }
leaf ipv6-prefix-length-lesser-or-equal { leaf ipv6-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 { type uint8 {
range "0..128"; range "0..128";
} }
description
"Specifies if matching prefixes with length lesser than
or equal to value";
} }
} }
case any { case any {
leaf any { leaf any {
description "Match anything";
type empty; type empty;
description "Match anything";
} }
} }
} }

View File

@ -16,6 +16,9 @@ module frr-ripd {
import frr-bfdd { import frr-bfdd {
prefix frr-bfdd; prefix frr-bfdd;
} }
import frr-filter {
prefix frr-filter;
}
import frr-interface { import frr-interface {
prefix frr-interface; prefix frr-interface;
} }
@ -258,6 +261,9 @@ module frr-ripd {
"A list of interfaces where the sending of RIP packets "A list of interfaces where the sending of RIP packets
is enabled."; is enabled.";
} }
uses frr-filter:distribute-list-group;
list redistribute { list redistribute {
key "protocol"; key "protocol";
description description
@ -380,9 +386,9 @@ module frr-ripd {
} }
leaf default-bfd-profile { leaf default-bfd-profile {
type frr-bfdd:profile-ref;
description description
"Use this BFD profile for all peers by default."; "Use this BFD profile for all peers by default.";
type frr-bfdd:profile-ref;
} }
/* /*
@ -691,12 +697,13 @@ module frr-ripd {
container bfd-monitoring { container bfd-monitoring {
presence presence
"Present if BFD is configured for RIP peers in this interface."; "Present if BFD is configured for RIP peers in this interface.";
description "Configure BFD use in RIPD";
leaf enable { leaf enable {
type boolean; type boolean;
default false;
description description
"Enable/disable BFD monitoring."; "Enable/disable BFD monitoring.";
default false;
} }
leaf profile { leaf profile {

View File

@ -13,6 +13,9 @@ module frr-ripngd {
import frr-if-rmap { import frr-if-rmap {
prefix frr-if-rmap; prefix frr-if-rmap;
} }
import frr-filter {
prefix frr-filter;
}
import frr-interface { import frr-interface {
prefix frr-interface; prefix frr-interface;
} }
@ -63,6 +66,7 @@ module frr-ripngd {
description description
"Changed interface references to use "Changed interface references to use
frr-interface:interface-ref typedef"; frr-interface:interface-ref typedef";
reference "FRRouting";
} }
revision 2018-11-27 { revision 2018-11-27 {
description description
@ -72,6 +76,7 @@ module frr-ripngd {
} }
container ripngd { container ripngd {
description "ripng routing instance data";
/* /*
* Routing instance configuration. * Routing instance configuration.
*/ */
@ -169,15 +174,18 @@ module frr-ripngd {
"A list of interfaces where the sending of RIPng packets "A list of interfaces where the sending of RIPng packets
is disabled."; is disabled.";
} }
uses frr-filter:distribute-list-group;
list redistribute { list redistribute {
key "protocol"; key "protocol";
description description
"Redistributes routes learned from other routing protocols."; "Redistributes routes learned from other routing protocols.";
leaf protocol { leaf protocol {
type frr-route-types:frr-route-types-v6; type frr-route-types:frr-route-types-v6;
must '. != "ripng"';
description description
"Routing protocol."; "Routing protocol.";
must '. != "ripng"';
} }
leaf route-map { leaf route-map {
type frr-route-map:route-map-ref; type frr-route-map:route-map-ref;
@ -330,6 +338,7 @@ module frr-ripngd {
* Per-interface configuration data * Per-interface configuration data
*/ */
augment "/frr-interface:lib/frr-interface:interface" { augment "/frr-interface:lib/frr-interface:interface" {
description "RIPng interface augmentation.";
container ripng { container ripng {
description description
"RIPng interface parameters."; "RIPng interface parameters.";