frr/lib/filter_cli.c
Rafael Zalamena ff94358e54 lib: fix rebase conflicts
Changes:
- Remove unused variable.
- Make prototypes static like the declaration.
- Fix new compilers complaint about uninitialized values.
- Fix new compilers complaint about small buffer for `snprintf` concatenation.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
2020-06-05 14:36:52 -03:00

1523 lines
44 KiB
C

/*
* 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 "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);
}
/*
* 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")
{
struct access_list *acl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char ipmask[64];
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[XPATH_MAXLEN + 64];
/*
* 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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use access-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = filter_new_seq_get(acl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (host_str != NULL && mask_str == NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/host",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, host_str);
} else if (host_str != NULL && mask_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/network",
xpath_entry);
concat_addr_mask_v4(host_str, mask_str, ipmask, sizeof(ipmask));
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ipmask);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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")
{
struct access_list *acl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char ipmask[64];
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[XPATH_MAXLEN + 64];
/*
* 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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use access-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = filter_new_seq_get(acl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (src_str != NULL && src_mask_str == NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/host",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, src_str);
} else if (src_str != NULL && src_mask_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/network",
xpath_entry);
concat_addr_mask_v4(src_str, src_mask_str, ipmask,
sizeof(ipmask));
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ipmask);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
if (dst_str != NULL && dst_mask_str == NULL) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/destination-host", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, src_str);
} else if (dst_str != NULL && dst_mask_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/destination-network", xpath_entry);
concat_addr_mask_v4(dst_str, dst_mask_str, ipmask,
sizeof(ipmask));
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ipmask);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/destination-any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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);
}
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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list-legacy[number='%s']", number_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 3);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
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);
}
/*
* 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")
{
struct access_list *acl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[XPATH_MAXLEN + 64];
/*
* 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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use access-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = filter_new_seq_get(acl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (prefix_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-prefix",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
prefix_str);
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv4-exact-match", xpath_entry);
if (exact)
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE,
NULL);
else
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY,
NULL);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 3);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
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);
}
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")
{
struct access_list *acl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[XPATH_MAXLEN + 64];
/*
* 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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use access-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = filter_new_seq_get(acl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (prefix_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-prefix",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
prefix_str);
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv6-exact-match", xpath_entry);
if (exact)
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE,
NULL);
else
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY,
NULL);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 3);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
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);
}
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")
{
struct access_list *acl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[XPATH_MAXLEN + 64];
/*
* 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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use access-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = filter_new_seq_get(acl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (mac_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/mac",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, mac_str);
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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/M$prefix [exact-match$exact]|any>",
NO_STR
MAC_STR
ACCESS_LIST_STR
ACCESS_LIST_ZEBRA_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"MAC address\n"
"Exact match of the prefixes\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, 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_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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='mac'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 3);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
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);
}
/*
* Prefix lists.
*/
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];
/* 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);
return nb_cli_apply_changes(vty, NULL);
}
/* 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. */
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);
return nb_cli_apply_changes(vty, NULL);
}
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")
{
struct prefix_list *pl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use prefix-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
pl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = prefix_new_seq_get(pl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (prefix_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-prefix",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
prefix_str);
if (ge_str) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv4-prefix-length-greater-or-equal",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
ge_str);
}
if (le_str) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv4-prefix-length-lesser-or-equal",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
le_str);
}
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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 remark 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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 4);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
XFREE(MTYPE_TMP, remark);
return rv;
}
DEFPY(
no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd,
"no ip prefix-list WORD$name remark",
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 remark 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")
{
struct prefix_list *pl;
struct lyd_node *dnode;
int rv;
int64_t sseq;
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
char xpath_value[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);
rv = nb_cli_apply_changes(vty, NULL);
if (rv != CMD_SUCCESS)
return rv;
/* Use prefix-list data structure to generate sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
pl = nb_running_get_entry(dnode, NULL, true);
if (seq_str == NULL) {
sseq = prefix_new_seq_get(pl);
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);
snprintf(xpath_value, sizeof(xpath_value), "%s/action", xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, action);
if (prefix_str != NULL) {
snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-prefix",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
prefix_str);
if (ge_str) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv6-prefix-length-greater-or-equal",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
ge_str);
}
if (le_str) {
snprintf(xpath_value, sizeof(xpath_value),
"%s/ipv6-prefix-length-lesser-or-equal",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
le_str);
}
} else {
snprintf(xpath_value, sizeof(xpath_value), "%s/any",
xpath_entry);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
}
return nb_cli_apply_changes(vty, NULL);
}
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 remark 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];
char xpath_remark[XPATH_MAXLEN + 32];
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_remark, sizeof(xpath_remark), "%s/remark", xpath);
remark = argv_concat(argv, argc, 4);
nb_cli_enqueue_change(vty, xpath_remark, NB_OP_CREATE, remark);
rv = nb_cli_apply_changes(vty, NULL);
XFREE(MTYPE_TMP, remark);
return rv;
}
DEFPY(
no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd,
"no ipv6 prefix-list WORD$name remark",
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 remark LINE...",
NO_STR
IPV6_STR
PREFIX_LIST_STR
PREFIX_LIST_NAME_STR
ACCESS_LIST_REMARK_STR
ACCESS_LIST_REMARK_LINE_STR)
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);
/* 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, &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, &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);
/* 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);
}