summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/babel_main.c1
-rw-r--r--bfdd/bfdd.c1
-rw-r--r--bgpd/bgp_io.c6
-rw-r--r--bgpd/bgp_main.c1
-rw-r--r--bgpd/bgp_route.c11
-rw-r--r--bgpd/bgp_vty.c9
-rw-r--r--bgpd/bgpd.c3
-rwxr-xr-xdocker/alpine/docker-start2
-rw-r--r--eigrpd/eigrp_main.c1
-rw-r--r--isisd/isis_adjacency.c17
-rw-r--r--isisd/isis_main.c1
-rw-r--r--ldpd/ldpd.c1
-rw-r--r--lib/filter.c2154
-rw-r--r--lib/filter.h120
-rw-r--r--lib/filter_cli.c1693
-rw-r--r--lib/filter_nb.c1286
-rw-r--r--lib/plist.c774
-rw-r--r--lib/plist.h14
-rw-r--r--lib/plist_int.h10
-rw-r--r--lib/routemap.c7
-rw-r--r--lib/subdir.am4
-rw-r--r--lib/yang.c26
-rw-r--r--lib/yang.h22
-rw-r--r--nhrpd/nhrp_main.c2
-rw-r--r--ospf6d/ospf6_main.c1
-rw-r--r--ospfd/ospf_main.c1
-rw-r--r--pbrd/pbr_main.c1
-rw-r--r--pimd/pim_main.c1
-rw-r--r--pimd/pim_mlag.c31
-rw-r--r--pimd/pim_oil.c14
-rw-r--r--pimd/pim_upstream.h3
-rw-r--r--ripd/rip_main.c1
-rw-r--r--ripngd/ripng_main.c1
-rw-r--r--sharpd/sharp_main.c1
-rw-r--r--staticd/static_main.c1
-rw-r--r--tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py4
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json16
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json28
-rw-r--r--tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json32
-rw-r--r--tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json42
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json8
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json18
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json8
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json20
-rwxr-xr-xtests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py92
-rw-r--r--vrrpd/vrrp_main.c1
-rwxr-xr-xvtysh/extract.pl.in2
-rw-r--r--yang/frr-filter.yang336
-rw-r--r--zebra/if_netlink.c9
-rw-r--r--zebra/main.c1
50 files changed, 3739 insertions, 3100 deletions
diff --git a/babeld/babel_main.c b/babeld/babel_main.c
index e7ba29ed06..14e583a35c 100644
--- a/babeld/babel_main.c
+++ b/babeld/babel_main.c
@@ -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,
};
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 39d51eb649..258f074e8c 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -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,
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index ab50c545b5..412c8e3e5e 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -201,7 +201,6 @@ static int bgp_process_reads(struct thread *thread)
while (more) {
/* static buffer for transferring packets */
- static unsigned char pktbuf[BGP_MAX_PACKET_SIZE];
/* shorter alias to peer's input buffer */
struct ringbuf *ibw = peer->ibuf_work;
/* packet size as given by header */
@@ -231,8 +230,9 @@ static int bgp_process_reads(struct thread *thread)
*/
if (ringbuf_remain(ibw) >= pktsize) {
struct stream *pkt = stream_new(pktsize);
- assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize);
- stream_put(pkt, pktbuf, pktsize);
+ assert(STREAM_WRITEABLE(pkt) == pktsize);
+ assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
+ stream_set_endp(pkt, pktsize);
frr_with_mutex(&peer->io_mtx) {
stream_fifo_push(peer->ibuf, pkt);
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 04be8d83eb..f9ff99cab0 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -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,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 32489459cb..b0fbdbcf01 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -13525,14 +13525,21 @@ void bgp_route_init(void)
install_element(BGP_IPV6M_NODE,
&no_ipv6_bgp_distance_source_access_list_cmd);
+ /* BGP dampening */
install_element(BGP_NODE, &bgp_damp_set_cmd);
install_element(BGP_NODE, &bgp_damp_unset_cmd);
install_element(BGP_IPV4_NODE, &bgp_damp_set_cmd);
install_element(BGP_IPV4_NODE, &bgp_damp_unset_cmd);
-
- /* IPv4 Multicast Mode */
install_element(BGP_IPV4M_NODE, &bgp_damp_set_cmd);
install_element(BGP_IPV4M_NODE, &bgp_damp_unset_cmd);
+ install_element(BGP_IPV4L_NODE, &bgp_damp_set_cmd);
+ install_element(BGP_IPV4L_NODE, &bgp_damp_unset_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_damp_set_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_damp_unset_cmd);
+ install_element(BGP_IPV6M_NODE, &bgp_damp_set_cmd);
+ install_element(BGP_IPV6M_NODE, &bgp_damp_unset_cmd);
+ install_element(BGP_IPV6L_NODE, &bgp_damp_set_cmd);
+ install_element(BGP_IPV6L_NODE, &bgp_damp_unset_cmd);
/* Large Communities */
install_element(VIEW_NODE, &show_ip_bgp_large_community_list_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index df82834b51..aa5857b9d4 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -14815,11 +14815,6 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
vty_out(vty, "\n");
}
- /* BGP flag dampening. */
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_DAMPENING))
- bgp_config_write_damp(vty, afi, safi);
-
/* Route reflector client. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REFLECTOR_CLIENT)) {
@@ -15044,6 +15039,10 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
bgp_config_write_redistribute(vty, bgp, afi, safi);
+ /* BGP flag dampening. */
+ if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
+ bgp_config_write_damp(vty, afi, safi);
+
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index faee7dad4a..ec6e00ea34 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2511,6 +2511,9 @@ static void peer_group2peer_config_copy(struct peer_group *group,
}
}
+ /* Update GR flags for the peer. */
+ bgp_peer_gr_flags_update(peer);
+
bgp_bfd_peer_group2peer_copy(conf, peer);
}
diff --git a/docker/alpine/docker-start b/docker/alpine/docker-start
index 52cfb664ce..3f7737d3bf 100755
--- a/docker/alpine/docker-start
+++ b/docker/alpine/docker-start
@@ -5,7 +5,7 @@ set -e
##
# For volume mounts...
##
-chown -R frr:frr /etc/frr
+chown -R frr:frr /etc/frr || true
/usr/lib/frr/frrinit.sh start
# Sleep forever
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
index cdf1c6acdb..6c44ce361c 100644
--- a/eigrpd/eigrp_main.c
+++ b/eigrpd/eigrp_main.c
@@ -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,
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index acfe3e2e1f..94e38435a3 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -268,10 +268,11 @@ void isis_adj_state_change(struct isis_adjacency **padj,
struct isis_circuit *circuit = adj->circuit;
bool del = false;
+ if (new_state == old_state)
+ return;
+
adj->adj_state = new_state;
- if (new_state != old_state) {
- send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
- }
+ send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
@@ -314,7 +315,7 @@ void isis_adj_state_change(struct isis_adjacency **padj,
* purposes */
adj->last_flap = time(NULL);
adj->flaps++;
- } else if (new_state == ISIS_ADJ_DOWN) {
+ } else if (old_state == ISIS_ADJ_UP) {
listnode_delete(circuit->u.bc.adjdb[level - 1],
adj);
@@ -323,7 +324,8 @@ void isis_adj_state_change(struct isis_adjacency **padj,
isis_tx_queue_clean(circuit->tx_queue);
hook_call(isis_adj_state_change_hook, adj);
- del = true;
+ if (new_state == ISIS_ADJ_DOWN)
+ del = true;
}
if (circuit->u.bc.lan_neighs[level - 1]) {
@@ -362,7 +364,7 @@ void isis_adj_state_change(struct isis_adjacency **padj,
circuit, 0,
&circuit->t_send_csnp[1]);
}
- } else if (new_state == ISIS_ADJ_DOWN) {
+ } else if (old_state == ISIS_ADJ_UP) {
if (adj->circuit->u.p2p.neighbor == adj)
adj->circuit->u.p2p.neighbor = NULL;
circuit->upadjcount[level - 1]--;
@@ -370,7 +372,8 @@ void isis_adj_state_change(struct isis_adjacency **padj,
isis_tx_queue_clean(circuit->tx_queue);
hook_call(isis_adj_state_change_hook, adj);
- del = true;
+ if (new_state == ISIS_ADJ_DOWN)
+ del = true;
}
}
}
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 78654b2f1c..7d45dd9c2e 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -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,
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index c6126b9396..56734a4f76 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -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,
};
diff --git a/lib/filter.c b/lib/filter.c
index d61b03cbe2..e6add0462b 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -29,70 +29,12 @@
#include "log.h"
#include "routemap.h"
#include "libfrr.h"
+#include "northbound_cli.h"
DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List")
DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str")
DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter")
-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;
-};
-
-/* Filter element of access list */
-struct filter {
- /* For doubly linked list. */
- struct filter *next;
- struct filter *prev;
-
- /* 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;
-};
-
-/* 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 *);
-};
-
/* Static structure for mac access_list's master. */
static struct access_master access_master_mac = {
{NULL, NULL},
@@ -129,7 +71,7 @@ static struct access_master *access_master_get(afi_t afi)
}
/* Allocate new filter structure. */
-static struct filter *filter_new(void)
+struct filter *filter_new(void)
{
return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
}
@@ -210,7 +152,7 @@ static void access_list_free(struct access_list *access)
}
/* Delete access_list from access_master and free it. */
-static void access_list_delete(struct access_list *access)
+void access_list_delete(struct access_list *access)
{
struct filter *filter;
struct filter *next;
@@ -356,7 +298,7 @@ struct access_list *access_list_lookup(afi_t afi, const char *name)
/* Get access list from list of access_list. If there isn't matched
access_list create new one and return it. */
-static struct access_list *access_list_get(afi_t afi, const char *name)
+struct access_list *access_list_get(afi_t afi, const char *name)
{
struct access_list *access;
@@ -406,7 +348,7 @@ void access_list_delete_hook(void (*func)(struct access_list *access))
}
/* Calculate new sequential number. */
-static int64_t filter_new_seq_get(struct access_list *access)
+int64_t filter_new_seq_get(struct access_list *access)
{
int64_t maxseq;
int64_t newseq;
@@ -436,22 +378,12 @@ static struct filter *filter_seq_check(struct access_list *access,
return NULL;
}
-/* If access_list has no filter then return 1. */
-static bool access_list_empty(struct access_list *access)
-{
- if (access->head == NULL && access->tail == NULL)
- return true;
- else
- return false;
-}
-
/* Delete filter from specified access_list. If there is hook
function execute it. */
-static void access_list_filter_delete(struct access_list *access,
- struct filter *filter)
+void access_list_filter_delete(struct access_list *access,
+ struct filter *filter)
{
struct access_master *master;
- struct filter *replace = filter;
master = access->master;
@@ -471,15 +403,11 @@ static void access_list_filter_delete(struct access_list *access,
/* Run hook function. */
if (master->delete_hook)
(*master->delete_hook)(access);
-
- /* If access_list becomes empty delete it from access_master. */
- if (access_list_empty(access) && !replace)
- access_list_delete(access);
}
/* Add new filter to the end of specified access_list. */
-static void access_list_filter_add(struct access_list *access,
- struct filter *filter)
+void access_list_filter_add(struct access_list *access,
+ struct filter *filter)
{
struct filter *replace;
struct filter *point;
@@ -541,8 +469,8 @@ static void access_list_filter_add(struct access_list *access,
host A single host address
*/
-static struct filter *filter_lookup_cisco(struct access_list *access,
- struct filter *mnew)
+struct filter *filter_lookup_cisco(struct access_list *access,
+ struct filter *mnew)
{
struct filter *mfilter;
struct filter_cisco *filter;
@@ -573,8 +501,8 @@ static struct filter *filter_lookup_cisco(struct access_list *access,
return NULL;
}
-static struct filter *filter_lookup_zebra(struct access_list *access,
- struct filter *mnew)
+struct filter *filter_lookup_zebra(struct access_list *access,
+ struct filter *mnew)
{
struct filter *mfilter;
struct filter_zebra *filter;
@@ -594,1905 +522,6 @@ static struct filter *filter_lookup_zebra(struct access_list *access,
return NULL;
}
-static int vty_access_list_remark_unset(struct vty *vty, afi_t afi,
- const char *name)
-{
- struct access_list *access;
-
- access = access_list_lookup(afi, name);
- if (!access) {
- vty_out(vty, "%% access-list %s doesn't exist\n", name);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- XFREE(MTYPE_TMP, access->remark);
-
- if (access->head == NULL && access->tail == NULL)
- access_list_delete(access);
-
- return CMD_SUCCESS;
-}
-
-static int filter_set_cisco(struct vty *vty, const char *name_str,
- const char *seq, const char *type_str,
- const char *addr_str, const char *addr_mask_str,
- const char *mask_str, const char *mask_mask_str,
- int extended, int set)
-{
- int ret;
- enum filter_type type = FILTER_DENY;
- struct filter *mfilter;
- struct filter_cisco *filter;
- struct access_list *access;
- struct in_addr addr;
- struct in_addr addr_mask;
- struct in_addr mask;
- struct in_addr mask_mask;
- int64_t seqnum = -1;
-
- if (seq)
- seqnum = (int64_t)atol(seq);
-
- /* Check of filter type. */
- if (type_str) {
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "%% filter type must be permit or deny\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- ret = inet_aton(addr_str, &addr);
- if (ret <= 0) {
- vty_out(vty, "%%Inconsistent address and mask\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ret = inet_aton(addr_mask_str, &addr_mask);
- if (ret <= 0) {
- vty_out(vty, "%%Inconsistent address and mask\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (extended) {
- ret = inet_aton(mask_str, &mask);
- if (ret <= 0) {
- vty_out(vty, "%%Inconsistent address and mask\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ret = inet_aton(mask_mask_str, &mask_mask);
- if (ret <= 0) {
- vty_out(vty, "%%Inconsistent address and mask\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- mfilter = filter_new();
- mfilter->type = type;
- mfilter->cisco = 1;
- mfilter->seq = seqnum;
- filter = &mfilter->u.cfilter;
- filter->extended = extended;
- filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
- filter->addr_mask.s_addr = addr_mask.s_addr;
-
- if (extended) {
- filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr;
- filter->mask_mask.s_addr = mask_mask.s_addr;
- }
-
- /* Install new filter to the access_list. */
- access = access_list_get(AFI_IP, name_str);
-
- if (set) {
- if (filter_lookup_cisco(access, mfilter))
- filter_free(mfilter);
- else
- access_list_filter_add(access, mfilter);
- } else {
- struct filter *delete_filter;
-
- delete_filter = filter_lookup_cisco(access, mfilter);
- if (delete_filter)
- access_list_filter_delete(access, delete_filter);
-
- filter_free(mfilter);
- }
-
- return CMD_SUCCESS;
-}
-
-/* Standard access-list */
-DEFUN (access_list_standard,
- access_list_standard_cmd,
- "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Address to match\n"
- "Wildcard bits\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
- char *wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- address = argv[idx]->arg;
- wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, wildcard, NULL, NULL, 0, 1);
-}
-
-DEFUN (access_list_standard_nomask,
- access_list_standard_nomask_cmd,
- "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Address to match\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- address = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, "0.0.0.0", NULL, NULL, 0, 1);
-}
-
-DEFUN (access_list_standard_host,
- access_list_standard_host_cmd,
- "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A single host address\n"
- "Address to match\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- address = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, "0.0.0.0", NULL, NULL, 0, 1);
-}
-
-DEFUN (access_list_standard_any,
- access_list_standard_any_cmd,
- "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any source host\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 1);
-}
-
-DEFUN (no_access_list_standard,
- no_access_list_standard_cmd,
- "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Address to match\n"
- "Wildcard bits\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
- char *wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- address = argv[idx]->arg;
- wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, wildcard, NULL, NULL, 0, 0);
-}
-
-DEFUN (no_access_list_standard_nomask,
- no_access_list_standard_nomask_cmd,
- "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Address to match\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- address = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, "0.0.0.0", NULL, NULL, 0, 0);
-}
-
-DEFUN (no_access_list_standard_host,
- no_access_list_standard_host_cmd,
- "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A single host address\n"
- "Address to match\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *address = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- address = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- address, "0.0.0.0", NULL, NULL, 0, 0);
-}
-
-DEFUN (no_access_list_standard_any,
- no_access_list_standard_any_cmd,
- "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP standard access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any source host\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 0);
-}
-
-/* Extended access-list */
-DEFUN (access_list_extended,
- access_list_extended_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *src_wildcard = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- dst = argv[idx + 2]->arg;
- dst_wildcard = argv[idx + 3]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, dst, dst_wildcard, 1, 1);
-}
-
-DEFUN (access_list_extended_mask_any,
- access_list_extended_mask_any_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "Any destination host\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *src_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, "0.0.0.0", "255.255.255.255", 1,
- 1);
-}
-
-DEFUN (access_list_extended_any_mask,
- access_list_extended_any_mask_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *dst = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- dst = argv[idx]->arg;
- dst_wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
- 1, 1);
-}
-
-DEFUN (access_list_extended_any_any,
- access_list_extended_any_any_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "Any destination host\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", "0.0.0.0",
- "255.255.255.255", 1, 1);
-}
-
-DEFUN (access_list_extended_mask_host,
- access_list_extended_mask_host_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *src_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- dst = argv[idx + 3]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, dst, "0.0.0.0", 1, 1);
-}
-
-DEFUN (access_list_extended_host_mask,
- access_list_extended_host_mask_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- dst = argv[idx + 1]->arg;
- dst_wildcard = argv[idx + 2]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", dst, dst_wildcard, 1, 1);
-}
-
-DEFUN (access_list_extended_host_host,
- access_list_extended_host_host_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- dst = argv[idx + 2]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", dst, "0.0.0.0", 1, 1);
-}
-
-DEFUN (access_list_extended_any_host,
- access_list_extended_any_host_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *dst = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- dst = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
- 1);
-}
-
-DEFUN (access_list_extended_host_any,
- access_list_extended_host_any_cmd,
- "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "Any destination host\n")
-{
- int idx_acl = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- src = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 1);
-}
-
-DEFUN (no_access_list_extended,
- no_access_list_extended_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *src_wildcard = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- dst = argv[idx + 2]->arg;
- dst_wildcard = argv[idx + 3]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, dst, dst_wildcard, 1, 0);
-}
-
-DEFUN (no_access_list_extended_mask_any,
- no_access_list_extended_mask_any_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "Any destination host\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *src_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, "0.0.0.0", "255.255.255.255", 1,
- 0);
-}
-
-DEFUN (no_access_list_extended_any_mask,
- no_access_list_extended_any_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *dst = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- dst = argv[idx]->arg;
- dst_wildcard = argv[idx + 1]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
- 1, 0);
-}
-
-DEFUN (no_access_list_extended_any_any,
- no_access_list_extended_any_any_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "Any destination host\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", "0.0.0.0",
- "255.255.255.255", 1, 0);
-}
-
-DEFUN (no_access_list_extended_mask_host,
- no_access_list_extended_mask_host_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Source address\n"
- "Source wildcard bits\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *src_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- src_wildcard = argv[idx + 1]->arg;
- dst = argv[idx + 3]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- src_wildcard, dst, "0.0.0.0", 1, 0);
-}
-
-DEFUN (no_access_list_extended_host_mask,
- no_access_list_extended_host_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "Destination address\n"
- "Destination Wildcard bits\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
- char *dst_wildcard = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- dst = argv[idx + 1]->arg;
- dst_wildcard = argv[idx + 2]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", dst, dst_wildcard, 1, 0);
-}
-
-DEFUN (no_access_list_extended_host_host,
- no_access_list_extended_host_host_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
- char *dst = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx) {
- src = argv[idx]->arg;
- dst = argv[idx + 2]->arg;
- }
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", dst, "0.0.0.0", 1, 0);
-}
-
-DEFUN (no_access_list_extended_any_host,
- no_access_list_extended_any_host_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "Any source host\n"
- "A single destination host\n"
- "Destination address\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *dst = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- dst = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
- "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
- 0);
-}
-
-DEFUN (no_access_list_extended_host_any,
- no_access_list_extended_host_any_cmd,
- "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
- NO_STR
- "Add an access list entry\n"
- "IP extended access list\n"
- "IP extended access list (expanded range)\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any Internet Protocol\n"
- "A single source host\n"
- "Source address\n"
- "Any destination host\n")
-{
- int idx_acl = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *src = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D", &idx);
- if (idx)
- src = argv[idx]->arg;
-
- return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
- "0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 0);
-}
-
-static int filter_set_zebra(struct vty *vty, const char *name_str,
- const char *seq, const char *type_str, afi_t afi,
- const char *prefix_str, int exact, int set)
-{
- int ret;
- enum filter_type type = FILTER_DENY;
- struct filter *mfilter;
- struct filter_zebra *filter;
- struct access_list *access;
- struct prefix p;
- int64_t seqnum = -1;
-
- if (strlen(name_str) > ACL_NAMSIZ) {
- vty_out(vty,
- "%% ACL name %s is invalid: length exceeds "
- "%d characters\n",
- name_str, ACL_NAMSIZ);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (seq)
- seqnum = (int64_t)atol(seq);
-
- /* Check of filter type. */
- if (type_str) {
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "filter type must be [permit|deny]\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- /* Check string format of prefix and prefixlen. */
- if (afi == AFI_IP) {
- ret = str2prefix_ipv4(prefix_str, (struct prefix_ipv4 *)&p);
- if (ret <= 0) {
- vty_out(vty,
- "IP address prefix/prefixlen is malformed\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else if (afi == AFI_IP6) {
- ret = str2prefix_ipv6(prefix_str, (struct prefix_ipv6 *)&p);
- if (ret <= 0) {
- vty_out(vty,
- "IPv6 address prefix/prefixlen is malformed\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else if (afi == AFI_L2VPN) {
- ret = str2prefix_eth(prefix_str, (struct prefix_eth *)&p);
- if (ret <= 0) {
- vty_out(vty, "MAC address is malformed\n");
- return CMD_WARNING;
- }
- } else
- return CMD_WARNING_CONFIG_FAILED;
-
- mfilter = filter_new();
- mfilter->type = type;
- mfilter->seq = seqnum;
- filter = &mfilter->u.zfilter;
- prefix_copy(&filter->prefix, &p);
-
- /* "exact-match" */
- if (exact)
- filter->exact = 1;
-
- /* Install new filter to the access_list. */
- access = access_list_get(afi, name_str);
-
- if (set) {
- if (filter_lookup_zebra(access, mfilter))
- filter_free(mfilter);
- else
- access_list_filter_add(access, mfilter);
- } else {
- struct filter *delete_filter;
- delete_filter = filter_lookup_zebra(access, mfilter);
- if (delete_filter)
- access_list_filter_delete(access, delete_filter);
-
- filter_free(mfilter);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (mac_access_list,
- mac_access_list_cmd,
- "mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
- "Add a mac access-list\n"
- "Add an access list entry\n"
- "MAC zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "MAC address to match. e.g. 00:01:00:01:00:01\n")
-{
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *mac = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "X:X:X:X:X:X", &idx);
- if (idx)
- mac = argv[idx]->arg;
- assert(mac);
-
- return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
- mac, 0, 1);
-}
-
-DEFUN (no_mac_access_list,
- no_mac_access_list_cmd,
- "no mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
- NO_STR
- "Remove a mac access-list\n"
- "Remove an access list entry\n"
- "MAC zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "MAC address to match. e.g. 00:01:00:01:00:01\n")
-{
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *mac = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "X:X:X:X:X:X", &idx);
- if (idx)
- mac = argv[idx]->arg;
- assert(mac);
-
- return filter_set_zebra(vty, argv[3]->arg, seq, permit_deny, AFI_L2VPN,
- mac, 0, 0);
-}
-
-DEFUN (mac_access_list_any,
- mac_access_list_any_cmd,
- "mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
- "Add a mac access-list\n"
- "Add an access list entry\n"
- "MAC zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "MAC address to match. e.g. 00:01:00:01:00:01\n")
-{
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
- "00:00:00:00:00:00", 0, 1);
-}
-
-DEFUN (no_mac_access_list_any,
- no_mac_access_list_any_cmd,
- "no mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
- NO_STR
- "Remove a mac access-list\n"
- "Remove an access list entry\n"
- "MAC zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "MAC address to match. e.g. 00:01:00:01:00:01\n")
-{
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
- "00:00:00:00:00:00", 0, 0);
-}
-
-DEFUN (access_list_exact,
- access_list_exact_cmd,
- "access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
- "Add an access list entry\n"
- "IP zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Prefix to match. e.g. 10.0.0.0/8\n"
- "Exact match of the prefixes\n")
-{
- int idx = 0;
- int exact = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *prefix = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D/M", &idx);
- if (idx)
- prefix = argv[idx]->arg;
- assert(prefix);
-
- idx = 0;
- if (argv_find(argv, argc, "exact-match", &idx))
- exact = 1;
-
- return filter_set_zebra(vty, argv[1]->arg, seq, permit_deny,
- AFI_IP, prefix, exact, 1);
-}
-
-DEFUN (access_list_any,
- access_list_any_cmd,
- "access-list WORD [seq (1-4294967295)] <deny|permit> any",
- "Add an access list entry\n"
- "IP zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Prefix to match. e.g. 10.0.0.0/8\n")
-{
- int idx_word = 1;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP, "0.0.0.0/0", 0, 1);
-}
-
-DEFUN (no_access_list_exact,
- no_access_list_exact_cmd,
- "no access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
- NO_STR
- "Add an access list entry\n"
- "IP zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Prefix to match. e.g. 10.0.0.0/8\n"
- "Exact match of the prefixes\n")
-{
- int idx = 0;
- int exact = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *prefix = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "A.B.C.D/M", &idx);
- if (idx)
- prefix = argv[idx]->arg;
- assert(prefix);
-
- idx = 0;
- if (argv_find(argv, argc, "exact-match", &idx))
- exact = 1;
-
- return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny,
- AFI_IP, prefix, exact, 0);
-}
-
-DEFUN (no_access_list_any,
- no_access_list_any_cmd,
- "no access-list WORD [seq (1-4294967295)] <deny|permit> any",
- NO_STR
- "Add an access list entry\n"
- "IP zebra access-list name\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Prefix to match. e.g. 10.0.0.0/8\n")
-{
- int idx_word = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP, "0.0.0.0/0", 0, 0);
-}
-
-DEFUN (no_access_list_all,
- no_access_list_all_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP extended access list\n"
- "IP standard access list (expanded range)\n"
- "IP extended access list (expanded range)\n"
- "IP zebra access-list name\n")
-{
- int idx_acl = 2;
- struct access_list *access;
- struct access_master *master;
-
- /* Looking up access_list. */
- access = access_list_lookup(AFI_IP, argv[idx_acl]->arg);
- if (access == NULL) {
- vty_out(vty, "%% access-list %s doesn't exist\n",
- argv[idx_acl]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- master = access->master;
-
- route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
- /* Run hook function. */
- if (master->delete_hook)
- (*master->delete_hook)(access);
-
- /* Delete all filter from access-list. */
- access_list_delete(access);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (access_list_remark,
- access_list_remark_cmd,
- "access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> remark LINE...",
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP extended access list\n"
- "IP standard access list (expanded range)\n"
- "IP extended access list (expanded range)\n"
- "IP zebra access-list\n"
- "Access list entry comment\n"
- "Comment up to 100 characters\n")
-{
- int idx_acl = 1;
- int idx_remark = 3;
- struct access_list *access;
-
- access = access_list_get(AFI_IP, argv[idx_acl]->arg);
-
- if (access->remark) {
- XFREE(MTYPE_TMP, access->remark);
- access->remark = NULL;
- }
- access->remark = argv_concat(argv, argc, idx_remark);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_access_list_remark,
- no_access_list_remark_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> remark",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP extended access list\n"
- "IP standard access list (expanded range)\n"
- "IP extended access list (expanded range)\n"
- "IP zebra access-list\n"
- "Access list entry comment\n")
-{
- int idx_acl = 2;
- return vty_access_list_remark_unset(vty, AFI_IP, argv[idx_acl]->arg);
-}
-
-/* ALIAS_FIXME */
-DEFUN (no_access_list_remark_comment,
- no_access_list_remark_comment_cmd,
- "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> remark LINE...",
- NO_STR
- "Add an access list entry\n"
- "IP standard access list\n"
- "IP extended access list\n"
- "IP standard access list (expanded range)\n"
- "IP extended access list (expanded range)\n"
- "IP zebra access-list\n"
- "Access list entry comment\n"
- "Comment up to 100 characters\n")
-{
- return no_access_list_remark(self, vty, argc, argv);
-}
-
-DEFUN (ipv6_access_list_exact,
- ipv6_access_list_exact_cmd,
- "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "IPv6 prefix\n"
- "Exact match of the prefixes\n")
-{
- int idx = 0;
- int exact = 0;
- int idx_word = 2;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *prefix = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "X:X::X:X/M", &idx);
- if (idx)
- prefix = argv[idx]->arg;
-
- idx = 0;
- if (argv_find(argv, argc, "exact-match", &idx))
- exact = 1;
-
- assert(prefix);
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP6, prefix, exact, 1);
-}
-
-DEFUN (ipv6_access_list_any,
- ipv6_access_list_any_cmd,
- "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any prefixi to match\n")
-{
- int idx_word = 2;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP6, "::/0", 0, 1);
-}
-
-DEFUN (no_ipv6_access_list_exact,
- no_ipv6_access_list_exact_cmd,
- "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
- NO_STR
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Prefix to match. e.g. 3ffe:506::/32\n"
- "Exact match of the prefixes\n")
-{
- int idx = 0;
- int exact = 0;
- int idx_word = 3;
- char *seq = NULL;
- char *permit_deny = NULL;
- char *prefix = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "X:X::X:X/M", &idx);
- if (idx)
- prefix = argv[idx]->arg;
- assert(prefix);
-
- idx = 0;
- if (argv_find(argv, argc, "exact-match", &idx))
- exact = 1;
-
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP6, prefix, exact, 0);
-}
-
-DEFUN (no_ipv6_access_list_any,
- no_ipv6_access_list_any_cmd,
- "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
- NO_STR
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Sequence number of an entry\n"
- "Sequence number\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "Any prefixi to match\n")
-{
- int idx_word = 3;
- int idx = 0;
- char *seq = NULL;
- char *permit_deny = NULL;
-
- argv_find(argv, argc, "(1-4294967295)", &idx);
- if (idx)
- seq = argv[idx]->arg;
-
- idx = 0;
- argv_find(argv, argc, "permit", &idx);
- argv_find(argv, argc, "deny", &idx);
- if (idx)
- permit_deny = argv[idx]->arg;
-
- return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
- AFI_IP6, "::/0", 0, 0);
-}
-
-
-DEFUN (no_ipv6_access_list_all,
- no_ipv6_access_list_all_cmd,
- "no ipv6 access-list WORD",
- NO_STR
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n")
-{
- int idx_word = 3;
- struct access_list *access;
- struct access_master *master;
-
- /* Looking up access_list. */
- access = access_list_lookup(AFI_IP6, argv[idx_word]->arg);
- if (access == NULL) {
- vty_out(vty, "%% access-list %s doesn't exist\n",
- argv[idx_word]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- master = access->master;
-
- route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
- /* Run hook function. */
- if (master->delete_hook)
- (*master->delete_hook)(access);
-
- /* Delete all filter from access-list. */
- access_list_delete(access);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (ipv6_access_list_remark,
- ipv6_access_list_remark_cmd,
- "ipv6 access-list WORD remark LINE...",
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Access list entry comment\n"
- "Comment up to 100 characters\n")
-{
- int idx_word = 2;
- int idx_line = 4;
- struct access_list *access;
-
- access = access_list_get(AFI_IP6, argv[idx_word]->arg);
-
- if (access->remark) {
- XFREE(MTYPE_TMP, access->remark);
- access->remark = NULL;
- }
- access->remark = argv_concat(argv, argc, idx_line);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ipv6_access_list_remark,
- no_ipv6_access_list_remark_cmd,
- "no ipv6 access-list WORD remark",
- NO_STR
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Access list entry comment\n")
-{
- int idx_word = 3;
- return vty_access_list_remark_unset(vty, AFI_IP6, argv[idx_word]->arg);
-}
-
-/* ALIAS_FIXME */
-DEFUN (no_ipv6_access_list_remark_comment,
- no_ipv6_access_list_remark_comment_cmd,
- "no ipv6 access-list WORD remark LINE...",
- NO_STR
- IPV6_STR
- "Add an access list entry\n"
- "IPv6 zebra access-list\n"
- "Access list entry comment\n"
- "Comment up to 100 characters\n")
-{
- return no_ipv6_access_list_remark(self, vty, argc, argv);
-}
-
static void config_write_access_zebra(struct vty *, struct filter *);
static void config_write_access_cisco(struct vty *, struct filter *);
@@ -2747,86 +776,12 @@ static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
vty_out(vty, "\n");
}
-static int config_write_access(struct vty *vty, afi_t afi)
-{
- struct access_list *access;
- struct access_master *master;
- struct filter *mfilter;
- int write = 0;
-
- master = access_master_get(afi);
- if (master == NULL)
- return 0;
-
- for (access = master->num.head; access; access = access->next) {
- if (access->remark) {
- vty_out(vty, "%saccess-list %s remark %s\n",
- (afi == AFI_IP) ? ("")
- : ((afi == AFI_IP6) ? ("ipv6 ")
- : ("mac ")),
- access->name, access->remark);
- write++;
- }
-
- for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
- (afi == AFI_IP) ? ("")
- : ((afi == AFI_IP6) ? ("ipv6 ")
- : ("mac ")),
- access->name, mfilter->seq,
- filter_type_str(mfilter));
-
- if (mfilter->cisco)
- config_write_access_cisco(vty, mfilter);
- else
- config_write_access_zebra(vty, mfilter);
-
- write++;
- }
- }
-
- for (access = master->str.head; access; access = access->next) {
- if (access->remark) {
- vty_out(vty, "%saccess-list %s remark %s\n",
- (afi == AFI_IP) ? ("")
- : ((afi == AFI_IP6) ? ("ipv6 ")
- : ("mac ")),
- access->name, access->remark);
- write++;
- }
-
- for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
- (afi == AFI_IP) ? ("")
- : ((afi == AFI_IP6) ? ("ipv6 ")
- : ("mac ")),
- access->name, mfilter->seq,
- filter_type_str(mfilter));
-
- if (mfilter->cisco)
- config_write_access_cisco(vty, mfilter);
- else
- config_write_access_zebra(vty, mfilter);
-
- write++;
- }
- }
- return write;
-}
-
-static int config_write_access_mac(struct vty *vty);
static struct cmd_node access_mac_node = {
.name = "MAC access list",
.node = ACCESS_MAC_NODE,
.prompt = "",
- .config_write = config_write_access_mac,
};
-static int config_write_access_mac(struct vty *vty)
-{
- return config_write_access(vty, AFI_L2VPN);
-}
-
static void access_list_reset_mac(void)
{
struct access_list *access;
@@ -2860,26 +815,29 @@ static void access_list_init_mac(void)
install_element(ENABLE_NODE, &show_mac_access_list_cmd);
install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
-
- /* Zebra access-list */
- install_element(CONFIG_NODE, &mac_access_list_cmd);
- install_element(CONFIG_NODE, &no_mac_access_list_cmd);
- install_element(CONFIG_NODE, &mac_access_list_any_cmd);
- install_element(CONFIG_NODE, &no_mac_access_list_any_cmd);
}
/* Access-list node. */
-static int config_write_access_ipv4(struct vty *vty);
+static int config_write_access(struct vty *vty);
static struct cmd_node access_node = {
.name = "ipv4 access list",
.node = ACCESS_NODE,
.prompt = "",
- .config_write = config_write_access_ipv4,
+ .config_write = config_write_access,
};
-static int config_write_access_ipv4(struct vty *vty)
+static int config_write_access(struct vty *vty)
{
- return config_write_access(vty, AFI_IP);
+ struct lyd_node *dnode;
+ int written = 0;
+
+ dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib");
+ if (dnode) {
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ written = 1;
+ }
+
+ return written;
}
static void access_list_reset_ipv4(void)
@@ -2915,62 +873,14 @@ static void access_list_init_ipv4(void)
install_element(ENABLE_NODE, &show_ip_access_list_cmd);
install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
-
- /* Zebra access-list */
- install_element(CONFIG_NODE, &access_list_exact_cmd);
- install_element(CONFIG_NODE, &access_list_any_cmd);
- install_element(CONFIG_NODE, &no_access_list_exact_cmd);
- install_element(CONFIG_NODE, &no_access_list_any_cmd);
-
- /* Standard access-list */
- install_element(CONFIG_NODE, &access_list_standard_cmd);
- install_element(CONFIG_NODE, &access_list_standard_nomask_cmd);
- install_element(CONFIG_NODE, &access_list_standard_host_cmd);
- install_element(CONFIG_NODE, &access_list_standard_any_cmd);
- install_element(CONFIG_NODE, &no_access_list_standard_cmd);
- install_element(CONFIG_NODE, &no_access_list_standard_nomask_cmd);
- install_element(CONFIG_NODE, &no_access_list_standard_host_cmd);
- install_element(CONFIG_NODE, &no_access_list_standard_any_cmd);
-
- /* Extended access-list */
- install_element(CONFIG_NODE, &access_list_extended_cmd);
- install_element(CONFIG_NODE, &access_list_extended_any_mask_cmd);
- install_element(CONFIG_NODE, &access_list_extended_mask_any_cmd);
- install_element(CONFIG_NODE, &access_list_extended_any_any_cmd);
- install_element(CONFIG_NODE, &access_list_extended_host_mask_cmd);
- install_element(CONFIG_NODE, &access_list_extended_mask_host_cmd);
- install_element(CONFIG_NODE, &access_list_extended_host_host_cmd);
- install_element(CONFIG_NODE, &access_list_extended_any_host_cmd);
- install_element(CONFIG_NODE, &access_list_extended_host_any_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_any_mask_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_mask_any_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_any_any_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_host_mask_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_mask_host_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_host_host_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_any_host_cmd);
- install_element(CONFIG_NODE, &no_access_list_extended_host_any_cmd);
-
- install_element(CONFIG_NODE, &access_list_remark_cmd);
- install_element(CONFIG_NODE, &no_access_list_all_cmd);
- install_element(CONFIG_NODE, &no_access_list_remark_cmd);
- install_element(CONFIG_NODE, &no_access_list_remark_comment_cmd);
}
-static int config_write_access_ipv6(struct vty *vty);
static struct cmd_node access_ipv6_node = {
.name = "ipv6 access list",
.node = ACCESS_IPV6_NODE,
.prompt = "",
- .config_write = config_write_access_ipv6,
};
-static int config_write_access_ipv6(struct vty *vty)
-{
- return config_write_access(vty, AFI_IP6);
-}
-
static void access_list_reset_ipv6(void)
{
struct access_list *access;
@@ -3003,16 +913,6 @@ static void access_list_init_ipv6(void)
install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
-
- install_element(CONFIG_NODE, &ipv6_access_list_exact_cmd);
- install_element(CONFIG_NODE, &ipv6_access_list_any_cmd);
- install_element(CONFIG_NODE, &no_ipv6_access_list_exact_cmd);
- install_element(CONFIG_NODE, &no_ipv6_access_list_any_cmd);
-
- install_element(CONFIG_NODE, &no_ipv6_access_list_all_cmd);
- install_element(CONFIG_NODE, &ipv6_access_list_remark_cmd);
- install_element(CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
- install_element(CONFIG_NODE, &no_ipv6_access_list_remark_comment_cmd);
}
void access_list_init(void)
@@ -3020,6 +920,8 @@ void access_list_init(void)
access_list_init_ipv4();
access_list_init_ipv6();
access_list_init_mac();
+
+ filter_cli_init();
}
void access_list_reset(void)
diff --git a/lib/filter.h b/lib/filter.h
index 3dd2eaaf15..76e992bf8e 100644
--- a/lib/filter.h
+++ b/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
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
new file mode 100644
index 0000000000..0091d8b03f
--- /dev/null
+++ b/lib/filter_cli.c
@@ -0,0 +1,1693 @@
+/*
+ * FRR filter CLI implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include "northbound.h"
+#include "prefix.h"
+#include "zebra.h"
+
+#include "lib/command.h"
+#include "lib/filter.h"
+#include "lib/northbound_cli.h"
+#include "lib/plist.h"
+#include "lib/plist_int.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/filter_cli_clippy.c"
+#endif /* VTYSH_EXTRACT_PL */
+
+#define ACCESS_LIST_STR "Access list entry\n"
+#define ACCESS_LIST_LEG_STR "IP standard access list\n"
+#define ACCESS_LIST_LEG_EXT_STR "IP standard access list (expanded range)\n"
+#define ACCESS_LIST_ELEG_STR "IP extended access list\n"
+#define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n"
+#define ACCESS_LIST_XLEG_STR \
+ ACCESS_LIST_LEG_STR \
+ ACCESS_LIST_LEG_EXT_STR \
+ ACCESS_LIST_ELEG_STR \
+ ACCESS_LIST_ELEG_EXT_STR
+#define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
+#define ACCESS_LIST_SEQ_STR \
+ "Sequence number of an entry\n" \
+ "Sequence number\n"
+#define ACCESS_LIST_ACTION_STR \
+ "Specify packets to reject\n" \
+ "Specify packets to forward\n"
+#define ACCESS_LIST_REMARK_STR "Access list entry comment\n"
+#define ACCESS_LIST_REMARK_LINE_STR "Comment up to 100 characters\n"
+
+#define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
+
+/*
+ * Helper function to locate filter data structures for Cisco-style ACLs.
+ */
+static int64_t acl_cisco_get_seq(struct access_list *acl, const char *action,
+ const char *src, const char *src_mask,
+ const char *dst, const char *dst_mask)
+{
+ struct filter_cisco *fc;
+ struct filter f, *fn;
+
+ memset(&f, 0, sizeof(f));
+ memset(&fc, 0, sizeof(fc));
+ f.cisco = 1;
+ if (strcmp(action, "permit") == 0)
+ f.type = FILTER_PERMIT;
+ else
+ f.type = FILTER_DENY;
+
+ fc = &f.u.cfilter;
+ inet_pton(AF_INET, src, &fc->addr);
+ inet_pton(AF_INET, src_mask, &fc->addr_mask);
+ fc->addr.s_addr &= ~fc->addr_mask.s_addr;
+ if (dst != NULL) {
+ fc->extended = 1;
+ inet_pton(AF_INET, dst, &fc->mask);
+ inet_pton(AF_INET, dst_mask, &fc->mask_mask);
+ fc->mask.s_addr &= ~fc->mask_mask.s_addr;
+ }
+
+ fn = filter_lookup_cisco(acl, &f);
+ if (fn == NULL)
+ return -1;
+
+ return fn->seq;
+}
+
+/*
+ * Helper function to locate filter data structures for zebra-style ACLs.
+ */
+static int64_t acl_zebra_get_seq(struct access_list *acl, const char *action,
+ const struct prefix *p, bool exact)
+{
+ struct filter_zebra *fz;
+ struct filter f, *fn;
+
+ memset(&f, 0, sizeof(f));
+ memset(&fz, 0, sizeof(fz));
+ if (strcmp(action, "permit") == 0)
+ f.type = FILTER_PERMIT;
+ else
+ f.type = FILTER_DENY;
+
+ fz = &f.u.zfilter;
+ fz->prefix = *p;
+ fz->exact = exact;
+
+ fn = filter_lookup_zebra(acl, &f);
+ if (fn == NULL)
+ return -1;
+
+ return fn->seq;
+}
+
+/*
+ * Helper function to concatenate address with mask in Cisco style.
+ */
+static void concat_addr_mask_v4(const char *addr, const char *mask, char *dst,
+ size_t dstlen)
+{
+ struct in_addr ia;
+ int plen;
+
+ assert(inet_pton(AF_INET, mask, &ia) == 1);
+ plen = ip_masklen(ia);
+ snprintf(dst, dstlen, "%s/%d", addr, plen);
+}
+
+/*
+ * Helper function to generate a sequence number for legacy commands.
+ */
+static int acl_get_seq_cb(const struct lyd_node *dnode, void *arg)
+{
+ int64_t *seq = arg;
+ int64_t cur_seq = yang_dnode_get_uint32(dnode, "sequence");
+
+ if (cur_seq > *seq)
+ *seq = cur_seq;
+
+ return YANG_ITER_CONTINUE;
+}
+
+/**
+ * Helper function that iterates over the XPath `xpath` on the candidate
+ * configuration in `vty->candidate_config`.
+ *
+ * \param[in] vty shell context with the candidate configuration.
+ * \param[in] xpath the XPath to look for the sequence leaf.
+ * \returns next unused sequence number.
+ */
+static long acl_get_seq(struct vty *vty, const char *xpath)
+{
+ int64_t seq = 0;
+
+ yang_dnode_iterate(acl_get_seq_cb, &seq, vty->candidate_config->dnode,
+ "%s/entry", xpath);
+
+ return seq + 5;
+}
+
+/*
+ * Cisco (legacy) access lists.
+ */
+DEFPY(
+ access_list_std, access_list_std_cmd,
+ "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ ACCESS_LIST_STR
+ ACCESS_LIST_LEG_STR
+ ACCESS_LIST_LEG_EXT_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "A single host address\n"
+ "Address to match\n"
+ "Address to match\n"
+ "Wildcard bits\n"
+ "Any source host\n")
+{
+ int64_t sseq;
+ char ipmask[64];
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the access-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (host_str != NULL && mask_str == NULL) {
+ nb_cli_enqueue_change(vty, "./host", NB_OP_MODIFY, host_str);
+ } else if (host_str != NULL && mask_str != NULL) {
+ concat_addr_mask_v4(host_str, mask_str, ipmask, sizeof(ipmask));
+ nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask);
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_access_list_std, no_access_list_std_cmd,
+ "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_LEG_STR
+ ACCESS_LIST_LEG_EXT_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "A single host address\n"
+ "Address to match\n"
+ "Address to match\n"
+ "Wildcard bits\n"
+ "Any source host\n")
+{
+ struct access_list *acl;
+ struct lyd_node *dnode;
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq_str != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
+ number_str, seq_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ acl = nb_running_get_entry(dnode, NULL, true);
+ if (host_str != NULL)
+ sseq = acl_cisco_get_seq(acl, action, host_str,
+ mask_str ? mask_str : "0.0.0.0", NULL,
+ NULL);
+ else
+ sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
+ "255.255.255.255", NULL, NULL);
+ if (sseq == -1)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ access_list_ext, access_list_ext_cmd,
+ "access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ ACCESS_LIST_STR
+ ACCESS_LIST_ELEG_STR
+ ACCESS_LIST_ELEG_EXT_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "IPv4 address\n"
+ "Source address to match\n"
+ "Source address mask to apply\n"
+ "Single source host\n"
+ "Source address to match\n"
+ "Any source host\n"
+ "Destination address to match\n"
+ "Destination address mask to apply\n"
+ "Single destination host\n"
+ "Destination address to match\n"
+ "Any destination host\n")
+{
+ int64_t sseq;
+ char ipmask[64];
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the access-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (src_str != NULL && src_mask_str == NULL) {
+ nb_cli_enqueue_change(vty, "./host", NB_OP_MODIFY, src_str);
+ } else if (src_str != NULL && src_mask_str != NULL) {
+ concat_addr_mask_v4(src_str, src_mask_str, ipmask,
+ sizeof(ipmask));
+ nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask);
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ if (dst_str != NULL && dst_mask_str == NULL) {
+ nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY,
+ src_str);
+ } else if (dst_str != NULL && dst_mask_str != NULL) {
+ concat_addr_mask_v4(dst_str, dst_mask_str, ipmask,
+ sizeof(ipmask));
+ nb_cli_enqueue_change(vty, "./destination-network",
+ NB_OP_MODIFY, ipmask);
+ } else {
+ nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,
+ NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_access_list_ext, no_access_list_ext_cmd,
+ "no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ELEG_STR
+ ACCESS_LIST_ELEG_EXT_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "Any Internet Protocol\n"
+ "Source address to match\n"
+ "Source address mask to apply\n"
+ "Single source host\n"
+ "Source address to match\n"
+ "Any source host\n"
+ "Destination address to match\n"
+ "Destination address mask to apply\n"
+ "Single destination host\n"
+ "Destination address to match\n"
+ "Any destination host\n")
+{
+ struct access_list *acl;
+ struct lyd_node *dnode;
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq_str != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
+ number_str, seq_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ acl = nb_running_get_entry(dnode, NULL, true);
+ if (src_str != NULL) {
+ if (dst_str != NULL)
+ sseq = acl_cisco_get_seq(
+ acl, action, src_str,
+ src_mask_str ? src_mask_str : "0.0.0.0",
+ dst_str,
+ dst_mask_str ? dst_mask_str : "0.0.0.0");
+ else
+ sseq = acl_cisco_get_seq(acl, action, src_str,
+ src_mask_str ? src_mask_str
+ : "0.0.0.0",
+ "0.0.0.0", "255.255.255.255");
+ } else {
+ if (dst_str != NULL)
+ sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
+ "255.255.255.255", dst_str,
+ dst_mask_str ? dst_mask_str
+ : "0.0.0.0");
+ else
+ sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
+ "255.255.255.255", "0.0.0.0",
+ "255.255.255.255");
+ }
+ if (sseq == -1)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_access_list_legacy, no_access_list_legacy_cmd,
+ "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_XLEG_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ uint16_t number = yang_dnode_get_uint16(dnode, "../number");
+ bool extended;
+ struct prefix p;
+ struct in_addr mask;
+
+ vty_out(vty, "access-list %d seq %s %s", number,
+ yang_dnode_get_string(dnode, "./sequence"),
+ yang_dnode_get_string(dnode, "./action"));
+
+ extended = (number >= 100 && number <= 199)
+ || (number >= 2000 && number <= 2699);
+ if (extended)
+ vty_out(vty, " ip");
+
+ if (yang_dnode_exists(dnode, "./network")) {
+ yang_dnode_get_prefix(&p, dnode, "./network");
+ masklen2ip(p.prefixlen, &mask);
+ vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
+ } else if (yang_dnode_exists(dnode, "./host")) {
+ if (extended)
+ vty_out(vty, " host");
+
+ vty_out(vty, " %s", yang_dnode_get_string(dnode, "./host"));
+ } else if (yang_dnode_exists(dnode, "./any"))
+ vty_out(vty, " any");
+
+ if (extended) {
+ if (yang_dnode_exists(dnode, "./destination-network")) {
+ yang_dnode_get_prefix(&p, dnode,
+ "./destination-network");
+ masklen2ip(p.prefixlen, &mask);
+ vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask);
+ } else if (yang_dnode_exists(dnode, "./destination-host"))
+ vty_out(vty, " host %s",
+ yang_dnode_get_string(dnode,
+ "./destination-host"));
+ else if (yang_dnode_exists(dnode, "./destination-any"))
+ vty_out(vty, " any");
+ }
+
+ vty_out(vty, "\n");
+}
+
+DEFPY(
+ access_list_legacy_remark, access_list_legacy_remark_cmd,
+ "access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
+ ACCESS_LIST_STR
+ ACCESS_LIST_XLEG_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']", number_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 3);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_access_list_legacy_remark, no_access_list_legacy_remark_cmd,
+ "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_XLEG_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list-legacy[number='%s']/remark",
+ number_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_access_list_legacy_remark, no_access_list_legacy_remark_line_cmd,
+ "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_XLEG_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+void access_list_legacy_remark_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, "access-list %s remark %s\n",
+ yang_dnode_get_string(dnode, "../number"),
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * Zebra access lists.
+ */
+DEFPY(
+ access_list, access_list_cmd,
+ "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n"
+ "Match any IPv4\n")
+{
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the access-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (prefix_str != NULL) {
+ nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
+ prefix_str);
+ nb_cli_enqueue_change(vty, "./ipv4-exact-match", NB_OP_MODIFY,
+ exact ? "true" : "false");
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_access_list, no_access_list_cmd,
+ "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n"
+ "Match any IPv4\n")
+{
+ struct access_list *acl;
+ struct lyd_node *dnode;
+ int64_t sseq;
+ struct prefix pany;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq_str != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
+ name, seq_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ acl = nb_running_get_entry(dnode, NULL, true);
+ if (prefix == NULL) {
+ memset(&pany, 0, sizeof(pany));
+ pany.family = AF_INET;
+ sseq = acl_zebra_get_seq(acl, action, &pany, exact);
+ } else
+ sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
+ exact);
+ if (sseq == -1)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_access_list_all, no_access_list_all_cmd,
+ "no access-list WORD$name",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ access_list_remark, access_list_remark_cmd,
+ "access-list WORD$name remark LINE...",
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 3);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_access_list_remark, no_access_list_remark_cmd,
+ "no access-list WORD$name remark",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_access_list_remark, no_access_list_remark_line_cmd,
+ "no access-list WORD$name remark LINE...",
+ NO_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+DEFPY(
+ ipv6_access_list, ipv6_access_list_cmd,
+ "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "IPv6 prefix\n"
+ "Exact match of the prefixes\n"
+ "Match any IPv6\n")
+{
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the access-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (prefix_str != NULL) {
+ nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
+ prefix_str);
+ nb_cli_enqueue_change(vty, "./ipv6-exact-match", NB_OP_MODIFY,
+ exact ? "true" : "false");
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_ipv6_access_list, no_ipv6_access_list_cmd,
+ "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
+ NO_STR
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "IPv6 prefix\n"
+ "Exact match of the prefixes\n"
+ "Match any IPv6\n")
+{
+ struct access_list *acl;
+ struct lyd_node *dnode;
+ int64_t sseq;
+ struct prefix pany;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq_str != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']/entry[sequence='%s']",
+ name, seq_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ acl = nb_running_get_entry(dnode, NULL, true);
+ if (prefix == NULL) {
+ memset(&pany, 0, sizeof(pany));
+ pany.family = AF_INET6;
+ sseq = acl_zebra_get_seq(acl, action, &pany, exact);
+ } else
+ sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
+ exact);
+ if (sseq == -1)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_ipv6_access_list_all, no_ipv6_access_list_all_cmd,
+ "no ipv6 access-list WORD$name",
+ NO_STR
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ ipv6_access_list_remark, ipv6_access_list_remark_cmd,
+ "ipv6 access-list WORD$name remark LINE...",
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 4);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd,
+ "no ipv6 access-list WORD$name remark",
+ NO_STR
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd,
+ "no ipv6 access-list WORD$name remark LINE...",
+ NO_STR
+ IPV6_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+DEFPY(
+ mac_access_list, mac_access_list_cmd,
+ "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "MAC address\n"
+ "Match any MAC address\n")
+{
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the access-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (mac_str != NULL) {
+ nb_cli_enqueue_change(vty, "./mac", NB_OP_MODIFY, mac_str);
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_mac_access_list, no_mac_access_list_cmd,
+ "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>",
+ NO_STR
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "MAC address\n"
+ "Match any MAC address\n")
+{
+ struct access_list *acl;
+ struct lyd_node *dnode;
+ int64_t sseq;
+ struct prefix pany;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq_str != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']/entry[sequence='%s']",
+ name, seq_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ acl = nb_running_get_entry(dnode, NULL, true);
+ if (prefix == NULL) {
+ memset(&pany, 0, sizeof(pany));
+ pany.family = AF_ETHERNET;
+ sseq = acl_zebra_get_seq(acl, action, &pany, false);
+ } else
+ sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
+ false);
+ if (sseq == -1)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_mac_access_list_all, no_mac_access_list_all_cmd,
+ "no mac access-list WORD$name",
+ NO_STR
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ mac_access_list_remark, mac_access_list_remark_cmd,
+ "mac access-list WORD$name remark LINE...",
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 4);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_mac_access_list_remark, no_mac_access_list_remark_cmd,
+ "no mac access-list WORD$name remark",
+ NO_STR
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_mac_access_list_remark, no_mac_access_list_remark_line_cmd,
+ "no mac access-list WORD$name remark LINE...",
+ NO_STR
+ MAC_STR
+ ACCESS_LIST_STR
+ ACCESS_LIST_ZEBRA_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+void access_list_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int type = yang_dnode_get_enum(dnode, "../type");
+ struct prefix p;
+ bool is_any;
+ bool is_exact = false;
+ char macstr[PREFIX2STR_BUFFER];
+
+ is_any = yang_dnode_exists(dnode, "./any");
+ switch (type) {
+ case YALT_IPV4:
+ if (is_any)
+ break;
+
+ yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
+ is_exact = yang_dnode_get_bool(dnode, "./ipv4-exact-match");
+ break;
+ case YALT_IPV6: /* ipv6 */
+ vty_out(vty, "ipv6 ");
+ if (is_any)
+ break;
+
+ yang_dnode_get_prefix(&p, dnode, "./ipv6-prefix");
+ is_exact = yang_dnode_get_bool(dnode, "./ipv6-exact-match");
+ break;
+ case YALT_MAC: /* mac */
+ vty_out(vty, "mac ");
+ if (is_any)
+ break;
+
+ yang_dnode_get_prefix(&p, dnode, "./mac");
+ break;
+ }
+
+ vty_out(vty, "access-list %s seq %s %s",
+ yang_dnode_get_string(dnode, "../name"),
+ yang_dnode_get_string(dnode, "./sequence"),
+ yang_dnode_get_string(dnode, "./action"));
+
+ if (!is_any) {
+ /* If type is MAC don't show '/mask'. */
+ if (type == 2 /* mac */) {
+ prefix_mac2str(&p.u.prefix_eth, macstr, sizeof(macstr));
+ vty_out(vty, " %s", macstr);
+ } else
+ vty_out(vty, " %pFX", &p);
+ } else
+ vty_out(vty, " any");
+
+ if (is_exact)
+ vty_out(vty, " exact-match");
+
+ vty_out(vty, "\n");
+}
+
+void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int type = yang_dnode_get_enum(dnode, "../type");
+
+ switch (type) {
+ case YALT_IPV4:
+ break;
+ case YALT_IPV6:
+ vty_out(vty, "ipv6 ");
+ break;
+ case YALT_MAC:
+ vty_out(vty, "mac ");
+ break;
+ }
+
+ vty_out(vty, "access-list %s remark %s\n",
+ yang_dnode_get_string(dnode, "../name"),
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * Prefix lists.
+ */
+
+/**
+ * Remove main data structure prefix list if there are no more entries or
+ * remark. This fixes compatibility with old CLI and tests.
+ */
+static int plist_remove_if_empty(struct vty *vty, const char *iptype,
+ const char *name)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
+ iptype, name);
+ /* List is not empty if there is a remark, check that: */
+ if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
+ return CMD_SUCCESS;
+
+ /* Check if we have any entries: */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype,
+ name);
+ /*
+ * NOTE: if the list is empty it will return the first sequence
+ * number: 5.
+ */
+ if (acl_get_seq(vty, xpath) != 5)
+ return CMD_SUCCESS;
+
+ /* Nobody is using this list, lets remove it. */
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+static int plist_remove(struct vty *vty, const char *iptype, const char *name,
+ const char *seq, const char *action, struct prefix *p,
+ long ge, long le)
+{
+ struct prefix_list_entry *pentry;
+ enum prefix_list_type plt;
+ struct prefix_list *pl;
+ struct lyd_node *dnode;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 32];
+ int rv;
+
+ /* If the user provided sequence number, then just go for it. */
+ if (seq != NULL) {
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
+ iptype, name, seq);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return plist_remove_if_empty(vty, iptype, name);
+
+ return rv;
+ }
+
+ /* Otherwise, to keep compatibility, we need to figure it out. */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype,
+ name);
+
+ /* Access-list must exist before entries. */
+ if (yang_dnode_exists(running_config->dnode, xpath) == false)
+ return CMD_WARNING;
+
+ /* Use access-list data structure to fetch sequence. */
+ assert(action != NULL);
+ if (strcmp(action, "permit") == 0)
+ plt = PREFIX_PERMIT;
+ else
+ plt = PREFIX_DENY;
+
+ dnode = yang_dnode_get(running_config->dnode, xpath);
+ pl = nb_running_get_entry(dnode, NULL, true);
+ pentry = prefix_list_entry_lookup(pl, p, plt, -1, le, ge);
+ if (pentry == NULL)
+ return CMD_WARNING;
+
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, pentry->seq);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return plist_remove_if_empty(vty, iptype, name);
+
+ return rv;
+}
+
+DEFPY(
+ ip_prefix_list, ip_prefix_list_cmd,
+ "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>",
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "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")
+{
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the prefix-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (prefix_str != NULL) {
+ nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
+ prefix_str);
+
+ if (ge_str)
+ nb_cli_enqueue_change(
+ vty, "./ipv4-prefix-length-greater-or-equal",
+ NB_OP_MODIFY, ge_str);
+ if (le_str)
+ nb_cli_enqueue_change(
+ vty, "./ipv4-prefix-length-lesser-or-equal",
+ NB_OP_MODIFY, le_str);
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_ip_prefix_list, no_ip_prefix_list_cmd,
+ "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "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 plist_remove(vty, "ipv4", name, seq_str, action,
+ (struct prefix *)prefix, ge, le);
+}
+
+DEFPY(
+ no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
+ "no ip prefix-list WORD$name seq (1-4294967295)$seq",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR)
+{
+ return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0);
+}
+
+DEFPY(
+ no_ip_prefix_list_all, no_ip_prefix_list_all_cmd,
+ "no ip prefix-list WORD$name",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ ip_prefix_list_remark, ip_prefix_list_remark_cmd,
+ "ip prefix-list WORD$name description LINE...",
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 4);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd,
+ "no ip prefix-list WORD$name description",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_ip_prefix_list_remark, no_ip_prefix_list_remark_line_cmd,
+ "no ip prefix-list WORD$name description LINE...",
+ NO_STR
+ IP_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+DEFPY(
+ ipv6_prefix_list, ipv6_prefix_list_cmd,
+ "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "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")
+{
+ int64_t sseq;
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+
+ /*
+ * Create the prefix-list first, so we can generate sequence if
+ * none given (backward compatibility).
+ */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (seq_str == NULL) {
+ /* Use XPath to find the next sequence number. */
+ sseq = acl_get_seq(vty, xpath);
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
+ } else
+ snprintf(xpath_entry, sizeof(xpath_entry),
+ "%s/entry[sequence='%s']", xpath, seq_str);
+
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
+ if (prefix_str != NULL) {
+ nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
+ prefix_str);
+
+ if (ge_str)
+ nb_cli_enqueue_change(
+ vty, "./ipv6-prefix-length-greater-or-equal",
+ NB_OP_MODIFY, ge_str);
+ if (le_str)
+ nb_cli_enqueue_change(
+ vty, "./ipv6-prefix-length-lesser-or-equal",
+ NB_OP_MODIFY, le_str);
+ } else {
+ nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
+ }
+
+ return nb_cli_apply_changes(vty, xpath_entry);
+}
+
+DEFPY(
+ no_ipv6_prefix_list, no_ipv6_prefix_list_cmd,
+ "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR
+ ACCESS_LIST_ACTION_STR
+ "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 plist_remove(vty, "ipv6", name, seq_str, action,
+ (struct prefix *)prefix, ge, le);
+}
+
+DEFPY(
+ no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd,
+ "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_SEQ_STR)
+{
+ return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0);
+}
+
+DEFPY(
+ no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd,
+ "no ipv6 prefix-list WORD$name",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd,
+ "ipv6 prefix-list WORD$name description LINE...",
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+{
+ int rv;
+ char *remark;
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ remark = argv_concat(argv, argc, 4);
+ nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
+ rv = nb_cli_apply_changes(vty, xpath);
+ XFREE(MTYPE_TMP, remark);
+
+ return rv;
+}
+
+DEFPY(
+ no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd,
+ "no ipv6 prefix-list WORD$name description",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+ALIAS(
+ no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_line_cmd,
+ "no ipv6 prefix-list WORD$name description LINE...",
+ NO_STR
+ IPV6_STR
+ PREFIX_LIST_STR
+ PREFIX_LIST_NAME_STR
+ ACCESS_LIST_REMARK_STR
+ ACCESS_LIST_REMARK_LINE_STR)
+
+void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int type = yang_dnode_get_enum(dnode, "../type");
+ const char *ge_str = NULL, *le_str = NULL;
+ bool is_any;
+ struct prefix p;
+
+ is_any = yang_dnode_exists(dnode, "./any");
+ switch (type) {
+ case YPLT_IPV4:
+ if (!is_any)
+ yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
+ if (yang_dnode_exists(dnode,
+ "./ipv4-prefix-length-greater-or-equal"))
+ ge_str = yang_dnode_get_string(
+ dnode, "./ipv4-prefix-length-greater-or-equal");
+ if (yang_dnode_exists(dnode,
+ "./ipv4-prefix-length-lesser-or-equal"))
+ le_str = yang_dnode_get_string(
+ dnode, "./ipv4-prefix-length-lesser-or-equal");
+
+ vty_out(vty, "ip ");
+ break;
+ case YPLT_IPV6:
+ if (!is_any)
+ yang_dnode_get_prefix(&p, dnode, "ipv6-prefix");
+ if (yang_dnode_exists(dnode,
+ "./ipv6-prefix-length-greater-or-equal"))
+ ge_str = yang_dnode_get_string(
+ dnode, "./ipv6-prefix-length-greater-or-equal");
+ if (yang_dnode_exists(dnode,
+ "./ipv6-prefix-length-lesser-or-equal"))
+ le_str = yang_dnode_get_string(
+ dnode, "./ipv6-prefix-length-lesser-or-equal");
+
+ vty_out(vty, "ipv6 ");
+ break;
+ }
+
+ vty_out(vty, "prefix-list %s seq %s %s",
+ yang_dnode_get_string(dnode, "../name"),
+ yang_dnode_get_string(dnode, "./sequence"),
+ yang_dnode_get_string(dnode, "./action"));
+
+ if (is_any) {
+ vty_out(vty, " any\n");
+ return;
+ }
+
+ vty_out(vty, " %pFX", &p);
+ if (ge_str)
+ vty_out(vty, " ge %s", ge_str);
+ if (le_str)
+ vty_out(vty, " le %s", le_str);
+
+ vty_out(vty, "\n");
+}
+
+void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ int type = yang_dnode_get_enum(dnode, "../type");
+
+ switch (type) {
+ case YPLT_IPV4:
+ vty_out(vty, "ip ");
+ break;
+ case YPLT_IPV6:
+ vty_out(vty, "ipv6 ");
+ break;
+ }
+
+ vty_out(vty, "prefix-list %s description %s\n",
+ yang_dnode_get_string(dnode, "../name"),
+ yang_dnode_get_string(dnode, NULL));
+}
+
+void filter_cli_init(void)
+{
+ /* access-list cisco-style (legacy). */
+ install_element(CONFIG_NODE, &access_list_std_cmd);
+ install_element(CONFIG_NODE, &no_access_list_std_cmd);
+ install_element(CONFIG_NODE, &access_list_ext_cmd);
+ install_element(CONFIG_NODE, &no_access_list_ext_cmd);
+ install_element(CONFIG_NODE, &no_access_list_legacy_cmd);
+ install_element(CONFIG_NODE, &access_list_legacy_remark_cmd);
+ install_element(CONFIG_NODE, &no_access_list_legacy_remark_cmd);
+ install_element(CONFIG_NODE, &no_access_list_legacy_remark_line_cmd);
+
+ /* access-list zebra-style. */
+ install_element(CONFIG_NODE, &access_list_cmd);
+ install_element(CONFIG_NODE, &no_access_list_cmd);
+ install_element(CONFIG_NODE, &no_access_list_all_cmd);
+ install_element(CONFIG_NODE, &access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_access_list_remark_line_cmd);
+
+ install_element(CONFIG_NODE, &ipv6_access_list_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_access_list_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_access_list_all_cmd);
+ install_element(CONFIG_NODE, &ipv6_access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_access_list_remark_line_cmd);
+
+ install_element(CONFIG_NODE, &mac_access_list_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_all_cmd);
+ install_element(CONFIG_NODE, &mac_access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_mac_access_list_remark_line_cmd);
+
+ /* prefix lists. */
+ 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_remark_cmd);
+ install_element(CONFIG_NODE, &no_ip_prefix_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_ip_prefix_list_remark_line_cmd);
+
+ 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_seq_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_prefix_list_all_cmd);
+ install_element(CONFIG_NODE, &ipv6_prefix_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_line_cmd);
+}
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
new file mode 100644
index 0000000000..83cf586ed3
--- /dev/null
+++ b/lib/filter_nb.c
@@ -0,0 +1,1286 @@
+/*
+ * FRR filter northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include "zebra.h"
+
+#include "lib/northbound.h"
+#include "lib/prefix.h"
+
+#include "lib/filter.h"
+#include "lib/plist.h"
+#include "lib/plist_int.h"
+
+/* Helper function. */
+static in_addr_t
+ipv4_network_addr(in_addr_t hostaddr, int masklen)
+{
+ struct in_addr mask;
+
+ masklen2ip(masklen, &mask);
+ return hostaddr & mask.s_addr;
+}
+
+static enum nb_error
+prefix_list_length_validate(const struct lyd_node *dnode)
+{
+ int type = yang_dnode_get_enum(dnode, "../../type");
+ const char *xpath_le = NULL, *xpath_ge = NULL;
+ struct prefix p;
+ uint8_t le, ge;
+
+ if (type == YPLT_IPV4) {
+ yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix");
+ xpath_le = "../ipv4-prefix-length-lesser-or-equal";
+ xpath_ge = "../ipv4-prefix-length-greater-or-equal";
+ } else {
+ yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix");
+ xpath_le = "../ipv6-prefix-length-lesser-or-equal";
+ xpath_ge = "../ipv6-prefix-length-greater-or-equal";
+ }
+
+ /*
+ * Check rule:
+ * prefix length <= le.
+ */
+ if (yang_dnode_exists(dnode, xpath_le)) {
+ le = yang_dnode_get_uint8(dnode, xpath_le);
+ if (p.prefixlen > le)
+ goto log_and_fail;
+
+ }
+
+ /*
+ * Check rule:
+ * prefix length < ge.
+ */
+ if (yang_dnode_exists(dnode, xpath_ge)) {
+ ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (p.prefixlen >= ge)
+ goto log_and_fail;
+ }
+
+ /*
+ * Check rule:
+ * ge <= le.
+ */
+ if (yang_dnode_exists(dnode, xpath_le) &&
+ yang_dnode_exists(dnode, xpath_ge)) {
+ le = yang_dnode_get_uint8(dnode, xpath_le);
+ ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (ge > le)
+ goto log_and_fail;
+ }
+
+ return NB_OK;
+
+ log_and_fail:
+ zlog_info("prefix-list: invalid prefix range for %pFX: "
+ "Make sure that mask length < ge <= le", &p);
+ return NB_ERR_VALIDATION;
+}
+
+/**
+ * Sets prefix list entry to blank value.
+ *
+ * \param[out] ple prefix list entry to modify.
+ */
+static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
+{
+ ple->any = false;
+ memset(&ple->prefix, 0, sizeof(ple->prefix));
+ ple->ge = 0;
+ ple->le = 0;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy
+ */
+static int lib_access_list_legacy_create(struct nb_cb_create_args *args)
+{
+ struct access_list *acl;
+ const char *acl_name;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl_name = yang_dnode_get_string(args->dnode, "./number");
+ acl = access_list_get(AFI_IP, acl_name);
+ nb_running_set_entry(args->dnode, acl);
+
+ return NB_OK;
+}
+
+static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args)
+{
+ struct access_master *am;
+ struct access_list *acl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl = nb_running_unset_entry(args->dnode);
+ am = acl->master;
+ if (am->delete_hook)
+ am->delete_hook(acl);
+
+ access_list_delete(acl);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/remark
+ */
+static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args)
+{
+ struct access_list *acl;
+ const char *remark;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl = nb_running_get_entry(args->dnode, NULL, true);
+ if (acl->remark)
+ XFREE(MTYPE_TMP, acl->remark);
+
+ remark = yang_dnode_get_string(args->dnode, NULL);
+ acl->remark = XSTRDUP(MTYPE_TMP, remark);
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args)
+{
+ struct access_list *acl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl = nb_running_get_entry(args->dnode, NULL, true);
+ if (acl->remark)
+ XFREE(MTYPE_TMP, acl->remark);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry
+ */
+static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args)
+{
+ struct filter_cisco *fc;
+ struct access_list *acl;
+ struct filter *f;
+ uint32_t aclno;
+
+ /* TODO: validate `filter_lookup_cisco` returns NULL. */
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ aclno = yang_dnode_get_uint16(args->dnode, "../number");
+
+ f = filter_new();
+ f->cisco = 1;
+ f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
+ fc = &f->u.cfilter;
+ if ((aclno >= 1 && aclno <= 99) || (aclno >= 1300 && aclno <= 1999))
+ fc->extended = 0;
+ else
+ fc->extended = 1;
+
+ acl = nb_running_get_entry(args->dnode, NULL, true);
+ f->acl = acl;
+ access_list_filter_add(acl, f);
+ nb_running_set_entry(args->dnode, f);
+
+ return NB_OK;
+}
+
+static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args)
+{
+ struct access_list *acl;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_unset_entry(args->dnode);
+ acl = f->acl;
+ access_list_filter_delete(acl, f);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/action
+ */
+static int
+lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args)
+{
+ const char *filter_type;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ filter_type = yang_dnode_get_string(args->dnode, NULL);
+ if (strcmp(filter_type, "permit") == 0)
+ f->type = FILTER_PERMIT;
+ else
+ f->type = FILTER_DENY;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/host
+ */
+static int
+lib_access_list_legacy_entry_host_modify(struct nb_cb_modify_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
+ fc->addr_mask.s_addr = INADDR_ANY;
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_legacy_entry_host_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/network
+ */
+static int
+lib_access_list_legacy_entry_network_modify(struct nb_cb_modify_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+ struct prefix p;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ yang_dnode_get_prefix(&p, args->dnode, NULL);
+ fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
+ masklen2ip(p.prefixlen, &fc->addr_mask);
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_legacy_entry_network_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/any
+ */
+static int
+lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->addr.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/destination-host
+ */
+static int lib_access_list_legacy_entry_destination_host_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
+ fc->mask_mask.s_addr = INADDR_ANY;
+
+ return NB_OK;
+}
+
+static int lib_access_list_legacy_entry_destination_host_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/destination-network
+ */
+static int lib_access_list_legacy_entry_destination_network_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+ struct prefix p;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ yang_dnode_get_prefix(&p, args->dnode, NULL);
+ fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
+ masklen2ip(p.prefixlen, &fc->mask_mask);
+
+ return NB_OK;
+}
+
+static int lib_access_list_legacy_entry_destination_network_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list-legacy/entry/destination-any
+ */
+static int lib_access_list_legacy_entry_destination_any_create(
+ struct nb_cb_create_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+static int lib_access_list_legacy_entry_destination_any_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = INADDR_NONE;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list
+ */
+static int lib_access_list_create(struct nb_cb_create_args *args)
+{
+ struct access_list *acl = NULL;
+ const char *acl_name;
+ int type;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ type = yang_dnode_get_enum(args->dnode, "./type");
+ acl_name = yang_dnode_get_string(args->dnode, "./name");
+
+ switch (type) {
+ case YALT_IPV4:
+ acl = access_list_get(AFI_IP, acl_name);
+ break;
+ case YALT_IPV6:
+ acl = access_list_get(AFI_IP6, acl_name);
+ break;
+ case YALT_MAC:
+ acl = access_list_get(AFI_L2VPN, acl_name);
+ break;
+ }
+
+ nb_running_set_entry(args->dnode, acl);
+
+ return NB_OK;
+}
+
+static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
+{
+ struct access_master *am;
+ struct access_list *acl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl = nb_running_unset_entry(args->dnode);
+ am = acl->master;
+ if (am->delete_hook)
+ am->delete_hook(acl);
+
+ access_list_delete(acl);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry
+ */
+static int lib_access_list_entry_create(struct nb_cb_create_args *args)
+{
+ struct access_list *acl;
+ struct filter *f;
+
+ /* TODO: validate `filter_lookup_zebra` returns NULL. */
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = filter_new();
+ f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
+
+ acl = nb_running_get_entry(args->dnode, NULL, true);
+ f->acl = acl;
+ access_list_filter_add(acl, f);
+ nb_running_set_entry(args->dnode, f);
+
+ return NB_OK;
+}
+
+static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
+{
+ struct access_list *acl;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_unset_entry(args->dnode);
+ acl = f->acl;
+ access_list_filter_delete(acl, f);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
+ */
+static int
+lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ memset(&fz->prefix, 0, sizeof(fz->prefix));
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
+ */
+static int
+lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ fz->exact = yang_dnode_get_bool(args->dnode, NULL);
+
+ return NB_OK;
+}
+
+static int
+lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ fz->exact = 0;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry/any
+ */
+static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+ int type;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ memset(&fz->prefix, 0, sizeof(fz->prefix));
+
+ type = yang_dnode_get_enum(args->dnode, "../../type");
+ switch (type) {
+ case YALT_IPV4:
+ fz->prefix.family = AF_INET;
+ break;
+ case YALT_IPV6:
+ fz->prefix.family = AF_INET6;
+ break;
+ case YALT_MAC:
+ fz->prefix.family = AF_ETHERNET;
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_zebra *fz;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fz = &f->u.zfilter;
+ fz->prefix.family = 0;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list
+ */
+static int lib_prefix_list_create(struct nb_cb_create_args *args)
+{
+ struct prefix_list *pl = NULL;
+ const char *name;
+ int type;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ type = yang_dnode_get_enum(args->dnode, "./type");
+ name = yang_dnode_get_string(args->dnode, "./name");
+ switch (type) {
+ case 0: /* ipv4 */
+ pl = prefix_list_get(AFI_IP, 0, name);
+ break;
+ case 1: /* ipv6 */
+ pl = prefix_list_get(AFI_IP6, 0, name);
+ break;
+ }
+
+ nb_running_set_entry(args->dnode, pl);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_destroy(struct nb_cb_destroy_args *args)
+{
+ struct prefix_list *pl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pl = nb_running_unset_entry(args->dnode);
+ prefix_list_delete(pl);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/remark
+ */
+static int lib_prefix_list_remark_modify(struct nb_cb_modify_args *args)
+{
+ struct prefix_list *pl;
+ const char *remark;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pl = nb_running_get_entry(args->dnode, NULL, true);
+ if (pl->desc)
+ XFREE(MTYPE_TMP, pl->desc);
+
+ remark = yang_dnode_get_string(args->dnode, NULL);
+ pl->desc = XSTRDUP(MTYPE_TMP, remark);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_remark_destroy(struct nb_cb_destroy_args *args)
+{
+ struct prefix_list *pl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pl = nb_running_get_entry(args->dnode, NULL, true);
+ if (pl->desc)
+ XFREE(MTYPE_TMP, pl->desc);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry
+ */
+static int lib_prefix_list_entry_create(struct nb_cb_create_args *args)
+{
+ struct prefix_list_entry *ple;
+ struct prefix_list *pl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pl = nb_running_get_entry(args->dnode, NULL, true);
+ ple = prefix_list_entry_new();
+ ple->pl = pl;
+ ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
+ prefix_list_entry_set_empty(ple);
+ nb_running_set_entry(args->dnode, ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_unset_entry(args->dnode);
+ if (ple->installed)
+ prefix_list_entry_delete2(ple);
+ else
+ prefix_list_entry_free(ple);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/action
+ */
+static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+ int action_type;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ action_type = yang_dnode_get_enum(args->dnode, NULL);
+ if (action_type == YPLA_PERMIT)
+ ple->type = PREFIX_PERMIT;
+ else
+ ple->type = PREFIX_DENY;
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
+ */
+static int
+lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+ struct prefix p;
+
+ if (args->event == NB_EV_VALIDATE) {
+ /*
+ * TODO: validate prefix_entry_dup_check() passes.
+ *
+ * This needs to be implemented using YANG lyd_node
+ * navigation, because the `priv` data structures are not
+ * available at `NB_EV_VALIDATE` phase. An easier
+ * alternative would be mark `ipvx-prefix` as unique
+ * (see RFC 7950, Section 7.8.3. The list "unique" Statement).
+ */
+ return NB_OK;
+ }
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ yang_dnode_get_prefix(&ple->prefix, args->dnode, NULL);
+
+ /* Apply mask and correct original address if necessary. */
+ prefix_copy(&p, &ple->prefix);
+ apply_mask(&p);
+ if (!prefix_same(&ple->prefix, &p)) {
+ zlog_info("%s: bad network %pFX correcting it to %pFX",
+ __func__, &ple->prefix, &p);
+ prefix_copy(&ple->prefix, &p);
+ }
+
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int
+lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ memset(&ple->prefix, 0, sizeof(ple->prefix));
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
+ */
+static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event == NB_EV_VALIDATE &&
+ prefix_list_length_validate(args->dnode) != NB_OK)
+ return NB_ERR_VALIDATION;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->ge = 0;
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
+ */
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event == NB_EV_VALIDATE &&
+ prefix_list_length_validate(args->dnode) != NB_OK)
+ return NB_ERR_VALIDATION;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->le = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->le = 0;
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/any
+ */
+static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
+{
+ struct prefix_list_entry *ple;
+ int type;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ ple->any = true;
+
+ /* Fill prefix struct from scratch. */
+ memset(&ple->prefix, 0, sizeof(ple->prefix));
+
+ type = yang_dnode_get_enum(args->dnode, "../../type");
+ switch (type) {
+ case YPLT_IPV4:
+ ple->prefix.family = AF_INET;
+ ple->ge = 0;
+ ple->le = IPV4_MAX_BITLEN;
+ break;
+ case YPLT_IPV6:
+ ple->prefix.family = AF_INET6;
+ ple->ge = 0;
+ ple->le = IPV6_MAX_BITLEN;
+ break;
+ }
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /* Start prefix entry update procedure. */
+ prefix_list_entry_update_start(ple);
+
+ prefix_list_entry_set_empty(ple);
+
+ /* Finish prefix entry update procedure. */
+ prefix_list_entry_update_finish(ple);
+
+ return NB_OK;
+}
+
+/* clang-format off */
+const struct frr_yang_module_info frr_filter_info = {
+ .name = "frr-filter",
+ .nodes = {
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy",
+ .cbs = {
+ .create = lib_access_list_legacy_create,
+ .destroy = lib_access_list_legacy_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/remark",
+ .cbs = {
+ .modify = lib_access_list_legacy_remark_modify,
+ .destroy = lib_access_list_legacy_remark_destroy,
+ .cli_show = access_list_legacy_remark_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry",
+ .cbs = {
+ .create = lib_access_list_legacy_entry_create,
+ .destroy = lib_access_list_legacy_entry_destroy,
+ .cli_show = access_list_legacy_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/action",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_action_modify,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/host",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_host_modify,
+ .destroy = lib_access_list_legacy_entry_host_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/network",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_network_modify,
+ .destroy = lib_access_list_legacy_entry_network_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/any",
+ .cbs = {
+ .create = lib_access_list_legacy_entry_any_create,
+ .destroy = lib_access_list_legacy_entry_any_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-host",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_destination_host_modify,
+ .destroy = lib_access_list_legacy_entry_destination_host_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-network",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_destination_network_modify,
+ .destroy = lib_access_list_legacy_entry_destination_network_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-any",
+ .cbs = {
+ .create = lib_access_list_legacy_entry_destination_any_create,
+ .destroy = lib_access_list_legacy_entry_destination_any_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list",
+ .cbs = {
+ .create = lib_access_list_create,
+ .destroy = lib_access_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/remark",
+ .cbs = {
+ .modify = lib_access_list_legacy_remark_modify,
+ .destroy = lib_access_list_legacy_remark_destroy,
+ .cli_show = access_list_remark_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry",
+ .cbs = {
+ .create = lib_access_list_entry_create,
+ .destroy = lib_access_list_entry_destroy,
+ .cli_show = access_list_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/action",
+ .cbs = {
+ .modify = lib_access_list_legacy_entry_action_modify,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
+ .cbs = {
+ .modify = lib_access_list_entry_ipv4_prefix_modify,
+ .destroy = lib_access_list_entry_ipv4_prefix_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
+ .cbs = {
+ .modify = lib_access_list_entry_ipv4_exact_match_modify,
+ .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/ipv6-prefix",
+ .cbs = {
+ .modify = lib_access_list_entry_ipv4_prefix_modify,
+ .destroy = lib_access_list_entry_ipv4_prefix_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/ipv6-exact-match",
+ .cbs = {
+ .modify = lib_access_list_entry_ipv4_exact_match_modify,
+ .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/mac",
+ .cbs = {
+ .modify = lib_access_list_entry_ipv4_prefix_modify,
+ .destroy = lib_access_list_entry_ipv4_prefix_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/access-list/entry/any",
+ .cbs = {
+ .create = lib_access_list_entry_any_create,
+ .destroy = lib_access_list_entry_any_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list",
+ .cbs = {
+ .create = lib_prefix_list_create,
+ .destroy = lib_prefix_list_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/remark",
+ .cbs = {
+ .modify = lib_prefix_list_remark_modify,
+ .destroy = lib_prefix_list_remark_destroy,
+ .cli_show = prefix_list_remark_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry",
+ .cbs = {
+ .create = lib_prefix_list_entry_create,
+ .destroy = lib_prefix_list_entry_destroy,
+ .cli_show = prefix_list_show,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/action",
+ .cbs = {
+ .modify = lib_prefix_list_entry_action_modify,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
+ .cbs = {
+ .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
+ .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-filter:lib/prefix-list/entry/any",
+ .cbs = {
+ .create = lib_prefix_list_entry_any_create,
+ .destroy = lib_prefix_list_entry_any_destroy,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/lib/plist.c b/lib/plist.c
index d18d51618a..981e86e2ac 100644
--- a/lib/plist.c
+++ b/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);
diff --git a/lib/plist.h b/lib/plist.h
index ba2846d74a..57eb763a68 100644
--- a/lib/plist.h
+++ b/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
diff --git a/lib/plist_int.h b/lib/plist_int.h
index ec8bbe1315..5e0beabbc6 100644
--- a/lib/plist_int.h
+++ b/lib/plist_int.h
@@ -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
diff --git a/lib/routemap.c b/lib/routemap.c
index 210512212d..3d69a3495a 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -2747,7 +2747,12 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
memset(&tmp_dep_data, 0, sizeof(struct route_map_dep_data));
tmp_dep_data.rname = rname;
dep_data = hash_lookup(dep->dep_rmap_hash, &tmp_dep_data);
- dep_data->refcnt--;
+
+ if (!dep_data)
+ goto out;
+
+ if (dep_data->refcnt)
+ dep_data->refcnt--;
if (!dep_data->refcnt) {
ret_dep_data = hash_release(dep->dep_rmap_hash,
diff --git a/lib/subdir.am b/lib/subdir.am
index b2f3e7c5de..57b2cea832 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -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 \
diff --git a/lib/yang.c b/lib/yang.c
index c80bf20306..7ac39f4182 100644
--- a/lib/yang.c
+++ b/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,
...)
{
diff --git a/lib/yang.h b/lib/yang.h
index 126521707b..3be0fe5383 100644
--- a/lib/yang.h
+++ b/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
@@ -358,6 +361,25 @@ 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.
*
diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c
index b58fe776ab..9fc13761c8 100644
--- a/nhrpd/nhrp_main.c
+++ b/nhrpd/nhrp_main.c
@@ -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,
};
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 4dbe5ca321..8ae5fdcf06 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -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,
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index 6a3ba9902d..e534e72a64 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -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,
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index b228847f06..57338738f6 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -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,
};
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 5c4c7151a5..132d913f68 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -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,
diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c
index 78be914cee..02f206144f 100644
--- a/pimd/pim_mlag.c
+++ b/pimd/pim_mlag.c
@@ -721,14 +721,19 @@ static void pim_mlag_process_vxlan_update(struct mlag_vxlan *msg)
static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg)
{
if (PIM_DEBUG_MLAG) {
+ struct prefix_sg sg;
+
+ sg.grp.s_addr = ntohl(msg.group_ip);
+ sg.src.s_addr = ntohl(msg.source_ip);
+
zlog_debug(
- "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x cost: %u",
- __func__, msg.vrf_name, msg.source_ip,
- msg.group_ip, msg.cost_to_rp);
+ "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x (%pSG4) cost: %u",
+ __func__, msg.vrf_name, msg.source_ip, msg.group_ip,
+ &sg, msg.cost_to_rp);
zlog_debug(
- "owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s",
- msg.owner_id, msg.am_i_dr, msg.am_i_dual_active,
- msg.vrf_id, msg.intf_name);
+ "(%pSG4)owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s",
+ &sg, msg.owner_id, msg.am_i_dr, msg.am_i_dual_active,
+ msg.vrf_id, msg.intf_name);
}
if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
@@ -746,12 +751,16 @@ static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg)
static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg)
{
if (PIM_DEBUG_MLAG) {
+ struct prefix_sg sg;
+
+ sg.grp.s_addr = ntohl(msg.group_ip);
+ sg.src.s_addr = ntohl(msg.source_ip);
zlog_debug(
- "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x ",
- __func__, msg.vrf_name, msg.source_ip,
- msg.group_ip);
- zlog_debug("owner_id: %d, vrf_id: 0x%x intf_name: %s",
- msg.owner_id, msg.vrf_id, msg.intf_name);
+ "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x(%pSG4)",
+ __func__, msg.vrf_name, msg.source_ip, msg.group_ip,
+ &sg);
+ zlog_debug("(%pSG4)owner_id: %d, vrf_id: 0x%x intf_name: %s",
+ &sg, msg.owner_id, msg.vrf_id, msg.intf_name);
}
if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 21febcc969..3ec0720fc4 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -375,6 +375,20 @@ static bool pim_channel_eval_oif_mute(struct channel_oil *c_oil,
return do_mute;
}
+ if (PIM_I_am_DualActive(pim_ifp)) {
+ struct pim_upstream *starup = c_oil->up->parent;
+ if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(c_oil->up->flags)
+ && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags)))
+ do_mute = true;
+
+ /* In case entry is (S,G), Negotiation happens at (*.G) */
+ if (starup
+
+ && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(starup->flags)
+ && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(starup->flags)))
+ do_mute = true;
+ return do_mute;
+ }
return do_mute;
}
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index b3379c67b2..8030835fb2 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -286,7 +286,8 @@ static inline bool pim_up_mlag_is_local(struct pim_upstream *up)
/* XXX: extend this to also return true if the channel-oil has
* any AA devices
*/
- return (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN);
+ return (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN
+ | PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE));
}
struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
index 9ec32a53e3..7e381887fc 100644
--- a/ripd/rip_main.c
+++ b/ripd/rip_main.c
@@ -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,
diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
index fbac750db3..010bac851b 100644
--- a/ripngd/ripng_main.c
+++ b/ripngd/ripng_main.c
@@ -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,
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index 120d704918..db65836388 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -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,
diff --git a/staticd/static_main.c b/staticd/static_main.c
index c77a99f280..08062f19d8 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -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,
};
diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
index ebd6075b52..459af486ff 100644
--- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
+++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
@@ -102,12 +102,12 @@ def test_bgp_as_wide_bgp_identifier():
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_converge, tgen.gears["r1"])
- success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5)
assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"])
test_func = functools.partial(_bgp_failed, tgen.gears["r3"])
- success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5)
assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format(
tgen.gears["r3"]
diff --git a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
index 652978aff8..0416bd6ce2 100644
--- a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json
@@ -113,32 +113,32 @@
"extendedLink":[
{
"prefix":"10.0.0.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
"prefix":"10.0.0.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r1-eth0",
"nexthop":"10.0.0.2"
},
{
"prefix":"10.0.1.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
},
{
"prefix":"10.0.1.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r1-eth1",
"nexthop":"10.0.1.2"
diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
index 88ba28da42..5ae2399e5c 100644
--- a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
@@ -1,5 +1,5 @@
-{
- "20100":{
+[
+ {
"inLabel":20100,
"installed":true,
"nexthops":[
@@ -11,7 +11,7 @@
}
]
},
- "20200":{
+ {
"inLabel":20200,
"installed":true,
"nexthops":[
@@ -31,7 +31,7 @@
}
]
},
- "20300":{
+ {
"inLabel":20300,
"installed":true,
"nexthops":[
@@ -51,7 +51,7 @@
}
]
},
- "20400":{
+ {
"inLabel":20400,
"installed":true,
"nexthops":[
@@ -71,8 +71,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -84,8 +84,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -97,8 +97,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -110,8 +110,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -123,4 +123,4 @@
}
]
}
-}
+]
diff --git a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
index 13437c9cf5..eb202b82cd 100644
--- a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json
@@ -27,64 +27,64 @@
"extendedLink":[
{
"prefix":"10.0.4.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth3",
"nexthop":"10.0.4.1"
},
{
"prefix":"10.0.4.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth3",
"nexthop":"10.0.4.1"
},
{
"prefix":"10.0.0.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth0",
"nexthop":"10.0.0.1"
},
{
"prefix":"10.0.0.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth0",
"nexthop":"10.0.0.1"
},
{
"prefix":"10.0.1.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth1",
"nexthop":"10.0.1.1"
},
{
"prefix":"10.0.1.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth1",
"nexthop":"10.0.1.1"
},
{
"prefix":"10.0.3.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth2",
"nexthop":"10.0.3.1"
},
{
"prefix":"10.0.3.2\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r2-eth2",
"nexthop":"10.0.3.1"
diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
index 2931b7dc34..aedcc5b8f8 100644
--- a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
@@ -1,5 +1,5 @@
-{
- "8100":{
+[
+ {
"inLabel":8100,
"installed":true,
"nexthops":[
@@ -19,7 +19,7 @@
}
]
},
- "8300":{
+ {
"inLabel":8300,
"installed":true,
"nexthops":[
@@ -32,7 +32,7 @@
}
]
},
- "8400":{
+ {
"inLabel":8400,
"installed":true,
"nexthops":[
@@ -45,8 +45,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -58,8 +58,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -71,8 +71,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -84,8 +84,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -97,8 +97,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -110,8 +110,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -123,8 +123,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -136,8 +136,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -149,4 +149,4 @@
}
]
}
-}
+]
diff --git a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
index d070aafb1e..b36fe674ad 100644
--- a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json
@@ -77,16 +77,16 @@
"extendedLink":[
{
"prefix":"10.0.3.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
},
{
"prefix":"10.0.3.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
index c9264d8a42..71e8366137 100644
--- a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
@@ -1,5 +1,5 @@
-{
- "10100":{
+[
+ {
"inLabel":10100,
"installed":true,
"nexthops":[
@@ -12,7 +12,7 @@
}
]
},
- "10200":{
+ {
"inLabel":10200,
"installed":true,
"nexthops":[
@@ -25,7 +25,7 @@
}
]
},
- "10400":{
+ {
"inLabel":10400,
"installed":true,
"nexthops":[
@@ -38,8 +38,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -51,8 +51,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -64,4 +64,4 @@
}
]
}
-}
+]
diff --git a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
index 17c0ea276e..d92ec91c72 100644
--- a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
+++ b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json
@@ -49,16 +49,16 @@
"extendedLink":[
{
"prefix":"10.0.4.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
},
{
"prefix":"10.0.4.1\/32",
- "sid":"XX",
- "inputLabel":"XX",
+ "sid":"*",
+ "inputLabel":"*",
"outputLabel":3,
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
diff --git a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
index 3a829fa858..b5767e1d7d 100644
--- a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
+++ b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
@@ -1,5 +1,5 @@
-{
- "10100":{
+[
+ {
"inLabel":10100,
"installed":true,
"nexthops":[
@@ -12,7 +12,7 @@
}
]
},
- "10200":{
+ {
"inLabel":10200,
"installed":true,
"nexthops":[
@@ -25,7 +25,7 @@
}
]
},
- "10300":{
+ {
"inLabel":10300,
"installed":true,
"nexthops":[
@@ -38,7 +38,7 @@
}
]
},
- "10400":{
+ {
"inLabel":10400,
"installed":true,
"nexthops":[
@@ -50,8 +50,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -63,8 +63,8 @@
}
]
},
- "XX":{
- "inLabel":"XX",
+ {
+ "inLabel":"*",
"installed":true,
"nexthops":[
{
@@ -76,4 +76,4 @@
}
]
}
-}
+]
diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
index 114de5861b..6792c56b3b 100755
--- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
+++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
@@ -29,6 +29,7 @@ test_ospf_sr_topo1.py: Test the FRR OSPF routing daemon with Segment Routing.
import os
import re
import sys
+import json
from functools import partial
# Save the Current Working Directory to find configuration files.
@@ -103,19 +104,6 @@ def setup_module(mod):
# Initialize all routers.
tgen.start_router()
- # Verify that version, MPLS and Segment Routing are OK
- for router in router_list.values():
- # Check for Version
- if router.has_version("<", "4"):
- tgen.set_error("Unsupported FRR version")
- break
- # Check that Segment Routing is available
- output = tgen.gears[router.name].vtysh_cmd(
- "show ip ospf database segment-routing json"
- )
- if output.find("Unknown") != -1:
- tgen.set_error("Segment Routing is not available")
-
def teardown_module(mod):
"Teardown the pytest environment"
@@ -126,37 +114,6 @@ def teardown_module(mod):
logger.info("\n\n---- OSPF Segment Routing tests End ----\n")
-# Shared test function to validate expected output.
-def compare_ospf_srdb(rname, expected):
- """
- Calls 'show ip ospf database segment-routing json' for router `rname`
- and compare the obtained result with the expected output.
- """
- tgen = get_topogen()
- current = tgen.gears[rname].vtysh_cmd("show ip ospf database segment-routing json")
- # Filter Adjacency SID allocation
- current = re.sub(r'"sid":5000[0-9],', '"sid":"XX",', current)
- current = re.sub(r'"inputLabel":5000[0-9],', '"inputLabel":"XX",', current)
- return topotest.difflines(
- current, expected, title1="Current output", title2="Expected output"
- )
-
-
-def compare_mpls_table(rname, expected):
- """
- Calls 'show mpls table json' for router `rname` and compare the obtained
- result with the expected output.
- """
- tgen = get_topogen()
- current = tgen.gears[rname].vtysh_cmd("show mpls table json")
- # Filter Adjacency SID allocation
- current = re.sub(r'"5000[0-9]":', '"XX":', current)
- current = re.sub(r'"inLabel":5000[0-9],', '"inLabel":"XX",', current)
- return topotest.difflines(
- current, expected, title1="Current output", title2="Expected output"
- )
-
-
def test_ospf_sr():
"Test OSPF daemon Segment Routing"
tgen = get_topogen()
@@ -172,12 +129,15 @@ def test_ospf_sr():
# Load expected results from the command
reffile = os.path.join(CWD, "{}/ospf_srdb.json".format(router))
- expected = open(reffile).read()
+ expected = json.loads(open(reffile).read())
# Run test function until we get an result. Wait at most 60 seconds.
- test_func = partial(compare_ospf_srdb, router, expected)
- result, diff = topotest.run_and_expect(test_func, "", count=25, wait=3)
- assert result, ("OSPF did not start Segment Routing on {}:\n{}").format(
+ rt = tgen.gears[router]
+ test_func = partial(
+ topotest.router_json_cmp, rt, 'show ip ospf database segment-routing json', expected
+ )
+ rv, diff = topotest.run_and_expect(test_func, None, count=25, wait=3)
+ assert rv, "OSPF did not start Segment Routing on {}:\n{}".format(
router, diff
)
@@ -190,6 +150,33 @@ def test_ospf_kernel_route():
logger.info("--- test OSPF Segment Routing MPLS tables ---")
+ def show_mpls_table_json_cmp(rt, expected):
+ """
+ Reformat MPLS table output to use a list of labels instead of dict.
+
+ Original:
+ {
+ "X": {
+ inLabel: "X",
+ # ...
+ }
+ }
+
+ List format:
+ [
+ {
+ inLabel: "X",
+ }
+ ]
+ """
+ out = rt.vtysh_cmd('show mpls table json', isjson=True)
+
+ outlist = []
+ for key in out.keys():
+ outlist.append(out[key])
+
+ return topotest.json_cmp(outlist, expected)
+
for rnum in range(1, 5):
router = "r{}".format(rnum)
@@ -197,12 +184,13 @@ def test_ospf_kernel_route():
# Load expected results from the command
reffile = os.path.join(CWD, "{}/zebra_mpls.json".format(router))
- expected = open(reffile).read()
+ expected = json.loads(open(reffile).read())
# Run test function until we get an result. Wait at most 60 seconds.
- test_func = partial(compare_mpls_table, router, expected)
- result, diff = topotest.run_and_expect(test_func, "", count=25, wait=3)
- assert result, ("OSPF did not properly instal MPLS table on {}:\n{}").format(
+ rt = tgen.gears[router]
+ test_func = partial(show_mpls_table_json_cmp, rt, expected)
+ rv, diff = topotest.run_and_expect(test_func, None, count=25, wait=3)
+ assert rv, "OSPF did not properly instal MPLS table on {}:\n{}".format(
router, diff
)
diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c
index 95b3cfad8f..d8c35dd2a3 100644
--- a/vrrpd/vrrp_main.c
+++ b/vrrpd/vrrp_main.c
@@ -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,
};
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index d5142b1b55..794e1f4c73 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -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$/) {
diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang
index c55af34161..78db201ea1 100644
--- a/yang/frr-filter.yang
+++ b/yang/frr-filter.yang
@@ -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;
+ key "sequence";
+
+ leaf sequence {
+ description "Access list sequence value";
+ type access-list-sequence;
}
- leaf any {
- description "Match any";
- type empty;
+
+ leaf action {
+ description "Access list action on match";
+ type access-list-action;
+ mandatory true;
}
- }
- choice extended-value {
- when "./sequence >= 100 and ./sequence <= 199 or
- ./sequence >= 2000 and ./sequence <= 2699";
- description "Destination value to match";
+ choice value {
+ description
+ "Standard access list: value to match.
+ Extended access list: source 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 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 sequence {
+ description "Access list sequence value";
+ type access-list-sequence;
+ }
- leaf ipv4-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 ipv6-prefix {
- when "./type = 'ipv6'";
- leaf ipv6-prefix {
- description "Configure IPv6 prefix to match";
- type inet:ipv6-prefix;
+ 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 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 ipv6-exact-match {
+ description "Exact match of prefix";
+ type boolean;
+ default false;
+ }
}
- }
- case mac {
- when "./type = 'mac'";
+ case mac {
+ when "../type = 'mac'";
- leaf mac {
- description "Configure MAC address to match";
- type yang:mac-address;
+ leaf mac {
+ description "Configure MAC address to match";
+ type yang:mac-address;
+ }
}
- }
- case any {
- leaf any {
- description "Match anything";
- type empty;
+ 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 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 ipv4-prefix-length-greater-or-equal {
- description
- "Specifies if matching prefixes with length greater than
- or equal to value";
- type uint8 {
- range "0..32";
+ 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-lesser-or-equal {
- description
- "Specifies if matching prefixes with length lesser than
- or equal to value";
- type uint8 {
- range "0..32";
+ 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";
+ }
}
- }
- }
- case ipv6-prefix {
- when "./type = 'ipv6'";
- leaf ipv6-prefix {
- description "Configure IPv6 prefix to match";
- type inet:ipv6-prefix;
+ 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-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 {
+ 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 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;
+ case any {
+ leaf any {
+ description "Match anything";
+ type empty;
+ }
}
}
}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index c743011224..7677db7efd 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1121,16 +1121,23 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
nl_msg_type_to_str(h->nlmsg_type));
return -1;
}
+
if (h->nlmsg_type == RTM_NEWADDR)
connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
ifa->ifa_prefixlen,
(struct in_addr *)broad, label,
metric);
- else
+ else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) {
+ /* Delete with a peer address */
+ connected_delete_ipv4(
+ ifp, flags, (struct in_addr *)addr,
+ ifa->ifa_prefixlen, broad);
+ } else
connected_delete_ipv4(
ifp, flags, (struct in_addr *)addr,
ifa->ifa_prefixlen, NULL);
}
+
if (ifa->ifa_family == AF_INET6) {
if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
zlog_err(
diff --git a/zebra/main.c b/zebra/main.c
index 05dd70ff7a..71c7ebb62f 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -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,