mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 06:34:44 +00:00
Merge pull request #5323 from opensourcerouting/filter-nb
lib: migrate FRR filter to northbound
This commit is contained in:
commit
2d8c1bc235
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
2154
lib/filter.c
2154
lib/filter.c
File diff suppressed because it is too large
Load Diff
120
lib/filter.h
120
lib/filter.h
@ -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
1693
lib/filter_cli.c
Normal file
File diff suppressed because it is too large
Load Diff
1286
lib/filter_nb.c
Normal file
1286
lib/filter_nb.c
Normal file
File diff suppressed because it is too large
Load Diff
774
lib/plist.c
774
lib/plist.c
@ -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);
|
||||
|
14
lib/plist.h
14
lib/plist.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
26
lib/yang.c
26
lib/yang.c
@ -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,
|
||||
...)
|
||||
{
|
||||
|
22
lib/yang.h
22
lib/yang.h
@ -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.
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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$/) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user