frr/lib/filter_nb.c
Rafael Zalamena 375d157f0e lib,yang: merge cisco/zebra access list styles
Merge the cisco style access list with zebra's logic so we can mix both
types of rules while keeping the commands.

With this the cisco style limitation of having 'destination-*' only for
specific number ranges no longer exist for users of YANG/northbound (the
CLI still has this limitation).

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
2020-07-19 15:27:56 -03:00

1182 lines
26 KiB
C

/*
* FRR filter northbound 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/northbound.h"
#include "lib/prefix.h"
#include "lib/filter.h"
#include "lib/plist.h"
#include "lib/plist_int.h"
/* Helper function. */
static in_addr_t
ipv4_network_addr(in_addr_t hostaddr, int masklen)
{
struct in_addr mask;
masklen2ip(masklen, &mask);
return hostaddr & mask.s_addr;
}
static enum nb_error
prefix_list_length_validate(const struct lyd_node *dnode)
{
int type = yang_dnode_get_enum(dnode, "../../type");
const char *xpath_le = NULL, *xpath_ge = NULL;
struct prefix p;
uint8_t le, ge;
if (type == YPLT_IPV4) {
yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix");
xpath_le = "../ipv4-prefix-length-lesser-or-equal";
xpath_ge = "../ipv4-prefix-length-greater-or-equal";
} else {
yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix");
xpath_le = "../ipv6-prefix-length-lesser-or-equal";
xpath_ge = "../ipv6-prefix-length-greater-or-equal";
}
/*
* Check rule:
* prefix length <= le.
*/
if (yang_dnode_exists(dnode, xpath_le)) {
le = yang_dnode_get_uint8(dnode, xpath_le);
if (p.prefixlen > le)
goto log_and_fail;
}
/*
* Check rule:
* prefix length < ge.
*/
if (yang_dnode_exists(dnode, xpath_ge)) {
ge = yang_dnode_get_uint8(dnode, xpath_ge);
if (p.prefixlen >= ge)
goto log_and_fail;
}
/*
* Check rule:
* ge <= le.
*/
if (yang_dnode_exists(dnode, xpath_le) &&
yang_dnode_exists(dnode, xpath_ge)) {
le = yang_dnode_get_uint8(dnode, xpath_le);
ge = yang_dnode_get_uint8(dnode, xpath_ge);
if (ge > le)
goto log_and_fail;
}
return NB_OK;
log_and_fail:
zlog_info("prefix-list: invalid prefix range for %pFX: Make sure that mask length < ge <= le", &p);
return NB_ERR_VALIDATION;
}
/**
* Sets prefix list entry to blank value.
*
* \param[out] ple prefix list entry to modify.
*/
static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
{
ple->any = false;
memset(&ple->prefix, 0, sizeof(ple->prefix));
ple->ge = 0;
ple->le = 0;
}
/*
* XPath: /frr-filter:lib/access-list
*/
static int lib_access_list_create(struct nb_cb_create_args *args)
{
struct access_list *acl = NULL;
const char *acl_name;
int type;
if (args->event != NB_EV_APPLY)
return NB_OK;
type = yang_dnode_get_enum(args->dnode, "./type");
acl_name = yang_dnode_get_string(args->dnode, "./name");
switch (type) {
case YALT_IPV4:
acl = access_list_get(AFI_IP, acl_name);
break;
case YALT_IPV6:
acl = access_list_get(AFI_IP6, acl_name);
break;
case YALT_MAC:
acl = access_list_get(AFI_L2VPN, acl_name);
break;
}
nb_running_set_entry(args->dnode, acl);
return NB_OK;
}
static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
{
struct access_master *am;
struct access_list *acl;
if (args->event != NB_EV_APPLY)
return NB_OK;
acl = nb_running_unset_entry(args->dnode);
am = acl->master;
if (am->delete_hook)
am->delete_hook(acl);
access_list_delete(acl);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/remark
*/
static int lib_access_list_remark_modify(struct nb_cb_modify_args *args)
{
struct access_list *acl;
const char *remark;
if (args->event != NB_EV_APPLY)
return NB_OK;
acl = nb_running_get_entry(args->dnode, NULL, true);
if (acl->remark)
XFREE(MTYPE_TMP, acl->remark);
remark = yang_dnode_get_string(args->dnode, NULL);
acl->remark = XSTRDUP(MTYPE_TMP, remark);
return NB_OK;
}
static int
lib_access_list_remark_destroy(struct nb_cb_destroy_args *args)
{
struct access_list *acl;
if (args->event != NB_EV_APPLY)
return NB_OK;
acl = nb_running_get_entry(args->dnode, NULL, true);
if (acl->remark)
XFREE(MTYPE_TMP, acl->remark);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry
*/
static int lib_access_list_entry_create(struct nb_cb_create_args *args)
{
struct access_list *acl;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = filter_new();
f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
acl = nb_running_get_entry(args->dnode, NULL, true);
f->acl = acl;
access_list_filter_add(acl, f);
nb_running_set_entry(args->dnode, f);
return NB_OK;
}
static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
{
struct access_list *acl;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_unset_entry(args->dnode);
acl = f->acl;
access_list_filter_delete(acl, f);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/action
*/
static int
lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
{
const char *filter_type;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
filter_type = yang_dnode_get_string(args->dnode, NULL);
if (strcmp(filter_type, "permit") == 0)
f->type = FILTER_PERMIT;
else
f->type = FILTER_DENY;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
*/
static int
lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
{
struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
f->cisco = 0;
fz = &f->u.zfilter;
yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
return NB_OK;
}
static int
lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
{
struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
*/
static int
lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
{
struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fz = &f->u.zfilter;
fz->exact = yang_dnode_get_bool(args->dnode, NULL);
return NB_OK;
}
static int
lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
{
struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fz = &f->u.zfilter;
fz->exact = 0;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/host
*/
static int
lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
f->cisco = 1;
fc = &f->u.cfilter;
yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
fc->addr_mask.s_addr = INADDR_ANY;
return NB_OK;
}
static int
lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/network
*/
static int
lib_access_list_entry_network_modify(struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
f->cisco = 1;
fc = &f->u.cfilter;
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->addr_mask);
return NB_OK;
}
static int
lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/source-any
*/
static int
lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
f->cisco = 1;
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
static int
lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
fc->addr_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/destination-host
*/
static int lib_access_list_entry_destination_host_modify(
struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 1;
yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
fc->mask_mask.s_addr = INADDR_ANY;
return NB_OK;
}
static int lib_access_list_entry_destination_host_destroy(
struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/destination-network
*/
static int lib_access_list_entry_destination_network_modify(
struct nb_cb_modify_args *args)
{
struct filter_cisco *fc;
struct filter *f;
struct prefix p;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 1;
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->mask_mask);
return NB_OK;
}
static int lib_access_list_entry_destination_network_destroy(
struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/destination-any
*/
static int lib_access_list_entry_destination_any_create(
struct nb_cb_create_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 1;
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
static int lib_access_list_entry_destination_any_destroy(
struct nb_cb_destroy_args *args)
{
struct filter_cisco *fc;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = INADDR_NONE;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/access-list/entry/any
*/
static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
{
struct filter_zebra *fz;
struct filter *f;
int type;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
f->cisco = 0;
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
type = yang_dnode_get_enum(args->dnode, "../../type");
switch (type) {
case YALT_IPV4:
fz->prefix.family = AF_INET;
break;
case YALT_IPV6:
fz->prefix.family = AF_INET6;
break;
case YALT_MAC:
fz->prefix.family = AF_ETHERNET;
break;
}
return NB_OK;
}
static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
{
struct filter_zebra *fz;
struct filter *f;
if (args->event != NB_EV_APPLY)
return NB_OK;
f = nb_running_get_entry(args->dnode, NULL, true);
fz = &f->u.zfilter;
fz->prefix.family = 0;
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list
*/
static int lib_prefix_list_create(struct nb_cb_create_args *args)
{
struct prefix_list *pl = NULL;
const char *name;
int type;
if (args->event != NB_EV_APPLY)
return NB_OK;
type = yang_dnode_get_enum(args->dnode, "./type");
name = yang_dnode_get_string(args->dnode, "./name");
switch (type) {
case 0: /* ipv4 */
pl = prefix_list_get(AFI_IP, 0, name);
break;
case 1: /* ipv6 */
pl = prefix_list_get(AFI_IP6, 0, name);
break;
}
nb_running_set_entry(args->dnode, pl);
return NB_OK;
}
static int lib_prefix_list_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list *pl;
if (args->event != NB_EV_APPLY)
return NB_OK;
pl = nb_running_unset_entry(args->dnode);
prefix_list_delete(pl);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/remark
*/
static int lib_prefix_list_remark_modify(struct nb_cb_modify_args *args)
{
struct prefix_list *pl;
const char *remark;
if (args->event != NB_EV_APPLY)
return NB_OK;
pl = nb_running_get_entry(args->dnode, NULL, true);
if (pl->desc)
XFREE(MTYPE_TMP, pl->desc);
remark = yang_dnode_get_string(args->dnode, NULL);
pl->desc = XSTRDUP(MTYPE_TMP, remark);
return NB_OK;
}
static int lib_prefix_list_remark_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list *pl;
if (args->event != NB_EV_APPLY)
return NB_OK;
pl = nb_running_get_entry(args->dnode, NULL, true);
if (pl->desc)
XFREE(MTYPE_TMP, pl->desc);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry
*/
static int lib_prefix_list_entry_create(struct nb_cb_create_args *args)
{
struct prefix_list_entry *ple;
struct prefix_list *pl;
if (args->event != NB_EV_APPLY)
return NB_OK;
pl = nb_running_get_entry(args->dnode, NULL, true);
ple = prefix_list_entry_new();
ple->pl = pl;
ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
prefix_list_entry_set_empty(ple);
nb_running_set_entry(args->dnode, ple);
return NB_OK;
}
static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_unset_entry(args->dnode);
if (ple->installed)
prefix_list_entry_delete2(ple);
else
prefix_list_entry_free(ple);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry/action
*/
static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
int action_type;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
action_type = yang_dnode_get_enum(args->dnode, NULL);
if (action_type == YPLA_PERMIT)
ple->type = PREFIX_PERMIT;
else
ple->type = PREFIX_DENY;
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
*/
static int
lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
struct prefix p;
if (args->event == NB_EV_VALIDATE) {
/*
* TODO: validate prefix_entry_dup_check() passes.
*
* This needs to be implemented using YANG lyd_node
* navigation, because the `priv` data structures are not
* available at `NB_EV_VALIDATE` phase. An easier
* alternative would be mark `ipvx-prefix` as unique
* (see RFC 7950, Section 7.8.3. The list "unique" Statement).
*/
return NB_OK;
}
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
yang_dnode_get_prefix(&ple->prefix, args->dnode, NULL);
/* Apply mask and correct original address if necessary. */
prefix_copy(&p, &ple->prefix);
apply_mask(&p);
if (!prefix_same(&ple->prefix, &p)) {
zlog_info("%s: bad network %pFX correcting it to %pFX",
__func__, &ple->prefix, &p);
prefix_copy(&ple->prefix, &p);
}
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
static int
lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
memset(&ple->prefix, 0, sizeof(ple->prefix));
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
*/
static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
prefix_list_length_validate(args->dnode) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
ple->ge = 0;
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
*/
static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
struct nb_cb_modify_args *args)
{
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
prefix_list_length_validate(args->dnode) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
ple->le = yang_dnode_get_uint8(args->dnode, NULL);
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
ple->le = 0;
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
/*
* XPath: /frr-filter:lib/prefix-list/entry/any
*/
static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
{
struct prefix_list_entry *ple;
int type;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
ple->any = true;
/* Fill prefix struct from scratch. */
memset(&ple->prefix, 0, sizeof(ple->prefix));
type = yang_dnode_get_enum(args->dnode, "../../type");
switch (type) {
case YPLT_IPV4:
ple->prefix.family = AF_INET;
ple->ge = 0;
ple->le = IPV4_MAX_BITLEN;
break;
case YPLT_IPV6:
ple->prefix.family = AF_INET6;
ple->ge = 0;
ple->le = IPV6_MAX_BITLEN;
break;
}
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
{
struct prefix_list_entry *ple;
if (args->event != NB_EV_APPLY)
return NB_OK;
ple = nb_running_get_entry(args->dnode, NULL, true);
/* Start prefix entry update procedure. */
prefix_list_entry_update_start(ple);
prefix_list_entry_set_empty(ple);
/* Finish prefix entry update procedure. */
prefix_list_entry_update_finish(ple);
return NB_OK;
}
/* clang-format off */
const struct frr_yang_module_info frr_filter_info = {
.name = "frr-filter",
.nodes = {
{
.xpath = "/frr-filter:lib/access-list",
.cbs = {
.create = lib_access_list_create,
.destroy = lib_access_list_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/remark",
.cbs = {
.modify = lib_access_list_remark_modify,
.destroy = lib_access_list_remark_destroy,
.cli_show = access_list_remark_show,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry",
.cbs = {
.create = lib_access_list_entry_create,
.destroy = lib_access_list_entry_destroy,
.cli_show = access_list_show,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/action",
.cbs = {
.modify = lib_access_list_entry_action_modify,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
.cbs = {
.modify = lib_access_list_entry_ipv4_prefix_modify,
.destroy = lib_access_list_entry_ipv4_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
.cbs = {
.modify = lib_access_list_entry_ipv4_exact_match_modify,
.destroy = lib_access_list_entry_ipv4_exact_match_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/host",
.cbs = {
.modify = lib_access_list_entry_host_modify,
.destroy = lib_access_list_entry_host_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/network",
.cbs = {
.modify = lib_access_list_entry_network_modify,
.destroy = lib_access_list_entry_network_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/source-any",
.cbs = {
.create = lib_access_list_entry_source_any_create,
.destroy = lib_access_list_entry_source_any_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/destination-host",
.cbs = {
.modify = lib_access_list_entry_destination_host_modify,
.destroy = lib_access_list_entry_destination_host_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/destination-network",
.cbs = {
.modify = lib_access_list_entry_destination_network_modify,
.destroy = lib_access_list_entry_destination_network_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/destination-any",
.cbs = {
.create = lib_access_list_entry_destination_any_create,
.destroy = lib_access_list_entry_destination_any_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/ipv6-prefix",
.cbs = {
.modify = lib_access_list_entry_ipv4_prefix_modify,
.destroy = lib_access_list_entry_ipv4_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/ipv6-exact-match",
.cbs = {
.modify = lib_access_list_entry_ipv4_exact_match_modify,
.destroy = lib_access_list_entry_ipv4_exact_match_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/mac",
.cbs = {
.modify = lib_access_list_entry_ipv4_prefix_modify,
.destroy = lib_access_list_entry_ipv4_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/access-list/entry/any",
.cbs = {
.create = lib_access_list_entry_any_create,
.destroy = lib_access_list_entry_any_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list",
.cbs = {
.create = lib_prefix_list_create,
.destroy = lib_prefix_list_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/remark",
.cbs = {
.modify = lib_prefix_list_remark_modify,
.destroy = lib_prefix_list_remark_destroy,
.cli_show = prefix_list_remark_show,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry",
.cbs = {
.create = lib_prefix_list_entry_create,
.destroy = lib_prefix_list_entry_destroy,
.cli_show = prefix_list_show,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/action",
.cbs = {
.modify = lib_prefix_list_entry_action_modify,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
.cbs = {
.modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
.destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
}
},
{
.xpath = "/frr-filter:lib/prefix-list/entry/any",
.cbs = {
.create = lib_prefix_list_entry_any_create,
.destroy = lib_prefix_list_entry_any_destroy,
}
},
{
.xpath = NULL,
},
}
};