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_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/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_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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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)] 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] $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] $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] $action ip ", + 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] $action ip ", + 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] $action ", + 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] $action ", + 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] $action ", + 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] $action ", + 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] $action ", + 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] $action ", + 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] $action ", + 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 /, 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] $action ", + 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 /, 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)] $action ", + 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 /, 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] $action ", + 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 /, 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)] $action ", - 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 /, 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)] $action ", - 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 /, 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)] $action ", - 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 /, 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)] $action ", - 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 /, 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/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 @@ -357,6 +360,25 @@ extern struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, extern bool yang_dnode_exists(const struct lyd_node *dnode, const char *xpath_fmt, ...); +/* + * Iterate over all libyang data nodes that satisfy an XPath query. + * + * cb + * Function to call with each data node. + * + * arg + * Arbitrary argument passed as the second parameter in each call to 'cb'. + * + * dnode + * Base libyang data node to operate on. + * + * xpath_fmt + * XPath expression (absolute or relative). + */ +void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg, + const struct lyd_node *dnode, const char *xpath_fmt, + ...); + /* * Check if the libyang data node contains a default value. Non-presence * containers are assumed to always contain a default value. 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/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/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; - } - leaf any { - description "Match any"; - type empty; - } - } + key "sequence"; - choice extended-value { - when "./sequence >= 100 and ./sequence <= 199 or - ./sequence >= 2000 and ./sequence <= 2699"; - description "Destination value to match"; + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } - leaf destination-host { - description "Host to match"; - type inet:ipv4-address; + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; } - leaf destination-network { - description "Network to match"; - type inet:ipv4-prefix; + + choice value { + description + "Standard access list: value to match. + Extended access list: source value to match."; + mandatory true; + + leaf host { + description "Host to match"; + type inet:ipv4-address; + } + leaf network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf any { + description "Match any"; + type empty; + } } - leaf destination-any { - description "Match any"; - type empty; + + choice extended-value { + when "../number >= 100 and ../number <= 199 or + ../number >= 2000 and ../number <= 2699"; + description "Destination value to match"; + mandatory true; + + leaf destination-host { + description "Host to match"; + type inet:ipv4-address; + } + leaf destination-network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf destination-any { + description "Match any"; + type empty; + } } } } @@ -170,7 +179,7 @@ module frr-filter { list access-list { description "Access list instance"; - key "type identifier sequence"; + key "type name"; leaf type { description "Access list content type"; @@ -187,85 +196,80 @@ module frr-filter { description "Media Access Control address"; value 2; } - - /* - * Protocol YANG models should augment the parent node to - * contain the routing protocol specific value. The protocol - * must also augment `value` leaf to include its specific - * values or expand the `when` statement on the existing cases. - */ - enum custom { - description "Custom data type"; - value 100; - } } } - leaf identifier { - description "Access list identifier"; + leaf name { + description "Access list name"; type access-list-name; } - leaf sequence { - description "Access list sequence value"; - type access-list-sequence; - } - - leaf action { - description "Access list action on match"; - type access-list-action; - mandatory true; - } - leaf remark { description "Access list remark"; type string; } - choice value { - description "Access list value to match"; - mandatory true; + list entry { + description "Access list entry"; - case ipv4-prefix { - when "./type = 'ipv4'"; + key "sequence"; - leaf ipv4-prefix { - description "Configure IPv4 prefix to match"; - type inet:ipv4-prefix; - } - - leaf ipv4-exact-match { - description "Exact match of prefix"; - type boolean; - default false; - } + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; } - case ipv6-prefix { - when "./type = 'ipv6'"; - leaf ipv6-prefix { - description "Configure IPv6 prefix to match"; - type inet:ipv6-prefix; - } - - leaf ipv6-exact-match { - description "Exact match of prefix"; - type boolean; - default false; - } + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; } - case mac { - when "./type = 'mac'"; - leaf mac { - description "Configure MAC address to match"; - type yang:mac-address; + choice value { + description "Access list value to match"; + mandatory true; + + case ipv4-prefix { + when "../type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } } - } - case any { - leaf any { - description "Match anything"; - type empty; + case ipv6-prefix { + when "../type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case mac { + when "../type = 'mac'"; + + leaf mac { + description "Configure MAC address to match"; + type yang:mac-address; + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } } } } @@ -274,7 +278,7 @@ module frr-filter { list prefix-list { description "Prefix list instance"; - key "type name sequence"; + key "type name"; leaf type { description "Prefix list type"; @@ -295,82 +299,88 @@ module frr-filter { type access-list-name; } - leaf sequence { - description "Access list sequence value"; - type access-list-sequence; - } - - leaf action { - description "Prefix list action on match"; - type access-list-action; - mandatory true; - } - - leaf description { + leaf remark { description "Prefix list user description"; type string; } - choice value { - description "Prefix list value to match"; - mandatory true; + list entry { + description "Prefix list entry"; - case ipv4-prefix { - when "./type = 'ipv4'"; + key "sequence"; - leaf ipv4-prefix { - description "Configure IPv4 prefix to match"; - type inet:ipv4-prefix; - } - - leaf ipv4-prefix-length-greater-or-equal { - description - "Specifies if matching prefixes with length greater than - or equal to value"; - type uint8 { - range "0..32"; - } - } - - leaf ipv4-prefix-length-lesser-or-equal { - description - "Specifies if matching prefixes with length lesser than - or equal to value"; - type uint8 { - range "0..32"; - } - } + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; } - case ipv6-prefix { - when "./type = 'ipv6'"; - leaf ipv6-prefix { - description "Configure IPv6 prefix to match"; - type inet:ipv6-prefix; - } - - leaf ipv6-prefix-length-greater-or-equal { - description - "Specifies if matching prefixes with length greater than - or equal to value"; - type uint8 { - range "0..128"; - } - } - - leaf ipv6-prefix-length-lesser-or-equal { - description - "Specifies if matching prefixes with length lesser than - or equal to value"; - type uint8 { - range "0..128"; - } - } + leaf action { + description "Prefix list action on match"; + type access-list-action; + mandatory true; } - case any { - leaf any { - description "Match anything"; - type empty; + + choice value { + description "Prefix list value to match"; + mandatory true; + + case ipv4-prefix { + when "../type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..32"; + } + } + + leaf ipv4-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix { + when "../type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..128"; + } + } + + leaf ipv6-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..128"; + } + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } } } } 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,