Merge pull request #5323 from opensourcerouting/filter-nb

lib: migrate FRR filter to northbound
This commit is contained in:
Donald Sharp 2020-06-10 06:59:32 -04:00 committed by GitHub
commit 2d8c1bc235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 3543 additions and 2940 deletions

View File

@ -137,6 +137,7 @@ struct option longopts[] =
};
static const struct frr_yang_module_info *const babeld_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_vrf_info,
};

View File

@ -111,6 +111,7 @@ static struct quagga_signal_t bfd_signals[] = {
};
static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_bfdd_info,
&frr_vrf_info,

View File

@ -359,6 +359,7 @@ static void bgp_vrf_terminate(void)
}
static const struct frr_yang_module_info *const bgpd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -139,6 +139,7 @@ struct quagga_signal_t eigrp_signals[] = {
static const struct frr_yang_module_info *const eigrpd_yang_modules[] = {
&frr_eigrpd_info,
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -166,6 +166,7 @@ struct quagga_signal_t isisd_signals[] = {
static const struct frr_yang_module_info *const isisd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
#ifndef FABRICD
&frr_isisd_info,

View File

@ -180,6 +180,7 @@ static struct quagga_signal_t ldp_signals[] =
};
static const struct frr_yang_module_info *const ldpd_yang_modules[] = {
&frr_filter_info,
&frr_vrf_info,
};

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
#define _ZEBRA_FILTER_H
#include "if.h"
#include "prefix.h"
#ifdef __cplusplus
extern "C" {
@ -41,6 +42,50 @@ enum filter_type { FILTER_DENY, FILTER_PERMIT, FILTER_DYNAMIC };
enum access_type { ACCESS_TYPE_STRING, ACCESS_TYPE_NUMBER };
struct filter_cisco {
/* Cisco access-list */
int extended;
struct in_addr addr;
struct in_addr addr_mask;
struct in_addr mask;
struct in_addr mask_mask;
};
struct filter_zebra {
/* If this filter is "exact" match then this flag is set. */
int exact;
/* Prefix information. */
struct prefix prefix;
};
/* Forward declaration of access-list struct. */
struct access_list;
/* Filter element of access list */
struct filter {
/* For doubly linked list. */
struct filter *next;
struct filter *prev;
/* Parent access-list pointer. */
struct access_list *acl;
/* Filter type information. */
enum filter_type type;
/* Sequence number */
int64_t seq;
/* Cisco access-list */
int cisco;
union {
struct filter_cisco cfilter;
struct filter_zebra zfilter;
} u;
};
/* Access list */
struct access_list {
char *name;
@ -57,6 +102,28 @@ struct access_list {
struct filter *tail;
};
/* List of access_list. */
struct access_list_list {
struct access_list *head;
struct access_list *tail;
};
/* Master structure of access_list. */
struct access_master {
/* List of access_list which name is number. */
struct access_list_list num;
/* List of access_list which name is string. */
struct access_list_list str;
/* Hook function which is executed when new access_list is added. */
void (*add_hook)(struct access_list *);
/* Hook function which is executed when access_list is deleted. */
void (*delete_hook)(struct access_list *);
};
/* Prototypes for access-list. */
extern void access_list_init(void);
extern void access_list_reset(void);
@ -66,6 +133,59 @@ extern struct access_list *access_list_lookup(afi_t, const char *);
extern enum filter_type access_list_apply(struct access_list *access,
const void *object);
struct access_list *access_list_get(afi_t afi, const char *name);
void access_list_delete(struct access_list *access);
struct filter *filter_new(void);
void access_list_filter_add(struct access_list *access,
struct filter *filter);
void access_list_filter_delete(struct access_list *access,
struct filter *filter);
int64_t filter_new_seq_get(struct access_list *access);
struct filter *filter_lookup_cisco(struct access_list *access,
struct filter *mnew);
struct filter *filter_lookup_zebra(struct access_list *access,
struct filter *mnew);
extern const struct frr_yang_module_info frr_filter_info;
/* filter_nb.c */
enum yang_access_list_type {
YALT_IPV4 = 0,
YALT_IPV6 = 1,
YALT_MAC = 2,
};
enum yang_prefix_list_type {
YPLT_IPV4 = 0,
YPLT_IPV6 = 1,
};
enum yang_prefix_list_action {
YPLA_DENY = 0,
YPLA_PERMIT = 1,
};
/* filter_cli.c */
struct lyd_node;
struct vty;
extern void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void access_list_legacy_remark_show(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
extern void access_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void filter_cli_init(void);
#ifdef __cplusplus
}
#endif

1693
lib/filter_cli.c Normal file

File diff suppressed because it is too large Load Diff

1286
lib/filter_nb.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -178,7 +178,7 @@ static void prefix_list_free(struct prefix_list *plist)
XFREE(MTYPE_PREFIX_LIST, plist);
}
static struct prefix_list_entry *prefix_list_entry_new(void)
struct prefix_list_entry *prefix_list_entry_new(void)
{
struct prefix_list_entry *new;
@ -187,7 +187,7 @@ static struct prefix_list_entry *prefix_list_entry_new(void)
return new;
}
static void prefix_list_entry_free(struct prefix_list_entry *pentry)
void prefix_list_entry_free(struct prefix_list_entry *pentry)
{
XFREE(MTYPE_PREFIX_LIST_ENTRY, pentry);
}
@ -279,7 +279,7 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
return plist;
}
static struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name)
struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name)
{
struct prefix_list *plist;
@ -294,7 +294,7 @@ static void prefix_list_trie_del(struct prefix_list *plist,
struct prefix_list_entry *pentry);
/* Delete prefix-list from prefix_list_master and free it. */
static void prefix_list_delete(struct prefix_list *plist)
void prefix_list_delete(struct prefix_list *plist)
{
struct prefix_list_list *list;
struct prefix_master *master;
@ -381,7 +381,7 @@ void prefix_list_delete_hook(void (*func)(struct prefix_list *plist))
}
/* Calculate new sequential number. */
static int64_t prefix_new_seq_get(struct prefix_list *plist)
int64_t prefix_new_seq_get(struct prefix_list *plist)
{
int64_t maxseq;
int64_t newseq;
@ -411,7 +411,7 @@ static struct prefix_list_entry *prefix_seq_check(struct prefix_list *plist,
return NULL;
}
static struct prefix_list_entry *
struct prefix_list_entry *
prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix,
enum prefix_list_type type, int64_t seq,
int le, int ge)
@ -502,9 +502,9 @@ static void prefix_list_trie_del(struct prefix_list *plist,
}
static void prefix_list_entry_delete(struct prefix_list *plist,
struct prefix_list_entry *pentry,
int update_list)
void prefix_list_entry_delete(struct prefix_list *plist,
struct prefix_list_entry *pentry,
int update_list)
{
if (plist == NULL || pentry == NULL)
return;
@ -646,6 +646,133 @@ static void prefix_list_entry_add(struct prefix_list *plist,
plist->master->recent = plist;
}
/**
* Prefix list entry update start procedure:
* Remove entry from previosly installed master list, tries and notify
* observers.
*
* \param[in] ple prefix list entry.
*/
void prefix_list_entry_update_start(struct prefix_list_entry *ple)
{
struct prefix_list *pl = ple->pl;
/* Not installed, nothing to do. */
if (!ple->installed)
return;
prefix_list_trie_del(pl, ple);
/* List manipulation: shameless copy from `prefix_list_entry_delete`. */
if (ple->prev)
ple->prev->next = ple->next;
else
pl->head = ple->next;
if (ple->next)
ple->next->prev = ple->prev;
else
pl->tail = ple->prev;
route_map_notify_pentry_dependencies(pl->name, ple,
RMAP_EVENT_PLIST_DELETED);
pl->count--;
route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_DELETED);
if (pl->master->delete_hook)
(*pl->master->delete_hook)(pl);
if (pl->head || pl->tail || pl->desc)
pl->master->recent = pl;
ple->installed = false;
}
/**
* Prefix list entry update finish procedure:
* Add entry back master list, to the trie, notify observers and call master
* hook.
*
* \param[in] ple prefix list entry.
*/
void prefix_list_entry_update_finish(struct prefix_list_entry *ple)
{
struct prefix_list *pl = ple->pl;
struct prefix_list_entry *point;
/* Already installed, nothing to do. */
if (ple->installed)
return;
/*
* Check if the entry is installable:
* We can only install entry if at least the prefix is provided (IPv4
* or IPv6).
*/
if (ple->prefix.family != AF_INET && ple->prefix.family != AF_INET6)
return;
/* List manipulation: shameless copy from `prefix_list_entry_add`. */
if (pl->tail && ple->seq > pl->tail->seq)
point = NULL;
else {
/* Check insert point. */
for (point = pl->head; point; point = point->next)
if (point->seq >= ple->seq)
break;
}
/* In case of this is the first element of the list. */
ple->next = point;
if (point) {
if (point->prev)
point->prev->next = ple;
else
pl->head = ple;
ple->prev = point->prev;
point->prev = ple;
} else {
if (pl->tail)
pl->tail->next = ple;
else
pl->head = ple;
ple->prev = pl->tail;
pl->tail = ple;
}
prefix_list_trie_add(pl, ple);
pl->count++;
route_map_notify_pentry_dependencies(pl->name, ple,
RMAP_EVENT_PLIST_ADDED);
/* Run hook function. */
if (pl->master->add_hook)
(*pl->master->add_hook)(pl);
route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_ADDED);
pl->master->recent = pl;
ple->installed = true;
}
/**
* Same as `prefix_list_entry_delete` but without `free()`ing the list if its
* empty.
*
* \param[in] ple prefix list entry.
*/
void prefix_list_entry_delete2(struct prefix_list_entry *ple)
{
/* Does the boiler plate list removal and entry removal notification. */
prefix_list_entry_update_start(ple);
/* Effective `free()` memory. */
prefix_list_entry_free(ple);
}
/* Return string of prefix_list_type. */
static const char *prefix_list_type_str(struct prefix_list_entry *pentry)
{
@ -832,280 +959,6 @@ prefix_entry_dup_check(struct prefix_list *plist, struct prefix_list_entry *new)
return NULL;
}
static int vty_invalid_prefix_range(struct vty *vty, const char *prefix)
{
vty_out(vty,
"%% Invalid prefix range for %s, make sure: len < ge-value <= le-value\n",
prefix);
return CMD_WARNING_CONFIG_FAILED;
}
static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name,
const char *seq, const char *typestr,
const char *prefix, const char *ge,
const char *le)
{
int ret;
enum prefix_list_type type;
struct prefix_list *plist;
struct prefix_list_entry *pentry;
struct prefix_list_entry *dup;
struct prefix p, p_tmp;
bool any = false;
int64_t seqnum = -1;
int lenum = 0;
int genum = 0;
if (name == NULL || prefix == NULL || typestr == NULL) {
vty_out(vty, "%% Missing prefix or type\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Sequential number. */
if (seq)
seqnum = (int64_t)atol(seq);
/* ge and le number */
if (ge)
genum = atoi(ge);
if (le)
lenum = atoi(le);
/* Check filter type. */
if (strncmp("permit", typestr, 1) == 0)
type = PREFIX_PERMIT;
else if (strncmp("deny", typestr, 1) == 0)
type = PREFIX_DENY;
else {
vty_out(vty, "%% prefix type must be permit or deny\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* "any" is special token for matching any IPv4 addresses. */
switch (afi) {
case AFI_IP:
if (strncmp("any", prefix, strlen(prefix)) == 0) {
ret = str2prefix_ipv4("0.0.0.0/0",
(struct prefix_ipv4 *)&p);
genum = 0;
lenum = IPV4_MAX_BITLEN;
any = true;
} else
ret = str2prefix_ipv4(prefix, (struct prefix_ipv4 *)&p);
if (ret <= 0) {
vty_out(vty, "%% Malformed IPv4 prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* make a copy to verify prefix matches mask length */
prefix_copy(&p_tmp, &p);
apply_mask_ipv4((struct prefix_ipv4 *)&p_tmp);
break;
case AFI_IP6:
if (strncmp("any", prefix, strlen(prefix)) == 0) {
ret = str2prefix_ipv6("::/0", (struct prefix_ipv6 *)&p);
genum = 0;
lenum = IPV6_MAX_BITLEN;
any = true;
} else
ret = str2prefix_ipv6(prefix, (struct prefix_ipv6 *)&p);
if (ret <= 0) {
vty_out(vty, "%% Malformed IPv6 prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* make a copy to verify prefix matches mask length */
prefix_copy(&p_tmp, &p);
apply_mask_ipv6((struct prefix_ipv6 *)&p_tmp);
break;
case AFI_L2VPN:
default:
vty_out(vty, "%% Unrecognized AFI (%d)\n", afi);
return CMD_WARNING_CONFIG_FAILED;
}
/* If prefix has bits not under the mask, adjust it to fit */
if (!prefix_same(&p_tmp, &p)) {
char buf[PREFIX2STR_BUFFER];
char buf_tmp[PREFIX2STR_BUFFER];
prefix2str(&p, buf, sizeof(buf));
prefix2str(&p_tmp, buf_tmp, sizeof(buf_tmp));
vty_out(vty,
"%% Prefix-list %s prefix changed from %s to %s to match length\n",
name, buf, buf_tmp);
zlog_info(
"Prefix-list %s prefix changed from %s to %s to match length",
name, buf, buf_tmp);
p = p_tmp;
}
/* ge and le check. */
if (genum && (genum <= p.prefixlen))
return vty_invalid_prefix_range(vty, prefix);
if (lenum && (lenum < p.prefixlen))
return vty_invalid_prefix_range(vty, prefix);
if (lenum && (genum > lenum))
return vty_invalid_prefix_range(vty, prefix);
if (genum && (lenum == (afi == AFI_IP ? 32 : 128)))
lenum = 0;
/* Get prefix_list with name. */
plist = prefix_list_get(afi, 0, name);
/* Make prefix entry. */
pentry = prefix_list_entry_make(&p, type, seqnum, lenum, genum, any);
/* Check same policy. */
dup = prefix_entry_dup_check(plist, pentry);
if (dup) {
prefix_list_entry_free(pentry);
return CMD_SUCCESS;
}
/* Install new filter to the access_list. */
prefix_list_entry_add(plist, pentry);
return CMD_SUCCESS;
}
static int vty_prefix_list_uninstall(struct vty *vty, afi_t afi,
const char *name, const char *seq,
const char *typestr, const char *prefix,
const char *ge, const char *le)
{
int ret;
enum prefix_list_type type;
struct prefix_list *plist;
struct prefix_list_entry *pentry;
struct prefix p;
int64_t seqnum = -1;
int lenum = 0;
int genum = 0;
/* Check prefix list name. */
plist = prefix_list_lookup(afi, name);
if (!plist) {
vty_out(vty, "%% Can't find specified prefix-list\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Only prefix-list name specified, delete the entire prefix-list. */
if (seq == NULL && typestr == NULL && prefix == NULL && ge == NULL
&& le == NULL) {
prefix_list_delete(plist);
return CMD_SUCCESS;
}
/* Check sequence number. */
if (seq)
seqnum = (int64_t)atol(seq);
/* Sequence number specified, but nothing else. */
if (seq && typestr == NULL && prefix == NULL && ge == NULL
&& le == NULL) {
pentry = prefix_seq_check(plist, seqnum);
if (pentry == NULL) {
vty_out(vty,
"%% Can't find prefix-list %s with sequence number %" PRIu64 "\n",
name, seqnum);
return CMD_WARNING_CONFIG_FAILED;
}
prefix_list_entry_delete(plist, pentry, 1);
return CMD_SUCCESS;
}
/* ge and le number */
if (ge)
genum = atoi(ge);
if (le)
lenum = atoi(le);
/* We must have, at a minimum, both the type and prefix here */
if ((typestr == NULL) || (prefix == NULL))
return CMD_WARNING_CONFIG_FAILED;
/* Check of filter type. */
if (strncmp("permit", typestr, 1) == 0)
type = PREFIX_PERMIT;
else if (strncmp("deny", typestr, 1) == 0)
type = PREFIX_DENY;
else {
vty_out(vty, "%% prefix type must be permit or deny\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* "any" is special token for matching any IPv4 addresses. */
if (afi == AFI_IP) {
if (strncmp("any", prefix, strlen(prefix)) == 0) {
ret = str2prefix_ipv4("0.0.0.0/0",
(struct prefix_ipv4 *)&p);
genum = 0;
lenum = IPV4_MAX_BITLEN;
} else
ret = str2prefix_ipv4(prefix, (struct prefix_ipv4 *)&p);
if (ret <= 0) {
vty_out(vty, "%% Malformed IPv4 prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
} else if (afi == AFI_IP6) {
if (strncmp("any", prefix, strlen(prefix)) == 0) {
ret = str2prefix_ipv6("::/0", (struct prefix_ipv6 *)&p);
genum = 0;
lenum = IPV6_MAX_BITLEN;
} else
ret = str2prefix_ipv6(prefix, (struct prefix_ipv6 *)&p);
if (ret <= 0) {
vty_out(vty, "%% Malformed IPv6 prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
/* Lookup prefix entry. */
pentry =
prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum);
if (pentry == NULL) {
vty_out(vty, "%% Can't find specified prefix-list\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Install new filter to the access_list. */
prefix_list_entry_delete(plist, pentry, 1);
return CMD_SUCCESS;
}
static int vty_prefix_list_desc_unset(struct vty *vty, afi_t afi,
const char *name)
{
struct prefix_list *plist;
plist = prefix_list_lookup(afi, name);
if (!plist) {
vty_out(vty, "%% Can't find specified prefix-list\n");
return CMD_WARNING_CONFIG_FAILED;
}
XFREE(MTYPE_TMP, plist->desc);
if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
prefix_list_delete(plist);
return CMD_SUCCESS;
}
enum display_type {
normal_display,
summary_display,
@ -1349,72 +1202,6 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
#include "lib/plist_clippy.c"
#endif
DEFPY (ip_prefix_list,
ip_prefix_list_cmd,
"ip prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|A.B.C.D/M$dest [{ge (0-32)|le (0-32)}]>",
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Minimum prefix length to be matched\n"
"Minimum prefix length\n"
"Maximum prefix length to be matched\n"
"Maximum prefix length\n")
{
return vty_prefix_list_install(vty, AFI_IP, prefix_list, seq_str,
action, dest, ge_str, le_str);
}
DEFPY (no_ip_prefix_list,
no_ip_prefix_list_cmd,
"no ip prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|A.B.C.D/M$dest [{ge (0-32)|le (0-32)}]>",
NO_STR
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Minimum prefix length to be matched\n"
"Minimum prefix length\n"
"Maximum prefix length to be matched\n"
"Maximum prefix length\n")
{
return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, seq_str,
action, dest, ge_str, le_str);
}
DEFPY(no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
"no ip prefix-list WORD seq (1-4294967295)",
NO_STR IP_STR PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n")
{
return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, seq_str,
NULL, NULL, NULL, NULL);
}
DEFPY (no_ip_prefix_list_all,
no_ip_prefix_list_all_cmd,
"no ip prefix-list WORD",
NO_STR
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n")
{
return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, NULL, NULL,
NULL, NULL, NULL);
}
DEFPY (ip_prefix_list_sequence_number,
ip_prefix_list_sequence_number_cmd,
"[no] ip prefix-list sequence-number",
@ -1427,56 +1214,6 @@ DEFPY (ip_prefix_list_sequence_number,
return CMD_SUCCESS;
}
DEFUN (ip_prefix_list_description,
ip_prefix_list_description_cmd,
"ip prefix-list WORD description LINE...",
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
int idx_word = 2;
int idx_line = 4;
struct prefix_list *plist;
plist = prefix_list_get(AFI_IP, 0, argv[idx_word]->arg);
if (plist->desc) {
XFREE(MTYPE_TMP, plist->desc);
plist->desc = NULL;
}
plist->desc = argv_concat(argv, argc, idx_line);
return CMD_SUCCESS;
}
DEFUN (no_ip_prefix_list_description,
no_ip_prefix_list_description_cmd,
"no ip prefix-list WORD description",
NO_STR
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n")
{
int idx_word = 3;
return vty_prefix_list_desc_unset(vty, AFI_IP, argv[idx_word]->arg);
}
/* ALIAS_FIXME */
DEFUN (no_ip_prefix_list_description_comment,
no_ip_prefix_list_description_comment_cmd,
"no ip prefix-list WORD description LINE...",
NO_STR
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
return no_ip_prefix_list_description(self, vty, argc, argv);
}
DEFPY (show_ip_prefix_list,
show_ip_prefix_list_cmd,
@ -1554,61 +1291,6 @@ DEFPY (clear_ip_prefix_list,
return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str);
}
DEFPY (ipv6_prefix_list,
ipv6_prefix_list_cmd,
"ipv6 prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|X:X::X:X/M$dest [{ge (0-128)|le (0-128)}]>",
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefix match. Same as \"::0/0 le 128\"\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
"Maximum prefix length to be matched\n"
"Maximum prefix length\n"
"Minimum prefix length to be matched\n"
"Minimum prefix length\n")
{
return vty_prefix_list_install(vty, AFI_IP6, prefix_list, seq_str,
action, dest, ge_str, le_str);
}
DEFPY (no_ipv6_prefix_list,
no_ipv6_prefix_list_cmd,
"no ipv6 prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|X:X::X:X/M$dest [{ge (0-128)|le (0-128)}]>",
NO_STR
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefix match. Same as \"::0/0 le 128\"\n"
"IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
"Maximum prefix length to be matched\n"
"Maximum prefix length\n"
"Minimum prefix length to be matched\n"
"Minimum prefix length\n")
{
return vty_prefix_list_uninstall(vty, AFI_IP6, prefix_list, seq_str,
action, dest, ge_str, le_str);
}
DEFPY (no_ipv6_prefix_list_all,
no_ipv6_prefix_list_all_cmd,
"no ipv6 prefix-list WORD",
NO_STR
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n")
{
return vty_prefix_list_uninstall(vty, AFI_IP6, prefix_list, NULL, NULL,
NULL, NULL, NULL);
}
DEFPY (ipv6_prefix_list_sequence_number,
ipv6_prefix_list_sequence_number_cmd,
"[no] ipv6 prefix-list sequence-number",
@ -1621,58 +1303,6 @@ DEFPY (ipv6_prefix_list_sequence_number,
return CMD_SUCCESS;
}
DEFUN (ipv6_prefix_list_description,
ipv6_prefix_list_description_cmd,
"ipv6 prefix-list WORD description LINE...",
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
int idx_word = 2;
int iddx_line = 4;
struct prefix_list *plist;
plist = prefix_list_get(AFI_IP6, 0, argv[idx_word]->arg);
if (plist->desc) {
XFREE(MTYPE_TMP, plist->desc);
plist->desc = NULL;
}
plist->desc = argv_concat(argv, argc, iddx_line);
return CMD_SUCCESS;
}
DEFUN (no_ipv6_prefix_list_description,
no_ipv6_prefix_list_description_cmd,
"no ipv6 prefix-list WORD description",
NO_STR
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n")
{
int idx_word = 3;
return vty_prefix_list_desc_unset(vty, AFI_IP6, argv[idx_word]->arg);
}
/* ALIAS_FIXME */
DEFUN (no_ipv6_prefix_list_description_comment,
no_ipv6_prefix_list_description_comment_cmd,
"no ipv6 prefix-list WORD description LINE...",
NO_STR
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"Prefix-list specific description\n"
"Up to 80 characters describing this prefix-list\n")
{
return no_ipv6_prefix_list_description(self, vty, argc, argv);
}
DEFPY (show_ipv6_prefix_list,
show_ipv6_prefix_list_cmd,
"show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
@ -1749,104 +1379,6 @@ DEFPY (clear_ipv6_prefix_list,
return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str);
}
/* Configuration write function. */
static int config_write_prefix_afi(afi_t afi, struct vty *vty)
{
struct prefix_list *plist;
struct prefix_list_entry *pentry;
struct prefix_master *master;
int write = 0;
master = prefix_master_get(afi, 0);
if (master == NULL)
return 0;
if (!master->seqnum) {
vty_out(vty, "no ip%s prefix-list sequence-number\n",
afi == AFI_IP ? "" : "v6");
vty_out(vty, "!\n");
}
for (plist = master->num.head; plist; plist = plist->next) {
if (plist->desc) {
vty_out(vty, "ip%s prefix-list %s description %s\n",
afi == AFI_IP ? "" : "v6", plist->name,
plist->desc);
write++;
}
for (pentry = plist->head; pentry; pentry = pentry->next) {
vty_out(vty, "ip%s prefix-list %s ",
afi == AFI_IP ? "" : "v6", plist->name);
if (master->seqnum)
vty_out(vty, "seq %" PRId64 " ", pentry->seq);
vty_out(vty, "%s ", prefix_list_type_str(pentry));
if (pentry->any)
vty_out(vty, "any");
else {
struct prefix *p = &pentry->prefix;
char buf[BUFSIZ];
vty_out(vty, "%s/%d",
inet_ntop(p->family, p->u.val, buf,
BUFSIZ),
p->prefixlen);
if (pentry->ge)
vty_out(vty, " ge %d", pentry->ge);
if (pentry->le)
vty_out(vty, " le %d", pentry->le);
}
vty_out(vty, "\n");
write++;
}
/* vty_out (vty, "!\n"); */
}
for (plist = master->str.head; plist; plist = plist->next) {
if (plist->desc) {
vty_out(vty, "ip%s prefix-list %s description %s\n",
afi == AFI_IP ? "" : "v6", plist->name,
plist->desc);
write++;
}
for (pentry = plist->head; pentry; pentry = pentry->next) {
vty_out(vty, "ip%s prefix-list %s ",
afi == AFI_IP ? "" : "v6", plist->name);
if (master->seqnum)
vty_out(vty, "seq %" PRId64 " ", pentry->seq);
vty_out(vty, "%s", prefix_list_type_str(pentry));
if (pentry->any)
vty_out(vty, " any");
else {
struct prefix *p = &pentry->prefix;
char buf[BUFSIZ];
vty_out(vty, " %s/%d",
inet_ntop(p->family, p->u.val, buf,
BUFSIZ),
p->prefixlen);
if (pentry->ge)
vty_out(vty, " ge %d", pentry->ge);
if (pentry->le)
vty_out(vty, " le %d", pentry->le);
}
vty_out(vty, "\n");
write++;
}
}
return write;
}
struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist,
uint8_t init_flag, uint8_t permit_flag,
uint8_t deny_flag)
@ -2042,21 +1574,13 @@ static void prefix_list_reset_afi(afi_t afi, int orf)
master->recent = NULL;
}
static int config_write_prefix_ipv4(struct vty *vty);
/* Prefix-list node. */
static struct cmd_node prefix_node = {
.name = "ipv4 prefix list",
.node = PREFIX_NODE,
.prompt = "",
.config_write = config_write_prefix_ipv4,
};
static int config_write_prefix_ipv4(struct vty *vty)
{
return config_write_prefix_afi(AFI_IP, vty);
}
static void plist_autocomplete_afi(afi_t afi, vector comps,
struct cmd_token *token)
{
@ -2090,16 +1614,6 @@ static void prefix_list_init_ipv4(void)
{
install_node(&prefix_node);
install_element(CONFIG_NODE, &ip_prefix_list_cmd);
install_element(CONFIG_NODE, &no_ip_prefix_list_cmd);
install_element(CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
install_element(CONFIG_NODE, &no_ip_prefix_list_all_cmd);
install_element(CONFIG_NODE, &ip_prefix_list_description_cmd);
install_element(CONFIG_NODE, &no_ip_prefix_list_description_cmd);
install_element(CONFIG_NODE,
&no_ip_prefix_list_description_comment_cmd);
install_element(CONFIG_NODE, &ip_prefix_list_sequence_number_cmd);
install_element(VIEW_NODE, &show_ip_prefix_list_cmd);
@ -2110,33 +1624,17 @@ static void prefix_list_init_ipv4(void)
install_element(ENABLE_NODE, &clear_ip_prefix_list_cmd);
}
static int config_write_prefix_ipv6(struct vty *vty);
/* Prefix-list node. */
static struct cmd_node prefix_ipv6_node = {
.name = "ipv6 prefix list",
.node = PREFIX_IPV6_NODE,
.prompt = "",
.config_write = config_write_prefix_ipv6,
};
static int config_write_prefix_ipv6(struct vty *vty)
{
return config_write_prefix_afi(AFI_IP6, vty);
}
static void prefix_list_init_ipv6(void)
{
install_node(&prefix_ipv6_node);
install_element(CONFIG_NODE, &ipv6_prefix_list_cmd);
install_element(CONFIG_NODE, &no_ipv6_prefix_list_cmd);
install_element(CONFIG_NODE, &no_ipv6_prefix_list_all_cmd);
install_element(CONFIG_NODE, &ipv6_prefix_list_description_cmd);
install_element(CONFIG_NODE, &no_ipv6_prefix_list_description_cmd);
install_element(CONFIG_NODE,
&no_ipv6_prefix_list_description_comment_cmd);
install_element(CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd);
install_element(VIEW_NODE, &show_ipv6_prefix_list_cmd);

View File

@ -79,6 +79,20 @@ extern void prefix_bgp_orf_remove_all(afi_t, char *);
extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
bool use_json);
extern struct prefix_list *prefix_list_get(afi_t afi, int orf,
const char *name);
extern void prefix_list_delete(struct prefix_list *plist);
extern int64_t prefix_new_seq_get(struct prefix_list *plist);
extern struct prefix_list_entry *prefix_list_entry_new(void);
extern void prefix_list_entry_delete(struct prefix_list *plist,
struct prefix_list_entry *pentry,
int update_list);
extern struct prefix_list_entry *
prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix,
enum prefix_list_type type, int64_t seq, int le,
int ge);
#ifdef __cplusplus
}
#endif

View File

@ -65,13 +65,23 @@ struct prefix_list_entry {
unsigned long refcnt;
unsigned long hitcnt;
struct prefix_list *pl;
struct prefix_list_entry *next;
struct prefix_list_entry *prev;
/* up the chain for best match search */
struct prefix_list_entry *next_best;
/* Flag to track trie/list installation status. */
bool installed;
};
extern void prefix_list_entry_free(struct prefix_list_entry *pentry);
extern void prefix_list_entry_delete2(struct prefix_list_entry *ple);
extern void prefix_list_entry_update_start(struct prefix_list_entry *ple);
extern void prefix_list_entry_update_finish(struct prefix_list_entry *ple);
#ifdef __cplusplus
}
#endif

View File

@ -22,6 +22,8 @@ lib_libfrr_la_SOURCES = \
lib/distribute.c \
lib/ferr.c \
lib/filter.c \
lib/filter_cli.c \
lib/filter_nb.c \
lib/frrcu.c \
lib/frrlua.c \
lib/frr_pthread.c \
@ -127,6 +129,7 @@ nodist_lib_libfrr_la_SOURCES = \
vtysh_scan += \
lib/distribute.c \
lib/filter.c \
lib/filter_cli.c \
lib/if.c \
lib/if_rmap.c \
lib/keychain.c \
@ -148,6 +151,7 @@ endif
clippy_scan += \
lib/if.c \
lib/filter_cli.c \
lib/log_vty.c \
lib/nexthop_group.c \
lib/northbound_cli.c \

View File

@ -448,6 +448,32 @@ bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath_fmt, ...)
return found;
}
void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
const struct lyd_node *dnode, const char *xpath_fmt,
...)
{
va_list ap;
char xpath[XPATH_MAXLEN];
struct ly_set *set;
va_start(ap, xpath_fmt);
vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
va_end(ap);
set = lyd_find_path(dnode, xpath);
assert(set);
for (unsigned int i = 0; i < set->number; i++) {
int ret;
dnode = set->set.d[i];
ret = (*cb)(dnode, arg);
if (ret == YANG_ITER_STOP)
return;
}
ly_set_free(set);
}
bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath_fmt,
...)
{

View File

@ -107,6 +107,9 @@ enum yang_iter_flags {
/* Callback used by the yang_snodes_iterate_*() family of functions. */
typedef int (*yang_iterate_cb)(const struct lys_node *snode, void *arg);
/* Callback used by the yang_dnode_iterate() function. */
typedef int (*yang_dnode_iter_cb)(const struct lyd_node *dnode, void *arg);
/* Return values of the 'yang_iterate_cb' callback. */
#define YANG_ITER_CONTINUE 0
#define YANG_ITER_STOP -1
@ -357,6 +360,25 @@ extern struct lyd_node *yang_dnode_get(const struct lyd_node *dnode,
extern bool yang_dnode_exists(const struct lyd_node *dnode,
const char *xpath_fmt, ...);
/*
* Iterate over all libyang data nodes that satisfy an XPath query.
*
* cb
* Function to call with each data node.
*
* arg
* Arbitrary argument passed as the second parameter in each call to 'cb'.
*
* dnode
* Base libyang data node to operate on.
*
* xpath_fmt
* XPath expression (absolute or relative).
*/
void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg,
const struct lyd_node *dnode, const char *xpath_fmt,
...);
/*
* Check if the libyang data node contains a default value. Non-presence
* containers are assumed to always contain a default value.

View File

@ -23,6 +23,7 @@
#include "memory.h"
#include "command.h"
#include "libfrr.h"
#include "filter.h"
#include "nhrpd.h"
#include "netlink.h"
@ -116,6 +117,7 @@ static struct quagga_signal_t sighandlers[] = {
};
static const struct frr_yang_module_info *const nhrpd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
};

View File

@ -166,6 +166,7 @@ struct quagga_signal_t ospf6_signals[] = {
};
static const struct frr_yang_module_info *const ospf6d_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -126,6 +126,7 @@ struct quagga_signal_t ospf_signals[] = {
};
static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -113,6 +113,7 @@ struct quagga_signal_t pbr_signals[] = {
#define PBR_VTY_PORT 2615
static const struct frr_yang_module_info *const pbrd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
};

View File

@ -73,6 +73,7 @@ struct zebra_privs_t pimd_privs = {
.cap_num_i = 0};
static const struct frr_yang_module_info *const pimd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -114,6 +114,7 @@ static struct quagga_signal_t ripd_signals[] = {
};
static const struct frr_yang_module_info *const ripd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_ripd_info,
&frr_route_map_info,

View File

@ -114,6 +114,7 @@ struct quagga_signal_t ripng_signals[] = {
};
static const struct frr_yang_module_info *const ripngd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_ripngd_info,
&frr_route_map_info,

View File

@ -112,6 +112,7 @@ struct quagga_signal_t sharp_signals[] = {
#define SHARP_VTY_PORT 2614
static const struct frr_yang_module_info *const sharpd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_vrf_info,

View File

@ -104,6 +104,7 @@ struct quagga_signal_t static_signals[] = {
};
static const struct frr_yang_module_info *const staticd_yang_modules[] = {
&frr_filter_info,
&frr_vrf_info,
};

View File

@ -111,6 +111,7 @@ struct quagga_signal_t vrrp_signals[] = {
};
static const struct frr_yang_module_info *const vrrp_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_vrrpd_info,
};

View File

@ -98,7 +98,7 @@ sub scan_file {
elsif ($file =~ /lib\/if\.c$/) {
$protocol = "VTYSH_INTERFACE";
}
elsif ($file =~ /lib\/(filter|lib_vty)\.c$/) {
elsif ($file =~ /lib\/(filter|filter_cli|lib_vty)\.c$/) {
$protocol = "VTYSH_ALL";
}
elsif ($file =~ /lib\/agentx\.c$/) {

View File

@ -73,7 +73,9 @@ module frr-filter {
typedef access-list-name {
description "Access list name formatting";
type string;
type string {
length 1..128;
}
}
typedef access-list-sequence {
@ -100,69 +102,76 @@ module frr-filter {
/*
* Configuration data.
*/
container filter-list {
container lib {
list access-list-legacy {
description "Access list legacy instance";
key "number sequence";
key "number";
leaf number {
description "Access list sequence value";
type access-list-legacy;
}
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
leaf action {
description "Access list action on match";
type access-list-action;
mandatory true;
}
leaf remark {
description "Access list remark";
type string;
}
choice value {
description
"Standard access list: value to match.
Extended access list: source value to match.";
mandatory true;
list entry {
description "Access list legacy entry";
leaf host {
description "Host to match";
type inet:ipv4-address;
}
leaf network {
description "Network to match";
type inet:ipv4-prefix;
}
leaf any {
description "Match any";
type empty;
}
}
key "sequence";
choice extended-value {
when "./sequence >= 100 and ./sequence <= 199 or
./sequence >= 2000 and ./sequence <= 2699";
description "Destination value to match";
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
leaf destination-host {
description "Host to match";
type inet:ipv4-address;
leaf action {
description "Access list action on match";
type access-list-action;
mandatory true;
}
leaf destination-network {
description "Network to match";
type inet:ipv4-prefix;
choice value {
description
"Standard access list: value to match.
Extended access list: source value to match.";
mandatory true;
leaf host {
description "Host to match";
type inet:ipv4-address;
}
leaf network {
description "Network to match";
type inet:ipv4-prefix;
}
leaf any {
description "Match any";
type empty;
}
}
leaf destination-any {
description "Match any";
type empty;
choice extended-value {
when "../number >= 100 and ../number <= 199 or
../number >= 2000 and ../number <= 2699";
description "Destination value to match";
mandatory true;
leaf destination-host {
description "Host to match";
type inet:ipv4-address;
}
leaf destination-network {
description "Network to match";
type inet:ipv4-prefix;
}
leaf destination-any {
description "Match any";
type empty;
}
}
}
}
@ -170,7 +179,7 @@ module frr-filter {
list access-list {
description "Access list instance";
key "type identifier sequence";
key "type name";
leaf type {
description "Access list content type";
@ -187,85 +196,80 @@ module frr-filter {
description "Media Access Control address";
value 2;
}
/*
* Protocol YANG models should augment the parent node to
* contain the routing protocol specific value. The protocol
* must also augment `value` leaf to include its specific
* values or expand the `when` statement on the existing cases.
*/
enum custom {
description "Custom data type";
value 100;
}
}
}
leaf identifier {
description "Access list identifier";
leaf name {
description "Access list name";
type access-list-name;
}
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
leaf action {
description "Access list action on match";
type access-list-action;
mandatory true;
}
leaf remark {
description "Access list remark";
type string;
}
choice value {
description "Access list value to match";
mandatory true;
list entry {
description "Access list entry";
case ipv4-prefix {
when "./type = 'ipv4'";
key "sequence";
leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix;
}
leaf ipv4-exact-match {
description "Exact match of prefix";
type boolean;
default false;
}
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
case ipv6-prefix {
when "./type = 'ipv6'";
leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix;
}
leaf ipv6-exact-match {
description "Exact match of prefix";
type boolean;
default false;
}
leaf action {
description "Access list action on match";
type access-list-action;
mandatory true;
}
case mac {
when "./type = 'mac'";
leaf mac {
description "Configure MAC address to match";
type yang:mac-address;
choice value {
description "Access list value to match";
mandatory true;
case ipv4-prefix {
when "../type = 'ipv4'";
leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix;
}
leaf ipv4-exact-match {
description "Exact match of prefix";
type boolean;
default false;
}
}
}
case any {
leaf any {
description "Match anything";
type empty;
case ipv6-prefix {
when "../type = 'ipv6'";
leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix;
}
leaf ipv6-exact-match {
description "Exact match of prefix";
type boolean;
default false;
}
}
case mac {
when "../type = 'mac'";
leaf mac {
description "Configure MAC address to match";
type yang:mac-address;
}
}
case any {
leaf any {
description "Match anything";
type empty;
}
}
}
}
@ -274,7 +278,7 @@ module frr-filter {
list prefix-list {
description "Prefix list instance";
key "type name sequence";
key "type name";
leaf type {
description "Prefix list type";
@ -295,82 +299,88 @@ module frr-filter {
type access-list-name;
}
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
leaf action {
description "Prefix list action on match";
type access-list-action;
mandatory true;
}
leaf description {
leaf remark {
description "Prefix list user description";
type string;
}
choice value {
description "Prefix list value to match";
mandatory true;
list entry {
description "Prefix list entry";
case ipv4-prefix {
when "./type = 'ipv4'";
key "sequence";
leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix;
}
leaf ipv4-prefix-length-greater-or-equal {
description
"Specifies if matching prefixes with length greater than
or equal to value";
type uint8 {
range "0..32";
}
}
leaf ipv4-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 {
range "0..32";
}
}
leaf sequence {
description "Access list sequence value";
type access-list-sequence;
}
case ipv6-prefix {
when "./type = 'ipv6'";
leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix;
}
leaf ipv6-prefix-length-greater-or-equal {
description
"Specifies if matching prefixes with length greater than
or equal to value";
type uint8 {
range "0..128";
}
}
leaf ipv6-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 {
range "0..128";
}
}
leaf action {
description "Prefix list action on match";
type access-list-action;
mandatory true;
}
case any {
leaf any {
description "Match anything";
type empty;
choice value {
description "Prefix list value to match";
mandatory true;
case ipv4-prefix {
when "../type = 'ipv4'";
leaf ipv4-prefix {
description "Configure IPv4 prefix to match";
type inet:ipv4-prefix;
}
leaf ipv4-prefix-length-greater-or-equal {
description
"Specifies if matching prefixes with length greater than
or equal to value";
type uint8 {
range "0..32";
}
}
leaf ipv4-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 {
range "0..32";
}
}
}
case ipv6-prefix {
when "../type = 'ipv6'";
leaf ipv6-prefix {
description "Configure IPv6 prefix to match";
type inet:ipv6-prefix;
}
leaf ipv6-prefix-length-greater-or-equal {
description
"Specifies if matching prefixes with length greater than
or equal to value";
type uint8 {
range "0..128";
}
}
leaf ipv6-prefix-length-lesser-or-equal {
description
"Specifies if matching prefixes with length lesser than
or equal to value";
type uint8 {
range "0..128";
}
}
}
case any {
leaf any {
description "Match anything";
type empty;
}
}
}
}

View File

@ -253,6 +253,7 @@ struct quagga_signal_t zebra_signals[] = {
};
static const struct frr_yang_module_info *const zebra_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
&frr_route_map_info,
&frr_zebra_info,